convex 1.13.3-alpha.0 → 1.14.1
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/browser/node_modules/.modules.yaml +19 -0
- package/dist/browser.bundle.js +1 -1
- package/dist/browser.bundle.js.map +1 -1
- package/dist/cjs/cli/run.js +2 -1
- package/dist/cjs/cli/run.js.map +2 -2
- package/dist/cjs/index.js +1 -1
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/react/ConvexAuthState.js +7 -1
- package/dist/cjs/react/ConvexAuthState.js.map +2 -2
- package/dist/cjs/server/components/index.js.map +2 -2
- package/dist/cjs/server/index.js.map +2 -2
- package/dist/cjs/server/registration.js.map +1 -1
- package/dist/cjs/values/validator.js +16 -16
- package/dist/cjs/values/validator.js.map +2 -2
- package/dist/cjs-types/cli/run.d.ts.map +1 -1
- package/dist/cjs-types/index.d.ts +1 -1
- package/dist/cjs-types/index.d.ts.map +1 -1
- package/dist/cjs-types/react/ConvexAuthState.d.ts.map +1 -1
- package/dist/cjs-types/server/components/index.d.ts +1 -93
- package/dist/cjs-types/server/components/index.d.ts.map +1 -1
- package/dist/cjs-types/server/index.d.ts +0 -2
- package/dist/cjs-types/server/index.d.ts.map +1 -1
- package/dist/cjs-types/server/registration.d.ts +0 -28
- package/dist/cjs-types/server/registration.d.ts.map +1 -1
- package/dist/cjs-types/values/validator.d.ts +16 -16
- package/dist/cjs-types/values/validator.d.ts.map +1 -1
- package/dist/cli.bundle.cjs +3 -2
- package/dist/cli.bundle.cjs.map +2 -2
- package/dist/esm/cli/run.js +2 -1
- package/dist/esm/cli/run.js.map +2 -2
- package/dist/esm/index.js +1 -1
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/react/ConvexAuthState.js +7 -1
- package/dist/esm/react/ConvexAuthState.js.map +2 -2
- package/dist/esm/server/components/index.js.map +2 -2
- package/dist/esm/server/index.js.map +2 -2
- package/dist/esm/values/validator.js +16 -16
- package/dist/esm/values/validator.js.map +2 -2
- package/dist/esm-types/cli/run.d.ts.map +1 -1
- package/dist/esm-types/index.d.ts +1 -1
- package/dist/esm-types/index.d.ts.map +1 -1
- package/dist/esm-types/react/ConvexAuthState.d.ts.map +1 -1
- package/dist/esm-types/server/components/index.d.ts +1 -93
- package/dist/esm-types/server/components/index.d.ts.map +1 -1
- package/dist/esm-types/server/index.d.ts +0 -2
- package/dist/esm-types/server/index.d.ts.map +1 -1
- package/dist/esm-types/server/registration.d.ts +0 -28
- package/dist/esm-types/server/registration.d.ts.map +1 -1
- package/dist/esm-types/values/validator.d.ts +16 -16
- package/dist/esm-types/values/validator.d.ts.map +1 -1
- package/dist/react.bundle.js +8 -2
- package/dist/react.bundle.js.map +2 -2
- package/package.json +1 -1
- package/react/node_modules/.modules.yaml +19 -0
- package/react-auth0/node_modules/.modules.yaml +19 -0
- package/react-clerk/node_modules/.modules.yaml +19 -0
- package/scripts/postpack.mjs +2 -2
- package/server/node_modules/.modules.yaml +19 -0
- package/src/cli/run.ts +2 -1
- package/src/index.ts +1 -1
- package/src/react/ConvexAuthState.tsx +11 -4
- package/src/server/components/index.ts +22 -0
- package/src/server/index.ts +7 -0
- package/src/server/registration.ts +3 -19
- package/src/values/validator.ts +20 -17
- package/values/node_modules/.modules.yaml +19 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../browser-bundle.js", "../src/index.ts", "../src/values/base64.ts", "../src/common/index.ts", "../src/values/value.ts", "../src/values/errors.ts", "../src/browser/logging.ts", "../src/browser/sync/udf_path_utils.ts", "../src/browser/sync/local_state.ts", "../src/browser/sync/request_manager.ts", "../src/server/api.ts", "../src/browser/sync/optimistic_updates_impl.ts", "../src/browser/long.ts", "../src/browser/sync/remote_query_set.ts", "../src/browser/sync/protocol.ts", "../src/browser/sync/web_socket_manager.ts", "../src/browser/sync/session.ts", "../../common/temp/node_modules/.pnpm/jwt-decode@3.1.2/node_modules/jwt-decode/lib/atob.js", "../../common/temp/node_modules/.pnpm/jwt-decode@3.1.2/node_modules/jwt-decode/lib/base64_url_decode.js", "../../common/temp/node_modules/.pnpm/jwt-decode@3.1.2/node_modules/jwt-decode/lib/index.js", "../src/browser/sync/authentication_manager.ts", "../src/browser/sync/metrics.ts", "../src/browser/sync/client.ts", "../src/browser/simple_client.ts", "../src/browser/http_client.ts"],
|
|
4
|
-
"sourcesContent": ["// Code exposed in the browser bundle\n\nexport * from \"./src/browser/index.js\";\nexport { anyApi } from \"./src/server/index.js\";\n", "export const version = \"1.13.3-alpha.0\";", "/* eslint-disable no-var */\n\n/*\nhttps://github.com/beatgammit/base64-js/blob/88957c9943c7e2a0f03cdf73e71d579e433627d3/index.js\nCopyright (c) 2014 Jameson Little\nThe MIT License (MIT)\n*/\n\n// Vendored because this library has no ESM build, and some environments\n// (SvelteKit) are happiest when all dependencies are ESM.\n\nvar lookup: string[] = [];\nvar revLookup: number[] = [];\nvar Arr = Uint8Array;\n\nvar code = \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/\";\nfor (var i = 0, len = code.length; i < len; ++i) {\n lookup[i] = code[i];\n revLookup[code.charCodeAt(i)] = i;\n}\n\n// Support decoding URL-safe base64 strings, as Node.js does.\n// See: https://en.wikipedia.org/wiki/Base64#URL_applications\nrevLookup[\"-\".charCodeAt(0)] = 62;\nrevLookup[\"_\".charCodeAt(0)] = 63;\n\nfunction getLens(b64: string) {\n var len = b64.length;\n\n if (len % 4 > 0) {\n throw new Error(\"Invalid string. Length must be a multiple of 4\");\n }\n\n // Trim off extra bytes after placeholder bytes are found\n // See: https://github.com/beatgammit/base64-js/issues/42\n var validLen = b64.indexOf(\"=\");\n if (validLen === -1) validLen = len;\n\n var placeHoldersLen = validLen === len ? 0 : 4 - (validLen % 4);\n\n return [validLen, placeHoldersLen];\n}\n\n// base64 is 4/3 + up to two characters of the original data\n/** @public */\nexport function byteLength(b64: string): number {\n var lens = getLens(b64);\n var validLen = lens[0];\n var placeHoldersLen = lens[1];\n return ((validLen + placeHoldersLen) * 3) / 4 - placeHoldersLen;\n}\n\nfunction _byteLength(_b64: string, validLen: number, placeHoldersLen: number) {\n return ((validLen + placeHoldersLen) * 3) / 4 - placeHoldersLen;\n}\n\n/** @public */\nexport function toByteArray(b64: string): Uint8Array {\n var tmp;\n var lens = getLens(b64);\n var validLen = lens[0];\n var placeHoldersLen = lens[1];\n\n var arr = new Arr(_byteLength(b64, validLen, placeHoldersLen));\n\n var curByte = 0;\n\n // if there are placeholders, only get up to the last complete 4 chars\n var len = placeHoldersLen > 0 ? validLen - 4 : validLen;\n\n var i;\n for (i = 0; i < len; i += 4) {\n tmp =\n (revLookup[b64.charCodeAt(i)] << 18) |\n (revLookup[b64.charCodeAt(i + 1)] << 12) |\n (revLookup[b64.charCodeAt(i + 2)] << 6) |\n revLookup[b64.charCodeAt(i + 3)];\n arr[curByte++] = (tmp >> 16) & 0xff;\n arr[curByte++] = (tmp >> 8) & 0xff;\n arr[curByte++] = tmp & 0xff;\n }\n\n if (placeHoldersLen === 2) {\n tmp =\n (revLookup[b64.charCodeAt(i)] << 2) |\n (revLookup[b64.charCodeAt(i + 1)] >> 4);\n arr[curByte++] = tmp & 0xff;\n }\n\n if (placeHoldersLen === 1) {\n tmp =\n (revLookup[b64.charCodeAt(i)] << 10) |\n (revLookup[b64.charCodeAt(i + 1)] << 4) |\n (revLookup[b64.charCodeAt(i + 2)] >> 2);\n arr[curByte++] = (tmp >> 8) & 0xff;\n arr[curByte++] = tmp & 0xff;\n }\n\n return arr;\n}\n\nfunction tripletToBase64(num: number) {\n return (\n lookup[(num >> 18) & 0x3f] +\n lookup[(num >> 12) & 0x3f] +\n lookup[(num >> 6) & 0x3f] +\n lookup[num & 0x3f]\n );\n}\n\nfunction encodeChunk(uint8: Uint8Array, start: number, end: number) {\n var tmp;\n var output = [];\n for (var i = start; i < end; i += 3) {\n tmp =\n ((uint8[i] << 16) & 0xff0000) +\n ((uint8[i + 1] << 8) & 0xff00) +\n (uint8[i + 2] & 0xff);\n output.push(tripletToBase64(tmp));\n }\n return output.join(\"\");\n}\n\n/** @public */\nexport function fromByteArray(uint8: Uint8Array): string {\n var tmp;\n var len = uint8.length;\n var extraBytes = len % 3; // if we have 1 byte left, pad 2 bytes\n var parts = [];\n var maxChunkLength = 16383; // must be multiple of 3\n\n // go through the array every three bytes, we'll deal with trailing stuff later\n for (var i = 0, len2 = len - extraBytes; i < len2; i += maxChunkLength) {\n parts.push(\n encodeChunk(\n uint8,\n i,\n i + maxChunkLength > len2 ? len2 : i + maxChunkLength,\n ),\n );\n }\n\n // pad the end with zeros, but make sure to not forget the extra bytes\n if (extraBytes === 1) {\n tmp = uint8[len - 1];\n parts.push(lookup[tmp >> 2] + lookup[(tmp << 4) & 0x3f] + \"==\");\n } else if (extraBytes === 2) {\n tmp = (uint8[len - 2] << 8) + uint8[len - 1];\n parts.push(\n lookup[tmp >> 10] +\n lookup[(tmp >> 4) & 0x3f] +\n lookup[(tmp << 2) & 0x3f] +\n \"=\",\n );\n }\n\n return parts.join(\"\");\n}\n", "import type { Value } from \"../values/value.js\";\n\n/**\n * Validate that the arguments to a Convex function are an object, defaulting\n * `undefined` to `{}`.\n */\nexport function parseArgs(\n args: Record<string, Value> | undefined,\n): Record<string, Value> {\n if (args === undefined) {\n return {};\n }\n if (!isSimpleObject(args)) {\n throw new Error(\n `The arguments to a Convex function must be an object. Received: ${\n args as any\n }`,\n );\n }\n return args;\n}\n\nexport function validateDeploymentUrl(deploymentUrl: string) {\n // Don't use things like `new URL(deploymentUrl).hostname` since these aren't\n // supported by React Native's JS environment\n if (typeof deploymentUrl === \"undefined\") {\n throw new Error(\n `Client created with undefined deployment address. If you used an environment variable, check that it's set.`,\n );\n }\n if (typeof deploymentUrl !== \"string\") {\n throw new Error(\n `Invalid deployment address: found ${deploymentUrl as any}\".`,\n );\n }\n if (\n !(deploymentUrl.startsWith(\"http:\") || deploymentUrl.startsWith(\"https:\"))\n ) {\n throw new Error(\n `Invalid deployment address: Must start with \"https://\" or \"http://\". Found \"${deploymentUrl}\".`,\n );\n }\n\n // Most clients should connect to \".convex.cloud\". But we also support localhost and\n // custom custom. We validate the deployment url is a valid url, which is the most\n // common failure pattern.\n try {\n new URL(deploymentUrl);\n } catch (err) {\n throw new Error(\n `Invalid deployment address: \"${deploymentUrl}\" is not a valid URL. If you believe this URL is correct, use the \\`skipConvexDeploymentUrlCheck\\` option to bypass this.`,\n );\n }\n\n // If a user uses .convex.site, this is very likely incorrect.\n if (deploymentUrl.endsWith(\".convex.site\")) {\n throw new Error(\n `Invalid deployment address: \"${deploymentUrl}\" ends with .convex.site, which is used for HTTP Actions. Convex deployment URLs typically end with .convex.cloud? If you believe this URL is correct, use the \\`skipConvexDeploymentUrlCheck\\` option to bypass this.`,\n );\n }\n}\n\n/**\n * Check whether a value is a plain old JavaScript object.\n */\nexport function isSimpleObject(value: unknown) {\n const isObject = typeof value === \"object\";\n const prototype = Object.getPrototypeOf(value);\n const isSimple =\n prototype === null ||\n prototype === Object.prototype ||\n // Objects generated from other contexts (e.g. across Node.js `vm` modules) will not satisfy the previous\n // conditions but are still simple objects.\n prototype?.constructor?.name === \"Object\";\n return isObject && isSimple;\n}\n", "/**\n * Utilities for working with values stored in Convex.\n *\n * You can see the full set of supported types at\n * [Types](https://docs.convex.dev/using/types).\n * @module\n */\nimport * as Base64 from \"./base64.js\";\nimport { isSimpleObject } from \"../common/index.js\";\n\nconst LITTLE_ENDIAN = true;\n// This code is used by code that may not have bigint literals.\nconst MIN_INT64 = BigInt(\"-9223372036854775808\");\nconst MAX_INT64 = BigInt(\"9223372036854775807\");\nconst ZERO = BigInt(\"0\");\nconst EIGHT = BigInt(\"8\");\nconst TWOFIFTYSIX = BigInt(\"256\");\n\n/**\n * The type of JavaScript values serializable to JSON.\n *\n * @public\n */\nexport type JSONValue =\n | null\n | boolean\n | number\n | string\n | JSONValue[]\n | { [key: string]: JSONValue };\n\n/**\n * An identifier for a document in Convex.\n *\n * Convex documents are uniquely identified by their `Id`, which is accessible\n * on the `_id` field. To learn more, see [Document IDs](https://docs.convex.dev/database/document-ids).\n *\n * Documents can be loaded using `db.get(id)` in query and mutation functions.\n *\n * IDs are base 32 encoded strings which are URL safe.\n *\n * IDs are just strings at runtime, but this type can be used to distinguish them from other\n * strings at compile time.\n *\n * If you're using code generation, use the `Id` type generated for your data model in\n * `convex/_generated/dataModel.d.ts`.\n *\n * @typeParam TableName - A string literal type of the table name (like \"users\").\n *\n * @public\n */\nexport type Id<TableName extends string> = string & { __tableName: TableName };\n\n/**\n * A value supported by Convex.\n *\n * Values can be:\n * - stored inside of documents.\n * - used as arguments and return types to queries and mutation functions.\n *\n * You can see the full set of supported types at\n * [Types](https://docs.convex.dev/using/types).\n *\n * @public\n */\nexport type Value =\n | null\n | bigint\n | number\n | boolean\n | string\n | ArrayBuffer\n | Value[]\n | { [key: string]: undefined | Value };\n\n/**\n * The types of {@link Value} that can be used to represent numbers.\n *\n * @public\n */\nexport type NumericValue = bigint | number;\n\nfunction isSpecial(n: number) {\n return Number.isNaN(n) || !Number.isFinite(n) || Object.is(n, -0);\n}\n\nexport function slowBigIntToBase64(value: bigint): string {\n // the conversion is easy if we pretend it's unsigned\n if (value < ZERO) {\n value -= MIN_INT64 + MIN_INT64;\n }\n let hex = value.toString(16);\n if (hex.length % 2 === 1) hex = \"0\" + hex;\n\n const bytes = new Uint8Array(new ArrayBuffer(8));\n let i = 0;\n for (const hexByte of hex.match(/.{2}/g)!.reverse()) {\n bytes.set([parseInt(hexByte, 16)], i++);\n value >>= EIGHT;\n }\n return Base64.fromByteArray(bytes);\n}\n\nexport function slowBase64ToBigInt(encoded: string): bigint {\n const integerBytes = Base64.toByteArray(encoded);\n if (integerBytes.byteLength !== 8) {\n throw new Error(\n `Received ${integerBytes.byteLength} bytes, expected 8 for $integer`,\n );\n }\n let value = ZERO;\n let power = ZERO;\n for (const byte of integerBytes) {\n value += BigInt(byte) * TWOFIFTYSIX ** power;\n power++;\n }\n if (value > MAX_INT64) {\n value += MIN_INT64 + MIN_INT64;\n }\n return value;\n}\n\nexport function modernBigIntToBase64(value: bigint): string {\n if (value < MIN_INT64 || MAX_INT64 < value) {\n throw new Error(\n `BigInt ${value} does not fit into a 64-bit signed integer.`,\n );\n }\n const buffer = new ArrayBuffer(8);\n new DataView(buffer).setBigInt64(0, value, true);\n return Base64.fromByteArray(new Uint8Array(buffer));\n}\n\nexport function modernBase64ToBigInt(encoded: string): bigint {\n const integerBytes = Base64.toByteArray(encoded);\n if (integerBytes.byteLength !== 8) {\n throw new Error(\n `Received ${integerBytes.byteLength} bytes, expected 8 for $integer`,\n );\n }\n const intBytesView = new DataView(integerBytes.buffer);\n return intBytesView.getBigInt64(0, true);\n}\n\n// Fall back to a slower version on Safari 14 which lacks these APIs.\nexport const bigIntToBase64 = (DataView.prototype as any).setBigInt64\n ? modernBigIntToBase64\n : slowBigIntToBase64;\nexport const base64ToBigInt = (DataView.prototype as any).getBigInt64\n ? modernBase64ToBigInt\n : slowBase64ToBigInt;\n\nconst MAX_IDENTIFIER_LEN = 1024;\n\nfunction validateObjectField(k: string) {\n if (k.length > MAX_IDENTIFIER_LEN) {\n throw new Error(\n `Field name ${k} exceeds maximum field name length ${MAX_IDENTIFIER_LEN}.`,\n );\n }\n if (k.startsWith(\"$\")) {\n throw new Error(`Field name ${k} starts with a '$', which is reserved.`);\n }\n for (let i = 0; i < k.length; i += 1) {\n const charCode = k.charCodeAt(i);\n // Non-control ASCII characters\n if (charCode < 32 || charCode >= 127) {\n throw new Error(\n `Field name ${k} has invalid character '${k[i]}': Field names can only contain non-control ASCII characters`,\n );\n }\n }\n}\n\n/**\n * Parse a Convex value from its JSON representation.\n *\n * This function will deserialize serialized Int64s to `BigInt`s, Bytes to `ArrayBuffer`s etc.\n *\n * To learn more about Convex values, see [Types](https://docs.convex.dev/using/types).\n *\n * @param value - The JSON representation of a Convex value previously created with {@link convexToJson}.\n * @returns The JavaScript representation of the Convex value.\n *\n * @public\n */\nexport function jsonToConvex(value: JSONValue): Value {\n if (value === null) {\n return value;\n }\n if (typeof value === \"boolean\") {\n return value;\n }\n if (typeof value === \"number\") {\n return value;\n }\n if (typeof value === \"string\") {\n return value;\n }\n if (Array.isArray(value)) {\n return value.map((value) => jsonToConvex(value));\n }\n if (typeof value !== \"object\") {\n throw new Error(`Unexpected type of ${value as any}`);\n }\n const entries = Object.entries(value);\n if (entries.length === 1) {\n const key = entries[0][0];\n if (key === \"$bytes\") {\n if (typeof value.$bytes !== \"string\") {\n throw new Error(`Malformed $bytes field on ${value as any}`);\n }\n return Base64.toByteArray(value.$bytes).buffer;\n }\n if (key === \"$integer\") {\n if (typeof value.$integer !== \"string\") {\n throw new Error(`Malformed $integer field on ${value as any}`);\n }\n return base64ToBigInt(value.$integer);\n }\n if (key === \"$float\") {\n if (typeof value.$float !== \"string\") {\n throw new Error(`Malformed $float field on ${value as any}`);\n }\n const floatBytes = Base64.toByteArray(value.$float);\n if (floatBytes.byteLength !== 8) {\n throw new Error(\n `Received ${floatBytes.byteLength} bytes, expected 8 for $float`,\n );\n }\n const floatBytesView = new DataView(floatBytes.buffer);\n const float = floatBytesView.getFloat64(0, LITTLE_ENDIAN);\n if (!isSpecial(float)) {\n throw new Error(`Float ${float} should be encoded as a number`);\n }\n return float;\n }\n if (key === \"$set\") {\n throw new Error(\n `Received a Set which is no longer supported as a Convex type.`,\n );\n }\n if (key === \"$map\") {\n throw new Error(\n `Received a Map which is no longer supported as a Convex type.`,\n );\n }\n }\n const out: { [key: string]: Value } = {};\n for (const [k, v] of Object.entries(value)) {\n validateObjectField(k);\n out[k] = jsonToConvex(v);\n }\n return out;\n}\n\nexport function stringifyValueForError(value: any) {\n return JSON.stringify(value, (_key, value) => {\n if (value === undefined) {\n // By default `JSON.stringify` converts undefined, functions, symbols,\n // Infinity, and NaN to null which produces a confusing error message.\n // We deal with `undefined` specifically because it's the most common.\n // Ideally we'd use a pretty-printing library that prints `undefined`\n // (no quotes), but it might not be worth the bundle size cost.\n return \"undefined\";\n }\n if (typeof value === \"bigint\") {\n // `JSON.stringify` throws on bigints by default.\n return `${value.toString()}n`;\n }\n return value;\n });\n}\n\nfunction convexToJsonInternal(\n value: Value,\n originalValue: Value,\n context: string,\n includeTopLevelUndefined: boolean,\n): JSONValue {\n if (value === undefined) {\n const contextText =\n context &&\n ` (present at path ${context} in original object ${stringifyValueForError(\n originalValue,\n )})`;\n throw new Error(\n `undefined is not a valid Convex value${contextText}. To learn about Convex's supported types, see https://docs.convex.dev/using/types.`,\n );\n }\n if (value === null) {\n return value;\n }\n if (typeof value === \"bigint\") {\n if (value < MIN_INT64 || MAX_INT64 < value) {\n throw new Error(\n `BigInt ${value} does not fit into a 64-bit signed integer.`,\n );\n }\n return { $integer: bigIntToBase64(value) };\n }\n if (typeof value === \"number\") {\n if (isSpecial(value)) {\n const buffer = new ArrayBuffer(8);\n new DataView(buffer).setFloat64(0, value, LITTLE_ENDIAN);\n return { $float: Base64.fromByteArray(new Uint8Array(buffer)) };\n } else {\n return value;\n }\n }\n if (typeof value === \"boolean\") {\n return value;\n }\n if (typeof value === \"string\") {\n return value;\n }\n if (value instanceof ArrayBuffer) {\n return { $bytes: Base64.fromByteArray(new Uint8Array(value)) };\n }\n if (Array.isArray(value)) {\n return value.map((value, i) =>\n convexToJsonInternal(value, originalValue, context + `[${i}]`, false),\n );\n }\n if (value instanceof Set) {\n throw new Error(\n errorMessageForUnsupportedType(context, \"Set\", [...value], originalValue),\n );\n }\n if (value instanceof Map) {\n throw new Error(\n errorMessageForUnsupportedType(context, \"Map\", [...value], originalValue),\n );\n }\n\n if (!isSimpleObject(value)) {\n const theType = value?.constructor?.name;\n const typeName = theType ? `${theType} ` : \"\";\n throw new Error(\n errorMessageForUnsupportedType(context, typeName, value, originalValue),\n );\n }\n\n const out: { [key: string]: JSONValue } = {};\n const entries = Object.entries(value);\n entries.sort(([k1, _v1], [k2, _v2]) => (k1 === k2 ? 0 : k1 < k2 ? -1 : 1));\n for (const [k, v] of entries) {\n if (v !== undefined) {\n validateObjectField(k);\n out[k] = convexToJsonInternal(v, originalValue, context + `.${k}`, false);\n } else if (includeTopLevelUndefined) {\n validateObjectField(k);\n out[k] = convexOrUndefinedToJsonInternal(\n v,\n originalValue,\n context + `.${k}`,\n );\n }\n }\n return out;\n}\n\nfunction errorMessageForUnsupportedType(\n context: string,\n typeName: string,\n value: any,\n originalValue: any,\n) {\n if (context) {\n return `${typeName}${stringifyValueForError(\n value,\n )} is not a supported Convex type (present at path ${context} in original object ${stringifyValueForError(\n originalValue,\n )}). To learn about Convex's supported types, see https://docs.convex.dev/using/types.`;\n } else {\n return `${typeName}${stringifyValueForError(\n value,\n )} is not a supported Convex type.`;\n }\n}\n\n// convexOrUndefinedToJsonInternal wrapper exists so we can pipe through the\n// `originalValue` and `context` through for better error messaging.\nfunction convexOrUndefinedToJsonInternal(\n value: Value | undefined,\n originalValue: Value | undefined,\n context: string,\n): JSONValue {\n if (value === undefined) {\n return { $undefined: null };\n } else {\n if (originalValue === undefined) {\n // This should not happen.\n throw new Error(\n `Programming error. Current value is ${stringifyValueForError(\n value,\n )} but original value is undefined`,\n );\n }\n return convexToJsonInternal(value, originalValue, context, false);\n }\n}\n\n/**\n * Convert a Convex value to its JSON representation.\n *\n * Use {@link jsonToConvex} to recreate the original value.\n *\n * To learn more about Convex values, see [Types](https://docs.convex.dev/using/types).\n *\n * @param value - A Convex value to convert into JSON.\n * @returns The JSON representation of `value`.\n *\n * @public\n */\nexport function convexToJson(value: Value): JSONValue {\n return convexToJsonInternal(value, value, \"\", false);\n}\n\n// Convert a Convex value or `undefined` into its JSON representation.\n// `undefined` is used in filters to represent a missing object field.\nexport function convexOrUndefinedToJson(value: Value | undefined): JSONValue {\n return convexOrUndefinedToJsonInternal(value, value, \"\");\n}\n\n/**\n * Similar to convexToJson but also serializes top level undefined fields\n * using convexOrUndefinedToJson().\n *\n * @param value - A Convex value to convert into JSON.\n * @returns The JSON representation of `value`.\n */\nexport function patchValueToJson(value: Value): JSONValue {\n return convexToJsonInternal(value, value, \"\", true);\n}\n", "import { Value, stringifyValueForError } from \"./value.js\";\n\nconst IDENTIFYING_FIELD = Symbol.for(\"ConvexError\");\n\nexport class ConvexError<TData extends Value> extends Error {\n name = \"ConvexError\";\n data: TData;\n [IDENTIFYING_FIELD] = true;\n\n constructor(data: TData) {\n super(typeof data === \"string\" ? data : stringifyValueForError(data));\n this.data = data;\n }\n}\n", "import { 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 function logToConsole(\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 console.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 console.log(\n `%c[CONVEX ${prefix}(${udfPath})] [${level}]`,\n INFO_COLOR,\n args,\n );\n } else {\n console.error(`[CONVEX ${prefix}(${udfPath})] ${message}`);\n }\n}\n\nexport function logFatalError(message: string): Error {\n const errorMessage = `[CONVEX FATAL ERROR] ${message}`;\n console.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", "import { convexToJson, Value } from \"../../values/index.js\";\n\nexport function canonicalizeUdfPath(udfPath: string): string {\n const pieces = udfPath.split(\":\");\n let moduleName: string;\n let functionName: string;\n if (pieces.length === 1) {\n moduleName = pieces[0];\n functionName = \"default\";\n } else {\n moduleName = pieces.slice(0, pieces.length - 1).join(\":\");\n functionName = pieces[pieces.length - 1];\n }\n if (moduleName.endsWith(\".js\")) {\n moduleName = moduleName.slice(0, -3);\n }\n return `${moduleName}:${functionName}`;\n}\n\n/**\n * A string representing the name and arguments of a query.\n *\n * This is used by the {@link BaseConvexClient}.\n *\n * @public\n */\nexport type QueryToken = string;\n\nexport function serializePathAndArgs(\n udfPath: string,\n args: Record<string, Value>,\n): QueryToken {\n return JSON.stringify({\n udfPath: canonicalizeUdfPath(udfPath),\n args: convexToJson(args),\n });\n}\n", "import { convexToJson, Value } from \"../../values/index.js\";\nimport {\n AddQuery,\n RemoveQuery,\n QueryId,\n QuerySetModification,\n QuerySetVersion,\n IdentityVersion,\n Authenticate,\n QueryJournal,\n Transition,\n AdminAuthentication,\n UserIdentityAttributes,\n} from \"./protocol.js\";\nimport {\n canonicalizeUdfPath,\n QueryToken,\n serializePathAndArgs,\n} from \"./udf_path_utils.js\";\n\ntype LocalQuery = {\n id: QueryId;\n canonicalizedUdfPath: string;\n args: Record<string, Value>;\n numSubscribers: number;\n journal?: QueryJournal;\n};\n\nexport class LocalSyncState {\n private nextQueryId: QueryId;\n private querySetVersion: QuerySetVersion;\n private readonly querySet: Map<QueryToken, LocalQuery>;\n private readonly queryIdToToken: Map<QueryId, QueryToken>;\n private identityVersion: IdentityVersion;\n private auth?: {\n tokenType: \"Admin\" | \"User\";\n value: string;\n impersonating?: UserIdentityAttributes;\n };\n private readonly outstandingQueriesOlderThanRestart: Set<QueryId>;\n private outstandingAuthOlderThanRestart: boolean;\n\n constructor() {\n this.nextQueryId = 0;\n this.querySetVersion = 0;\n this.identityVersion = 0;\n this.querySet = new Map();\n this.queryIdToToken = new Map();\n this.outstandingQueriesOlderThanRestart = new Set();\n this.outstandingAuthOlderThanRestart = false;\n }\n\n hasSyncedPastLastReconnect(): boolean {\n return (\n this.outstandingQueriesOlderThanRestart.size === 0 &&\n !this.outstandingAuthOlderThanRestart\n );\n }\n\n markAuthCompletion() {\n this.outstandingAuthOlderThanRestart = false;\n }\n\n subscribe(\n udfPath: string,\n args: Record<string, Value>,\n journal?: QueryJournal,\n componentPath?: string,\n ): {\n queryToken: QueryToken;\n modification: QuerySetModification | null;\n unsubscribe: () => QuerySetModification | null;\n } {\n const canonicalizedUdfPath = canonicalizeUdfPath(udfPath);\n const queryToken = serializePathAndArgs(canonicalizedUdfPath, args);\n\n const existingEntry = this.querySet.get(queryToken);\n\n if (existingEntry !== undefined) {\n existingEntry.numSubscribers += 1;\n return {\n queryToken,\n modification: null,\n unsubscribe: () => this.removeSubscriber(queryToken),\n };\n } else {\n const queryId = this.nextQueryId++;\n const query: LocalQuery = {\n id: queryId,\n canonicalizedUdfPath,\n args,\n numSubscribers: 1,\n journal,\n };\n this.querySet.set(queryToken, query);\n this.queryIdToToken.set(queryId, queryToken);\n\n const baseVersion = this.querySetVersion;\n const newVersion = ++this.querySetVersion;\n\n const add: AddQuery = {\n type: \"Add\",\n queryId,\n udfPath: canonicalizedUdfPath,\n args: [convexToJson(args)],\n journal,\n componentPath,\n };\n const modification: QuerySetModification = {\n type: \"ModifyQuerySet\",\n baseVersion,\n newVersion,\n modifications: [add],\n };\n return {\n queryToken,\n modification,\n unsubscribe: () => this.removeSubscriber(queryToken),\n };\n }\n }\n\n transition(transition: Transition) {\n for (const modification of transition.modifications) {\n switch (modification.type) {\n case \"QueryUpdated\":\n case \"QueryFailed\": {\n this.outstandingQueriesOlderThanRestart.delete(modification.queryId);\n const journal = modification.journal;\n if (journal !== undefined) {\n const queryToken = this.queryIdToToken.get(modification.queryId);\n // We may have already unsubscribed to this query by the time the server\n // sends us the journal. If so, just ignore it.\n if (queryToken !== undefined) {\n this.querySet.get(queryToken)!.journal = journal;\n }\n }\n\n break;\n }\n case \"QueryRemoved\": {\n this.outstandingQueriesOlderThanRestart.delete(modification.queryId);\n break;\n }\n default: {\n // Enforce that the switch-case is exhaustive.\n const _: never = modification;\n throw new Error(`Invalid modification ${(modification as any).type}`);\n }\n }\n }\n }\n\n queryId(udfPath: string, args: Record<string, Value>): QueryId | null {\n const canonicalizedUdfPath = canonicalizeUdfPath(udfPath);\n const queryToken = serializePathAndArgs(canonicalizedUdfPath, args);\n const existingEntry = this.querySet.get(queryToken);\n if (existingEntry !== undefined) {\n return existingEntry.id;\n }\n return null;\n }\n\n isCurrentOrNewerAuthVersion(version: IdentityVersion): boolean {\n return version >= this.identityVersion;\n }\n\n setAuth(value: string): Authenticate {\n this.auth = {\n tokenType: \"User\",\n value: value,\n };\n const baseVersion = this.identityVersion++;\n return {\n type: \"Authenticate\",\n baseVersion: baseVersion,\n ...this.auth,\n };\n }\n\n setAdminAuth(\n value: string,\n actingAs?: UserIdentityAttributes,\n ): AdminAuthentication {\n const auth: typeof this.auth & {\n tokenType: \"Admin\";\n } = {\n tokenType: \"Admin\",\n value,\n impersonating: actingAs,\n };\n this.auth = auth;\n const baseVersion = this.identityVersion++;\n return {\n type: \"Authenticate\",\n baseVersion: baseVersion,\n ...auth,\n };\n }\n\n clearAuth(): Authenticate {\n this.auth = undefined;\n this.markAuthCompletion();\n const baseVersion = this.identityVersion++;\n return {\n type: \"Authenticate\",\n tokenType: \"None\",\n baseVersion: baseVersion,\n };\n }\n\n hasAuth(): boolean {\n return !!this.auth;\n }\n\n isNewAuth(value: string): boolean {\n return this.auth?.value !== value;\n }\n\n queryPath(queryId: QueryId): string | null {\n const pathAndArgs = this.queryIdToToken.get(queryId);\n if (pathAndArgs) {\n return this.querySet.get(pathAndArgs)!.canonicalizedUdfPath;\n }\n return null;\n }\n\n queryArgs(queryId: QueryId): Record<string, Value> | null {\n const pathAndArgs = this.queryIdToToken.get(queryId);\n if (pathAndArgs) {\n return this.querySet.get(pathAndArgs)!.args;\n }\n return null;\n }\n\n queryToken(queryId: QueryId): string | null {\n return this.queryIdToToken.get(queryId) ?? null;\n }\n\n queryJournal(queryToken: QueryToken): QueryJournal | undefined {\n return this.querySet.get(queryToken)?.journal;\n }\n\n restart(\n oldRemoteQueryResults: Set<QueryId>,\n ): [QuerySetModification, Authenticate?] {\n this.outstandingQueriesOlderThanRestart.clear();\n const modifications = [];\n for (const localQuery of this.querySet.values()) {\n const add: AddQuery = {\n type: \"Add\",\n queryId: localQuery.id,\n udfPath: localQuery.canonicalizedUdfPath,\n args: [convexToJson(localQuery.args)],\n journal: localQuery.journal,\n };\n modifications.push(add);\n\n if (!oldRemoteQueryResults.has(localQuery.id)) {\n this.outstandingQueriesOlderThanRestart.add(localQuery.id);\n }\n }\n this.querySetVersion = 1;\n const querySet: QuerySetModification = {\n type: \"ModifyQuerySet\",\n baseVersion: 0,\n newVersion: 1,\n modifications,\n };\n // If there's no auth, no need to send an update as the server will also start with an unknown identity.\n if (!this.auth) {\n this.identityVersion = 0;\n return [querySet, undefined];\n }\n this.outstandingAuthOlderThanRestart = true;\n const authenticate: Authenticate = {\n type: \"Authenticate\",\n baseVersion: 0,\n ...this.auth,\n };\n this.identityVersion = 1;\n return [querySet, authenticate];\n }\n\n resume(\n remoteQueryResults: Set<QueryId>,\n ): [QuerySetModification?, Authenticate?] {\n const localQueryIds = new Set();\n const modifications = [];\n for (const localQuery of this.querySet.values()) {\n localQueryIds.add(localQuery.id);\n\n if (!remoteQueryResults.has(localQuery.id)) {\n const add: AddQuery = {\n type: \"Add\",\n queryId: localQuery.id,\n udfPath: localQuery.canonicalizedUdfPath,\n args: [convexToJson(localQuery.args)],\n journal: localQuery.journal,\n };\n modifications.push(add);\n }\n }\n\n for (const remoteQueryId of remoteQueryResults) {\n if (!localQueryIds.has(remoteQueryId)) {\n const remove: RemoveQuery = {\n type: \"Remove\",\n queryId: remoteQueryId,\n };\n modifications.push(remove);\n }\n }\n\n const querySet: QuerySetModification | undefined =\n modifications.length > 0\n ? {\n type: \"ModifyQuerySet\",\n baseVersion: this.querySetVersion,\n newVersion: this.querySetVersion + 1,\n modifications,\n }\n : undefined;\n const authenticate: Authenticate | undefined =\n this.auth !== undefined\n ? {\n type: \"Authenticate\",\n baseVersion: this.identityVersion,\n ...this.auth,\n }\n : undefined;\n return [querySet, authenticate];\n }\n\n private removeSubscriber(\n queryToken: QueryToken,\n ): QuerySetModification | null {\n const localQuery = this.querySet.get(queryToken)!;\n\n if (localQuery.numSubscribers > 1) {\n localQuery.numSubscribers -= 1;\n return null;\n } else {\n this.querySet.delete(queryToken);\n this.queryIdToToken.delete(localQuery.id);\n this.outstandingQueriesOlderThanRestart.delete(localQuery.id);\n const baseVersion = this.querySetVersion;\n const newVersion = ++this.querySetVersion;\n const remove: RemoveQuery = {\n type: \"Remove\",\n queryId: localQuery.id,\n };\n return {\n type: \"ModifyQuerySet\",\n baseVersion,\n newVersion,\n modifications: [remove],\n };\n }\n }\n}\n", "import { jsonToConvex } from \"../../values/index.js\";\nimport { logToConsole } from \"../logging.js\";\nimport { Long } from \"../long.js\";\nimport { FunctionResult } from \"./function_result.js\";\nimport {\n ActionRequest,\n ActionResponse,\n ClientMessage,\n MutationRequest,\n MutationResponse,\n RequestId,\n} from \"./protocol.js\";\n\ntype RequestStatus =\n | {\n status: \"Requested\" | \"NotSent\";\n onResult: (result: FunctionResult) => void;\n requestedAt: Date;\n }\n | {\n status: \"Completed\";\n onResolve: () => void;\n ts: Long;\n };\n\nexport class RequestManager {\n private inflightRequests: Map<\n RequestId,\n {\n message: MutationRequest | ActionRequest;\n status: RequestStatus;\n }\n >;\n private requestsOlderThanRestart: Set<RequestId>;\n constructor() {\n this.inflightRequests = new Map();\n this.requestsOlderThanRestart = new Set();\n }\n\n request(\n message: MutationRequest | ActionRequest,\n sent: boolean,\n ): Promise<FunctionResult> {\n const result = new Promise<FunctionResult>((resolve) => {\n const status = sent ? \"Requested\" : \"NotSent\";\n this.inflightRequests.set(message.requestId, {\n message,\n status: { status, requestedAt: new Date(), onResult: resolve },\n });\n });\n\n return result;\n }\n\n /**\n * Update the state after receiving a response.\n *\n * @returns A RequestId if the request is complete and its optimistic update\n * can be dropped, null otherwise.\n */\n onResponse(response: MutationResponse | ActionResponse): RequestId | null {\n const requestInfo = this.inflightRequests.get(response.requestId);\n if (requestInfo === undefined) {\n // Annoyingly we can occasionally get responses to mutations that we're no\n // longer tracking. One flow where this happens is:\n // 1. Client sends mutation 1\n // 2. Client gets response for mutation 1. The sever says that it was committed at ts=10.\n // 3. Client is disconnected\n // 4. Client reconnects and re-issues queries and this mutation.\n // 5. Server sends transition message to ts=20\n // 6. Client drops mutation because it's already been observed.\n // 7. Client receives a second response for mutation 1 but doesn't know about it anymore.\n\n // The right fix for this is probably to add a reconciliation phase on\n // reconnection where we receive responses to all the mutations before\n // the transition message so this flow could never happen (CX-1513).\n\n // For now though, we can just ignore this message.\n return null;\n }\n\n // Because `.restart()` re-requests completed requests, we may get some\n // responses for requests that are already in the \"Completed\" state.\n // We can safely ignore those because we've already notified the UI about\n // their results.\n if (requestInfo.status.status === \"Completed\") {\n return null;\n }\n\n const udfType =\n requestInfo.message.type === \"Mutation\" ? \"mutation\" : \"action\";\n const udfPath = requestInfo.message.udfPath;\n\n for (const line of response.logLines) {\n logToConsole(\"info\", udfType, udfPath, line);\n }\n\n const status = requestInfo.status;\n let onResolve;\n if (response.success) {\n onResolve = () =>\n status.onResult({\n success: true,\n logLines: response.logLines,\n value: jsonToConvex(response.result),\n });\n } else {\n const errorMessage = response.result as string;\n const { errorData } = response;\n logToConsole(\"error\", udfType, udfPath, errorMessage);\n onResolve = () =>\n status.onResult({\n success: false,\n errorMessage,\n errorData:\n errorData !== undefined ? jsonToConvex(errorData) : undefined,\n logLines: response.logLines,\n });\n }\n\n // We can resolve Mutation failures immediately since they don't have any\n // side effects. Actions are intentionally decoupled from\n // queries/mutations here on the sync protocol since they have different\n // guarantees.\n if (response.type === \"ActionResponse\" || !response.success) {\n onResolve();\n this.inflightRequests.delete(response.requestId);\n this.requestsOlderThanRestart.delete(response.requestId);\n return response.requestId;\n }\n\n // We have to wait to resolve the request promise until after we transition\n // past this timestamp so clients can read their own writes.\n requestInfo.status = {\n status: \"Completed\",\n ts: response.ts,\n onResolve,\n };\n\n return null;\n }\n\n // Remove and returns completed requests.\n removeCompleted(ts: Long): Set<RequestId> {\n const completeRequests: Set<RequestId> = new Set();\n for (const [requestId, requestInfo] of this.inflightRequests.entries()) {\n const status = requestInfo.status;\n if (status.status === \"Completed\" && status.ts.lessThanOrEqual(ts)) {\n status.onResolve();\n completeRequests.add(requestId);\n this.inflightRequests.delete(requestId);\n this.requestsOlderThanRestart.delete(requestId);\n }\n }\n return completeRequests;\n }\n\n restart(): ClientMessage[] {\n // When we reconnect to the backend, re-request all requests that are safe\n // to be resend.\n\n this.requestsOlderThanRestart = new Set(this.inflightRequests.keys());\n const allMessages = [];\n for (const [requestId, value] of this.inflightRequests) {\n if (value.status.status === \"NotSent\") {\n value.status.status = \"Requested\";\n allMessages.push(value.message);\n continue;\n }\n\n if (value.message.type === \"Mutation\") {\n // This includes ones that have already been completed because we still\n // want to tell the backend to transition the client past the completed\n // timestamp. This is safe since mutations are idempotent.\n allMessages.push(value.message);\n } else {\n // Unlike mutations, actions are not idempotent. When we reconnect to the\n // backend, we don't know if it is safe to resend in-flight actions, so we\n // cancel them and consider them failed.\n this.inflightRequests.delete(requestId);\n this.requestsOlderThanRestart.delete(requestId);\n if (value.status.status === \"Completed\") {\n throw new Error(\"Action should never be in 'Completed' state\");\n }\n value.status.onResult({\n success: false,\n errorMessage: \"Connection lost while action was in flight\",\n logLines: [],\n });\n }\n }\n return allMessages;\n }\n\n resume(): ClientMessage[] {\n const allMessages = [];\n for (const [, value] of this.inflightRequests) {\n if (value.status.status === \"NotSent\") {\n value.status.status = \"Requested\";\n allMessages.push(value.message);\n continue;\n }\n }\n return allMessages;\n }\n\n /**\n * @returns true if there are any requests that have been requested but have\n * not be completed yet.\n */\n hasIncompleteRequests(): boolean {\n for (const requestInfo of this.inflightRequests.values()) {\n if (requestInfo.status.status === \"Requested\") {\n return true;\n }\n }\n return false;\n }\n\n /**\n * @returns true if there are any inflight requests, including ones that have\n * completed on the server, but have not been applied.\n */\n hasInflightRequests(): boolean {\n return this.inflightRequests.size > 0;\n }\n\n /**\n * @returns true if there are any inflight requests, that have been hanging around\n * since prior to the most recent restart.\n */\n hasSyncedPastLastReconnect(): boolean {\n return this.requestsOlderThanRestart.size === 0;\n }\n\n timeOfOldestInflightRequest(): Date | null {\n if (this.inflightRequests.size === 0) {\n return null;\n }\n let oldestInflightRequest = Date.now();\n for (const request of this.inflightRequests.values()) {\n if (request.status.status !== \"Completed\") {\n if (request.status.requestedAt.getTime() < oldestInflightRequest) {\n oldestInflightRequest = request.status.requestedAt.getTime();\n }\n }\n }\n return new Date(oldestInflightRequest);\n }\n}\n", "import {\n EmptyObject,\n DefaultFunctionArgs,\n FunctionVisibility,\n RegisteredAction,\n RegisteredMutation,\n RegisteredQuery,\n} from \"./registration.js\";\nimport { Expand, UnionToIntersection } from \"../type_utils.js\";\nimport { PaginationOptions, PaginationResult } from \"./pagination.js\";\n\n/**\n * The type of a Convex function.\n *\n * @public\n */\nexport type FunctionType = \"query\" | \"mutation\" | \"action\";\n\n/**\n * A reference to a registered Convex function.\n *\n * You can create a {@link FunctionReference} using the generated `api` utility:\n * ```js\n * import { api } from \"../convex/_generated/api\";\n *\n * const reference = api.myModule.myFunction;\n * ```\n *\n * If you aren't using code generation, you can create references using\n * {@link anyApi}:\n * ```js\n * import { anyApi } from \"convex/server\";\n *\n * const reference = anyApi.myModule.myFunction;\n * ```\n *\n * Function references can be used to invoke functions from the client. For\n * example, in React you can pass references to the {@link react.useQuery} hook:\n * ```js\n * const result = useQuery(api.myModule.myFunction);\n * ```\n *\n * @typeParam Type - The type of the function (\"query\", \"mutation\", or \"action\").\n * @typeParam Visibility - The visibility of the function (\"public\" or \"internal\").\n * @typeParam Args - The arguments to this function. This is an object mapping\n * argument names to their types.\n * @typeParam ReturnType - The return type of this function.\n * @public\n */\nexport type FunctionReference<\n Type extends FunctionType,\n Visibility extends FunctionVisibility = \"public\",\n Args extends DefaultFunctionArgs = any,\n ReturnType = any,\n ComponentPath = string | undefined,\n> = {\n _type: Type;\n _visibility: Visibility;\n _args: Args;\n _returnType: ReturnType;\n _componentPath: ComponentPath;\n};\n\n/**\n * A symbol for accessing the name of a {@link FunctionReference} at runtime.\n */\nexport const functionName = Symbol.for(\"functionName\");\n\n/**\n * Get the name of a function from a {@link FunctionReference}.\n *\n * The name is a string like \"myDir/myModule:myFunction\". If the exported name\n * of the function is `\"default\"`, the function name is omitted\n * (e.g. \"myDir/myModule\").\n *\n * @param functionReference - A {@link FunctionReference} to get the name of.\n * @returns A string of the function's name.\n *\n * @public\n */\nexport function getFunctionName(\n functionReference: AnyFunctionReference,\n): string {\n // Both a legacy thing and also a convenience for interactive use:\n // the types won't check but a string is always allowed at runtime.\n if (typeof functionReference === \"string\") return functionReference;\n\n // Two different runtime values for FunctionReference implement this\n // interface: api objects returned from `createApi()` and standalone\n // function reference objects returned from makeFunctionReference.\n const name = (functionReference as any)[functionName];\n if (!name) {\n throw new Error(`${functionReference as any} is not a functionReference`);\n }\n return name;\n}\n\n/**\n * FunctionReferences generally come from generated code, but in custom clients\n * it may be useful to be able to build one manually.\n *\n * Real function references are empty objects at runtime, but the same interface\n * can be implemented with an object for tests and clients which don't use\n * code generation.\n *\n * @param name - The identifier of the function. E.g. `path/to/file:functionName`\n * @public\n */\nexport function makeFunctionReference<\n type extends FunctionType,\n args extends DefaultFunctionArgs = any,\n ret = any,\n>(name: string): FunctionReference<type, \"public\", args, ret> {\n return { [functionName]: name } as unknown as FunctionReference<\n type,\n \"public\",\n args,\n ret\n >;\n}\n\n/**\n * Create a runtime API object that implements {@link AnyApi}.\n *\n * This allows accessing any path regardless of what directories, modules,\n * or functions are defined.\n *\n * @param pathParts - The path to the current node in the API.\n * @returns An {@link AnyApi}\n * @public\n */\nfunction createApi(pathParts: string[] = []): AnyApi {\n const handler: ProxyHandler<object> = {\n get(_, prop: string | symbol) {\n if (typeof prop === \"string\") {\n const newParts = [...pathParts, prop];\n return createApi(newParts);\n } else if (prop === functionName) {\n if (pathParts.length < 2) {\n const found = [\"api\", ...pathParts].join(\".\");\n throw new Error(\n `API path is expected to be of the form \\`api.moduleName.functionName\\`. Found: \\`${found}\\``,\n );\n }\n const path = pathParts.slice(0, -1).join(\"/\");\n const exportName = pathParts[pathParts.length - 1];\n if (exportName === \"default\") {\n return path;\n } else {\n return path + \":\" + exportName;\n }\n } else if (prop === Symbol.toStringTag) {\n return \"FunctionReference\";\n } else {\n return undefined;\n }\n },\n };\n\n return new Proxy({}, handler);\n}\n\n/**\n * Given an export from a module, convert it to a {@link FunctionReference}\n * if it is a Convex function.\n */\nexport type FunctionReferenceFromExport<Export> =\n Export extends RegisteredQuery<\n infer Visibility,\n infer Args,\n infer ReturnValue\n >\n ? FunctionReference<\n \"query\",\n Visibility,\n Args,\n ConvertReturnType<ReturnValue>\n >\n : Export extends RegisteredMutation<\n infer Visibility,\n infer Args,\n infer ReturnValue\n >\n ? FunctionReference<\n \"mutation\",\n Visibility,\n Args,\n ConvertReturnType<ReturnValue>\n >\n : Export extends RegisteredAction<\n infer Visibility,\n infer Args,\n infer ReturnValue\n >\n ? FunctionReference<\n \"action\",\n Visibility,\n Args,\n ConvertReturnType<ReturnValue>\n >\n : never;\n\n/**\n * Given a module, convert all the Convex functions into\n * {@link FunctionReference}s and remove the other exports.\n *\n * BE CAREFUL WHEN EDITING THIS!\n *\n * This is written carefully to preserve jumping to function definitions using\n * cmd+click. If you edit it, please test that cmd+click still works.\n */\ntype FunctionReferencesInModule<Module extends Record<string, any>> = {\n -readonly [ExportName in keyof Module as Module[ExportName][\"isConvexFunction\"] extends true\n ? ExportName\n : never]: FunctionReferenceFromExport<Module[ExportName]>;\n};\n\n/**\n * Given a path to a module and it's type, generate an API type for this module.\n *\n * This is a nested object according to the module's path.\n */\ntype ApiForModule<\n ModulePath extends string,\n Module extends object,\n> = ModulePath extends `${infer First}/${infer Second}`\n ? {\n [_ in First]: ApiForModule<Second, Module>;\n }\n : { [_ in ModulePath]: FunctionReferencesInModule<Module> };\n\n/**\n * Given the types of all modules in the `convex/` directory, construct the type\n * of `api`.\n *\n * `api` is a utility for constructing {@link FunctionReference}s.\n *\n * @typeParam AllModules - A type mapping module paths (like `\"dir/myModule\"`) to\n * the types of the modules.\n * @public\n */\nexport type ApiFromModules<AllModules extends Record<string, object>> =\n FilterApi<\n ApiFromModulesAllowEmptyNodes<AllModules>,\n FunctionReference<any, any, any, any>\n >;\n\ntype ApiFromModulesAllowEmptyNodes<AllModules extends Record<string, object>> =\n ExpandModulesAndDirs<\n UnionToIntersection<\n {\n [ModulePath in keyof AllModules]: ApiForModule<\n ModulePath & string,\n AllModules[ModulePath]\n >;\n }[keyof AllModules]\n >\n >;\n\n/**\n * @public\n *\n * Filter a Convex deployment api object for functions which meet criteria,\n * for example all public queries.\n */\nexport type FilterApi<API, Predicate> = Expand<{\n [mod in keyof API as API[mod] extends Predicate\n ? mod\n : API[mod] extends FunctionReference<any, any, any, any>\n ? never\n : FilterApi<API[mod], Predicate> extends Record<string, never>\n ? never\n : mod]: API[mod] extends Predicate\n ? API[mod]\n : FilterApi<API[mod], Predicate>;\n}>;\n\n/**\n * Given an api of type API and a FunctionReference subtype, return an api object\n * containing only the function references that match.\n *\n * ```ts\n * const q = filterApi<typeof api, FunctionReference<\"query\">>(api)\n * ```\n *\n * @public\n */\nexport function filterApi<API, Predicate>(api: API): FilterApi<API, Predicate> {\n return api as any;\n}\n\n// These just* API filter helpers require no type parameters so are useable from JavaScript.\n/** @public */\nexport function justInternal<API>(\n api: API,\n): FilterApi<API, FunctionReference<any, \"internal\", any, any>> {\n return api as any;\n}\n\n/** @public */\nexport function justPublic<API>(\n api: API,\n): FilterApi<API, FunctionReference<any, \"public\", any, any>> {\n return api as any;\n}\n\n/** @public */\nexport function justQueries<API>(\n api: API,\n): FilterApi<API, FunctionReference<\"query\", any, any, any>> {\n return api as any;\n}\n\n/** @public */\nexport function justMutations<API>(\n api: API,\n): FilterApi<API, FunctionReference<\"mutation\", any, any, any>> {\n return api as any;\n}\n\n/** @public */\nexport function justActions<API>(\n api: API,\n): FilterApi<API, FunctionReference<\"action\", any, any, any>> {\n return api as any;\n}\n\n/** @public */\nexport function justPaginatedQueries<API>(\n api: API,\n): FilterApi<\n API,\n FunctionReference<\n \"query\",\n any,\n { paginationOpts: PaginationOptions },\n PaginationResult<any>\n >\n> {\n return api as any;\n}\n\n/** @public */\nexport function justSchedulable<API>(\n api: API,\n): FilterApi<API, FunctionReference<\"mutation\" | \"action\", any, any, any>> {\n return api as any;\n}\n\n/**\n * Like {@link Expand}, this simplifies how TypeScript displays object types.\n * The differences are:\n * 1. This version is recursive.\n * 2. This stops recursing when it hits a {@link FunctionReference}.\n */\ntype ExpandModulesAndDirs<ObjectType> = ObjectType extends AnyFunctionReference\n ? ObjectType\n : {\n [Key in keyof ObjectType]: ExpandModulesAndDirs<ObjectType[Key]>;\n };\n\n/**\n * A {@link FunctionReference} of any type and any visibility with any\n * arguments and any return type.\n *\n * @public\n */\nexport type AnyFunctionReference = FunctionReference<any, any>;\n\ntype AnyModuleDirOrFunc = {\n [key: string]: AnyModuleDirOrFunc;\n} & AnyFunctionReference;\n\n/**\n * The type that Convex api objects extend. If you were writing an api from\n * scratch it should extend this type.\n *\n * @public\n */\nexport type AnyApi = Record<string, Record<string, AnyModuleDirOrFunc>>;\n\n/**\n * Recursive partial API, useful for defining a subset of an API when mocking\n * or building custom api objects.\n *\n * @public\n */\nexport type PartialApi<API> = {\n [mod in keyof API]?: API[mod] extends FunctionReference<any, any, any, any>\n ? API[mod]\n : PartialApi<API[mod]>;\n};\n\n/**\n * A utility for constructing {@link FunctionReference}s in projects that\n * are not using code generation.\n *\n * You can create a reference to a function like:\n * ```js\n * const reference = anyApi.myModule.myFunction;\n * ```\n *\n * This supports accessing any path regardless of what directories and modules\n * are in your project. All function references are typed as\n * {@link AnyFunctionReference}.\n *\n *\n * If you're using code generation, use `api` from `convex/_generated/api`\n * instead. It will be more type-safe and produce better auto-complete\n * in your editor.\n *\n * @public\n */\nexport const anyApi: AnyApi = createApi() as any;\n\n/**\n * Given a {@link FunctionReference}, get the return type of the function.\n *\n * This is represented as an object mapping argument names to values.\n * @public\n */\nexport type FunctionArgs<FuncRef extends AnyFunctionReference> =\n FuncRef[\"_args\"];\n\n/**\n * A tuple type of the (maybe optional) arguments to `FuncRef`.\n *\n * This type is used to make methods involving arguments type safe while allowing\n * skipping the arguments for functions that don't require arguments.\n *\n * @public\n */\nexport type OptionalRestArgs<FuncRef extends AnyFunctionReference> =\n FuncRef[\"_args\"] extends EmptyObject\n ? [args?: EmptyObject]\n : [args: FuncRef[\"_args\"]];\n\n/**\n * A tuple type of the (maybe optional) arguments to `FuncRef`, followed by an options\n * object of type `Options`.\n *\n * This type is used to make methods like `useQuery` type-safe while allowing\n * 1. Skipping arguments for functions that don't require arguments.\n * 2. Skipping the options object.\n * @public\n */\nexport type ArgsAndOptions<\n FuncRef extends AnyFunctionReference,\n Options,\n> = FuncRef[\"_args\"] extends EmptyObject\n ? [args?: EmptyObject, options?: Options]\n : [args: FuncRef[\"_args\"], options?: Options];\n\n/**\n * Given a {@link FunctionReference}, get the return type of the function.\n *\n * @public\n */\nexport type FunctionReturnType<FuncRef extends AnyFunctionReference> =\n FuncRef[\"_returnType\"];\n\ntype UndefinedToNull<T> = T extends void ? null : T;\n\ntype NullToUndefinedOrNull<T> = T extends null ? T | undefined | void : T;\n\n/**\n * Convert the return type of a function to it's client-facing format.\n *\n * This means:\n * - Converting `undefined` and `void` to `null`\n * - Removing all `Promise` wrappers\n */\nexport type ConvertReturnType<T> = UndefinedToNull<Awaited<T>>;\n\nexport type ValidatorTypeToReturnType<T> =\n | Promise<NullToUndefinedOrNull<T>>\n | NullToUndefinedOrNull<T>;\n", "import {\n FunctionArgs,\n FunctionReference,\n FunctionReturnType,\n OptionalRestArgs,\n getFunctionName,\n} from \"../../server/api.js\";\nimport { parseArgs } from \"../../common/index.js\";\nimport { Value } from \"../../values/index.js\";\nimport { createHybridErrorStacktrace, forwardData } from \"../logging.js\";\nimport { FunctionResult } from \"./function_result.js\";\nimport { OptimisticLocalStore } from \"./optimistic_updates.js\";\nimport { RequestId } from \"./protocol.js\";\nimport {\n canonicalizeUdfPath,\n QueryToken,\n serializePathAndArgs,\n} from \"./udf_path_utils.js\";\nimport { ConvexError } from \"../../values/errors.js\";\n\n/**\n * An optimistic update function that has been curried over its arguments.\n */\ntype WrappedOptimisticUpdate = (locaQueryStore: OptimisticLocalStore) => void;\n\n/**\n * The implementation of `OptimisticLocalStore`.\n *\n * This class provides the interface for optimistic updates to modify query results.\n */\nclass OptimisticLocalStoreImpl implements OptimisticLocalStore {\n // A references of the query results in OptimisticQueryResults\n private readonly queryResults: QueryResultsMap;\n\n // All of the queries modified by this class\n readonly modifiedQueries: QueryToken[];\n\n constructor(queryResults: QueryResultsMap) {\n this.queryResults = queryResults;\n this.modifiedQueries = [];\n }\n\n getQuery<Query extends FunctionReference<\"query\">>(\n query: Query,\n ...args: OptionalRestArgs<Query>\n ): undefined | FunctionReturnType<Query> {\n const queryArgs = parseArgs(args[0]);\n const name = getFunctionName(query);\n const queryResult = this.queryResults.get(\n serializePathAndArgs(name, queryArgs),\n );\n if (queryResult === undefined) {\n return undefined;\n }\n return OptimisticLocalStoreImpl.queryValue(queryResult.result);\n }\n\n getAllQueries<Query extends FunctionReference<\"query\">>(\n query: Query,\n ): {\n args: FunctionArgs<Query>;\n value: undefined | FunctionReturnType<Query>;\n }[] {\n const queriesWithName: {\n args: FunctionArgs<Query>;\n value: undefined | FunctionReturnType<Query>;\n }[] = [];\n const name = getFunctionName(query);\n for (const queryResult of this.queryResults.values()) {\n if (queryResult.udfPath === canonicalizeUdfPath(name)) {\n queriesWithName.push({\n args: queryResult.args as FunctionArgs<Query>,\n value: OptimisticLocalStoreImpl.queryValue(queryResult.result),\n });\n }\n }\n return queriesWithName;\n }\n\n setQuery<QueryReference extends FunctionReference<\"query\">>(\n queryReference: QueryReference,\n args: FunctionArgs<QueryReference>,\n value: undefined | FunctionReturnType<QueryReference>,\n ): void {\n const queryArgs = parseArgs(args);\n const name = getFunctionName(queryReference);\n const queryToken = serializePathAndArgs(name, queryArgs);\n\n let result: FunctionResult | undefined;\n if (value === undefined) {\n result = undefined;\n } else {\n result = {\n success: true,\n value,\n // It's an optimistic update, so there are no function logs to show.\n logLines: [],\n };\n }\n const query: Query = {\n udfPath: name,\n args: queryArgs,\n result,\n };\n this.queryResults.set(queryToken, query);\n this.modifiedQueries.push(queryToken);\n }\n\n private static queryValue(\n result: FunctionResult | undefined,\n ): Value | undefined {\n if (result === undefined) {\n return undefined;\n } else if (result.success) {\n return result.value;\n } else {\n // If the query is an error state, just return `undefined` as though\n // it's loading. Optimistic updates should already handle `undefined` well\n // and there isn't a need to break the whole update because it tried\n // to load a single query that errored.\n return undefined;\n }\n }\n}\n\ntype OptimisticUpdateAndId = {\n update: WrappedOptimisticUpdate;\n mutationId: RequestId;\n};\n\ntype Query = {\n // undefined means the query was set to be loading (undefined) in an optimistic update.\n // Note that we can also have queries not present in the QueryResultMap\n // at all because they are still loading from the server.\n result: FunctionResult | undefined;\n udfPath: string;\n args: Record<string, Value>;\n};\nexport type QueryResultsMap = Map<QueryToken, Query>;\n\ntype ChangedQueries = QueryToken[];\n\n/**\n * A view of all of our query results with optimistic updates applied on top.\n */\nexport class OptimisticQueryResults {\n private queryResults: QueryResultsMap;\n private optimisticUpdates: OptimisticUpdateAndId[];\n\n constructor() {\n this.queryResults = new Map();\n this.optimisticUpdates = [];\n }\n\n ingestQueryResultsFromServer(\n serverQueryResults: QueryResultsMap,\n optimisticUpdatesToDrop: Set<RequestId>,\n ): ChangedQueries {\n this.optimisticUpdates = this.optimisticUpdates.filter((updateAndId) => {\n return !optimisticUpdatesToDrop.has(updateAndId.mutationId);\n });\n\n const oldQueryResults = this.queryResults;\n this.queryResults = new Map(serverQueryResults);\n const localStore = new OptimisticLocalStoreImpl(this.queryResults);\n for (const updateAndId of this.optimisticUpdates) {\n updateAndId.update(localStore);\n }\n\n // To find the changed queries, just do a shallow comparison\n // TODO(CX-733): Change this so we avoid unnecessary rerenders\n const changedQueries: ChangedQueries = [];\n for (const [queryToken, query] of this.queryResults) {\n const oldQuery = oldQueryResults.get(queryToken);\n if (oldQuery === undefined || oldQuery.result !== query.result) {\n changedQueries.push(queryToken);\n }\n }\n\n return changedQueries;\n }\n\n applyOptimisticUpdate(\n update: WrappedOptimisticUpdate,\n mutationId: RequestId,\n ): ChangedQueries {\n // Apply the update to our store\n this.optimisticUpdates.push({\n update,\n mutationId,\n });\n const localStore = new OptimisticLocalStoreImpl(this.queryResults);\n update(localStore);\n\n // Notify about any query results that changed\n // TODO(CX-733): Change this so we avoid unnecessary rerenders\n return localStore.modifiedQueries;\n }\n\n queryResult(queryToken: QueryToken): Value | undefined {\n const query = this.queryResults.get(queryToken);\n if (query === undefined) {\n return undefined;\n }\n const result = query.result;\n if (result === undefined) {\n return undefined;\n } else if (result.success) {\n return result.value;\n } else {\n if (result.errorData !== undefined) {\n throw forwardData(\n result,\n new ConvexError(\n createHybridErrorStacktrace(\"query\", query.udfPath, result),\n ),\n );\n }\n throw new Error(\n createHybridErrorStacktrace(\"query\", query.udfPath, result),\n );\n }\n }\n\n hasQueryResult(queryToken: QueryToken): boolean {\n return this.queryResults.get(queryToken) !== undefined;\n }\n\n /**\n * @internal\n */\n queryLogs(queryToken: QueryToken): string[] | undefined {\n const query = this.queryResults.get(queryToken);\n return query?.result?.logLines;\n }\n}\n", "// Implements an unsigned long.\n// This is a subset of https://github.com/dcodeIO/Long.js,\n// vendored to decrease bundle size.\n// Copyright Daniel Wirtz <dcode@dcode.io>\n// License: Apache Version 2.0\n/*\n\n Apache License\n Version 2.0, January 2004\n http://www.apache.org/licenses/\n\n TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n 1. Definitions.\n\n \"License\" shall mean the terms and conditions for use, reproduction,\n and distribution as defined by Sections 1 through 9 of this document.\n\n \"Licensor\" shall mean the copyright owner or entity authorized by\n the copyright owner that is granting the License.\n\n \"Legal Entity\" shall mean the union of the acting entity and all\n other entities that control, are controlled by, or are under common\n control with that entity. For the purposes of this definition,\n \"control\" means (i) the power, direct or indirect, to cause the\n direction or management of such entity, whether by contract or\n otherwise, or (ii) ownership of fifty percent (50%) or more of the\n outstanding shares, or (iii) beneficial ownership of such entity.\n\n \"You\" (or \"Your\") shall mean an individual or Legal Entity\n exercising permissions granted by this License.\n\n \"Source\" form shall mean the preferred form for making modifications,\n including but not limited to software source code, documentation\n source, and configuration files.\n\n \"Object\" form shall mean any form resulting from mechanical\n transformation or translation of a Source form, including but\n not limited to compiled object code, generated documentation,\n and conversions to other media types.\n\n \"Work\" shall mean the work of authorship, whether in Source or\n Object form, made available under the License, as indicated by a\n copyright notice that is included in or attached to the work\n (an example is provided in the Appendix below).\n\n \"Derivative Works\" shall mean any work, whether in Source or Object\n form, that is based on (or derived from) the Work and for which the\n editorial revisions, annotations, elaborations, or other modifications\n represent, as a whole, an original work of authorship. For the purposes\n of this License, Derivative Works shall not include works that remain\n separable from, or merely link (or bind by name) to the interfaces of,\n the Work and Derivative Works thereof.\n\n \"Contribution\" shall mean any work of authorship, including\n the original version of the Work and any modifications or additions\n to that Work or Derivative Works thereof, that is intentionally\n submitted to Licensor for inclusion in the Work by the copyright owner\n or by an individual or Legal Entity authorized to submit on behalf of\n the copyright owner. For the purposes of this definition, \"submitted\"\n means any form of electronic, verbal, or written communication sent\n to the Licensor or its representatives, including but not limited to\n communication on electronic mailing lists, source code control systems,\n and issue tracking systems that are managed by, or on behalf of, the\n Licensor for the purpose of discussing and improving the Work, but\n excluding communication that is conspicuously marked or otherwise\n designated in writing by the copyright owner as \"Not a Contribution.\"\n\n \"Contributor\" shall mean Licensor and any individual or Legal Entity\n on behalf of whom a Contribution has been received by Licensor and\n subsequently incorporated within the Work.\n\n 2. Grant of Copyright License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n copyright license to reproduce, prepare Derivative Works of,\n publicly display, publicly perform, sublicense, and distribute the\n Work and such Derivative Works in Source or Object form.\n\n 3. Grant of Patent License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n (except as stated in this section) patent license to make, have made,\n use, offer to sell, sell, import, and otherwise transfer the Work,\n where such license applies only to those patent claims licensable\n by such Contributor that are necessarily infringed by their\n Contribution(s) alone or by combination of their Contribution(s)\n with the Work to which such Contribution(s) was submitted. If You\n institute patent litigation against any entity (including a\n cross-claim or counterclaim in a lawsuit) alleging that the Work\n or a Contribution incorporated within the Work constitutes direct\n or contributory patent infringement, then any patent licenses\n granted to You under this License for that Work shall terminate\n as of the date such litigation is filed.\n\n 4. Redistribution. You may reproduce and distribute copies of the\n Work or Derivative Works thereof in any medium, with or without\n modifications, and in Source or Object form, provided that You\n meet the following conditions:\n\n (a) You must give any other recipients of the Work or\n Derivative Works a copy of this License; and\n\n (b) You must cause any modified files to carry prominent notices\n stating that You changed the files; and\n\n (c) You must retain, in the Source form of any Derivative Works\n that You distribute, all copyright, patent, trademark, and\n attribution notices from the Source form of the Work,\n excluding those notices that do not pertain to any part of\n the Derivative Works; and\n\n (d) If the Work includes a \"NOTICE\" text file as part of its\n distribution, then any Derivative Works that You distribute must\n include a readable copy of the attribution notices contained\n within such NOTICE file, excluding those notices that do not\n pertain to any part of the Derivative Works, in at least one\n of the following places: within a NOTICE text file distributed\n as part of the Derivative Works; within the Source form or\n documentation, if provided along with the Derivative Works; or,\n within a display generated by the Derivative Works, if and\n wherever such third-party notices normally appear. The contents\n of the NOTICE file are for informational purposes only and\n do not modify the License. You may add Your own attribution\n notices within Derivative Works that You distribute, alongside\n or as an addendum to the NOTICE text from the Work, provided\n that such additional attribution notices cannot be construed\n as modifying the License.\n\n You may add Your own copyright statement to Your modifications and\n may provide additional or different license terms and conditions\n for use, reproduction, or distribution of Your modifications, or\n for any such Derivative Works as a whole, provided Your use,\n reproduction, and distribution of the Work otherwise complies with\n the conditions stated in this License.\n\n 5. Submission of Contributions. Unless You explicitly state otherwise,\n any Contribution intentionally submitted for inclusion in the Work\n by You to the Licensor shall be under the terms and conditions of\n this License, without any additional terms or conditions.\n Notwithstanding the above, nothing herein shall supersede or modify\n the terms of any separate license agreement you may have executed\n with Licensor regarding such Contributions.\n\n 6. Trademarks. This License does not grant permission to use the trade\n names, trademarks, service marks, or product names of the Licensor,\n except as required for reasonable and customary use in describing the\n origin of the Work and reproducing the content of the NOTICE file.\n\n 7. Disclaimer of Warranty. Unless required by applicable law or\n agreed to in writing, Licensor provides the Work (and each\n Contributor provides its Contributions) on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n implied, including, without limitation, any warranties or conditions\n of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n PARTICULAR PURPOSE. You are solely responsible for determining the\n appropriateness of using or redistributing the Work and assume any\n risks associated with Your exercise of permissions under this License.\n\n 8. Limitation of Liability. In no event and under no legal theory,\n whether in tort (including negligence), contract, or otherwise,\n unless required by applicable law (such as deliberate and grossly\n negligent acts) or agreed to in writing, shall any Contributor be\n liable to You for damages, including any direct, indirect, special,\n incidental, or consequential damages of any character arising as a\n result of this License or out of the use or inability to use the\n Work (including but not limited to damages for loss of goodwill,\n work stoppage, computer failure or malfunction, or any and all\n other commercial damages or losses), even if such Contributor\n has been advised of the possibility of such damages.\n\n 9. Accepting Warranty or Additional Liability. While redistributing\n the Work or Derivative Works thereof, You may choose to offer,\n and charge a fee for, acceptance of support, warranty, indemnity,\n or other liability obligations and/or rights consistent with this\n License. However, in accepting such obligations, You may act only\n on Your own behalf and on Your sole responsibility, not on behalf\n of any other Contributor, and only if You agree to indemnify,\n defend, and hold each Contributor harmless for any liability\n incurred by, or claims asserted against, such Contributor by reason\n of your accepting any such warranty or additional liability.\n\n END OF TERMS AND CONDITIONS\n\n APPENDIX: How to apply the Apache License to your work.\n\n To apply the Apache License to your work, attach the following\n boilerplate notice, with the fields enclosed by brackets \"[]\"\n replaced with your own identifying information. (Don't include\n the brackets!) The text should be enclosed in the appropriate\n comment syntax for the file format. We also recommend that a\n file or class name and description of purpose be included on the\n same \"printed page\" as the copyright notice for easier\n identification within third-party archives.\n\n Copyright 2023 Daniel Wirtz <dcode@dcode.io>\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n*/\n\n// This works... but don't try to compare one to a real Long.js Long!\n// For internal use only.\n// `| 0` assures the runtime that we are using integer arithmetic\nexport class Long {\n low: number;\n high: number;\n __isUnsignedLong__: boolean;\n\n static isLong(obj: Long) {\n return (obj && obj.__isUnsignedLong__) === true;\n }\n\n constructor(low: number, high: number) {\n this.low = low | 0;\n this.high = high | 0;\n this.__isUnsignedLong__ = true;\n }\n\n // prettier-ignore\n static fromBytesLE(bytes: number[]): Long {\n return new Long(\n bytes[0] |\n bytes[1] << 8 |\n bytes[2] << 16 |\n bytes[3] << 24,\n bytes[4] |\n bytes[5] << 8 |\n bytes[6] << 16 |\n bytes[7] << 24,\n );\n }\n\n // prettier-ignore\n toBytesLE() {\n const hi = this.high;\n const lo = this.low;\n return [\n lo & 0xff,\n lo >>> 8 & 0xff,\n lo >>> 16 & 0xff,\n lo >>> 24,\n hi & 0xff,\n hi >>> 8 & 0xff,\n hi >>> 16 & 0xff,\n hi >>> 24\n ];\n }\n\n static fromNumber(value: number) {\n if (isNaN(value)) return UZERO;\n if (value < 0) return UZERO;\n if (value >= TWO_PWR_64_DBL) return MAX_UNSIGNED_VALUE;\n return new Long(value % TWO_PWR_32_DBL | 0, (value / TWO_PWR_32_DBL) | 0);\n }\n\n toString() {\n return (\n BigInt(this.high) * BigInt(TWO_PWR_32_DBL) +\n BigInt(this.low)\n ).toString();\n }\n\n equals(other: Long) {\n if (!Long.isLong(other)) other = Long.fromValue(other);\n if (this.high >>> 31 === 1 && other.high >>> 31 === 1) return false;\n return this.high === other.high && this.low === other.low;\n }\n\n notEquals(other: Long) {\n return !this.equals(other);\n }\n\n comp(other: Long) {\n if (!Long.isLong(other)) other = Long.fromValue(other);\n if (this.equals(other)) return 0;\n return other.high >>> 0 > this.high >>> 0 ||\n (other.high === this.high && other.low >>> 0 > this.low >>> 0)\n ? -1\n : 1;\n }\n\n lessThanOrEqual(other: Long) {\n return this.comp(/* validates */ other) <= 0;\n }\n\n static fromValue(val: any) {\n if (typeof val === \"number\") return Long.fromNumber(val);\n // Throws for non-objects, converts non-instanceof Long:\n return new Long(val.low, val.high);\n }\n}\n\nconst UZERO = new Long(0, 0);\nconst TWO_PWR_16_DBL = 1 << 16;\nconst TWO_PWR_32_DBL = TWO_PWR_16_DBL * TWO_PWR_16_DBL;\nconst TWO_PWR_64_DBL = TWO_PWR_32_DBL * TWO_PWR_32_DBL;\nconst MAX_UNSIGNED_VALUE = new Long(0xffffffff | 0, 0xffffffff | 0);\n", "import { jsonToConvex } from \"../../values/index.js\";\nimport { Long } from \"../long.js\";\nimport { logToConsole } from \"../logging.js\";\nimport { QueryId, StateVersion, Transition } from \"./protocol.js\";\nimport { FunctionResult } from \"./function_result.js\";\n\n/**\n * A represention of the query results we've received on the current WebSocket\n * connection.\n */\nexport class RemoteQuerySet {\n private version: StateVersion;\n private readonly remoteQuerySet: Map<QueryId, FunctionResult>;\n private readonly queryPath: (queryId: QueryId) => string | null;\n\n constructor(queryPath: (queryId: QueryId) => string | null) {\n this.version = { querySet: 0, ts: Long.fromNumber(0), identity: 0 };\n this.remoteQuerySet = new Map();\n this.queryPath = queryPath;\n }\n\n transition(transition: Transition): void {\n const start = transition.startVersion;\n if (\n this.version.querySet !== start.querySet ||\n this.version.ts.notEquals(start.ts) ||\n this.version.identity !== start.identity\n ) {\n throw new Error(\n `Invalid start version: ${start.ts.toString()}:${start.querySet}`,\n );\n }\n for (const modification of transition.modifications) {\n switch (modification.type) {\n case \"QueryUpdated\": {\n const queryPath = this.queryPath(modification.queryId);\n if (queryPath) {\n for (const line of modification.logLines) {\n logToConsole(\"info\", \"query\", queryPath, line);\n }\n }\n const value = jsonToConvex(modification.value ?? null);\n this.remoteQuerySet.set(modification.queryId, {\n success: true,\n value,\n logLines: modification.logLines,\n });\n break;\n }\n case \"QueryFailed\": {\n const queryPath = this.queryPath(modification.queryId);\n if (queryPath) {\n for (const line of modification.logLines) {\n logToConsole(\"info\", \"query\", queryPath, line);\n }\n }\n const { errorData } = modification;\n this.remoteQuerySet.set(modification.queryId, {\n success: false,\n errorMessage: modification.errorMessage,\n errorData:\n errorData !== undefined ? jsonToConvex(errorData) : undefined,\n logLines: modification.logLines,\n });\n break;\n }\n case \"QueryRemoved\": {\n this.remoteQuerySet.delete(modification.queryId);\n break;\n }\n default: {\n // Enforce that the switch-case is exhaustive.\n const _: never = modification;\n throw new Error(`Invalid modification ${(modification as any).type}`);\n }\n }\n }\n this.version = transition.endVersion;\n }\n\n remoteQueryResults(): Map<QueryId, FunctionResult> {\n return this.remoteQuerySet;\n }\n\n timestamp(): Long {\n return this.version.ts;\n }\n}\n", "import type { UserIdentityAttributes } from \"../../server/authentication.js\";\nexport type { UserIdentityAttributes } from \"../../server/authentication.js\";\nimport { JSONValue, Base64 } from \"../../values/index.js\";\nimport { Long } from \"../long.js\";\n\n/**\n * Shared schema\n */\n\nexport function u64ToLong(encoded: EncodedU64): U64 {\n const integerBytes = Base64.toByteArray(encoded);\n return Long.fromBytesLE(Array.from(integerBytes));\n}\n\nexport function longToU64(raw: U64): EncodedU64 {\n const integerBytes = new Uint8Array(raw.toBytesLE());\n return Base64.fromByteArray(integerBytes);\n}\n\nexport function parseServerMessage(\n encoded: EncodedServerMessage,\n): ServerMessage {\n switch (encoded.type) {\n case \"FatalError\":\n case \"AuthError\":\n case \"ActionResponse\":\n case \"Ping\": {\n return { ...encoded };\n }\n case \"MutationResponse\": {\n if (encoded.success) {\n return { ...encoded, ts: u64ToLong(encoded.ts) };\n } else {\n return { ...encoded };\n }\n }\n case \"Transition\": {\n return {\n ...encoded,\n startVersion: {\n ...encoded.startVersion,\n ts: u64ToLong(encoded.startVersion.ts),\n },\n endVersion: {\n ...encoded.endVersion,\n ts: u64ToLong(encoded.endVersion.ts),\n },\n };\n }\n default: {\n const _exhaustivenessCheck: never = encoded;\n }\n }\n return undefined as never;\n}\n\nexport function encodeClientMessage(\n message: ClientMessage,\n): EncodedClientMessage {\n switch (message.type) {\n case \"Authenticate\":\n case \"ModifyQuerySet\":\n case \"Mutation\":\n case \"Action\":\n case \"Event\": {\n return { ...message };\n }\n case \"Connect\": {\n if (message.maxObservedTimestamp !== undefined) {\n return {\n ...message,\n maxObservedTimestamp: longToU64(message.maxObservedTimestamp),\n };\n } else {\n return { ...message, maxObservedTimestamp: undefined };\n }\n }\n default: {\n const _exhaustivenessCheck: never = message;\n }\n }\n return undefined as never;\n}\n\ntype U64 = Long;\ntype EncodedU64 = string;\n\n/**\n * Unique nonnegative integer identifying a single query.\n */\nexport type QueryId = number; // nonnegative int\n\nexport type QuerySetVersion = number; // nonnegative int\n\nexport type RequestId = number; // nonnegative int\n\nexport type IdentityVersion = number; // nonnegative int\n\n/**\n * A serialized representation of decisions made during a query's execution.\n *\n * A journal is produced when a query function first executes and is re-used\n * when a query is re-executed.\n *\n * Currently this is used to store pagination end cursors to ensure\n * that pages of paginated queries will always end at the same cursor. This\n * enables gapless, reactive pagination.\n *\n * `null` is used to represent empty journals.\n * @public\n */\nexport type QueryJournal = string | null;\n\n/**\n * Client message schema\n */\n\ntype Connect = {\n type: \"Connect\";\n sessionId: string;\n connectionCount: number;\n lastCloseReason: string | null;\n maxObservedTimestamp?: TS;\n};\n\nexport type AddQuery = {\n type: \"Add\";\n queryId: QueryId;\n udfPath: string;\n args: JSONValue[];\n journal?: QueryJournal;\n /**\n * @internal\n */\n componentPath?: string;\n};\n\nexport type RemoveQuery = {\n type: \"Remove\";\n queryId: QueryId;\n};\n\nexport type QuerySetModification = {\n type: \"ModifyQuerySet\";\n baseVersion: QuerySetVersion;\n newVersion: QuerySetVersion;\n modifications: (AddQuery | RemoveQuery)[];\n};\n\nexport type MutationRequest = {\n type: \"Mutation\";\n requestId: RequestId;\n udfPath: string;\n args: JSONValue[];\n // Execute the mutation on a specific component.\n // Only admin auth is allowed to run mutations on non-root components.\n componentPath?: string;\n};\n\nexport type ActionRequest = {\n type: \"Action\";\n requestId: RequestId;\n udfPath: string;\n args: JSONValue[];\n // Execute the action on a specific component.\n // Only admin auth is allowed to run actions on non-root components.\n componentPath?: string;\n};\n\nexport type AdminAuthentication = {\n type: \"Authenticate\";\n tokenType: \"Admin\";\n value: string;\n baseVersion: IdentityVersion;\n impersonating?: UserIdentityAttributes;\n};\n\nexport type Authenticate =\n | AdminAuthentication\n | {\n type: \"Authenticate\";\n tokenType: \"User\";\n value: string;\n baseVersion: IdentityVersion;\n }\n | {\n type: \"Authenticate\";\n tokenType: \"None\";\n baseVersion: IdentityVersion;\n };\n\nexport type Event = {\n type: \"Event\";\n eventType: string;\n event: any;\n};\nexport type ClientMessage =\n | Connect\n | Authenticate\n | QuerySetModification\n | MutationRequest\n | ActionRequest\n | Event;\n\ntype EncodedConnect = Omit<Connect, \"maxObservedTimestamp\"> & {\n maxObservedTimestamp?: EncodedTS;\n};\n\ntype EncodedClientMessage =\n | EncodedConnect\n | Authenticate\n | QuerySetModification\n | MutationRequest\n | ActionRequest\n | Event;\n\n/**\n * Server message schema\n */\nexport type TS = U64;\ntype EncodedTS = EncodedU64;\ntype LogLines = string[];\n\nexport type StateVersion = {\n querySet: QuerySetVersion;\n ts: TS;\n identity: IdentityVersion;\n};\ntype EncodedStateVersion = Omit<StateVersion, \"ts\"> & { ts: EncodedTS };\n\ntype StateModification =\n | {\n type: \"QueryUpdated\";\n queryId: QueryId;\n value: JSONValue;\n logLines: LogLines;\n // Optional because old backend versions don't send this.\n journal?: QueryJournal;\n }\n | {\n type: \"QueryFailed\";\n queryId: QueryId;\n errorMessage: string;\n logLines: LogLines;\n errorData: JSONValue;\n // Optional because old backend versions don't send this.\n journal?: QueryJournal;\n }\n | {\n type: \"QueryRemoved\";\n queryId: QueryId;\n };\n\nexport type Transition = {\n type: \"Transition\";\n startVersion: StateVersion;\n endVersion: StateVersion;\n modifications: StateModification[];\n};\n\ntype MutationSuccess = {\n type: \"MutationResponse\";\n requestId: RequestId;\n success: true;\n result: JSONValue;\n ts: TS;\n logLines: LogLines;\n};\ntype MutationFailed = {\n type: \"MutationResponse\";\n requestId: RequestId;\n success: false;\n result: string;\n logLines: LogLines;\n errorData?: JSONValue;\n};\nexport type MutationResponse = MutationSuccess | MutationFailed;\ntype ActionSuccess = {\n type: \"ActionResponse\";\n requestId: RequestId;\n success: true;\n result: JSONValue;\n logLines: LogLines;\n};\ntype ActionFailed = {\n type: \"ActionResponse\";\n requestId: RequestId;\n success: false;\n result: string;\n logLines: LogLines;\n errorData?: JSONValue;\n};\nexport type ActionResponse = ActionSuccess | ActionFailed;\nexport type AuthError = {\n type: \"AuthError\";\n error: string;\n baseVersion?: IdentityVersion;\n};\ntype FatalError = {\n type: \"FatalError\";\n error: string;\n};\ntype Ping = {\n type: \"Ping\";\n};\n\nexport type ServerMessage =\n | Transition\n | MutationResponse\n | ActionResponse\n | FatalError\n | AuthError\n | Ping;\n\ntype EncodedTransition = Omit<Transition, \"startVersion\" | \"endVersion\"> & {\n startVersion: EncodedStateVersion;\n endVersion: EncodedStateVersion;\n};\ntype EncodedMutationSuccess = Omit<MutationSuccess, \"ts\"> & { ts: EncodedTS };\ntype EncodedMutationResponse = MutationFailed | EncodedMutationSuccess;\n\ntype EncodedServerMessage =\n | EncodedTransition\n | EncodedMutationResponse\n | ActionResponse\n | FatalError\n | AuthError\n | Ping;\n", "import {\n ClientMessage,\n encodeClientMessage,\n parseServerMessage,\n ServerMessage,\n} from \"./protocol.js\";\n\nconst CLOSE_NORMAL = 1000;\nconst CLOSE_GOING_AWAY = 1001;\nconst CLOSE_NO_STATUS = 1005;\n/** Convex-specific close code representing a \"404 Not Found\".\n * The edge Onramp accepts websocket upgrades before confirming that the\n * intended destination exists, so this code is sent once we've discovered that\n * the destination does not exist.\n */\nconst CLOSE_NOT_FOUND = 4040;\n\n/**\n * The various states our WebSocket can be in:\n *\n * - \"disconnected\": We don't have a WebSocket, but plan to create one.\n * - \"connecting\": We have created the WebSocket and are waiting for the\n * `onOpen` callback.\n * - \"ready\": We have an open WebSocket.\n * - \"stopped\": The WebSocket was closed and a new one can be created via `.restart()`.\n * - \"terminated\": We have closed the WebSocket and will never create a new one.\n *\n *\n * WebSocket State Machine\n * -----------------------\n * initialState: disconnected\n * validTransitions:\n * disconnected:\n * new WebSocket() -> connecting\n * terminate() -> terminated\n * connecting:\n * onopen -> ready\n * close() -> disconnected\n * terminate() -> terminated\n * ready:\n * close() -> disconnected\n * stop() -> stopped\n * terminate() -> terminated\n * stopped:\n * restart() -> connecting\n * terminate() -> terminated\n * terminalStates:\n * terminated\n *\n *\n *\n * \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n * \u250C\u2500\u2500\u2500\u2500terminate()\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2502 disconnected \u2502\u25C0\u2500\u2510\n * \u2502 \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518 \u2502\n * \u25BC \u2502 \u25B2 \u2502\n * \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510 new WebSocket() \u2502 \u2502\n * \u250C\u2500\u25B6\u2502 terminated \u2502\u25C0\u2500\u2500\u2500\u2500\u2500\u2500\u2510 \u2502 \u2502 \u2502\n * \u2502 \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518 \u2502 \u2502 \u2502 \u2502\n * \u2502 \u25B2 terminate() \u2502 close() close()\n * \u2502 terminate() \u2502 \u2502 \u2502 \u2502\n * \u2502 \u2502 \u2502 \u25BC \u2502 \u2502\n * \u2502 \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510 \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510 \u2502\n * \u2502 \u2502 stopped \u2502\u2500\u2500restart()\u2500\u2500\u2500\u25B6\u2502 connecting \u2502 \u2502\n * \u2502 \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518 \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518 \u2502\n * \u2502 \u25B2 \u2502 \u2502\n * \u2502 \u2502 onopen \u2502\n * \u2502 \u2502 \u2502 \u2502\n * \u2502 \u2502 \u25BC \u2502\n * terminate() \u2502 \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510 \u2502\n * \u2502 \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500stop()\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2502 ready \u2502\u2500\u2500\u2518\n * \u2502 \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n * \u2502 \u2502\n * \u2502 \u2502\n * \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n *\n * The `connecting` and `ready` state have a sub-state-machine for pausing.\n */\n\ntype Socket =\n | { state: \"disconnected\" }\n | { state: \"connecting\"; ws: WebSocket; paused: \"yes\" | \"no\" }\n | { state: \"ready\"; ws: WebSocket; paused: \"yes\" | \"no\" | \"uninitialized\" }\n | { state: \"stopped\" }\n | { state: \"terminated\" };\n\nexport type ReconnectMetadata = {\n connectionCount: number;\n lastCloseReason: string | null;\n};\n\nexport type OnMessageResponse = {\n hasSyncedPastLastReconnect: boolean;\n};\n\n/**\n * A wrapper around a websocket that handles errors, reconnection, and message\n * parsing.\n */\nexport class WebSocketManager {\n private socket: Socket;\n\n private connectionCount: number;\n private lastCloseReason: string | null;\n\n /** Upon HTTPS/WSS failure, the first jittered backoff duration, in ms. */\n private readonly initialBackoff: number;\n\n /** We backoff exponentially, but we need to cap that--this is the jittered max. */\n private readonly maxBackoff: number;\n\n /** How many times have we failed consecutively? */\n private retries: number;\n\n /** How long before lack of server response causes us to initiate a reconnect,\n * in ms */\n private readonly serverInactivityThreshold: number;\n\n private reconnectDueToServerInactivityTimeout: ReturnType<\n typeof setTimeout\n > | null;\n\n private readonly uri: string;\n private readonly onOpen: (reconnectMetadata: ReconnectMetadata) => void;\n private readonly onResume: () => void;\n private readonly onMessage: (message: ServerMessage) => OnMessageResponse;\n private readonly webSocketConstructor: typeof WebSocket;\n private readonly verbose: boolean;\n\n constructor(\n uri: string,\n callbacks: {\n onOpen: (reconnectMetadata: ReconnectMetadata) => void;\n onResume: () => void;\n onMessage: (message: ServerMessage) => OnMessageResponse;\n },\n webSocketConstructor: typeof WebSocket,\n verbose: boolean,\n ) {\n this.webSocketConstructor = webSocketConstructor;\n this.socket = { state: \"disconnected\" };\n this.connectionCount = 0;\n this.lastCloseReason = \"InitialConnect\";\n\n this.initialBackoff = 100;\n this.maxBackoff = 16000;\n this.retries = 0;\n\n this.serverInactivityThreshold = 30000;\n this.reconnectDueToServerInactivityTimeout = null;\n\n this.uri = uri;\n this.onOpen = callbacks.onOpen;\n this.onResume = callbacks.onResume;\n this.onMessage = callbacks.onMessage;\n this.verbose = verbose;\n\n this.connect();\n }\n\n private connect() {\n if (this.socket.state === \"terminated\") {\n return;\n }\n if (\n this.socket.state !== \"disconnected\" &&\n this.socket.state !== \"stopped\"\n ) {\n throw new Error(\n \"Didn't start connection from disconnected state: \" + this.socket.state,\n );\n }\n\n const ws = new this.webSocketConstructor(this.uri);\n this._logVerbose(\"constructed WebSocket\");\n this.socket = {\n state: \"connecting\",\n ws,\n paused: \"no\",\n };\n\n // Kick off server inactivity timer before WebSocket connection is established\n // so we can detect cases where handshake fails.\n // The `onopen` event only fires after the connection is established:\n // Source: https://datatracker.ietf.org/doc/html/rfc6455#page-19:~:text=_The%20WebSocket%20Connection%20is%20Established_,-and\n this.resetServerInactivityTimeout();\n\n ws.onopen = () => {\n this._logVerbose(\"begin ws.onopen\");\n if (this.socket.state !== \"connecting\") {\n throw new Error(\"onopen called with socket not in connecting state\");\n }\n this.socket = {\n state: \"ready\",\n ws,\n paused: this.socket.paused === \"yes\" ? \"uninitialized\" : \"no\",\n };\n this.resetServerInactivityTimeout();\n if (this.socket.paused === \"no\") {\n this.onOpen({\n connectionCount: this.connectionCount,\n lastCloseReason: this.lastCloseReason,\n });\n }\n\n if (this.lastCloseReason !== \"InitialConnect\") {\n console.log(\"WebSocket reconnected\");\n }\n\n this.connectionCount += 1;\n this.lastCloseReason = null;\n };\n // NB: The WebSocket API calls `onclose` even if connection fails, so we can route all error paths through `onclose`.\n ws.onerror = (error) => {\n const message = (error as ErrorEvent).message;\n console.log(`WebSocket error: ${message}`);\n };\n ws.onmessage = (message) => {\n this.resetServerInactivityTimeout();\n const serverMessage = parseServerMessage(JSON.parse(message.data));\n this._logVerbose(`received ws message with type ${serverMessage.type}`);\n const response = this.onMessage(serverMessage);\n if (response.hasSyncedPastLastReconnect) {\n // Reset backoff to 0 once all outstanding requests are complete.\n this.retries = 0;\n }\n };\n ws.onclose = (event) => {\n this._logVerbose(\"begin ws.onclose\");\n if (this.lastCloseReason === null) {\n this.lastCloseReason = event.reason ?? \"OnCloseInvoked\";\n }\n if (\n event.code !== CLOSE_NORMAL &&\n event.code !== CLOSE_GOING_AWAY && // This commonly gets fired on mobile apps when the app is backgrounded\n event.code !== CLOSE_NO_STATUS &&\n event.code !== CLOSE_NOT_FOUND // Note that we want to retry on a 404, as it can be transient during a push.\n ) {\n let msg = `WebSocket closed with code ${event.code}`;\n if (event.reason) {\n msg += `: ${event.reason}`;\n }\n console.log(msg);\n }\n this.scheduleReconnect();\n return;\n };\n }\n\n /**\n * @returns The state of the {@link Socket}.\n */\n socketState(): string {\n return this.socket.state;\n }\n\n /**\n * @param message - A ClientMessage to send.\n * @returns Whether the message (might have been) sent.\n */\n sendMessage(message: ClientMessage) {\n this._logVerbose(`sending message with type ${message.type}`);\n\n if (this.socket.state === \"ready\" && this.socket.paused === \"no\") {\n const encodedMessage = encodeClientMessage(message);\n const request = JSON.stringify(encodedMessage);\n try {\n this.socket.ws.send(request);\n } catch (error: any) {\n console.log(\n `Failed to send message on WebSocket, reconnecting: ${error}`,\n );\n this.closeAndReconnect(\"FailedToSendMessage\");\n }\n // We are not sure if this was sent or not.\n return true;\n }\n return false;\n }\n\n private resetServerInactivityTimeout() {\n if (this.socket.state === \"terminated\") {\n // Don't reset any timers if we were trying to terminate.\n return;\n }\n if (this.reconnectDueToServerInactivityTimeout !== null) {\n clearTimeout(this.reconnectDueToServerInactivityTimeout);\n this.reconnectDueToServerInactivityTimeout = null;\n }\n this.reconnectDueToServerInactivityTimeout = setTimeout(() => {\n this.closeAndReconnect(\"InactiveServer\");\n }, this.serverInactivityThreshold);\n }\n\n private scheduleReconnect() {\n this.socket = { state: \"disconnected\" };\n const backoff = this.nextBackoff();\n console.log(`Attempting reconnect in ${backoff}ms`);\n setTimeout(() => this.connect(), backoff);\n }\n\n /**\n * Close the WebSocket and schedule a reconnect.\n *\n * This should be used when we hit an error and would like to restart the session.\n */\n private closeAndReconnect(closeReason: string) {\n this._logVerbose(`begin closeAndReconnect with reason ${closeReason}`);\n switch (this.socket.state) {\n case \"disconnected\":\n case \"terminated\":\n case \"stopped\":\n // Nothing to do if we don't have a WebSocket.\n return;\n case \"connecting\":\n case \"ready\": {\n this.lastCloseReason = closeReason;\n // Close the old socket asynchronously, we'll open a new socket in reconnect.\n void this.close();\n this.scheduleReconnect();\n return;\n }\n default: {\n // Enforce that the switch-case is exhaustive.\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n const _: never = this.socket;\n }\n }\n }\n\n /**\n * Close the WebSocket, being careful to clear the onclose handler to avoid re-entrant\n * calls. Use this instead of directly calling `ws.close()`\n *\n * It is the callers responsibility to update the state after this method is called so that the\n * closed socket is not accessible or used again after this method is called\n */\n private close(): Promise<void> {\n switch (this.socket.state) {\n case \"disconnected\":\n case \"terminated\":\n case \"stopped\":\n // Nothing to do if we don't have a WebSocket.\n return Promise.resolve();\n case \"connecting\": {\n const ws = this.socket.ws;\n return new Promise((r) => {\n ws.onclose = () => {\n this._logVerbose(\"Closed after connecting\");\n r();\n };\n ws.onopen = () => {\n this._logVerbose(\"Opened after connecting\");\n ws.close();\n };\n });\n }\n case \"ready\": {\n this._logVerbose(\"ws.close called\");\n const ws = this.socket.ws;\n const result: Promise<void> = new Promise((r) => {\n ws.onclose = () => {\n r();\n };\n });\n ws.close();\n return result;\n }\n default: {\n // Enforce that the switch-case is exhaustive.\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n const _: never = this.socket;\n return Promise.resolve();\n }\n }\n }\n\n /**\n * Close the WebSocket and do not reconnect.\n * @returns A Promise that resolves when the WebSocket `onClose` callback is called.\n */\n terminate(): Promise<void> {\n if (this.reconnectDueToServerInactivityTimeout) {\n clearTimeout(this.reconnectDueToServerInactivityTimeout);\n }\n switch (this.socket.state) {\n case \"terminated\":\n case \"stopped\":\n case \"disconnected\":\n case \"connecting\":\n case \"ready\": {\n const result = this.close();\n this.socket = { state: \"terminated\" };\n return result;\n }\n default: {\n // Enforce that the switch-case is exhaustive.\n const _: never = this.socket;\n throw new Error(\n `Invalid websocket state: ${(this.socket as any).state}`,\n );\n }\n }\n }\n\n stop(): Promise<void> {\n switch (this.socket.state) {\n case \"terminated\":\n // If we're terminating we ignore stop\n return Promise.resolve();\n case \"connecting\":\n case \"stopped\":\n case \"disconnected\":\n case \"ready\": {\n const result = this.close();\n this.socket = { state: \"stopped\" };\n return result;\n }\n default: {\n // Enforce that the switch-case is exhaustive.\n const _: never = this.socket;\n return Promise.resolve();\n }\n }\n }\n\n /**\n * Create a new WebSocket after a previous `stop()`, unless `terminate()` was\n * called before.\n */\n restart(): void {\n switch (this.socket.state) {\n case \"stopped\":\n break;\n case \"terminated\":\n // If we're terminating we ignore restart\n return;\n case \"connecting\":\n case \"ready\":\n case \"disconnected\":\n throw new Error(\"`restart()` is only valid after `stop()`\");\n default: {\n // Enforce that the switch-case is exhaustive.\n const _: never = this.socket;\n }\n }\n this.connect();\n }\n\n pause(): void {\n switch (this.socket.state) {\n case \"disconnected\":\n case \"stopped\":\n case \"terminated\":\n // If already stopped or stopping ignore.\n return;\n case \"connecting\":\n case \"ready\": {\n this.socket = { ...this.socket, paused: \"yes\" };\n return;\n }\n default: {\n // Enforce that the switch-case is exhaustive.\n const _: never = this.socket;\n return;\n }\n }\n }\n\n /**\n * Resume the state machine if previously paused.\n */\n resume(): void {\n switch (this.socket.state) {\n case \"connecting\":\n this.socket = { ...this.socket, paused: \"no\" };\n return;\n case \"ready\":\n if (this.socket.paused === \"uninitialized\") {\n this.socket = { ...this.socket, paused: \"no\" };\n this.onOpen({\n connectionCount: this.connectionCount,\n lastCloseReason: this.lastCloseReason,\n });\n } else if (this.socket.paused === \"yes\") {\n this.socket = { ...this.socket, paused: \"no\" };\n this.onResume();\n }\n return;\n case \"terminated\":\n case \"stopped\":\n case \"disconnected\":\n // Ignore resume if not paused, perhaps we already resumed.\n return;\n default: {\n // Enforce that the switch-case is exhaustive.\n const _: never = this.socket;\n }\n }\n this.connect();\n }\n\n private _logVerbose(message: string) {\n if (this.verbose) {\n console.debug(`${new Date().toISOString()} ${message}`);\n }\n }\n\n private nextBackoff(): number {\n const baseBackoff = this.initialBackoff * Math.pow(2, this.retries);\n this.retries += 1;\n const actualBackoff = Math.min(baseBackoff, this.maxBackoff);\n const jitter = actualBackoff * (Math.random() - 0.5);\n return actualBackoff + jitter;\n }\n}\n", "export function newSessionId() {\n return uuidv4();\n}\n\n// From https://stackoverflow.com/a/2117523\nfunction uuidv4() {\n return \"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx\".replace(/[xy]/g, (c) => {\n const r = (Math.random() * 16) | 0,\n v = c === \"x\" ? r : (r & 0x3) | 0x8;\n return v.toString(16);\n });\n}\n", "/**\n * The code was extracted from:\n * https://github.com/davidchambers/Base64.js\n */\n\nvar chars = \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=\";\n\nfunction InvalidCharacterError(message) {\n this.message = message;\n}\n\nInvalidCharacterError.prototype = new Error();\nInvalidCharacterError.prototype.name = \"InvalidCharacterError\";\n\nfunction polyfill(input) {\n var str = String(input).replace(/=+$/, \"\");\n if (str.length % 4 == 1) {\n throw new InvalidCharacterError(\n \"'atob' failed: The string to be decoded is not correctly encoded.\"\n );\n }\n for (\n // initialize result and counters\n var bc = 0, bs, buffer, idx = 0, output = \"\";\n // get next character\n (buffer = str.charAt(idx++));\n // character found in table? initialize bit storage and add its ascii value;\n ~buffer &&\n ((bs = bc % 4 ? bs * 64 + buffer : buffer),\n // and if not first of each 4 characters,\n // convert the first 8 bits to one ascii character\n bc++ % 4) ?\n (output += String.fromCharCode(255 & (bs >> ((-2 * bc) & 6)))) :\n 0\n ) {\n // try to find character in table (0-63, not found => -1)\n buffer = chars.indexOf(buffer);\n }\n return output;\n}\n\nexport default (typeof window !== \"undefined\" &&\n window.atob &&\n window.atob.bind(window)) ||\npolyfill;", "import atob from \"./atob\";\n\nfunction b64DecodeUnicode(str) {\n return decodeURIComponent(\n atob(str).replace(/(.)/g, function(m, p) {\n var code = p.charCodeAt(0).toString(16).toUpperCase();\n if (code.length < 2) {\n code = \"0\" + code;\n }\n return \"%\" + code;\n })\n );\n}\n\nexport default function(str) {\n var output = str.replace(/-/g, \"+\").replace(/_/g, \"/\");\n switch (output.length % 4) {\n case 0:\n break;\n case 2:\n output += \"==\";\n break;\n case 3:\n output += \"=\";\n break;\n default:\n throw \"Illegal base64url string!\";\n }\n\n try {\n return b64DecodeUnicode(output);\n } catch (err) {\n return atob(output);\n }\n}", "\"use strict\";\n\nimport base64_url_decode from \"./base64_url_decode\";\n\nexport function InvalidTokenError(message) {\n this.message = message;\n}\n\nInvalidTokenError.prototype = new Error();\nInvalidTokenError.prototype.name = \"InvalidTokenError\";\n\nexport default function(token, options) {\n if (typeof token !== \"string\") {\n throw new InvalidTokenError(\"Invalid token specified\");\n }\n\n options = options || {};\n var pos = options.header === true ? 0 : 1;\n try {\n return JSON.parse(base64_url_decode(token.split(\".\")[pos]));\n } catch (e) {\n throw new InvalidTokenError(\"Invalid token specified: \" + e.message);\n }\n}", "import { LocalSyncState } from \"./local_state.js\";\nimport { AuthError, Transition } from \"./protocol.js\";\nimport jwtDecode from \"jwt-decode\";\n\n// setTimout uses 32 bit integer, so it can only\n// schedule about 24 days in the future.\nconst MAXIMUM_REFRESH_DELAY = 20 * 24 * 60 * 60 * 1000; // 20 days\n\n/**\n * An async function returning the JWT-encoded OpenID Connect Identity Token\n * if available.\n *\n * `forceRefreshToken` is `true` if the server rejected a previously\n * returned token, and the client should try to fetch a new one.\n *\n * See {@link ConvexReactClient.setAuth}.\n *\n * @public\n */\nexport type AuthTokenFetcher = (args: {\n forceRefreshToken: boolean;\n}) => Promise<string | null | undefined>;\n\n/**\n * What is provided to the client.\n */\ntype AuthConfig = {\n fetchToken: AuthTokenFetcher;\n onAuthChange: (isAuthenticated: boolean) => void;\n};\n\n/**\n * In general we take 3 steps:\n * 1. Fetch a possibly cached token\n * 2. Immediately fetch a fresh token without using a cache\n * 3. Repeat step 2 before the end of the fresh token's lifetime\n *\n * When we fetch without using a cache we know when the token\n * will expire, and can schedule refetching it.\n *\n * If we get an error before a scheduled refetch, we go back\n * to step 2.\n */\ntype AuthState =\n | { state: \"noAuth\" }\n | {\n state: \"waitingForServerConfirmationOfCachedToken\";\n config: AuthConfig;\n hasRetried: boolean;\n }\n | {\n state: \"initialRefetch\";\n config: AuthConfig;\n }\n | {\n state: \"waitingForServerConfirmationOfFreshToken\";\n config: AuthConfig;\n hadAuth: boolean;\n token: string;\n }\n | {\n state: \"waitingForScheduledRefetch\";\n config: AuthConfig;\n refetchTokenTimeoutId: ReturnType<typeof setTimeout>;\n }\n // Special/weird state when we got a valid token\n // but could not fetch a new one.\n | {\n state: \"notRefetching\";\n config: AuthConfig;\n };\n\n/**\n * Handles the state transitions for auth. The server is the source\n * of truth.\n */\nexport class AuthenticationManager {\n private authState: AuthState = { state: \"noAuth\" };\n // Used to detect races involving `setConfig` calls\n // while a token is being fetched.\n private configVersion = 0;\n // Shared by the BaseClient so that the auth manager can easily inspect it\n private readonly syncState: LocalSyncState;\n // Passed down by BaseClient, sends a message to the server\n private readonly authenticate: (token: string) => void;\n private readonly stopSocket: () => Promise<void>;\n private readonly restartSocket: () => void;\n private readonly pauseSocket: () => void;\n private readonly resumeSocket: () => void;\n // Passed down by BaseClient, sends a message to the server\n private readonly clearAuth: () => void;\n private readonly verbose: boolean;\n\n constructor(\n syncState: LocalSyncState,\n {\n authenticate,\n stopSocket,\n restartSocket,\n pauseSocket,\n resumeSocket,\n clearAuth,\n verbose,\n }: {\n authenticate: (token: string) => void;\n stopSocket: () => Promise<void>;\n restartSocket: () => void;\n pauseSocket: () => void;\n resumeSocket: () => void;\n clearAuth: () => void;\n verbose: boolean;\n },\n ) {\n this.syncState = syncState;\n this.authenticate = authenticate;\n this.stopSocket = stopSocket;\n this.restartSocket = restartSocket;\n this.pauseSocket = pauseSocket;\n this.resumeSocket = resumeSocket;\n this.clearAuth = clearAuth;\n this.verbose = verbose;\n }\n\n async setConfig(\n fetchToken: AuthTokenFetcher,\n onChange: (isAuthenticated: boolean) => void,\n ) {\n this.resetAuthState();\n this._logVerbose(\"pausing WS for auth token fetch\");\n this.pauseSocket();\n const token = await this.fetchTokenAndGuardAgainstRace(fetchToken, {\n forceRefreshToken: false,\n });\n if (token.isFromOutdatedConfig) {\n return;\n }\n if (token.value) {\n this.setAuthState({\n state: \"waitingForServerConfirmationOfCachedToken\",\n config: { fetchToken, onAuthChange: onChange },\n hasRetried: false,\n });\n this.authenticate(token.value);\n this._logVerbose(\"resuming WS after auth token fetch\");\n this.resumeSocket();\n } else {\n this.setAuthState({\n state: \"initialRefetch\",\n config: { fetchToken, onAuthChange: onChange },\n });\n // Try again with `forceRefreshToken: true`\n await this.refetchToken();\n }\n }\n\n onTransition(serverMessage: Transition) {\n if (\n !this.syncState.isCurrentOrNewerAuthVersion(\n serverMessage.endVersion.identity,\n )\n ) {\n // This is a stale transition - client has moved on to\n // a newer auth version.\n return;\n }\n if (\n serverMessage.endVersion.identity <= serverMessage.startVersion.identity\n ) {\n // This transition did not change auth - it is not a response to Authenticate.\n return;\n }\n\n if (this.authState.state === \"waitingForServerConfirmationOfCachedToken\") {\n this._logVerbose(\"server confirmed auth token is valid\");\n void this.refetchToken();\n this.authState.config.onAuthChange(true);\n return;\n }\n if (this.authState.state === \"waitingForServerConfirmationOfFreshToken\") {\n this._logVerbose(\"server confirmed new auth token is valid\");\n this.scheduleTokenRefetch(this.authState.token);\n if (!this.authState.hadAuth) {\n this.authState.config.onAuthChange(true);\n }\n }\n }\n\n onAuthError(serverMessage: AuthError) {\n const { baseVersion } = serverMessage;\n // Versioned AuthErrors are ignored if the client advanced to\n // a newer auth identity\n if (baseVersion !== null && baseVersion !== undefined) {\n // Error are reporting the previous version, since the server\n // didn't advance, hence `+ 1`.\n if (!this.syncState.isCurrentOrNewerAuthVersion(baseVersion + 1)) {\n this._logVerbose(\"ignoring auth error for previous auth attempt\");\n return;\n }\n void this.tryToReauthenticate(serverMessage);\n return;\n }\n\n // TODO: Remove after all AuthErrors are versioned\n void this.tryToReauthenticate(serverMessage);\n }\n\n // This is similar to `refetchToken` defined below, in fact we\n // don't represent them as different states, but it is different\n // in that we pause the WebSocket so that mutations\n // don't retry with bad auth.\n private async tryToReauthenticate(serverMessage: AuthError) {\n // We only retry once, to avoid infinite retries\n if (\n // No way to fetch another token, kaboom\n this.authState.state === \"noAuth\" ||\n // We failed on a fresh token, trying another one won't help\n this.authState.state === \"waitingForServerConfirmationOfFreshToken\"\n ) {\n console.error(\n `Failed to authenticate: \"${serverMessage.error}\", check your server auth config`,\n );\n if (this.syncState.hasAuth()) {\n this.syncState.clearAuth();\n }\n if (this.authState.state !== \"noAuth\") {\n this.setAndReportAuthFailed(this.authState.config.onAuthChange);\n }\n return;\n }\n this._logVerbose(\"attempting to reauthenticate\");\n await this.stopSocket();\n const token = await this.fetchTokenAndGuardAgainstRace(\n this.authState.config.fetchToken,\n {\n forceRefreshToken: true,\n },\n );\n if (token.isFromOutdatedConfig) {\n return;\n }\n\n if (token.value && this.syncState.isNewAuth(token.value)) {\n this.authenticate(token.value);\n this.setAuthState({\n state: \"waitingForServerConfirmationOfFreshToken\",\n config: this.authState.config,\n token: token.value,\n hadAuth:\n this.authState.state === \"notRefetching\" ||\n this.authState.state === \"waitingForScheduledRefetch\",\n });\n } else {\n this._logVerbose(\"reauthentication failed, could not fetch a new token\");\n if (this.syncState.hasAuth()) {\n this.syncState.clearAuth();\n }\n this.setAndReportAuthFailed(this.authState.config.onAuthChange);\n }\n this.restartSocket();\n }\n\n // Force refetch the token and schedule another refetch\n // before the token expires - an active client should never\n // need to reauthenticate.\n private async refetchToken() {\n if (this.authState.state === \"noAuth\") {\n return;\n }\n this._logVerbose(\"refetching auth token\");\n const token = await this.fetchTokenAndGuardAgainstRace(\n this.authState.config.fetchToken,\n {\n forceRefreshToken: true,\n },\n );\n if (token.isFromOutdatedConfig) {\n return;\n }\n\n if (token.value) {\n if (this.syncState.isNewAuth(token.value)) {\n this.setAuthState({\n state: \"waitingForServerConfirmationOfFreshToken\",\n hadAuth: this.syncState.hasAuth(),\n token: token.value,\n config: this.authState.config,\n });\n this.authenticate(token.value);\n } else {\n this.setAuthState({\n state: \"notRefetching\",\n config: this.authState.config,\n });\n }\n } else {\n this._logVerbose(\"refetching token failed\");\n if (this.syncState.hasAuth()) {\n this.clearAuth();\n }\n this.setAndReportAuthFailed(this.authState.config.onAuthChange);\n }\n // Resuming in case this refetch was triggered\n // by an invalid cached token.\n this._logVerbose(\n \"resuming WS after auth token fetch (if currently paused)\",\n );\n this.resumeSocket();\n }\n\n private scheduleTokenRefetch(token: string) {\n if (this.authState.state === \"noAuth\") {\n return;\n }\n const decodedToken = this.decodeToken(token);\n if (!decodedToken) {\n // This is no longer really possible, because\n // we wait on server response before scheduling token refetch,\n // and the server currently requires JWT tokens.\n console.error(\"Auth token is not a valid JWT, cannot refetch the token\");\n return;\n }\n // iat: issued at time, UTC seconds timestamp at which the JWT was issued\n // exp: expiration time, UTC seconds timestamp at which the JWT will expire\n const { iat, exp } = decodedToken as { iat?: number; exp?: number };\n if (!iat || !exp) {\n console.error(\n \"Auth token does not have required fields, cannot refetch the token\",\n );\n return;\n }\n const leewaySeconds = 2;\n // Because the client and server clocks may be out of sync,\n // we only know that the token will expire after `exp - iat`,\n // and since we just fetched a fresh one we know when that\n // will happen.\n const delay = Math.min(\n MAXIMUM_REFRESH_DELAY,\n (exp - iat - leewaySeconds) * 1000,\n );\n if (delay <= 0) {\n console.error(\n \"Auth token does not live long enough, cannot refetch the token\",\n );\n return;\n }\n const refetchTokenTimeoutId = setTimeout(() => {\n void this.refetchToken();\n }, delay);\n this.setAuthState({\n state: \"waitingForScheduledRefetch\",\n refetchTokenTimeoutId,\n config: this.authState.config,\n });\n this._logVerbose(\n `scheduled preemptive auth token refetching in ${delay}ms`,\n );\n }\n\n // Protects against simultaneous calls to `setConfig`\n // while we're fetching a token\n private async fetchTokenAndGuardAgainstRace(\n fetchToken: AuthTokenFetcher,\n fetchArgs: {\n forceRefreshToken: boolean;\n },\n ) {\n const originalConfigVersion = ++this.configVersion;\n const token = await fetchToken(fetchArgs);\n if (this.configVersion !== originalConfigVersion) {\n // This is a stale config\n return { isFromOutdatedConfig: true };\n }\n return { isFromOutdatedConfig: false, value: token };\n }\n\n stop() {\n this.resetAuthState();\n // Bump this in case we are mid-token-fetch when we get stopped\n this.configVersion++;\n }\n\n private setAndReportAuthFailed(\n onAuthChange: (authenticated: boolean) => void,\n ) {\n onAuthChange(false);\n this.resetAuthState();\n }\n\n private resetAuthState() {\n this.setAuthState({ state: \"noAuth\" });\n }\n\n private setAuthState(newAuth: AuthState) {\n if (this.authState.state === \"waitingForScheduledRefetch\") {\n clearTimeout(this.authState.refetchTokenTimeoutId);\n\n // The waitingForScheduledRefetch state is the most quiesced authed state.\n // Let the syncState know that auth is in a good state, so it can reset failure backoffs\n this.syncState.markAuthCompletion();\n }\n this.authState = newAuth;\n }\n\n private decodeToken(token: string) {\n try {\n return jwtDecode(token);\n } catch (e) {\n return null;\n }\n }\n\n private _logVerbose(message: string) {\n if (this.verbose) {\n console.debug(\n `${new Date().toISOString()} ${message} [v${this.configVersion}]`,\n );\n }\n }\n}\n", "// Marks share a global namespace with other developer code.\nconst markNames = [\n \"convexClientConstructed\",\n \"convexWebSocketOpen\",\n \"convexFirstMessageReceived\",\n] as const;\nexport type MarkName = (typeof markNames)[number];\n\n// Mark details are not reported to the server.\ntype MarkDetail = {\n sessionId: string;\n};\n\n// `PerformanceMark`s are efficient and show up in browser's performance\n// timeline. They can be cleared with `performance.clearMarks()`.\n// This is a memory leak, but a worthwhile one: automatic\n// cleanup would make in-browser debugging more difficult.\nexport function mark(name: MarkName, sessionId: string) {\n const detail: MarkDetail = { sessionId };\n // `performance` APIs exists in browsers, Node.js, Deno, and more but it\n // is not required by the Convex client.\n if (typeof performance === \"undefined\" || !performance.mark) return;\n performance.mark(name, { detail });\n}\n\n// `PerfomanceMark` has a built-in toJSON() but the return type varies\n// between implementations, e.g. Node.js returns details but Chrome does not.\nfunction performanceMarkToJson(mark: PerformanceMark): MarkJson {\n // Remove \"convex\" prefix\n let name = mark.name.slice(\"convex\".length);\n // lowercase the first letter\n name = name.charAt(0).toLowerCase() + name.slice(1);\n return {\n name,\n startTime: mark.startTime,\n };\n}\n\n// Similar to the return type of `PerformanceMark.toJson()`.\nexport type MarkJson = {\n name: string;\n // `startTime` is in milliseconds since the time origin like `performance.now()`.\n // https://developer.mozilla.org/en-US/docs/Web/API/DOMHighResTimeStamp#the_time_origin\n startTime: number;\n};\n\nexport function getMarksReport(sessionId: string): MarkJson[] {\n if (typeof performance === \"undefined\" || !performance.getEntriesByName) {\n return [];\n }\n const allMarks: PerformanceMark[] = [];\n for (const name of markNames) {\n const marks = (\n performance\n .getEntriesByName(name)\n .filter((entry) => entry.entryType === \"mark\") as PerformanceMark[]\n ).filter((mark) => mark.detail.sessionId === sessionId);\n allMarks.push(...marks);\n }\n return allMarks.map(performanceMarkToJson);\n}\n", "import { version } from \"../../index.js\";\nimport { convexToJson, Value } from \"../../values/index.js\";\nimport {\n createHybridErrorStacktrace,\n forwardData,\n logFatalError,\n} from \"../logging.js\";\nimport { LocalSyncState } from \"./local_state.js\";\nimport { RequestManager } from \"./request_manager.js\";\nimport {\n OptimisticLocalStore,\n OptimisticUpdate,\n} from \"./optimistic_updates.js\";\nimport {\n OptimisticQueryResults,\n QueryResultsMap,\n} from \"./optimistic_updates_impl.js\";\nimport {\n ActionRequest,\n MutationRequest,\n QueryId,\n QueryJournal,\n RequestId,\n ServerMessage,\n TS,\n UserIdentityAttributes,\n} from \"./protocol.js\";\nimport { RemoteQuerySet } from \"./remote_query_set.js\";\nimport { QueryToken, serializePathAndArgs } from \"./udf_path_utils.js\";\nimport { ReconnectMetadata, WebSocketManager } from \"./web_socket_manager.js\";\nimport { newSessionId } from \"./session.js\";\nimport { FunctionResult } from \"./function_result.js\";\nimport {\n AuthenticationManager,\n AuthTokenFetcher,\n} from \"./authentication_manager.js\";\nexport { type AuthTokenFetcher } from \"./authentication_manager.js\";\nimport { getMarksReport, mark, MarkName } from \"./metrics.js\";\nimport { parseArgs, validateDeploymentUrl } from \"../../common/index.js\";\nimport { ConvexError } from \"../../values/errors.js\";\n\n/**\n * Options for {@link BaseConvexClient}.\n *\n * @public\n */\nexport interface BaseConvexClientOptions {\n /**\n * Whether to prompt the user if they have unsaved changes pending\n * when navigating away or closing a web page.\n *\n * This is only possible when the `window` object exists, i.e. in a browser.\n *\n * The default value is `true` in browsers.\n */\n unsavedChangesWarning?: boolean;\n /**\n * Specifies an alternate\n * [WebSocket](https://developer.mozilla.org/en-US/docs/Web/API/WebSocket)\n * constructor to use for client communication with the Convex cloud.\n * The default behavior is to use `WebSocket` from the global environment.\n */\n webSocketConstructor?: typeof WebSocket;\n /**\n * Adds additional logging for debugging purposes.\n *\n * The default value is `false`.\n */\n verbose?: boolean;\n /**\n * Sends additional metrics to Convex for debugging purposes.\n *\n * The default value is `false`.\n */\n reportDebugInfoToConvex?: boolean;\n /**\n * Skip validating that the Convex deployment URL looks like\n * `https://happy-animal-123.convex.cloud` or localhost.\n *\n * This can be useful if running a self-hosted Convex backend that uses a different\n * URL.\n *\n * The default value is `false`\n */\n skipConvexDeploymentUrlCheck?: boolean;\n}\n\n/**\n * State describing the client's connection with the Convex backend.\n *\n * @public\n */\nexport type ConnectionState = {\n hasInflightRequests: boolean;\n isWebSocketConnected: boolean;\n timeOfOldestInflightRequest: Date | null;\n};\n\n/**\n * Options for {@link BaseConvexClient.subscribe}.\n *\n * @public\n */\nexport interface SubscribeOptions {\n /**\n * An (optional) journal produced from a previous execution of this query\n * function.\n *\n * If there is an existing subscription to a query function with the same\n * name and arguments, this journal will have no effect.\n */\n journal?: QueryJournal;\n\n /**\n * @internal\n */\n componentPath?: string;\n}\n\n/**\n * Options for {@link BaseConvexClient.mutation}.\n *\n * @public\n */\nexport interface MutationOptions {\n /**\n * An optimistic update to apply along with this mutation.\n *\n * An optimistic update locally updates queries while a mutation is pending.\n * Once the mutation completes, the update will be rolled back.\n */\n optimisticUpdate?: OptimisticUpdate<any>;\n}\n\n/**\n * Low-level client for directly integrating state management libraries\n * with Convex.\n *\n * Most developers should use higher level clients, like\n * the {@link ConvexHttpClient} or the React hook based {@link react.ConvexReactClient}.\n *\n * @public\n */\nexport class BaseConvexClient {\n private readonly address: string;\n private readonly state: LocalSyncState;\n private readonly requestManager: RequestManager;\n private readonly webSocketManager: WebSocketManager;\n private readonly authenticationManager: AuthenticationManager;\n private remoteQuerySet: RemoteQuerySet;\n private readonly optimisticQueryResults: OptimisticQueryResults;\n private readonly onTransition: (updatedQueries: QueryToken[]) => void;\n private _nextRequestId: RequestId;\n private readonly _sessionId: string;\n private firstMessageReceived = false;\n private readonly verbose: boolean;\n private readonly debug: boolean;\n private maxObservedTimestamp: TS | undefined;\n\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 onTransition - A callback receiving an array of query tokens\n * corresponding to query results that have changed.\n * @param options - See {@link BaseConvexClientOptions} for a full description.\n */\n constructor(\n address: string,\n onTransition: (updatedQueries: QueryToken[]) => void,\n options?: BaseConvexClientOptions,\n ) {\n if (typeof address === \"object\") {\n throw new Error(\n \"Passing a ClientConfig object is no longer supported. Pass the URL of the Convex deployment as a string directly.\",\n );\n }\n if (options?.skipConvexDeploymentUrlCheck !== true) {\n validateDeploymentUrl(address);\n }\n options = { ...options };\n let webSocketConstructor = options.webSocketConstructor;\n if (!webSocketConstructor && typeof WebSocket === \"undefined\") {\n throw new Error(\n \"No WebSocket global variable defined! To use Convex in an environment without WebSocket try the HTTP client: https://docs.convex.dev/api/classes/browser.ConvexHttpClient\",\n );\n }\n webSocketConstructor = webSocketConstructor || WebSocket;\n this.verbose = options.verbose ?? false;\n this.debug = options.reportDebugInfoToConvex ?? false;\n this.address = address;\n\n // Substitute http(s) with ws(s)\n const i = address.search(\"://\");\n if (i === -1) {\n throw new Error(\"Provided address was not an absolute URL.\");\n }\n const origin = address.substring(i + 3); // move past the double slash\n const protocol = address.substring(0, i);\n let wsProtocol;\n if (protocol === \"http\") {\n wsProtocol = \"ws\";\n } else if (protocol === \"https\") {\n wsProtocol = \"wss\";\n } else {\n throw new Error(`Unknown parent protocol ${protocol}`);\n }\n const wsUri = `${wsProtocol}://${origin}/api/${version}/sync`;\n\n this.state = new LocalSyncState();\n this.remoteQuerySet = new RemoteQuerySet((queryId) =>\n this.state.queryPath(queryId),\n );\n this.requestManager = new RequestManager();\n this.authenticationManager = new AuthenticationManager(this.state, {\n authenticate: (token) => {\n const message = this.state.setAuth(token);\n this.webSocketManager.sendMessage(message);\n },\n stopSocket: () => this.webSocketManager.stop(),\n restartSocket: () => this.webSocketManager.restart(),\n pauseSocket: () => this.webSocketManager.pause(),\n resumeSocket: () => this.webSocketManager.resume(),\n clearAuth: () => {\n this.clearAuth();\n },\n verbose: this.verbose,\n });\n this.optimisticQueryResults = new OptimisticQueryResults();\n this.onTransition = onTransition;\n this._nextRequestId = 0;\n this._sessionId = newSessionId();\n\n const { unsavedChangesWarning } = options;\n if (\n typeof window === \"undefined\" ||\n typeof window.addEventListener === \"undefined\"\n ) {\n if (unsavedChangesWarning === true) {\n throw new Error(\n \"unsavedChangesWarning requested, but window.addEventListener not found! Remove {unsavedChangesWarning: true} from Convex client options.\",\n );\n }\n } else if (unsavedChangesWarning !== false) {\n // Listen for tab close events and notify the user on unsaved changes.\n window.addEventListener(\"beforeunload\", (e) => {\n if (this.requestManager.hasIncompleteRequests()) {\n // There are 3 different ways to trigger this pop up so just try all of\n // them.\n\n e.preventDefault();\n // This confirmation message doesn't actually appear in most modern\n // browsers but we tried.\n const confirmationMessage =\n \"Are you sure you want to leave? Your changes may not be saved.\";\n (e || window.event).returnValue = confirmationMessage;\n return confirmationMessage;\n }\n });\n }\n\n this.webSocketManager = new WebSocketManager(\n wsUri,\n {\n onOpen: (reconnectMetadata: ReconnectMetadata) => {\n // We have a new WebSocket!\n this.mark(\"convexWebSocketOpen\");\n this.webSocketManager.sendMessage({\n ...reconnectMetadata,\n type: \"Connect\",\n sessionId: this._sessionId,\n maxObservedTimestamp: this.maxObservedTimestamp,\n });\n\n // Throw out our remote query, reissue queries\n // and outstanding mutations, and reauthenticate.\n const oldRemoteQueryResults = new Set(\n this.remoteQuerySet.remoteQueryResults().keys(),\n );\n this.remoteQuerySet = new RemoteQuerySet((queryId) =>\n this.state.queryPath(queryId),\n );\n const [querySetModification, authModification] = this.state.restart(\n oldRemoteQueryResults,\n );\n if (authModification) {\n this.webSocketManager.sendMessage(authModification);\n }\n this.webSocketManager.sendMessage(querySetModification);\n for (const message of this.requestManager.restart()) {\n this.webSocketManager.sendMessage(message);\n }\n },\n onResume: () => {\n const remoteQueryResults = new Set(\n this.remoteQuerySet.remoteQueryResults().keys(),\n );\n const [querySetModification, authModification] =\n this.state.resume(remoteQueryResults);\n if (authModification) {\n this.webSocketManager.sendMessage(authModification);\n }\n if (querySetModification) {\n this.webSocketManager.sendMessage(querySetModification);\n }\n for (const message of this.requestManager.resume()) {\n this.webSocketManager.sendMessage(message);\n }\n },\n onMessage: (serverMessage: ServerMessage) => {\n // Metrics events grow linearly with reconnection attempts so this\n // conditional prevents n^2 metrics reporting.\n if (!this.firstMessageReceived) {\n this.firstMessageReceived = true;\n this.mark(\"convexFirstMessageReceived\");\n this.reportMarks();\n }\n switch (serverMessage.type) {\n case \"Transition\": {\n this.observedTimestamp(serverMessage.endVersion.ts);\n this.authenticationManager.onTransition(serverMessage);\n this.remoteQuerySet.transition(serverMessage);\n this.state.transition(serverMessage);\n const completedRequests = this.requestManager.removeCompleted(\n this.remoteQuerySet.timestamp(),\n );\n this.notifyOnQueryResultChanges(completedRequests);\n break;\n }\n case \"MutationResponse\": {\n if (serverMessage.success) {\n this.observedTimestamp(serverMessage.ts);\n }\n const completedMutationId =\n this.requestManager.onResponse(serverMessage);\n if (completedMutationId !== null) {\n this.notifyOnQueryResultChanges(new Set([completedMutationId]));\n }\n break;\n }\n case \"ActionResponse\": {\n this.requestManager.onResponse(serverMessage);\n break;\n }\n case \"AuthError\": {\n this.authenticationManager.onAuthError(serverMessage);\n break;\n }\n case \"FatalError\": {\n const error = logFatalError(serverMessage.error);\n void this.webSocketManager.terminate();\n throw error;\n }\n case \"Ping\":\n break; // do nothing\n default: {\n const _typeCheck: never = serverMessage;\n }\n }\n\n return {\n hasSyncedPastLastReconnect: this.hasSyncedPastLastReconnect(),\n };\n },\n },\n webSocketConstructor,\n this.verbose,\n );\n this.mark(\"convexClientConstructed\");\n }\n\n /**\n * Return true if there is outstanding work from prior to the time of the most recent restart.\n * This indicates that the client has not proven itself to have gotten past the issue that\n * potentially led to the restart. Use this to influence when to reset backoff after a failure.\n */\n private hasSyncedPastLastReconnect() {\n const hasSyncedPastLastReconnect =\n this.requestManager.hasSyncedPastLastReconnect() ||\n this.state.hasSyncedPastLastReconnect();\n return hasSyncedPastLastReconnect;\n }\n\n private observedTimestamp(observedTs: TS) {\n if (\n this.maxObservedTimestamp === undefined ||\n this.maxObservedTimestamp.lessThanOrEqual(observedTs)\n ) {\n this.maxObservedTimestamp = observedTs;\n }\n }\n\n getMaxObservedTimestamp() {\n return this.maxObservedTimestamp;\n }\n\n /**\n * Compute the current query results based on the remoteQuerySet and the\n * current optimistic updates and call `onTransition` for all the changed\n * queries.\n *\n * @param completedMutations - A set of mutation IDs whose optimistic updates\n * are no longer needed.\n */\n private notifyOnQueryResultChanges(completedRequest: Set<RequestId>) {\n const remoteQueryResults: Map<QueryId, FunctionResult> =\n this.remoteQuerySet.remoteQueryResults();\n const queryTokenToValue: QueryResultsMap = new Map();\n for (const [queryId, result] of remoteQueryResults) {\n const queryToken = this.state.queryToken(queryId);\n // It's possible that we've already unsubscribed to this query but\n // the server hasn't learned about that yet. If so, ignore this one.\n\n if (queryToken !== null) {\n const query = {\n result,\n udfPath: this.state.queryPath(queryId)!,\n args: this.state.queryArgs(queryId)!,\n };\n queryTokenToValue.set(queryToken, query);\n }\n }\n\n this.onTransition(\n this.optimisticQueryResults.ingestQueryResultsFromServer(\n queryTokenToValue,\n completedRequest,\n ),\n );\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-encoded 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 void this.authenticationManager.setConfig(fetchToken, onChange);\n }\n\n hasAuth() {\n return this.state.hasAuth();\n }\n\n /** @internal */\n setAdminAuth(value: string, fakeUserIdentity?: UserIdentityAttributes) {\n const message = this.state.setAdminAuth(value, fakeUserIdentity);\n this.webSocketManager.sendMessage(message);\n }\n\n clearAuth() {\n const message = this.state.clearAuth();\n this.webSocketManager.sendMessage(message);\n }\n\n /**\n * Subscribe to a query function.\n *\n * Whenever this query's result changes, the `onTransition` callback\n * passed into the constructor will be called.\n *\n * @param name - The name of the query.\n * @param args - An arguments object for the query. If this is omitted, the\n * arguments will be `{}`.\n * @param options - A {@link SubscribeOptions} options object for this query.\n\n * @returns An object containing a {@link QueryToken} corresponding to this\n * query and an `unsubscribe` callback.\n */\n subscribe(\n name: string,\n args?: Record<string, Value>,\n options?: SubscribeOptions,\n ): { queryToken: QueryToken; unsubscribe: () => void } {\n const argsObject = parseArgs(args);\n\n const { modification, queryToken, unsubscribe } = this.state.subscribe(\n name,\n argsObject,\n options?.journal,\n options?.componentPath,\n );\n if (modification !== null) {\n this.webSocketManager.sendMessage(modification);\n }\n return {\n queryToken,\n unsubscribe: () => {\n const modification = unsubscribe();\n if (modification) {\n this.webSocketManager.sendMessage(modification);\n }\n },\n };\n }\n\n /**\n * A query result based only on the current, local state.\n *\n * The only way this will return a value is if we're already subscribed to the\n * query or its value has been set optimistically.\n */\n localQueryResult(\n udfPath: string,\n args?: Record<string, Value>,\n ): Value | undefined {\n const argsObject = parseArgs(args);\n const queryToken = serializePathAndArgs(udfPath, argsObject);\n return this.optimisticQueryResults.queryResult(queryToken);\n }\n\n /**\n * Get query result by query token based on current, local state\n *\n * The only way this will return a value is if we're already subscribed to the\n * query or its value has been set optimistically.\n *\n * @internal\n */\n localQueryResultByToken(queryToken: QueryToken): Value | undefined {\n return this.optimisticQueryResults.queryResult(queryToken);\n }\n\n /**\n * Whether local query result is available for a toke.\n *\n * This method does not throw if the result is an error.\n *\n * @internal\n */\n hasLocalQueryResultByToken(queryToken: QueryToken): boolean {\n return this.optimisticQueryResults.hasQueryResult(queryToken);\n }\n\n /**\n * @internal\n */\n localQueryLogs(\n udfPath: string,\n args?: Record<string, Value>,\n ): string[] | undefined {\n const argsObject = parseArgs(args);\n const queryToken = serializePathAndArgs(udfPath, argsObject);\n return this.optimisticQueryResults.queryLogs(queryToken);\n }\n\n /**\n * Retrieve the current {@link QueryJournal} for this query function.\n *\n * If we have not yet received a result for this query, this will be `undefined`.\n *\n * @param name - The name of the query.\n * @param args - The arguments object for this query.\n * @returns The query's {@link QueryJournal} or `undefined`.\n */\n queryJournal(\n name: string,\n args?: Record<string, Value>,\n ): QueryJournal | undefined {\n const argsObject = parseArgs(args);\n const queryToken = serializePathAndArgs(name, argsObject);\n return this.state.queryJournal(queryToken);\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 return {\n hasInflightRequests: this.requestManager.hasInflightRequests(),\n isWebSocketConnected: this.webSocketManager.socketState() === \"ready\",\n timeOfOldestInflightRequest:\n this.requestManager.timeOfOldestInflightRequest(),\n };\n }\n\n /**\n * Execute a mutation function.\n *\n * @param name - The name of the mutation.\n * @param args - An arguments object for the mutation. If this is omitted,\n * the arguments will be `{}`.\n * @param options - A {@link MutationOptions} options object for this mutation.\n\n * @returns - A promise of the mutation's result.\n */\n async mutation(\n name: string,\n args?: Record<string, Value>,\n options?: MutationOptions,\n ): Promise<any> {\n const result = await this.mutationInternal(name, args, options);\n if (!result.success) {\n if (result.errorData !== undefined) {\n throw forwardData(\n result,\n new ConvexError(\n createHybridErrorStacktrace(\"mutation\", name, result),\n ),\n );\n }\n throw new Error(createHybridErrorStacktrace(\"mutation\", name, result));\n }\n return result.value;\n }\n\n /**\n * @internal\n */\n async mutationInternal(\n udfPath: string,\n args?: Record<string, Value>,\n options?: MutationOptions,\n componentPath?: string,\n ): Promise<FunctionResult> {\n const mutationArgs = parseArgs(args);\n this.tryReportLongDisconnect();\n const requestId = this.nextRequestId;\n this._nextRequestId++;\n\n if (options !== undefined) {\n const optimisticUpdate = options.optimisticUpdate;\n if (optimisticUpdate !== undefined) {\n const wrappedUpdate = (localQueryStore: OptimisticLocalStore) => {\n optimisticUpdate(localQueryStore, mutationArgs);\n };\n\n const changedQueries =\n this.optimisticQueryResults.applyOptimisticUpdate(\n wrappedUpdate,\n requestId,\n );\n this.onTransition(changedQueries);\n }\n }\n\n const message: MutationRequest = {\n type: \"Mutation\",\n requestId,\n udfPath,\n componentPath,\n args: [convexToJson(mutationArgs)],\n };\n const mightBeSent = this.webSocketManager.sendMessage(message);\n return this.requestManager.request(message, mightBeSent);\n }\n\n /**\n * Execute an action function.\n *\n * @param name - The name of the action.\n * @param args - An 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(name: string, args?: Record<string, Value>): Promise<any> {\n const result = await this.actionInternal(name, args);\n if (!result.success) {\n if (result.errorData !== undefined) {\n throw forwardData(\n result,\n new ConvexError(createHybridErrorStacktrace(\"action\", name, result)),\n );\n }\n throw new Error(createHybridErrorStacktrace(\"action\", name, result));\n }\n return result.value;\n }\n\n /**\n * @internal\n */\n async actionInternal(\n udfPath: string,\n args?: Record<string, Value>,\n componentPath?: string,\n ): Promise<FunctionResult> {\n const actionArgs = parseArgs(args);\n const requestId = this.nextRequestId;\n this._nextRequestId++;\n this.tryReportLongDisconnect();\n\n const message: ActionRequest = {\n type: \"Action\",\n requestId,\n udfPath,\n componentPath,\n args: [convexToJson(actionArgs)],\n };\n\n const mightBeSent = this.webSocketManager.sendMessage(message);\n return this.requestManager.request(message, mightBeSent);\n }\n\n /**\n * Close any network handles associated with this client and stop all subscriptions.\n *\n * Call this method when you're done with an {@link BaseConvexClient} to\n * dispose of its sockets and resources.\n *\n * @returns A `Promise` fulfilled when the connection has been completely closed.\n */\n async close(): Promise<void> {\n this.authenticationManager.stop();\n return this.webSocketManager.terminate();\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 * @internal\n */\n get nextRequestId() {\n return this._nextRequestId;\n }\n\n /**\n * @internal\n */\n get sessionId() {\n return this._sessionId;\n }\n\n // Instance property so that `mark()` doesn't need to be called as a method.\n private mark = (name: MarkName) => {\n if (this.debug) {\n mark(name, this.sessionId);\n }\n };\n\n /**\n * Reports performance marks to the server. This should only be called when\n * we have a functional websocket.\n */\n private reportMarks() {\n if (this.debug) {\n const report = getMarksReport(this.sessionId);\n this.webSocketManager.sendMessage({\n type: \"Event\",\n eventType: \"ClientConnect\",\n event: report,\n });\n }\n }\n\n private tryReportLongDisconnect() {\n if (!this.debug) {\n return;\n }\n const timeOfOldestRequest =\n this.connectionState().timeOfOldestInflightRequest;\n if (\n timeOfOldestRequest === null ||\n Date.now() - timeOfOldestRequest.getTime() <= 60 * 1000\n ) {\n return;\n }\n const endpoint = `${this.address}/api/debug_event`;\n fetch(endpoint, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n \"Convex-Client\": `npm-${version}`,\n },\n body: JSON.stringify({ event: \"LongWebsocketDisconnect\" }),\n })\n .then((response) => {\n if (!response.ok) {\n console.warn(\n \"Analytics request failed with response:\",\n response.body,\n );\n }\n })\n .catch((error) => {\n console.warn(\"Analytics response failed with error:\", error);\n });\n }\n}\n", "import { validateDeploymentUrl } from \"../common/index.js\";\nimport {\n BaseConvexClient,\n BaseConvexClientOptions,\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 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\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-encoded 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 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 ): Promise<Awaited<FunctionReturnType<Mutation>>> {\n if (this.disabled) throw new Error(\"ConvexClient is disabled\");\n return await this.client.mutation(getFunctionName(mutation), args);\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 | Query[\"_returnType\"]\n | undefined;\n if (value !== undefined) return 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", "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 { logToConsole } from \"./logging.js\";\nimport { FunctionArgs, UserIdentityAttributes } 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\n/**\n * A Convex client that runs queries and mutations over HTTP.\n *\n * This is appropriate for server-side code (like Netlify Lambdas) or non-reactive\n * webapps.\n *\n * If you're building a React app, consider using\n * {@link react.ConvexReactClient} instead.\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\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 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 */\n constructor(address: string, skipConvexDeploymentUrlCheck?: boolean) {\n if (skipConvexDeploymentUrlCheck !== true) {\n validateDeploymentUrl(address);\n }\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 * @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 credentials: \"include\",\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 credentials: \"include\",\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 logToConsole(\"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 /**\n * Execute a Convex mutation function.\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 * @returns A promise of the mutation's result.\n */\n async mutation<Mutation extends FunctionReference<\"mutation\">>(\n mutation: Mutation,\n ...args: OptionalRestArgs<Mutation>\n ): Promise<FunctionReturnType<Mutation>> {\n const mutationArgs = parseArgs(args[0]);\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 credentials: \"include\",\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 logToConsole(\"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 /**\n * Execute a Convex action function.\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 credentials: \"include\",\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 logToConsole(\"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.\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 credentials: \"include\",\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 logToConsole(\"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"],
|
|
4
|
+
"sourcesContent": ["// Code exposed in the browser bundle\n\nexport * from \"./src/browser/index.js\";\nexport { anyApi } from \"./src/server/index.js\";\n", "export const version = \"1.14.1\";\n", "/* eslint-disable no-var */\n\n/*\nhttps://github.com/beatgammit/base64-js/blob/88957c9943c7e2a0f03cdf73e71d579e433627d3/index.js\nCopyright (c) 2014 Jameson Little\nThe MIT License (MIT)\n*/\n\n// Vendored because this library has no ESM build, and some environments\n// (SvelteKit) are happiest when all dependencies are ESM.\n\nvar lookup: string[] = [];\nvar revLookup: number[] = [];\nvar Arr = Uint8Array;\n\nvar code = \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/\";\nfor (var i = 0, len = code.length; i < len; ++i) {\n lookup[i] = code[i];\n revLookup[code.charCodeAt(i)] = i;\n}\n\n// Support decoding URL-safe base64 strings, as Node.js does.\n// See: https://en.wikipedia.org/wiki/Base64#URL_applications\nrevLookup[\"-\".charCodeAt(0)] = 62;\nrevLookup[\"_\".charCodeAt(0)] = 63;\n\nfunction getLens(b64: string) {\n var len = b64.length;\n\n if (len % 4 > 0) {\n throw new Error(\"Invalid string. Length must be a multiple of 4\");\n }\n\n // Trim off extra bytes after placeholder bytes are found\n // See: https://github.com/beatgammit/base64-js/issues/42\n var validLen = b64.indexOf(\"=\");\n if (validLen === -1) validLen = len;\n\n var placeHoldersLen = validLen === len ? 0 : 4 - (validLen % 4);\n\n return [validLen, placeHoldersLen];\n}\n\n// base64 is 4/3 + up to two characters of the original data\n/** @public */\nexport function byteLength(b64: string): number {\n var lens = getLens(b64);\n var validLen = lens[0];\n var placeHoldersLen = lens[1];\n return ((validLen + placeHoldersLen) * 3) / 4 - placeHoldersLen;\n}\n\nfunction _byteLength(_b64: string, validLen: number, placeHoldersLen: number) {\n return ((validLen + placeHoldersLen) * 3) / 4 - placeHoldersLen;\n}\n\n/** @public */\nexport function toByteArray(b64: string): Uint8Array {\n var tmp;\n var lens = getLens(b64);\n var validLen = lens[0];\n var placeHoldersLen = lens[1];\n\n var arr = new Arr(_byteLength(b64, validLen, placeHoldersLen));\n\n var curByte = 0;\n\n // if there are placeholders, only get up to the last complete 4 chars\n var len = placeHoldersLen > 0 ? validLen - 4 : validLen;\n\n var i;\n for (i = 0; i < len; i += 4) {\n tmp =\n (revLookup[b64.charCodeAt(i)] << 18) |\n (revLookup[b64.charCodeAt(i + 1)] << 12) |\n (revLookup[b64.charCodeAt(i + 2)] << 6) |\n revLookup[b64.charCodeAt(i + 3)];\n arr[curByte++] = (tmp >> 16) & 0xff;\n arr[curByte++] = (tmp >> 8) & 0xff;\n arr[curByte++] = tmp & 0xff;\n }\n\n if (placeHoldersLen === 2) {\n tmp =\n (revLookup[b64.charCodeAt(i)] << 2) |\n (revLookup[b64.charCodeAt(i + 1)] >> 4);\n arr[curByte++] = tmp & 0xff;\n }\n\n if (placeHoldersLen === 1) {\n tmp =\n (revLookup[b64.charCodeAt(i)] << 10) |\n (revLookup[b64.charCodeAt(i + 1)] << 4) |\n (revLookup[b64.charCodeAt(i + 2)] >> 2);\n arr[curByte++] = (tmp >> 8) & 0xff;\n arr[curByte++] = tmp & 0xff;\n }\n\n return arr;\n}\n\nfunction tripletToBase64(num: number) {\n return (\n lookup[(num >> 18) & 0x3f] +\n lookup[(num >> 12) & 0x3f] +\n lookup[(num >> 6) & 0x3f] +\n lookup[num & 0x3f]\n );\n}\n\nfunction encodeChunk(uint8: Uint8Array, start: number, end: number) {\n var tmp;\n var output = [];\n for (var i = start; i < end; i += 3) {\n tmp =\n ((uint8[i] << 16) & 0xff0000) +\n ((uint8[i + 1] << 8) & 0xff00) +\n (uint8[i + 2] & 0xff);\n output.push(tripletToBase64(tmp));\n }\n return output.join(\"\");\n}\n\n/** @public */\nexport function fromByteArray(uint8: Uint8Array): string {\n var tmp;\n var len = uint8.length;\n var extraBytes = len % 3; // if we have 1 byte left, pad 2 bytes\n var parts = [];\n var maxChunkLength = 16383; // must be multiple of 3\n\n // go through the array every three bytes, we'll deal with trailing stuff later\n for (var i = 0, len2 = len - extraBytes; i < len2; i += maxChunkLength) {\n parts.push(\n encodeChunk(\n uint8,\n i,\n i + maxChunkLength > len2 ? len2 : i + maxChunkLength,\n ),\n );\n }\n\n // pad the end with zeros, but make sure to not forget the extra bytes\n if (extraBytes === 1) {\n tmp = uint8[len - 1];\n parts.push(lookup[tmp >> 2] + lookup[(tmp << 4) & 0x3f] + \"==\");\n } else if (extraBytes === 2) {\n tmp = (uint8[len - 2] << 8) + uint8[len - 1];\n parts.push(\n lookup[tmp >> 10] +\n lookup[(tmp >> 4) & 0x3f] +\n lookup[(tmp << 2) & 0x3f] +\n \"=\",\n );\n }\n\n return parts.join(\"\");\n}\n", "import type { Value } from \"../values/value.js\";\n\n/**\n * Validate that the arguments to a Convex function are an object, defaulting\n * `undefined` to `{}`.\n */\nexport function parseArgs(\n args: Record<string, Value> | undefined,\n): Record<string, Value> {\n if (args === undefined) {\n return {};\n }\n if (!isSimpleObject(args)) {\n throw new Error(\n `The arguments to a Convex function must be an object. Received: ${\n args as any\n }`,\n );\n }\n return args;\n}\n\nexport function validateDeploymentUrl(deploymentUrl: string) {\n // Don't use things like `new URL(deploymentUrl).hostname` since these aren't\n // supported by React Native's JS environment\n if (typeof deploymentUrl === \"undefined\") {\n throw new Error(\n `Client created with undefined deployment address. If you used an environment variable, check that it's set.`,\n );\n }\n if (typeof deploymentUrl !== \"string\") {\n throw new Error(\n `Invalid deployment address: found ${deploymentUrl as any}\".`,\n );\n }\n if (\n !(deploymentUrl.startsWith(\"http:\") || deploymentUrl.startsWith(\"https:\"))\n ) {\n throw new Error(\n `Invalid deployment address: Must start with \"https://\" or \"http://\". Found \"${deploymentUrl}\".`,\n );\n }\n\n // Most clients should connect to \".convex.cloud\". But we also support localhost and\n // custom custom. We validate the deployment url is a valid url, which is the most\n // common failure pattern.\n try {\n new URL(deploymentUrl);\n } catch (err) {\n throw new Error(\n `Invalid deployment address: \"${deploymentUrl}\" is not a valid URL. If you believe this URL is correct, use the \\`skipConvexDeploymentUrlCheck\\` option to bypass this.`,\n );\n }\n\n // If a user uses .convex.site, this is very likely incorrect.\n if (deploymentUrl.endsWith(\".convex.site\")) {\n throw new Error(\n `Invalid deployment address: \"${deploymentUrl}\" ends with .convex.site, which is used for HTTP Actions. Convex deployment URLs typically end with .convex.cloud? If you believe this URL is correct, use the \\`skipConvexDeploymentUrlCheck\\` option to bypass this.`,\n );\n }\n}\n\n/**\n * Check whether a value is a plain old JavaScript object.\n */\nexport function isSimpleObject(value: unknown) {\n const isObject = typeof value === \"object\";\n const prototype = Object.getPrototypeOf(value);\n const isSimple =\n prototype === null ||\n prototype === Object.prototype ||\n // Objects generated from other contexts (e.g. across Node.js `vm` modules) will not satisfy the previous\n // conditions but are still simple objects.\n prototype?.constructor?.name === \"Object\";\n return isObject && isSimple;\n}\n", "/**\n * Utilities for working with values stored in Convex.\n *\n * You can see the full set of supported types at\n * [Types](https://docs.convex.dev/using/types).\n * @module\n */\nimport * as Base64 from \"./base64.js\";\nimport { isSimpleObject } from \"../common/index.js\";\n\nconst LITTLE_ENDIAN = true;\n// This code is used by code that may not have bigint literals.\nconst MIN_INT64 = BigInt(\"-9223372036854775808\");\nconst MAX_INT64 = BigInt(\"9223372036854775807\");\nconst ZERO = BigInt(\"0\");\nconst EIGHT = BigInt(\"8\");\nconst TWOFIFTYSIX = BigInt(\"256\");\n\n/**\n * The type of JavaScript values serializable to JSON.\n *\n * @public\n */\nexport type JSONValue =\n | null\n | boolean\n | number\n | string\n | JSONValue[]\n | { [key: string]: JSONValue };\n\n/**\n * An identifier for a document in Convex.\n *\n * Convex documents are uniquely identified by their `Id`, which is accessible\n * on the `_id` field. To learn more, see [Document IDs](https://docs.convex.dev/database/document-ids).\n *\n * Documents can be loaded using `db.get(id)` in query and mutation functions.\n *\n * IDs are base 32 encoded strings which are URL safe.\n *\n * IDs are just strings at runtime, but this type can be used to distinguish them from other\n * strings at compile time.\n *\n * If you're using code generation, use the `Id` type generated for your data model in\n * `convex/_generated/dataModel.d.ts`.\n *\n * @typeParam TableName - A string literal type of the table name (like \"users\").\n *\n * @public\n */\nexport type Id<TableName extends string> = string & { __tableName: TableName };\n\n/**\n * A value supported by Convex.\n *\n * Values can be:\n * - stored inside of documents.\n * - used as arguments and return types to queries and mutation functions.\n *\n * You can see the full set of supported types at\n * [Types](https://docs.convex.dev/using/types).\n *\n * @public\n */\nexport type Value =\n | null\n | bigint\n | number\n | boolean\n | string\n | ArrayBuffer\n | Value[]\n | { [key: string]: undefined | Value };\n\n/**\n * The types of {@link Value} that can be used to represent numbers.\n *\n * @public\n */\nexport type NumericValue = bigint | number;\n\nfunction isSpecial(n: number) {\n return Number.isNaN(n) || !Number.isFinite(n) || Object.is(n, -0);\n}\n\nexport function slowBigIntToBase64(value: bigint): string {\n // the conversion is easy if we pretend it's unsigned\n if (value < ZERO) {\n value -= MIN_INT64 + MIN_INT64;\n }\n let hex = value.toString(16);\n if (hex.length % 2 === 1) hex = \"0\" + hex;\n\n const bytes = new Uint8Array(new ArrayBuffer(8));\n let i = 0;\n for (const hexByte of hex.match(/.{2}/g)!.reverse()) {\n bytes.set([parseInt(hexByte, 16)], i++);\n value >>= EIGHT;\n }\n return Base64.fromByteArray(bytes);\n}\n\nexport function slowBase64ToBigInt(encoded: string): bigint {\n const integerBytes = Base64.toByteArray(encoded);\n if (integerBytes.byteLength !== 8) {\n throw new Error(\n `Received ${integerBytes.byteLength} bytes, expected 8 for $integer`,\n );\n }\n let value = ZERO;\n let power = ZERO;\n for (const byte of integerBytes) {\n value += BigInt(byte) * TWOFIFTYSIX ** power;\n power++;\n }\n if (value > MAX_INT64) {\n value += MIN_INT64 + MIN_INT64;\n }\n return value;\n}\n\nexport function modernBigIntToBase64(value: bigint): string {\n if (value < MIN_INT64 || MAX_INT64 < value) {\n throw new Error(\n `BigInt ${value} does not fit into a 64-bit signed integer.`,\n );\n }\n const buffer = new ArrayBuffer(8);\n new DataView(buffer).setBigInt64(0, value, true);\n return Base64.fromByteArray(new Uint8Array(buffer));\n}\n\nexport function modernBase64ToBigInt(encoded: string): bigint {\n const integerBytes = Base64.toByteArray(encoded);\n if (integerBytes.byteLength !== 8) {\n throw new Error(\n `Received ${integerBytes.byteLength} bytes, expected 8 for $integer`,\n );\n }\n const intBytesView = new DataView(integerBytes.buffer);\n return intBytesView.getBigInt64(0, true);\n}\n\n// Fall back to a slower version on Safari 14 which lacks these APIs.\nexport const bigIntToBase64 = (DataView.prototype as any).setBigInt64\n ? modernBigIntToBase64\n : slowBigIntToBase64;\nexport const base64ToBigInt = (DataView.prototype as any).getBigInt64\n ? modernBase64ToBigInt\n : slowBase64ToBigInt;\n\nconst MAX_IDENTIFIER_LEN = 1024;\n\nfunction validateObjectField(k: string) {\n if (k.length > MAX_IDENTIFIER_LEN) {\n throw new Error(\n `Field name ${k} exceeds maximum field name length ${MAX_IDENTIFIER_LEN}.`,\n );\n }\n if (k.startsWith(\"$\")) {\n throw new Error(`Field name ${k} starts with a '$', which is reserved.`);\n }\n for (let i = 0; i < k.length; i += 1) {\n const charCode = k.charCodeAt(i);\n // Non-control ASCII characters\n if (charCode < 32 || charCode >= 127) {\n throw new Error(\n `Field name ${k} has invalid character '${k[i]}': Field names can only contain non-control ASCII characters`,\n );\n }\n }\n}\n\n/**\n * Parse a Convex value from its JSON representation.\n *\n * This function will deserialize serialized Int64s to `BigInt`s, Bytes to `ArrayBuffer`s etc.\n *\n * To learn more about Convex values, see [Types](https://docs.convex.dev/using/types).\n *\n * @param value - The JSON representation of a Convex value previously created with {@link convexToJson}.\n * @returns The JavaScript representation of the Convex value.\n *\n * @public\n */\nexport function jsonToConvex(value: JSONValue): Value {\n if (value === null) {\n return value;\n }\n if (typeof value === \"boolean\") {\n return value;\n }\n if (typeof value === \"number\") {\n return value;\n }\n if (typeof value === \"string\") {\n return value;\n }\n if (Array.isArray(value)) {\n return value.map((value) => jsonToConvex(value));\n }\n if (typeof value !== \"object\") {\n throw new Error(`Unexpected type of ${value as any}`);\n }\n const entries = Object.entries(value);\n if (entries.length === 1) {\n const key = entries[0][0];\n if (key === \"$bytes\") {\n if (typeof value.$bytes !== \"string\") {\n throw new Error(`Malformed $bytes field on ${value as any}`);\n }\n return Base64.toByteArray(value.$bytes).buffer;\n }\n if (key === \"$integer\") {\n if (typeof value.$integer !== \"string\") {\n throw new Error(`Malformed $integer field on ${value as any}`);\n }\n return base64ToBigInt(value.$integer);\n }\n if (key === \"$float\") {\n if (typeof value.$float !== \"string\") {\n throw new Error(`Malformed $float field on ${value as any}`);\n }\n const floatBytes = Base64.toByteArray(value.$float);\n if (floatBytes.byteLength !== 8) {\n throw new Error(\n `Received ${floatBytes.byteLength} bytes, expected 8 for $float`,\n );\n }\n const floatBytesView = new DataView(floatBytes.buffer);\n const float = floatBytesView.getFloat64(0, LITTLE_ENDIAN);\n if (!isSpecial(float)) {\n throw new Error(`Float ${float} should be encoded as a number`);\n }\n return float;\n }\n if (key === \"$set\") {\n throw new Error(\n `Received a Set which is no longer supported as a Convex type.`,\n );\n }\n if (key === \"$map\") {\n throw new Error(\n `Received a Map which is no longer supported as a Convex type.`,\n );\n }\n }\n const out: { [key: string]: Value } = {};\n for (const [k, v] of Object.entries(value)) {\n validateObjectField(k);\n out[k] = jsonToConvex(v);\n }\n return out;\n}\n\nexport function stringifyValueForError(value: any) {\n return JSON.stringify(value, (_key, value) => {\n if (value === undefined) {\n // By default `JSON.stringify` converts undefined, functions, symbols,\n // Infinity, and NaN to null which produces a confusing error message.\n // We deal with `undefined` specifically because it's the most common.\n // Ideally we'd use a pretty-printing library that prints `undefined`\n // (no quotes), but it might not be worth the bundle size cost.\n return \"undefined\";\n }\n if (typeof value === \"bigint\") {\n // `JSON.stringify` throws on bigints by default.\n return `${value.toString()}n`;\n }\n return value;\n });\n}\n\nfunction convexToJsonInternal(\n value: Value,\n originalValue: Value,\n context: string,\n includeTopLevelUndefined: boolean,\n): JSONValue {\n if (value === undefined) {\n const contextText =\n context &&\n ` (present at path ${context} in original object ${stringifyValueForError(\n originalValue,\n )})`;\n throw new Error(\n `undefined is not a valid Convex value${contextText}. To learn about Convex's supported types, see https://docs.convex.dev/using/types.`,\n );\n }\n if (value === null) {\n return value;\n }\n if (typeof value === \"bigint\") {\n if (value < MIN_INT64 || MAX_INT64 < value) {\n throw new Error(\n `BigInt ${value} does not fit into a 64-bit signed integer.`,\n );\n }\n return { $integer: bigIntToBase64(value) };\n }\n if (typeof value === \"number\") {\n if (isSpecial(value)) {\n const buffer = new ArrayBuffer(8);\n new DataView(buffer).setFloat64(0, value, LITTLE_ENDIAN);\n return { $float: Base64.fromByteArray(new Uint8Array(buffer)) };\n } else {\n return value;\n }\n }\n if (typeof value === \"boolean\") {\n return value;\n }\n if (typeof value === \"string\") {\n return value;\n }\n if (value instanceof ArrayBuffer) {\n return { $bytes: Base64.fromByteArray(new Uint8Array(value)) };\n }\n if (Array.isArray(value)) {\n return value.map((value, i) =>\n convexToJsonInternal(value, originalValue, context + `[${i}]`, false),\n );\n }\n if (value instanceof Set) {\n throw new Error(\n errorMessageForUnsupportedType(context, \"Set\", [...value], originalValue),\n );\n }\n if (value instanceof Map) {\n throw new Error(\n errorMessageForUnsupportedType(context, \"Map\", [...value], originalValue),\n );\n }\n\n if (!isSimpleObject(value)) {\n const theType = value?.constructor?.name;\n const typeName = theType ? `${theType} ` : \"\";\n throw new Error(\n errorMessageForUnsupportedType(context, typeName, value, originalValue),\n );\n }\n\n const out: { [key: string]: JSONValue } = {};\n const entries = Object.entries(value);\n entries.sort(([k1, _v1], [k2, _v2]) => (k1 === k2 ? 0 : k1 < k2 ? -1 : 1));\n for (const [k, v] of entries) {\n if (v !== undefined) {\n validateObjectField(k);\n out[k] = convexToJsonInternal(v, originalValue, context + `.${k}`, false);\n } else if (includeTopLevelUndefined) {\n validateObjectField(k);\n out[k] = convexOrUndefinedToJsonInternal(\n v,\n originalValue,\n context + `.${k}`,\n );\n }\n }\n return out;\n}\n\nfunction errorMessageForUnsupportedType(\n context: string,\n typeName: string,\n value: any,\n originalValue: any,\n) {\n if (context) {\n return `${typeName}${stringifyValueForError(\n value,\n )} is not a supported Convex type (present at path ${context} in original object ${stringifyValueForError(\n originalValue,\n )}). To learn about Convex's supported types, see https://docs.convex.dev/using/types.`;\n } else {\n return `${typeName}${stringifyValueForError(\n value,\n )} is not a supported Convex type.`;\n }\n}\n\n// convexOrUndefinedToJsonInternal wrapper exists so we can pipe through the\n// `originalValue` and `context` through for better error messaging.\nfunction convexOrUndefinedToJsonInternal(\n value: Value | undefined,\n originalValue: Value | undefined,\n context: string,\n): JSONValue {\n if (value === undefined) {\n return { $undefined: null };\n } else {\n if (originalValue === undefined) {\n // This should not happen.\n throw new Error(\n `Programming error. Current value is ${stringifyValueForError(\n value,\n )} but original value is undefined`,\n );\n }\n return convexToJsonInternal(value, originalValue, context, false);\n }\n}\n\n/**\n * Convert a Convex value to its JSON representation.\n *\n * Use {@link jsonToConvex} to recreate the original value.\n *\n * To learn more about Convex values, see [Types](https://docs.convex.dev/using/types).\n *\n * @param value - A Convex value to convert into JSON.\n * @returns The JSON representation of `value`.\n *\n * @public\n */\nexport function convexToJson(value: Value): JSONValue {\n return convexToJsonInternal(value, value, \"\", false);\n}\n\n// Convert a Convex value or `undefined` into its JSON representation.\n// `undefined` is used in filters to represent a missing object field.\nexport function convexOrUndefinedToJson(value: Value | undefined): JSONValue {\n return convexOrUndefinedToJsonInternal(value, value, \"\");\n}\n\n/**\n * Similar to convexToJson but also serializes top level undefined fields\n * using convexOrUndefinedToJson().\n *\n * @param value - A Convex value to convert into JSON.\n * @returns The JSON representation of `value`.\n */\nexport function patchValueToJson(value: Value): JSONValue {\n return convexToJsonInternal(value, value, \"\", true);\n}\n", "import { Value, stringifyValueForError } from \"./value.js\";\n\nconst IDENTIFYING_FIELD = Symbol.for(\"ConvexError\");\n\nexport class ConvexError<TData extends Value> extends Error {\n name = \"ConvexError\";\n data: TData;\n [IDENTIFYING_FIELD] = true;\n\n constructor(data: TData) {\n super(typeof data === \"string\" ? data : stringifyValueForError(data));\n this.data = data;\n }\n}\n", "import { 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 function logToConsole(\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 console.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 console.log(\n `%c[CONVEX ${prefix}(${udfPath})] [${level}]`,\n INFO_COLOR,\n args,\n );\n } else {\n console.error(`[CONVEX ${prefix}(${udfPath})] ${message}`);\n }\n}\n\nexport function logFatalError(message: string): Error {\n const errorMessage = `[CONVEX FATAL ERROR] ${message}`;\n console.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", "import { convexToJson, Value } from \"../../values/index.js\";\n\nexport function canonicalizeUdfPath(udfPath: string): string {\n const pieces = udfPath.split(\":\");\n let moduleName: string;\n let functionName: string;\n if (pieces.length === 1) {\n moduleName = pieces[0];\n functionName = \"default\";\n } else {\n moduleName = pieces.slice(0, pieces.length - 1).join(\":\");\n functionName = pieces[pieces.length - 1];\n }\n if (moduleName.endsWith(\".js\")) {\n moduleName = moduleName.slice(0, -3);\n }\n return `${moduleName}:${functionName}`;\n}\n\n/**\n * A string representing the name and arguments of a query.\n *\n * This is used by the {@link BaseConvexClient}.\n *\n * @public\n */\nexport type QueryToken = string;\n\nexport function serializePathAndArgs(\n udfPath: string,\n args: Record<string, Value>,\n): QueryToken {\n return JSON.stringify({\n udfPath: canonicalizeUdfPath(udfPath),\n args: convexToJson(args),\n });\n}\n", "import { convexToJson, Value } from \"../../values/index.js\";\nimport {\n AddQuery,\n RemoveQuery,\n QueryId,\n QuerySetModification,\n QuerySetVersion,\n IdentityVersion,\n Authenticate,\n QueryJournal,\n Transition,\n AdminAuthentication,\n UserIdentityAttributes,\n} from \"./protocol.js\";\nimport {\n canonicalizeUdfPath,\n QueryToken,\n serializePathAndArgs,\n} from \"./udf_path_utils.js\";\n\ntype LocalQuery = {\n id: QueryId;\n canonicalizedUdfPath: string;\n args: Record<string, Value>;\n numSubscribers: number;\n journal?: QueryJournal;\n};\n\nexport class LocalSyncState {\n private nextQueryId: QueryId;\n private querySetVersion: QuerySetVersion;\n private readonly querySet: Map<QueryToken, LocalQuery>;\n private readonly queryIdToToken: Map<QueryId, QueryToken>;\n private identityVersion: IdentityVersion;\n private auth?: {\n tokenType: \"Admin\" | \"User\";\n value: string;\n impersonating?: UserIdentityAttributes;\n };\n private readonly outstandingQueriesOlderThanRestart: Set<QueryId>;\n private outstandingAuthOlderThanRestart: boolean;\n\n constructor() {\n this.nextQueryId = 0;\n this.querySetVersion = 0;\n this.identityVersion = 0;\n this.querySet = new Map();\n this.queryIdToToken = new Map();\n this.outstandingQueriesOlderThanRestart = new Set();\n this.outstandingAuthOlderThanRestart = false;\n }\n\n hasSyncedPastLastReconnect(): boolean {\n return (\n this.outstandingQueriesOlderThanRestart.size === 0 &&\n !this.outstandingAuthOlderThanRestart\n );\n }\n\n markAuthCompletion() {\n this.outstandingAuthOlderThanRestart = false;\n }\n\n subscribe(\n udfPath: string,\n args: Record<string, Value>,\n journal?: QueryJournal,\n componentPath?: string,\n ): {\n queryToken: QueryToken;\n modification: QuerySetModification | null;\n unsubscribe: () => QuerySetModification | null;\n } {\n const canonicalizedUdfPath = canonicalizeUdfPath(udfPath);\n const queryToken = serializePathAndArgs(canonicalizedUdfPath, args);\n\n const existingEntry = this.querySet.get(queryToken);\n\n if (existingEntry !== undefined) {\n existingEntry.numSubscribers += 1;\n return {\n queryToken,\n modification: null,\n unsubscribe: () => this.removeSubscriber(queryToken),\n };\n } else {\n const queryId = this.nextQueryId++;\n const query: LocalQuery = {\n id: queryId,\n canonicalizedUdfPath,\n args,\n numSubscribers: 1,\n journal,\n };\n this.querySet.set(queryToken, query);\n this.queryIdToToken.set(queryId, queryToken);\n\n const baseVersion = this.querySetVersion;\n const newVersion = ++this.querySetVersion;\n\n const add: AddQuery = {\n type: \"Add\",\n queryId,\n udfPath: canonicalizedUdfPath,\n args: [convexToJson(args)],\n journal,\n componentPath,\n };\n const modification: QuerySetModification = {\n type: \"ModifyQuerySet\",\n baseVersion,\n newVersion,\n modifications: [add],\n };\n return {\n queryToken,\n modification,\n unsubscribe: () => this.removeSubscriber(queryToken),\n };\n }\n }\n\n transition(transition: Transition) {\n for (const modification of transition.modifications) {\n switch (modification.type) {\n case \"QueryUpdated\":\n case \"QueryFailed\": {\n this.outstandingQueriesOlderThanRestart.delete(modification.queryId);\n const journal = modification.journal;\n if (journal !== undefined) {\n const queryToken = this.queryIdToToken.get(modification.queryId);\n // We may have already unsubscribed to this query by the time the server\n // sends us the journal. If so, just ignore it.\n if (queryToken !== undefined) {\n this.querySet.get(queryToken)!.journal = journal;\n }\n }\n\n break;\n }\n case \"QueryRemoved\": {\n this.outstandingQueriesOlderThanRestart.delete(modification.queryId);\n break;\n }\n default: {\n // Enforce that the switch-case is exhaustive.\n const _: never = modification;\n throw new Error(`Invalid modification ${(modification as any).type}`);\n }\n }\n }\n }\n\n queryId(udfPath: string, args: Record<string, Value>): QueryId | null {\n const canonicalizedUdfPath = canonicalizeUdfPath(udfPath);\n const queryToken = serializePathAndArgs(canonicalizedUdfPath, args);\n const existingEntry = this.querySet.get(queryToken);\n if (existingEntry !== undefined) {\n return existingEntry.id;\n }\n return null;\n }\n\n isCurrentOrNewerAuthVersion(version: IdentityVersion): boolean {\n return version >= this.identityVersion;\n }\n\n setAuth(value: string): Authenticate {\n this.auth = {\n tokenType: \"User\",\n value: value,\n };\n const baseVersion = this.identityVersion++;\n return {\n type: \"Authenticate\",\n baseVersion: baseVersion,\n ...this.auth,\n };\n }\n\n setAdminAuth(\n value: string,\n actingAs?: UserIdentityAttributes,\n ): AdminAuthentication {\n const auth: typeof this.auth & {\n tokenType: \"Admin\";\n } = {\n tokenType: \"Admin\",\n value,\n impersonating: actingAs,\n };\n this.auth = auth;\n const baseVersion = this.identityVersion++;\n return {\n type: \"Authenticate\",\n baseVersion: baseVersion,\n ...auth,\n };\n }\n\n clearAuth(): Authenticate {\n this.auth = undefined;\n this.markAuthCompletion();\n const baseVersion = this.identityVersion++;\n return {\n type: \"Authenticate\",\n tokenType: \"None\",\n baseVersion: baseVersion,\n };\n }\n\n hasAuth(): boolean {\n return !!this.auth;\n }\n\n isNewAuth(value: string): boolean {\n return this.auth?.value !== value;\n }\n\n queryPath(queryId: QueryId): string | null {\n const pathAndArgs = this.queryIdToToken.get(queryId);\n if (pathAndArgs) {\n return this.querySet.get(pathAndArgs)!.canonicalizedUdfPath;\n }\n return null;\n }\n\n queryArgs(queryId: QueryId): Record<string, Value> | null {\n const pathAndArgs = this.queryIdToToken.get(queryId);\n if (pathAndArgs) {\n return this.querySet.get(pathAndArgs)!.args;\n }\n return null;\n }\n\n queryToken(queryId: QueryId): string | null {\n return this.queryIdToToken.get(queryId) ?? null;\n }\n\n queryJournal(queryToken: QueryToken): QueryJournal | undefined {\n return this.querySet.get(queryToken)?.journal;\n }\n\n restart(\n oldRemoteQueryResults: Set<QueryId>,\n ): [QuerySetModification, Authenticate?] {\n this.outstandingQueriesOlderThanRestart.clear();\n const modifications = [];\n for (const localQuery of this.querySet.values()) {\n const add: AddQuery = {\n type: \"Add\",\n queryId: localQuery.id,\n udfPath: localQuery.canonicalizedUdfPath,\n args: [convexToJson(localQuery.args)],\n journal: localQuery.journal,\n };\n modifications.push(add);\n\n if (!oldRemoteQueryResults.has(localQuery.id)) {\n this.outstandingQueriesOlderThanRestart.add(localQuery.id);\n }\n }\n this.querySetVersion = 1;\n const querySet: QuerySetModification = {\n type: \"ModifyQuerySet\",\n baseVersion: 0,\n newVersion: 1,\n modifications,\n };\n // If there's no auth, no need to send an update as the server will also start with an unknown identity.\n if (!this.auth) {\n this.identityVersion = 0;\n return [querySet, undefined];\n }\n this.outstandingAuthOlderThanRestart = true;\n const authenticate: Authenticate = {\n type: \"Authenticate\",\n baseVersion: 0,\n ...this.auth,\n };\n this.identityVersion = 1;\n return [querySet, authenticate];\n }\n\n resume(\n remoteQueryResults: Set<QueryId>,\n ): [QuerySetModification?, Authenticate?] {\n const localQueryIds = new Set();\n const modifications = [];\n for (const localQuery of this.querySet.values()) {\n localQueryIds.add(localQuery.id);\n\n if (!remoteQueryResults.has(localQuery.id)) {\n const add: AddQuery = {\n type: \"Add\",\n queryId: localQuery.id,\n udfPath: localQuery.canonicalizedUdfPath,\n args: [convexToJson(localQuery.args)],\n journal: localQuery.journal,\n };\n modifications.push(add);\n }\n }\n\n for (const remoteQueryId of remoteQueryResults) {\n if (!localQueryIds.has(remoteQueryId)) {\n const remove: RemoveQuery = {\n type: \"Remove\",\n queryId: remoteQueryId,\n };\n modifications.push(remove);\n }\n }\n\n const querySet: QuerySetModification | undefined =\n modifications.length > 0\n ? {\n type: \"ModifyQuerySet\",\n baseVersion: this.querySetVersion,\n newVersion: this.querySetVersion + 1,\n modifications,\n }\n : undefined;\n const authenticate: Authenticate | undefined =\n this.auth !== undefined\n ? {\n type: \"Authenticate\",\n baseVersion: this.identityVersion,\n ...this.auth,\n }\n : undefined;\n return [querySet, authenticate];\n }\n\n private removeSubscriber(\n queryToken: QueryToken,\n ): QuerySetModification | null {\n const localQuery = this.querySet.get(queryToken)!;\n\n if (localQuery.numSubscribers > 1) {\n localQuery.numSubscribers -= 1;\n return null;\n } else {\n this.querySet.delete(queryToken);\n this.queryIdToToken.delete(localQuery.id);\n this.outstandingQueriesOlderThanRestart.delete(localQuery.id);\n const baseVersion = this.querySetVersion;\n const newVersion = ++this.querySetVersion;\n const remove: RemoveQuery = {\n type: \"Remove\",\n queryId: localQuery.id,\n };\n return {\n type: \"ModifyQuerySet\",\n baseVersion,\n newVersion,\n modifications: [remove],\n };\n }\n }\n}\n", "import { jsonToConvex } from \"../../values/index.js\";\nimport { logToConsole } from \"../logging.js\";\nimport { Long } from \"../long.js\";\nimport { FunctionResult } from \"./function_result.js\";\nimport {\n ActionRequest,\n ActionResponse,\n ClientMessage,\n MutationRequest,\n MutationResponse,\n RequestId,\n} from \"./protocol.js\";\n\ntype RequestStatus =\n | {\n status: \"Requested\" | \"NotSent\";\n onResult: (result: FunctionResult) => void;\n requestedAt: Date;\n }\n | {\n status: \"Completed\";\n onResolve: () => void;\n ts: Long;\n };\n\nexport class RequestManager {\n private inflightRequests: Map<\n RequestId,\n {\n message: MutationRequest | ActionRequest;\n status: RequestStatus;\n }\n >;\n private requestsOlderThanRestart: Set<RequestId>;\n constructor() {\n this.inflightRequests = new Map();\n this.requestsOlderThanRestart = new Set();\n }\n\n request(\n message: MutationRequest | ActionRequest,\n sent: boolean,\n ): Promise<FunctionResult> {\n const result = new Promise<FunctionResult>((resolve) => {\n const status = sent ? \"Requested\" : \"NotSent\";\n this.inflightRequests.set(message.requestId, {\n message,\n status: { status, requestedAt: new Date(), onResult: resolve },\n });\n });\n\n return result;\n }\n\n /**\n * Update the state after receiving a response.\n *\n * @returns A RequestId if the request is complete and its optimistic update\n * can be dropped, null otherwise.\n */\n onResponse(response: MutationResponse | ActionResponse): RequestId | null {\n const requestInfo = this.inflightRequests.get(response.requestId);\n if (requestInfo === undefined) {\n // Annoyingly we can occasionally get responses to mutations that we're no\n // longer tracking. One flow where this happens is:\n // 1. Client sends mutation 1\n // 2. Client gets response for mutation 1. The sever says that it was committed at ts=10.\n // 3. Client is disconnected\n // 4. Client reconnects and re-issues queries and this mutation.\n // 5. Server sends transition message to ts=20\n // 6. Client drops mutation because it's already been observed.\n // 7. Client receives a second response for mutation 1 but doesn't know about it anymore.\n\n // The right fix for this is probably to add a reconciliation phase on\n // reconnection where we receive responses to all the mutations before\n // the transition message so this flow could never happen (CX-1513).\n\n // For now though, we can just ignore this message.\n return null;\n }\n\n // Because `.restart()` re-requests completed requests, we may get some\n // responses for requests that are already in the \"Completed\" state.\n // We can safely ignore those because we've already notified the UI about\n // their results.\n if (requestInfo.status.status === \"Completed\") {\n return null;\n }\n\n const udfType =\n requestInfo.message.type === \"Mutation\" ? \"mutation\" : \"action\";\n const udfPath = requestInfo.message.udfPath;\n\n for (const line of response.logLines) {\n logToConsole(\"info\", udfType, udfPath, line);\n }\n\n const status = requestInfo.status;\n let onResolve;\n if (response.success) {\n onResolve = () =>\n status.onResult({\n success: true,\n logLines: response.logLines,\n value: jsonToConvex(response.result),\n });\n } else {\n const errorMessage = response.result as string;\n const { errorData } = response;\n logToConsole(\"error\", udfType, udfPath, errorMessage);\n onResolve = () =>\n status.onResult({\n success: false,\n errorMessage,\n errorData:\n errorData !== undefined ? jsonToConvex(errorData) : undefined,\n logLines: response.logLines,\n });\n }\n\n // We can resolve Mutation failures immediately since they don't have any\n // side effects. Actions are intentionally decoupled from\n // queries/mutations here on the sync protocol since they have different\n // guarantees.\n if (response.type === \"ActionResponse\" || !response.success) {\n onResolve();\n this.inflightRequests.delete(response.requestId);\n this.requestsOlderThanRestart.delete(response.requestId);\n return response.requestId;\n }\n\n // We have to wait to resolve the request promise until after we transition\n // past this timestamp so clients can read their own writes.\n requestInfo.status = {\n status: \"Completed\",\n ts: response.ts,\n onResolve,\n };\n\n return null;\n }\n\n // Remove and returns completed requests.\n removeCompleted(ts: Long): Set<RequestId> {\n const completeRequests: Set<RequestId> = new Set();\n for (const [requestId, requestInfo] of this.inflightRequests.entries()) {\n const status = requestInfo.status;\n if (status.status === \"Completed\" && status.ts.lessThanOrEqual(ts)) {\n status.onResolve();\n completeRequests.add(requestId);\n this.inflightRequests.delete(requestId);\n this.requestsOlderThanRestart.delete(requestId);\n }\n }\n return completeRequests;\n }\n\n restart(): ClientMessage[] {\n // When we reconnect to the backend, re-request all requests that are safe\n // to be resend.\n\n this.requestsOlderThanRestart = new Set(this.inflightRequests.keys());\n const allMessages = [];\n for (const [requestId, value] of this.inflightRequests) {\n if (value.status.status === \"NotSent\") {\n value.status.status = \"Requested\";\n allMessages.push(value.message);\n continue;\n }\n\n if (value.message.type === \"Mutation\") {\n // This includes ones that have already been completed because we still\n // want to tell the backend to transition the client past the completed\n // timestamp. This is safe since mutations are idempotent.\n allMessages.push(value.message);\n } else {\n // Unlike mutations, actions are not idempotent. When we reconnect to the\n // backend, we don't know if it is safe to resend in-flight actions, so we\n // cancel them and consider them failed.\n this.inflightRequests.delete(requestId);\n this.requestsOlderThanRestart.delete(requestId);\n if (value.status.status === \"Completed\") {\n throw new Error(\"Action should never be in 'Completed' state\");\n }\n value.status.onResult({\n success: false,\n errorMessage: \"Connection lost while action was in flight\",\n logLines: [],\n });\n }\n }\n return allMessages;\n }\n\n resume(): ClientMessage[] {\n const allMessages = [];\n for (const [, value] of this.inflightRequests) {\n if (value.status.status === \"NotSent\") {\n value.status.status = \"Requested\";\n allMessages.push(value.message);\n continue;\n }\n }\n return allMessages;\n }\n\n /**\n * @returns true if there are any requests that have been requested but have\n * not be completed yet.\n */\n hasIncompleteRequests(): boolean {\n for (const requestInfo of this.inflightRequests.values()) {\n if (requestInfo.status.status === \"Requested\") {\n return true;\n }\n }\n return false;\n }\n\n /**\n * @returns true if there are any inflight requests, including ones that have\n * completed on the server, but have not been applied.\n */\n hasInflightRequests(): boolean {\n return this.inflightRequests.size > 0;\n }\n\n /**\n * @returns true if there are any inflight requests, that have been hanging around\n * since prior to the most recent restart.\n */\n hasSyncedPastLastReconnect(): boolean {\n return this.requestsOlderThanRestart.size === 0;\n }\n\n timeOfOldestInflightRequest(): Date | null {\n if (this.inflightRequests.size === 0) {\n return null;\n }\n let oldestInflightRequest = Date.now();\n for (const request of this.inflightRequests.values()) {\n if (request.status.status !== \"Completed\") {\n if (request.status.requestedAt.getTime() < oldestInflightRequest) {\n oldestInflightRequest = request.status.requestedAt.getTime();\n }\n }\n }\n return new Date(oldestInflightRequest);\n }\n}\n", "import {\n EmptyObject,\n DefaultFunctionArgs,\n FunctionVisibility,\n RegisteredAction,\n RegisteredMutation,\n RegisteredQuery,\n} from \"./registration.js\";\nimport { Expand, UnionToIntersection } from \"../type_utils.js\";\nimport { PaginationOptions, PaginationResult } from \"./pagination.js\";\n\n/**\n * The type of a Convex function.\n *\n * @public\n */\nexport type FunctionType = \"query\" | \"mutation\" | \"action\";\n\n/**\n * A reference to a registered Convex function.\n *\n * You can create a {@link FunctionReference} using the generated `api` utility:\n * ```js\n * import { api } from \"../convex/_generated/api\";\n *\n * const reference = api.myModule.myFunction;\n * ```\n *\n * If you aren't using code generation, you can create references using\n * {@link anyApi}:\n * ```js\n * import { anyApi } from \"convex/server\";\n *\n * const reference = anyApi.myModule.myFunction;\n * ```\n *\n * Function references can be used to invoke functions from the client. For\n * example, in React you can pass references to the {@link react.useQuery} hook:\n * ```js\n * const result = useQuery(api.myModule.myFunction);\n * ```\n *\n * @typeParam Type - The type of the function (\"query\", \"mutation\", or \"action\").\n * @typeParam Visibility - The visibility of the function (\"public\" or \"internal\").\n * @typeParam Args - The arguments to this function. This is an object mapping\n * argument names to their types.\n * @typeParam ReturnType - The return type of this function.\n * @public\n */\nexport type FunctionReference<\n Type extends FunctionType,\n Visibility extends FunctionVisibility = \"public\",\n Args extends DefaultFunctionArgs = any,\n ReturnType = any,\n ComponentPath = string | undefined,\n> = {\n _type: Type;\n _visibility: Visibility;\n _args: Args;\n _returnType: ReturnType;\n _componentPath: ComponentPath;\n};\n\n/**\n * A symbol for accessing the name of a {@link FunctionReference} at runtime.\n */\nexport const functionName = Symbol.for(\"functionName\");\n\n/**\n * Get the name of a function from a {@link FunctionReference}.\n *\n * The name is a string like \"myDir/myModule:myFunction\". If the exported name\n * of the function is `\"default\"`, the function name is omitted\n * (e.g. \"myDir/myModule\").\n *\n * @param functionReference - A {@link FunctionReference} to get the name of.\n * @returns A string of the function's name.\n *\n * @public\n */\nexport function getFunctionName(\n functionReference: AnyFunctionReference,\n): string {\n // Both a legacy thing and also a convenience for interactive use:\n // the types won't check but a string is always allowed at runtime.\n if (typeof functionReference === \"string\") return functionReference;\n\n // Two different runtime values for FunctionReference implement this\n // interface: api objects returned from `createApi()` and standalone\n // function reference objects returned from makeFunctionReference.\n const name = (functionReference as any)[functionName];\n if (!name) {\n throw new Error(`${functionReference as any} is not a functionReference`);\n }\n return name;\n}\n\n/**\n * FunctionReferences generally come from generated code, but in custom clients\n * it may be useful to be able to build one manually.\n *\n * Real function references are empty objects at runtime, but the same interface\n * can be implemented with an object for tests and clients which don't use\n * code generation.\n *\n * @param name - The identifier of the function. E.g. `path/to/file:functionName`\n * @public\n */\nexport function makeFunctionReference<\n type extends FunctionType,\n args extends DefaultFunctionArgs = any,\n ret = any,\n>(name: string): FunctionReference<type, \"public\", args, ret> {\n return { [functionName]: name } as unknown as FunctionReference<\n type,\n \"public\",\n args,\n ret\n >;\n}\n\n/**\n * Create a runtime API object that implements {@link AnyApi}.\n *\n * This allows accessing any path regardless of what directories, modules,\n * or functions are defined.\n *\n * @param pathParts - The path to the current node in the API.\n * @returns An {@link AnyApi}\n * @public\n */\nfunction createApi(pathParts: string[] = []): AnyApi {\n const handler: ProxyHandler<object> = {\n get(_, prop: string | symbol) {\n if (typeof prop === \"string\") {\n const newParts = [...pathParts, prop];\n return createApi(newParts);\n } else if (prop === functionName) {\n if (pathParts.length < 2) {\n const found = [\"api\", ...pathParts].join(\".\");\n throw new Error(\n `API path is expected to be of the form \\`api.moduleName.functionName\\`. Found: \\`${found}\\``,\n );\n }\n const path = pathParts.slice(0, -1).join(\"/\");\n const exportName = pathParts[pathParts.length - 1];\n if (exportName === \"default\") {\n return path;\n } else {\n return path + \":\" + exportName;\n }\n } else if (prop === Symbol.toStringTag) {\n return \"FunctionReference\";\n } else {\n return undefined;\n }\n },\n };\n\n return new Proxy({}, handler);\n}\n\n/**\n * Given an export from a module, convert it to a {@link FunctionReference}\n * if it is a Convex function.\n */\nexport type FunctionReferenceFromExport<Export> =\n Export extends RegisteredQuery<\n infer Visibility,\n infer Args,\n infer ReturnValue\n >\n ? FunctionReference<\n \"query\",\n Visibility,\n Args,\n ConvertReturnType<ReturnValue>\n >\n : Export extends RegisteredMutation<\n infer Visibility,\n infer Args,\n infer ReturnValue\n >\n ? FunctionReference<\n \"mutation\",\n Visibility,\n Args,\n ConvertReturnType<ReturnValue>\n >\n : Export extends RegisteredAction<\n infer Visibility,\n infer Args,\n infer ReturnValue\n >\n ? FunctionReference<\n \"action\",\n Visibility,\n Args,\n ConvertReturnType<ReturnValue>\n >\n : never;\n\n/**\n * Given a module, convert all the Convex functions into\n * {@link FunctionReference}s and remove the other exports.\n *\n * BE CAREFUL WHEN EDITING THIS!\n *\n * This is written carefully to preserve jumping to function definitions using\n * cmd+click. If you edit it, please test that cmd+click still works.\n */\ntype FunctionReferencesInModule<Module extends Record<string, any>> = {\n -readonly [ExportName in keyof Module as Module[ExportName][\"isConvexFunction\"] extends true\n ? ExportName\n : never]: FunctionReferenceFromExport<Module[ExportName]>;\n};\n\n/**\n * Given a path to a module and it's type, generate an API type for this module.\n *\n * This is a nested object according to the module's path.\n */\ntype ApiForModule<\n ModulePath extends string,\n Module extends object,\n> = ModulePath extends `${infer First}/${infer Second}`\n ? {\n [_ in First]: ApiForModule<Second, Module>;\n }\n : { [_ in ModulePath]: FunctionReferencesInModule<Module> };\n\n/**\n * Given the types of all modules in the `convex/` directory, construct the type\n * of `api`.\n *\n * `api` is a utility for constructing {@link FunctionReference}s.\n *\n * @typeParam AllModules - A type mapping module paths (like `\"dir/myModule\"`) to\n * the types of the modules.\n * @public\n */\nexport type ApiFromModules<AllModules extends Record<string, object>> =\n FilterApi<\n ApiFromModulesAllowEmptyNodes<AllModules>,\n FunctionReference<any, any, any, any>\n >;\n\ntype ApiFromModulesAllowEmptyNodes<AllModules extends Record<string, object>> =\n ExpandModulesAndDirs<\n UnionToIntersection<\n {\n [ModulePath in keyof AllModules]: ApiForModule<\n ModulePath & string,\n AllModules[ModulePath]\n >;\n }[keyof AllModules]\n >\n >;\n\n/**\n * @public\n *\n * Filter a Convex deployment api object for functions which meet criteria,\n * for example all public queries.\n */\nexport type FilterApi<API, Predicate> = Expand<{\n [mod in keyof API as API[mod] extends Predicate\n ? mod\n : API[mod] extends FunctionReference<any, any, any, any>\n ? never\n : FilterApi<API[mod], Predicate> extends Record<string, never>\n ? never\n : mod]: API[mod] extends Predicate\n ? API[mod]\n : FilterApi<API[mod], Predicate>;\n}>;\n\n/**\n * Given an api of type API and a FunctionReference subtype, return an api object\n * containing only the function references that match.\n *\n * ```ts\n * const q = filterApi<typeof api, FunctionReference<\"query\">>(api)\n * ```\n *\n * @public\n */\nexport function filterApi<API, Predicate>(api: API): FilterApi<API, Predicate> {\n return api as any;\n}\n\n// These just* API filter helpers require no type parameters so are useable from JavaScript.\n/** @public */\nexport function justInternal<API>(\n api: API,\n): FilterApi<API, FunctionReference<any, \"internal\", any, any>> {\n return api as any;\n}\n\n/** @public */\nexport function justPublic<API>(\n api: API,\n): FilterApi<API, FunctionReference<any, \"public\", any, any>> {\n return api as any;\n}\n\n/** @public */\nexport function justQueries<API>(\n api: API,\n): FilterApi<API, FunctionReference<\"query\", any, any, any>> {\n return api as any;\n}\n\n/** @public */\nexport function justMutations<API>(\n api: API,\n): FilterApi<API, FunctionReference<\"mutation\", any, any, any>> {\n return api as any;\n}\n\n/** @public */\nexport function justActions<API>(\n api: API,\n): FilterApi<API, FunctionReference<\"action\", any, any, any>> {\n return api as any;\n}\n\n/** @public */\nexport function justPaginatedQueries<API>(\n api: API,\n): FilterApi<\n API,\n FunctionReference<\n \"query\",\n any,\n { paginationOpts: PaginationOptions },\n PaginationResult<any>\n >\n> {\n return api as any;\n}\n\n/** @public */\nexport function justSchedulable<API>(\n api: API,\n): FilterApi<API, FunctionReference<\"mutation\" | \"action\", any, any, any>> {\n return api as any;\n}\n\n/**\n * Like {@link Expand}, this simplifies how TypeScript displays object types.\n * The differences are:\n * 1. This version is recursive.\n * 2. This stops recursing when it hits a {@link FunctionReference}.\n */\ntype ExpandModulesAndDirs<ObjectType> = ObjectType extends AnyFunctionReference\n ? ObjectType\n : {\n [Key in keyof ObjectType]: ExpandModulesAndDirs<ObjectType[Key]>;\n };\n\n/**\n * A {@link FunctionReference} of any type and any visibility with any\n * arguments and any return type.\n *\n * @public\n */\nexport type AnyFunctionReference = FunctionReference<any, any>;\n\ntype AnyModuleDirOrFunc = {\n [key: string]: AnyModuleDirOrFunc;\n} & AnyFunctionReference;\n\n/**\n * The type that Convex api objects extend. If you were writing an api from\n * scratch it should extend this type.\n *\n * @public\n */\nexport type AnyApi = Record<string, Record<string, AnyModuleDirOrFunc>>;\n\n/**\n * Recursive partial API, useful for defining a subset of an API when mocking\n * or building custom api objects.\n *\n * @public\n */\nexport type PartialApi<API> = {\n [mod in keyof API]?: API[mod] extends FunctionReference<any, any, any, any>\n ? API[mod]\n : PartialApi<API[mod]>;\n};\n\n/**\n * A utility for constructing {@link FunctionReference}s in projects that\n * are not using code generation.\n *\n * You can create a reference to a function like:\n * ```js\n * const reference = anyApi.myModule.myFunction;\n * ```\n *\n * This supports accessing any path regardless of what directories and modules\n * are in your project. All function references are typed as\n * {@link AnyFunctionReference}.\n *\n *\n * If you're using code generation, use `api` from `convex/_generated/api`\n * instead. It will be more type-safe and produce better auto-complete\n * in your editor.\n *\n * @public\n */\nexport const anyApi: AnyApi = createApi() as any;\n\n/**\n * Given a {@link FunctionReference}, get the return type of the function.\n *\n * This is represented as an object mapping argument names to values.\n * @public\n */\nexport type FunctionArgs<FuncRef extends AnyFunctionReference> =\n FuncRef[\"_args\"];\n\n/**\n * A tuple type of the (maybe optional) arguments to `FuncRef`.\n *\n * This type is used to make methods involving arguments type safe while allowing\n * skipping the arguments for functions that don't require arguments.\n *\n * @public\n */\nexport type OptionalRestArgs<FuncRef extends AnyFunctionReference> =\n FuncRef[\"_args\"] extends EmptyObject\n ? [args?: EmptyObject]\n : [args: FuncRef[\"_args\"]];\n\n/**\n * A tuple type of the (maybe optional) arguments to `FuncRef`, followed by an options\n * object of type `Options`.\n *\n * This type is used to make methods like `useQuery` type-safe while allowing\n * 1. Skipping arguments for functions that don't require arguments.\n * 2. Skipping the options object.\n * @public\n */\nexport type ArgsAndOptions<\n FuncRef extends AnyFunctionReference,\n Options,\n> = FuncRef[\"_args\"] extends EmptyObject\n ? [args?: EmptyObject, options?: Options]\n : [args: FuncRef[\"_args\"], options?: Options];\n\n/**\n * Given a {@link FunctionReference}, get the return type of the function.\n *\n * @public\n */\nexport type FunctionReturnType<FuncRef extends AnyFunctionReference> =\n FuncRef[\"_returnType\"];\n\ntype UndefinedToNull<T> = T extends void ? null : T;\n\ntype NullToUndefinedOrNull<T> = T extends null ? T | undefined | void : T;\n\n/**\n * Convert the return type of a function to it's client-facing format.\n *\n * This means:\n * - Converting `undefined` and `void` to `null`\n * - Removing all `Promise` wrappers\n */\nexport type ConvertReturnType<T> = UndefinedToNull<Awaited<T>>;\n\nexport type ValidatorTypeToReturnType<T> =\n | Promise<NullToUndefinedOrNull<T>>\n | NullToUndefinedOrNull<T>;\n", "import {\n FunctionArgs,\n FunctionReference,\n FunctionReturnType,\n OptionalRestArgs,\n getFunctionName,\n} from \"../../server/api.js\";\nimport { parseArgs } from \"../../common/index.js\";\nimport { Value } from \"../../values/index.js\";\nimport { createHybridErrorStacktrace, forwardData } from \"../logging.js\";\nimport { FunctionResult } from \"./function_result.js\";\nimport { OptimisticLocalStore } from \"./optimistic_updates.js\";\nimport { RequestId } from \"./protocol.js\";\nimport {\n canonicalizeUdfPath,\n QueryToken,\n serializePathAndArgs,\n} from \"./udf_path_utils.js\";\nimport { ConvexError } from \"../../values/errors.js\";\n\n/**\n * An optimistic update function that has been curried over its arguments.\n */\ntype WrappedOptimisticUpdate = (locaQueryStore: OptimisticLocalStore) => void;\n\n/**\n * The implementation of `OptimisticLocalStore`.\n *\n * This class provides the interface for optimistic updates to modify query results.\n */\nclass OptimisticLocalStoreImpl implements OptimisticLocalStore {\n // A references of the query results in OptimisticQueryResults\n private readonly queryResults: QueryResultsMap;\n\n // All of the queries modified by this class\n readonly modifiedQueries: QueryToken[];\n\n constructor(queryResults: QueryResultsMap) {\n this.queryResults = queryResults;\n this.modifiedQueries = [];\n }\n\n getQuery<Query extends FunctionReference<\"query\">>(\n query: Query,\n ...args: OptionalRestArgs<Query>\n ): undefined | FunctionReturnType<Query> {\n const queryArgs = parseArgs(args[0]);\n const name = getFunctionName(query);\n const queryResult = this.queryResults.get(\n serializePathAndArgs(name, queryArgs),\n );\n if (queryResult === undefined) {\n return undefined;\n }\n return OptimisticLocalStoreImpl.queryValue(queryResult.result);\n }\n\n getAllQueries<Query extends FunctionReference<\"query\">>(\n query: Query,\n ): {\n args: FunctionArgs<Query>;\n value: undefined | FunctionReturnType<Query>;\n }[] {\n const queriesWithName: {\n args: FunctionArgs<Query>;\n value: undefined | FunctionReturnType<Query>;\n }[] = [];\n const name = getFunctionName(query);\n for (const queryResult of this.queryResults.values()) {\n if (queryResult.udfPath === canonicalizeUdfPath(name)) {\n queriesWithName.push({\n args: queryResult.args as FunctionArgs<Query>,\n value: OptimisticLocalStoreImpl.queryValue(queryResult.result),\n });\n }\n }\n return queriesWithName;\n }\n\n setQuery<QueryReference extends FunctionReference<\"query\">>(\n queryReference: QueryReference,\n args: FunctionArgs<QueryReference>,\n value: undefined | FunctionReturnType<QueryReference>,\n ): void {\n const queryArgs = parseArgs(args);\n const name = getFunctionName(queryReference);\n const queryToken = serializePathAndArgs(name, queryArgs);\n\n let result: FunctionResult | undefined;\n if (value === undefined) {\n result = undefined;\n } else {\n result = {\n success: true,\n value,\n // It's an optimistic update, so there are no function logs to show.\n logLines: [],\n };\n }\n const query: Query = {\n udfPath: name,\n args: queryArgs,\n result,\n };\n this.queryResults.set(queryToken, query);\n this.modifiedQueries.push(queryToken);\n }\n\n private static queryValue(\n result: FunctionResult | undefined,\n ): Value | undefined {\n if (result === undefined) {\n return undefined;\n } else if (result.success) {\n return result.value;\n } else {\n // If the query is an error state, just return `undefined` as though\n // it's loading. Optimistic updates should already handle `undefined` well\n // and there isn't a need to break the whole update because it tried\n // to load a single query that errored.\n return undefined;\n }\n }\n}\n\ntype OptimisticUpdateAndId = {\n update: WrappedOptimisticUpdate;\n mutationId: RequestId;\n};\n\ntype Query = {\n // undefined means the query was set to be loading (undefined) in an optimistic update.\n // Note that we can also have queries not present in the QueryResultMap\n // at all because they are still loading from the server.\n result: FunctionResult | undefined;\n udfPath: string;\n args: Record<string, Value>;\n};\nexport type QueryResultsMap = Map<QueryToken, Query>;\n\ntype ChangedQueries = QueryToken[];\n\n/**\n * A view of all of our query results with optimistic updates applied on top.\n */\nexport class OptimisticQueryResults {\n private queryResults: QueryResultsMap;\n private optimisticUpdates: OptimisticUpdateAndId[];\n\n constructor() {\n this.queryResults = new Map();\n this.optimisticUpdates = [];\n }\n\n ingestQueryResultsFromServer(\n serverQueryResults: QueryResultsMap,\n optimisticUpdatesToDrop: Set<RequestId>,\n ): ChangedQueries {\n this.optimisticUpdates = this.optimisticUpdates.filter((updateAndId) => {\n return !optimisticUpdatesToDrop.has(updateAndId.mutationId);\n });\n\n const oldQueryResults = this.queryResults;\n this.queryResults = new Map(serverQueryResults);\n const localStore = new OptimisticLocalStoreImpl(this.queryResults);\n for (const updateAndId of this.optimisticUpdates) {\n updateAndId.update(localStore);\n }\n\n // To find the changed queries, just do a shallow comparison\n // TODO(CX-733): Change this so we avoid unnecessary rerenders\n const changedQueries: ChangedQueries = [];\n for (const [queryToken, query] of this.queryResults) {\n const oldQuery = oldQueryResults.get(queryToken);\n if (oldQuery === undefined || oldQuery.result !== query.result) {\n changedQueries.push(queryToken);\n }\n }\n\n return changedQueries;\n }\n\n applyOptimisticUpdate(\n update: WrappedOptimisticUpdate,\n mutationId: RequestId,\n ): ChangedQueries {\n // Apply the update to our store\n this.optimisticUpdates.push({\n update,\n mutationId,\n });\n const localStore = new OptimisticLocalStoreImpl(this.queryResults);\n update(localStore);\n\n // Notify about any query results that changed\n // TODO(CX-733): Change this so we avoid unnecessary rerenders\n return localStore.modifiedQueries;\n }\n\n queryResult(queryToken: QueryToken): Value | undefined {\n const query = this.queryResults.get(queryToken);\n if (query === undefined) {\n return undefined;\n }\n const result = query.result;\n if (result === undefined) {\n return undefined;\n } else if (result.success) {\n return result.value;\n } else {\n if (result.errorData !== undefined) {\n throw forwardData(\n result,\n new ConvexError(\n createHybridErrorStacktrace(\"query\", query.udfPath, result),\n ),\n );\n }\n throw new Error(\n createHybridErrorStacktrace(\"query\", query.udfPath, result),\n );\n }\n }\n\n hasQueryResult(queryToken: QueryToken): boolean {\n return this.queryResults.get(queryToken) !== undefined;\n }\n\n /**\n * @internal\n */\n queryLogs(queryToken: QueryToken): string[] | undefined {\n const query = this.queryResults.get(queryToken);\n return query?.result?.logLines;\n }\n}\n", "// Implements an unsigned long.\n// This is a subset of https://github.com/dcodeIO/Long.js,\n// vendored to decrease bundle size.\n// Copyright Daniel Wirtz <dcode@dcode.io>\n// License: Apache Version 2.0\n/*\n\n Apache License\n Version 2.0, January 2004\n http://www.apache.org/licenses/\n\n TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n 1. Definitions.\n\n \"License\" shall mean the terms and conditions for use, reproduction,\n and distribution as defined by Sections 1 through 9 of this document.\n\n \"Licensor\" shall mean the copyright owner or entity authorized by\n the copyright owner that is granting the License.\n\n \"Legal Entity\" shall mean the union of the acting entity and all\n other entities that control, are controlled by, or are under common\n control with that entity. For the purposes of this definition,\n \"control\" means (i) the power, direct or indirect, to cause the\n direction or management of such entity, whether by contract or\n otherwise, or (ii) ownership of fifty percent (50%) or more of the\n outstanding shares, or (iii) beneficial ownership of such entity.\n\n \"You\" (or \"Your\") shall mean an individual or Legal Entity\n exercising permissions granted by this License.\n\n \"Source\" form shall mean the preferred form for making modifications,\n including but not limited to software source code, documentation\n source, and configuration files.\n\n \"Object\" form shall mean any form resulting from mechanical\n transformation or translation of a Source form, including but\n not limited to compiled object code, generated documentation,\n and conversions to other media types.\n\n \"Work\" shall mean the work of authorship, whether in Source or\n Object form, made available under the License, as indicated by a\n copyright notice that is included in or attached to the work\n (an example is provided in the Appendix below).\n\n \"Derivative Works\" shall mean any work, whether in Source or Object\n form, that is based on (or derived from) the Work and for which the\n editorial revisions, annotations, elaborations, or other modifications\n represent, as a whole, an original work of authorship. For the purposes\n of this License, Derivative Works shall not include works that remain\n separable from, or merely link (or bind by name) to the interfaces of,\n the Work and Derivative Works thereof.\n\n \"Contribution\" shall mean any work of authorship, including\n the original version of the Work and any modifications or additions\n to that Work or Derivative Works thereof, that is intentionally\n submitted to Licensor for inclusion in the Work by the copyright owner\n or by an individual or Legal Entity authorized to submit on behalf of\n the copyright owner. For the purposes of this definition, \"submitted\"\n means any form of electronic, verbal, or written communication sent\n to the Licensor or its representatives, including but not limited to\n communication on electronic mailing lists, source code control systems,\n and issue tracking systems that are managed by, or on behalf of, the\n Licensor for the purpose of discussing and improving the Work, but\n excluding communication that is conspicuously marked or otherwise\n designated in writing by the copyright owner as \"Not a Contribution.\"\n\n \"Contributor\" shall mean Licensor and any individual or Legal Entity\n on behalf of whom a Contribution has been received by Licensor and\n subsequently incorporated within the Work.\n\n 2. Grant of Copyright License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n copyright license to reproduce, prepare Derivative Works of,\n publicly display, publicly perform, sublicense, and distribute the\n Work and such Derivative Works in Source or Object form.\n\n 3. Grant of Patent License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n (except as stated in this section) patent license to make, have made,\n use, offer to sell, sell, import, and otherwise transfer the Work,\n where such license applies only to those patent claims licensable\n by such Contributor that are necessarily infringed by their\n Contribution(s) alone or by combination of their Contribution(s)\n with the Work to which such Contribution(s) was submitted. If You\n institute patent litigation against any entity (including a\n cross-claim or counterclaim in a lawsuit) alleging that the Work\n or a Contribution incorporated within the Work constitutes direct\n or contributory patent infringement, then any patent licenses\n granted to You under this License for that Work shall terminate\n as of the date such litigation is filed.\n\n 4. Redistribution. You may reproduce and distribute copies of the\n Work or Derivative Works thereof in any medium, with or without\n modifications, and in Source or Object form, provided that You\n meet the following conditions:\n\n (a) You must give any other recipients of the Work or\n Derivative Works a copy of this License; and\n\n (b) You must cause any modified files to carry prominent notices\n stating that You changed the files; and\n\n (c) You must retain, in the Source form of any Derivative Works\n that You distribute, all copyright, patent, trademark, and\n attribution notices from the Source form of the Work,\n excluding those notices that do not pertain to any part of\n the Derivative Works; and\n\n (d) If the Work includes a \"NOTICE\" text file as part of its\n distribution, then any Derivative Works that You distribute must\n include a readable copy of the attribution notices contained\n within such NOTICE file, excluding those notices that do not\n pertain to any part of the Derivative Works, in at least one\n of the following places: within a NOTICE text file distributed\n as part of the Derivative Works; within the Source form or\n documentation, if provided along with the Derivative Works; or,\n within a display generated by the Derivative Works, if and\n wherever such third-party notices normally appear. The contents\n of the NOTICE file are for informational purposes only and\n do not modify the License. You may add Your own attribution\n notices within Derivative Works that You distribute, alongside\n or as an addendum to the NOTICE text from the Work, provided\n that such additional attribution notices cannot be construed\n as modifying the License.\n\n You may add Your own copyright statement to Your modifications and\n may provide additional or different license terms and conditions\n for use, reproduction, or distribution of Your modifications, or\n for any such Derivative Works as a whole, provided Your use,\n reproduction, and distribution of the Work otherwise complies with\n the conditions stated in this License.\n\n 5. Submission of Contributions. Unless You explicitly state otherwise,\n any Contribution intentionally submitted for inclusion in the Work\n by You to the Licensor shall be under the terms and conditions of\n this License, without any additional terms or conditions.\n Notwithstanding the above, nothing herein shall supersede or modify\n the terms of any separate license agreement you may have executed\n with Licensor regarding such Contributions.\n\n 6. Trademarks. This License does not grant permission to use the trade\n names, trademarks, service marks, or product names of the Licensor,\n except as required for reasonable and customary use in describing the\n origin of the Work and reproducing the content of the NOTICE file.\n\n 7. Disclaimer of Warranty. Unless required by applicable law or\n agreed to in writing, Licensor provides the Work (and each\n Contributor provides its Contributions) on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n implied, including, without limitation, any warranties or conditions\n of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n PARTICULAR PURPOSE. You are solely responsible for determining the\n appropriateness of using or redistributing the Work and assume any\n risks associated with Your exercise of permissions under this License.\n\n 8. Limitation of Liability. In no event and under no legal theory,\n whether in tort (including negligence), contract, or otherwise,\n unless required by applicable law (such as deliberate and grossly\n negligent acts) or agreed to in writing, shall any Contributor be\n liable to You for damages, including any direct, indirect, special,\n incidental, or consequential damages of any character arising as a\n result of this License or out of the use or inability to use the\n Work (including but not limited to damages for loss of goodwill,\n work stoppage, computer failure or malfunction, or any and all\n other commercial damages or losses), even if such Contributor\n has been advised of the possibility of such damages.\n\n 9. Accepting Warranty or Additional Liability. While redistributing\n the Work or Derivative Works thereof, You may choose to offer,\n and charge a fee for, acceptance of support, warranty, indemnity,\n or other liability obligations and/or rights consistent with this\n License. However, in accepting such obligations, You may act only\n on Your own behalf and on Your sole responsibility, not on behalf\n of any other Contributor, and only if You agree to indemnify,\n defend, and hold each Contributor harmless for any liability\n incurred by, or claims asserted against, such Contributor by reason\n of your accepting any such warranty or additional liability.\n\n END OF TERMS AND CONDITIONS\n\n APPENDIX: How to apply the Apache License to your work.\n\n To apply the Apache License to your work, attach the following\n boilerplate notice, with the fields enclosed by brackets \"[]\"\n replaced with your own identifying information. (Don't include\n the brackets!) The text should be enclosed in the appropriate\n comment syntax for the file format. We also recommend that a\n file or class name and description of purpose be included on the\n same \"printed page\" as the copyright notice for easier\n identification within third-party archives.\n\n Copyright 2023 Daniel Wirtz <dcode@dcode.io>\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n*/\n\n// This works... but don't try to compare one to a real Long.js Long!\n// For internal use only.\n// `| 0` assures the runtime that we are using integer arithmetic\nexport class Long {\n low: number;\n high: number;\n __isUnsignedLong__: boolean;\n\n static isLong(obj: Long) {\n return (obj && obj.__isUnsignedLong__) === true;\n }\n\n constructor(low: number, high: number) {\n this.low = low | 0;\n this.high = high | 0;\n this.__isUnsignedLong__ = true;\n }\n\n // prettier-ignore\n static fromBytesLE(bytes: number[]): Long {\n return new Long(\n bytes[0] |\n bytes[1] << 8 |\n bytes[2] << 16 |\n bytes[3] << 24,\n bytes[4] |\n bytes[5] << 8 |\n bytes[6] << 16 |\n bytes[7] << 24,\n );\n }\n\n // prettier-ignore\n toBytesLE() {\n const hi = this.high;\n const lo = this.low;\n return [\n lo & 0xff,\n lo >>> 8 & 0xff,\n lo >>> 16 & 0xff,\n lo >>> 24,\n hi & 0xff,\n hi >>> 8 & 0xff,\n hi >>> 16 & 0xff,\n hi >>> 24\n ];\n }\n\n static fromNumber(value: number) {\n if (isNaN(value)) return UZERO;\n if (value < 0) return UZERO;\n if (value >= TWO_PWR_64_DBL) return MAX_UNSIGNED_VALUE;\n return new Long(value % TWO_PWR_32_DBL | 0, (value / TWO_PWR_32_DBL) | 0);\n }\n\n toString() {\n return (\n BigInt(this.high) * BigInt(TWO_PWR_32_DBL) +\n BigInt(this.low)\n ).toString();\n }\n\n equals(other: Long) {\n if (!Long.isLong(other)) other = Long.fromValue(other);\n if (this.high >>> 31 === 1 && other.high >>> 31 === 1) return false;\n return this.high === other.high && this.low === other.low;\n }\n\n notEquals(other: Long) {\n return !this.equals(other);\n }\n\n comp(other: Long) {\n if (!Long.isLong(other)) other = Long.fromValue(other);\n if (this.equals(other)) return 0;\n return other.high >>> 0 > this.high >>> 0 ||\n (other.high === this.high && other.low >>> 0 > this.low >>> 0)\n ? -1\n : 1;\n }\n\n lessThanOrEqual(other: Long) {\n return this.comp(/* validates */ other) <= 0;\n }\n\n static fromValue(val: any) {\n if (typeof val === \"number\") return Long.fromNumber(val);\n // Throws for non-objects, converts non-instanceof Long:\n return new Long(val.low, val.high);\n }\n}\n\nconst UZERO = new Long(0, 0);\nconst TWO_PWR_16_DBL = 1 << 16;\nconst TWO_PWR_32_DBL = TWO_PWR_16_DBL * TWO_PWR_16_DBL;\nconst TWO_PWR_64_DBL = TWO_PWR_32_DBL * TWO_PWR_32_DBL;\nconst MAX_UNSIGNED_VALUE = new Long(0xffffffff | 0, 0xffffffff | 0);\n", "import { jsonToConvex } from \"../../values/index.js\";\nimport { Long } from \"../long.js\";\nimport { logToConsole } from \"../logging.js\";\nimport { QueryId, StateVersion, Transition } from \"./protocol.js\";\nimport { FunctionResult } from \"./function_result.js\";\n\n/**\n * A represention of the query results we've received on the current WebSocket\n * connection.\n */\nexport class RemoteQuerySet {\n private version: StateVersion;\n private readonly remoteQuerySet: Map<QueryId, FunctionResult>;\n private readonly queryPath: (queryId: QueryId) => string | null;\n\n constructor(queryPath: (queryId: QueryId) => string | null) {\n this.version = { querySet: 0, ts: Long.fromNumber(0), identity: 0 };\n this.remoteQuerySet = new Map();\n this.queryPath = queryPath;\n }\n\n transition(transition: Transition): void {\n const start = transition.startVersion;\n if (\n this.version.querySet !== start.querySet ||\n this.version.ts.notEquals(start.ts) ||\n this.version.identity !== start.identity\n ) {\n throw new Error(\n `Invalid start version: ${start.ts.toString()}:${start.querySet}`,\n );\n }\n for (const modification of transition.modifications) {\n switch (modification.type) {\n case \"QueryUpdated\": {\n const queryPath = this.queryPath(modification.queryId);\n if (queryPath) {\n for (const line of modification.logLines) {\n logToConsole(\"info\", \"query\", queryPath, line);\n }\n }\n const value = jsonToConvex(modification.value ?? null);\n this.remoteQuerySet.set(modification.queryId, {\n success: true,\n value,\n logLines: modification.logLines,\n });\n break;\n }\n case \"QueryFailed\": {\n const queryPath = this.queryPath(modification.queryId);\n if (queryPath) {\n for (const line of modification.logLines) {\n logToConsole(\"info\", \"query\", queryPath, line);\n }\n }\n const { errorData } = modification;\n this.remoteQuerySet.set(modification.queryId, {\n success: false,\n errorMessage: modification.errorMessage,\n errorData:\n errorData !== undefined ? jsonToConvex(errorData) : undefined,\n logLines: modification.logLines,\n });\n break;\n }\n case \"QueryRemoved\": {\n this.remoteQuerySet.delete(modification.queryId);\n break;\n }\n default: {\n // Enforce that the switch-case is exhaustive.\n const _: never = modification;\n throw new Error(`Invalid modification ${(modification as any).type}`);\n }\n }\n }\n this.version = transition.endVersion;\n }\n\n remoteQueryResults(): Map<QueryId, FunctionResult> {\n return this.remoteQuerySet;\n }\n\n timestamp(): Long {\n return this.version.ts;\n }\n}\n", "import type { UserIdentityAttributes } from \"../../server/authentication.js\";\nexport type { UserIdentityAttributes } from \"../../server/authentication.js\";\nimport { JSONValue, Base64 } from \"../../values/index.js\";\nimport { Long } from \"../long.js\";\n\n/**\n * Shared schema\n */\n\nexport function u64ToLong(encoded: EncodedU64): U64 {\n const integerBytes = Base64.toByteArray(encoded);\n return Long.fromBytesLE(Array.from(integerBytes));\n}\n\nexport function longToU64(raw: U64): EncodedU64 {\n const integerBytes = new Uint8Array(raw.toBytesLE());\n return Base64.fromByteArray(integerBytes);\n}\n\nexport function parseServerMessage(\n encoded: EncodedServerMessage,\n): ServerMessage {\n switch (encoded.type) {\n case \"FatalError\":\n case \"AuthError\":\n case \"ActionResponse\":\n case \"Ping\": {\n return { ...encoded };\n }\n case \"MutationResponse\": {\n if (encoded.success) {\n return { ...encoded, ts: u64ToLong(encoded.ts) };\n } else {\n return { ...encoded };\n }\n }\n case \"Transition\": {\n return {\n ...encoded,\n startVersion: {\n ...encoded.startVersion,\n ts: u64ToLong(encoded.startVersion.ts),\n },\n endVersion: {\n ...encoded.endVersion,\n ts: u64ToLong(encoded.endVersion.ts),\n },\n };\n }\n default: {\n const _exhaustivenessCheck: never = encoded;\n }\n }\n return undefined as never;\n}\n\nexport function encodeClientMessage(\n message: ClientMessage,\n): EncodedClientMessage {\n switch (message.type) {\n case \"Authenticate\":\n case \"ModifyQuerySet\":\n case \"Mutation\":\n case \"Action\":\n case \"Event\": {\n return { ...message };\n }\n case \"Connect\": {\n if (message.maxObservedTimestamp !== undefined) {\n return {\n ...message,\n maxObservedTimestamp: longToU64(message.maxObservedTimestamp),\n };\n } else {\n return { ...message, maxObservedTimestamp: undefined };\n }\n }\n default: {\n const _exhaustivenessCheck: never = message;\n }\n }\n return undefined as never;\n}\n\ntype U64 = Long;\ntype EncodedU64 = string;\n\n/**\n * Unique nonnegative integer identifying a single query.\n */\nexport type QueryId = number; // nonnegative int\n\nexport type QuerySetVersion = number; // nonnegative int\n\nexport type RequestId = number; // nonnegative int\n\nexport type IdentityVersion = number; // nonnegative int\n\n/**\n * A serialized representation of decisions made during a query's execution.\n *\n * A journal is produced when a query function first executes and is re-used\n * when a query is re-executed.\n *\n * Currently this is used to store pagination end cursors to ensure\n * that pages of paginated queries will always end at the same cursor. This\n * enables gapless, reactive pagination.\n *\n * `null` is used to represent empty journals.\n * @public\n */\nexport type QueryJournal = string | null;\n\n/**\n * Client message schema\n */\n\ntype Connect = {\n type: \"Connect\";\n sessionId: string;\n connectionCount: number;\n lastCloseReason: string | null;\n maxObservedTimestamp?: TS;\n};\n\nexport type AddQuery = {\n type: \"Add\";\n queryId: QueryId;\n udfPath: string;\n args: JSONValue[];\n journal?: QueryJournal;\n /**\n * @internal\n */\n componentPath?: string;\n};\n\nexport type RemoveQuery = {\n type: \"Remove\";\n queryId: QueryId;\n};\n\nexport type QuerySetModification = {\n type: \"ModifyQuerySet\";\n baseVersion: QuerySetVersion;\n newVersion: QuerySetVersion;\n modifications: (AddQuery | RemoveQuery)[];\n};\n\nexport type MutationRequest = {\n type: \"Mutation\";\n requestId: RequestId;\n udfPath: string;\n args: JSONValue[];\n // Execute the mutation on a specific component.\n // Only admin auth is allowed to run mutations on non-root components.\n componentPath?: string;\n};\n\nexport type ActionRequest = {\n type: \"Action\";\n requestId: RequestId;\n udfPath: string;\n args: JSONValue[];\n // Execute the action on a specific component.\n // Only admin auth is allowed to run actions on non-root components.\n componentPath?: string;\n};\n\nexport type AdminAuthentication = {\n type: \"Authenticate\";\n tokenType: \"Admin\";\n value: string;\n baseVersion: IdentityVersion;\n impersonating?: UserIdentityAttributes;\n};\n\nexport type Authenticate =\n | AdminAuthentication\n | {\n type: \"Authenticate\";\n tokenType: \"User\";\n value: string;\n baseVersion: IdentityVersion;\n }\n | {\n type: \"Authenticate\";\n tokenType: \"None\";\n baseVersion: IdentityVersion;\n };\n\nexport type Event = {\n type: \"Event\";\n eventType: string;\n event: any;\n};\nexport type ClientMessage =\n | Connect\n | Authenticate\n | QuerySetModification\n | MutationRequest\n | ActionRequest\n | Event;\n\ntype EncodedConnect = Omit<Connect, \"maxObservedTimestamp\"> & {\n maxObservedTimestamp?: EncodedTS;\n};\n\ntype EncodedClientMessage =\n | EncodedConnect\n | Authenticate\n | QuerySetModification\n | MutationRequest\n | ActionRequest\n | Event;\n\n/**\n * Server message schema\n */\nexport type TS = U64;\ntype EncodedTS = EncodedU64;\ntype LogLines = string[];\n\nexport type StateVersion = {\n querySet: QuerySetVersion;\n ts: TS;\n identity: IdentityVersion;\n};\ntype EncodedStateVersion = Omit<StateVersion, \"ts\"> & { ts: EncodedTS };\n\ntype StateModification =\n | {\n type: \"QueryUpdated\";\n queryId: QueryId;\n value: JSONValue;\n logLines: LogLines;\n // Optional because old backend versions don't send this.\n journal?: QueryJournal;\n }\n | {\n type: \"QueryFailed\";\n queryId: QueryId;\n errorMessage: string;\n logLines: LogLines;\n errorData: JSONValue;\n // Optional because old backend versions don't send this.\n journal?: QueryJournal;\n }\n | {\n type: \"QueryRemoved\";\n queryId: QueryId;\n };\n\nexport type Transition = {\n type: \"Transition\";\n startVersion: StateVersion;\n endVersion: StateVersion;\n modifications: StateModification[];\n};\n\ntype MutationSuccess = {\n type: \"MutationResponse\";\n requestId: RequestId;\n success: true;\n result: JSONValue;\n ts: TS;\n logLines: LogLines;\n};\ntype MutationFailed = {\n type: \"MutationResponse\";\n requestId: RequestId;\n success: false;\n result: string;\n logLines: LogLines;\n errorData?: JSONValue;\n};\nexport type MutationResponse = MutationSuccess | MutationFailed;\ntype ActionSuccess = {\n type: \"ActionResponse\";\n requestId: RequestId;\n success: true;\n result: JSONValue;\n logLines: LogLines;\n};\ntype ActionFailed = {\n type: \"ActionResponse\";\n requestId: RequestId;\n success: false;\n result: string;\n logLines: LogLines;\n errorData?: JSONValue;\n};\nexport type ActionResponse = ActionSuccess | ActionFailed;\nexport type AuthError = {\n type: \"AuthError\";\n error: string;\n baseVersion?: IdentityVersion;\n};\ntype FatalError = {\n type: \"FatalError\";\n error: string;\n};\ntype Ping = {\n type: \"Ping\";\n};\n\nexport type ServerMessage =\n | Transition\n | MutationResponse\n | ActionResponse\n | FatalError\n | AuthError\n | Ping;\n\ntype EncodedTransition = Omit<Transition, \"startVersion\" | \"endVersion\"> & {\n startVersion: EncodedStateVersion;\n endVersion: EncodedStateVersion;\n};\ntype EncodedMutationSuccess = Omit<MutationSuccess, \"ts\"> & { ts: EncodedTS };\ntype EncodedMutationResponse = MutationFailed | EncodedMutationSuccess;\n\ntype EncodedServerMessage =\n | EncodedTransition\n | EncodedMutationResponse\n | ActionResponse\n | FatalError\n | AuthError\n | Ping;\n", "import {\n ClientMessage,\n encodeClientMessage,\n parseServerMessage,\n ServerMessage,\n} from \"./protocol.js\";\n\nconst CLOSE_NORMAL = 1000;\nconst CLOSE_GOING_AWAY = 1001;\nconst CLOSE_NO_STATUS = 1005;\n/** Convex-specific close code representing a \"404 Not Found\".\n * The edge Onramp accepts websocket upgrades before confirming that the\n * intended destination exists, so this code is sent once we've discovered that\n * the destination does not exist.\n */\nconst CLOSE_NOT_FOUND = 4040;\n\n/**\n * The various states our WebSocket can be in:\n *\n * - \"disconnected\": We don't have a WebSocket, but plan to create one.\n * - \"connecting\": We have created the WebSocket and are waiting for the\n * `onOpen` callback.\n * - \"ready\": We have an open WebSocket.\n * - \"stopped\": The WebSocket was closed and a new one can be created via `.restart()`.\n * - \"terminated\": We have closed the WebSocket and will never create a new one.\n *\n *\n * WebSocket State Machine\n * -----------------------\n * initialState: disconnected\n * validTransitions:\n * disconnected:\n * new WebSocket() -> connecting\n * terminate() -> terminated\n * connecting:\n * onopen -> ready\n * close() -> disconnected\n * terminate() -> terminated\n * ready:\n * close() -> disconnected\n * stop() -> stopped\n * terminate() -> terminated\n * stopped:\n * restart() -> connecting\n * terminate() -> terminated\n * terminalStates:\n * terminated\n *\n *\n *\n * \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n * \u250C\u2500\u2500\u2500\u2500terminate()\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2502 disconnected \u2502\u25C0\u2500\u2510\n * \u2502 \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518 \u2502\n * \u25BC \u2502 \u25B2 \u2502\n * \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510 new WebSocket() \u2502 \u2502\n * \u250C\u2500\u25B6\u2502 terminated \u2502\u25C0\u2500\u2500\u2500\u2500\u2500\u2500\u2510 \u2502 \u2502 \u2502\n * \u2502 \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518 \u2502 \u2502 \u2502 \u2502\n * \u2502 \u25B2 terminate() \u2502 close() close()\n * \u2502 terminate() \u2502 \u2502 \u2502 \u2502\n * \u2502 \u2502 \u2502 \u25BC \u2502 \u2502\n * \u2502 \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510 \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510 \u2502\n * \u2502 \u2502 stopped \u2502\u2500\u2500restart()\u2500\u2500\u2500\u25B6\u2502 connecting \u2502 \u2502\n * \u2502 \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518 \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518 \u2502\n * \u2502 \u25B2 \u2502 \u2502\n * \u2502 \u2502 onopen \u2502\n * \u2502 \u2502 \u2502 \u2502\n * \u2502 \u2502 \u25BC \u2502\n * terminate() \u2502 \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510 \u2502\n * \u2502 \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500stop()\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2502 ready \u2502\u2500\u2500\u2518\n * \u2502 \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n * \u2502 \u2502\n * \u2502 \u2502\n * \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n *\n * The `connecting` and `ready` state have a sub-state-machine for pausing.\n */\n\ntype Socket =\n | { state: \"disconnected\" }\n | { state: \"connecting\"; ws: WebSocket; paused: \"yes\" | \"no\" }\n | { state: \"ready\"; ws: WebSocket; paused: \"yes\" | \"no\" | \"uninitialized\" }\n | { state: \"stopped\" }\n | { state: \"terminated\" };\n\nexport type ReconnectMetadata = {\n connectionCount: number;\n lastCloseReason: string | null;\n};\n\nexport type OnMessageResponse = {\n hasSyncedPastLastReconnect: boolean;\n};\n\n/**\n * A wrapper around a websocket that handles errors, reconnection, and message\n * parsing.\n */\nexport class WebSocketManager {\n private socket: Socket;\n\n private connectionCount: number;\n private lastCloseReason: string | null;\n\n /** Upon HTTPS/WSS failure, the first jittered backoff duration, in ms. */\n private readonly initialBackoff: number;\n\n /** We backoff exponentially, but we need to cap that--this is the jittered max. */\n private readonly maxBackoff: number;\n\n /** How many times have we failed consecutively? */\n private retries: number;\n\n /** How long before lack of server response causes us to initiate a reconnect,\n * in ms */\n private readonly serverInactivityThreshold: number;\n\n private reconnectDueToServerInactivityTimeout: ReturnType<\n typeof setTimeout\n > | null;\n\n private readonly uri: string;\n private readonly onOpen: (reconnectMetadata: ReconnectMetadata) => void;\n private readonly onResume: () => void;\n private readonly onMessage: (message: ServerMessage) => OnMessageResponse;\n private readonly webSocketConstructor: typeof WebSocket;\n private readonly verbose: boolean;\n\n constructor(\n uri: string,\n callbacks: {\n onOpen: (reconnectMetadata: ReconnectMetadata) => void;\n onResume: () => void;\n onMessage: (message: ServerMessage) => OnMessageResponse;\n },\n webSocketConstructor: typeof WebSocket,\n verbose: boolean,\n ) {\n this.webSocketConstructor = webSocketConstructor;\n this.socket = { state: \"disconnected\" };\n this.connectionCount = 0;\n this.lastCloseReason = \"InitialConnect\";\n\n this.initialBackoff = 100;\n this.maxBackoff = 16000;\n this.retries = 0;\n\n this.serverInactivityThreshold = 30000;\n this.reconnectDueToServerInactivityTimeout = null;\n\n this.uri = uri;\n this.onOpen = callbacks.onOpen;\n this.onResume = callbacks.onResume;\n this.onMessage = callbacks.onMessage;\n this.verbose = verbose;\n\n this.connect();\n }\n\n private connect() {\n if (this.socket.state === \"terminated\") {\n return;\n }\n if (\n this.socket.state !== \"disconnected\" &&\n this.socket.state !== \"stopped\"\n ) {\n throw new Error(\n \"Didn't start connection from disconnected state: \" + this.socket.state,\n );\n }\n\n const ws = new this.webSocketConstructor(this.uri);\n this._logVerbose(\"constructed WebSocket\");\n this.socket = {\n state: \"connecting\",\n ws,\n paused: \"no\",\n };\n\n // Kick off server inactivity timer before WebSocket connection is established\n // so we can detect cases where handshake fails.\n // The `onopen` event only fires after the connection is established:\n // Source: https://datatracker.ietf.org/doc/html/rfc6455#page-19:~:text=_The%20WebSocket%20Connection%20is%20Established_,-and\n this.resetServerInactivityTimeout();\n\n ws.onopen = () => {\n this._logVerbose(\"begin ws.onopen\");\n if (this.socket.state !== \"connecting\") {\n throw new Error(\"onopen called with socket not in connecting state\");\n }\n this.socket = {\n state: \"ready\",\n ws,\n paused: this.socket.paused === \"yes\" ? \"uninitialized\" : \"no\",\n };\n this.resetServerInactivityTimeout();\n if (this.socket.paused === \"no\") {\n this.onOpen({\n connectionCount: this.connectionCount,\n lastCloseReason: this.lastCloseReason,\n });\n }\n\n if (this.lastCloseReason !== \"InitialConnect\") {\n console.log(\"WebSocket reconnected\");\n }\n\n this.connectionCount += 1;\n this.lastCloseReason = null;\n };\n // NB: The WebSocket API calls `onclose` even if connection fails, so we can route all error paths through `onclose`.\n ws.onerror = (error) => {\n const message = (error as ErrorEvent).message;\n console.log(`WebSocket error: ${message}`);\n };\n ws.onmessage = (message) => {\n this.resetServerInactivityTimeout();\n const serverMessage = parseServerMessage(JSON.parse(message.data));\n this._logVerbose(`received ws message with type ${serverMessage.type}`);\n const response = this.onMessage(serverMessage);\n if (response.hasSyncedPastLastReconnect) {\n // Reset backoff to 0 once all outstanding requests are complete.\n this.retries = 0;\n }\n };\n ws.onclose = (event) => {\n this._logVerbose(\"begin ws.onclose\");\n if (this.lastCloseReason === null) {\n this.lastCloseReason = event.reason ?? \"OnCloseInvoked\";\n }\n if (\n event.code !== CLOSE_NORMAL &&\n event.code !== CLOSE_GOING_AWAY && // This commonly gets fired on mobile apps when the app is backgrounded\n event.code !== CLOSE_NO_STATUS &&\n event.code !== CLOSE_NOT_FOUND // Note that we want to retry on a 404, as it can be transient during a push.\n ) {\n let msg = `WebSocket closed with code ${event.code}`;\n if (event.reason) {\n msg += `: ${event.reason}`;\n }\n console.log(msg);\n }\n this.scheduleReconnect();\n return;\n };\n }\n\n /**\n * @returns The state of the {@link Socket}.\n */\n socketState(): string {\n return this.socket.state;\n }\n\n /**\n * @param message - A ClientMessage to send.\n * @returns Whether the message (might have been) sent.\n */\n sendMessage(message: ClientMessage) {\n this._logVerbose(`sending message with type ${message.type}`);\n\n if (this.socket.state === \"ready\" && this.socket.paused === \"no\") {\n const encodedMessage = encodeClientMessage(message);\n const request = JSON.stringify(encodedMessage);\n try {\n this.socket.ws.send(request);\n } catch (error: any) {\n console.log(\n `Failed to send message on WebSocket, reconnecting: ${error}`,\n );\n this.closeAndReconnect(\"FailedToSendMessage\");\n }\n // We are not sure if this was sent or not.\n return true;\n }\n return false;\n }\n\n private resetServerInactivityTimeout() {\n if (this.socket.state === \"terminated\") {\n // Don't reset any timers if we were trying to terminate.\n return;\n }\n if (this.reconnectDueToServerInactivityTimeout !== null) {\n clearTimeout(this.reconnectDueToServerInactivityTimeout);\n this.reconnectDueToServerInactivityTimeout = null;\n }\n this.reconnectDueToServerInactivityTimeout = setTimeout(() => {\n this.closeAndReconnect(\"InactiveServer\");\n }, this.serverInactivityThreshold);\n }\n\n private scheduleReconnect() {\n this.socket = { state: \"disconnected\" };\n const backoff = this.nextBackoff();\n console.log(`Attempting reconnect in ${backoff}ms`);\n setTimeout(() => this.connect(), backoff);\n }\n\n /**\n * Close the WebSocket and schedule a reconnect.\n *\n * This should be used when we hit an error and would like to restart the session.\n */\n private closeAndReconnect(closeReason: string) {\n this._logVerbose(`begin closeAndReconnect with reason ${closeReason}`);\n switch (this.socket.state) {\n case \"disconnected\":\n case \"terminated\":\n case \"stopped\":\n // Nothing to do if we don't have a WebSocket.\n return;\n case \"connecting\":\n case \"ready\": {\n this.lastCloseReason = closeReason;\n // Close the old socket asynchronously, we'll open a new socket in reconnect.\n void this.close();\n this.scheduleReconnect();\n return;\n }\n default: {\n // Enforce that the switch-case is exhaustive.\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n const _: never = this.socket;\n }\n }\n }\n\n /**\n * Close the WebSocket, being careful to clear the onclose handler to avoid re-entrant\n * calls. Use this instead of directly calling `ws.close()`\n *\n * It is the callers responsibility to update the state after this method is called so that the\n * closed socket is not accessible or used again after this method is called\n */\n private close(): Promise<void> {\n switch (this.socket.state) {\n case \"disconnected\":\n case \"terminated\":\n case \"stopped\":\n // Nothing to do if we don't have a WebSocket.\n return Promise.resolve();\n case \"connecting\": {\n const ws = this.socket.ws;\n return new Promise((r) => {\n ws.onclose = () => {\n this._logVerbose(\"Closed after connecting\");\n r();\n };\n ws.onopen = () => {\n this._logVerbose(\"Opened after connecting\");\n ws.close();\n };\n });\n }\n case \"ready\": {\n this._logVerbose(\"ws.close called\");\n const ws = this.socket.ws;\n const result: Promise<void> = new Promise((r) => {\n ws.onclose = () => {\n r();\n };\n });\n ws.close();\n return result;\n }\n default: {\n // Enforce that the switch-case is exhaustive.\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n const _: never = this.socket;\n return Promise.resolve();\n }\n }\n }\n\n /**\n * Close the WebSocket and do not reconnect.\n * @returns A Promise that resolves when the WebSocket `onClose` callback is called.\n */\n terminate(): Promise<void> {\n if (this.reconnectDueToServerInactivityTimeout) {\n clearTimeout(this.reconnectDueToServerInactivityTimeout);\n }\n switch (this.socket.state) {\n case \"terminated\":\n case \"stopped\":\n case \"disconnected\":\n case \"connecting\":\n case \"ready\": {\n const result = this.close();\n this.socket = { state: \"terminated\" };\n return result;\n }\n default: {\n // Enforce that the switch-case is exhaustive.\n const _: never = this.socket;\n throw new Error(\n `Invalid websocket state: ${(this.socket as any).state}`,\n );\n }\n }\n }\n\n stop(): Promise<void> {\n switch (this.socket.state) {\n case \"terminated\":\n // If we're terminating we ignore stop\n return Promise.resolve();\n case \"connecting\":\n case \"stopped\":\n case \"disconnected\":\n case \"ready\": {\n const result = this.close();\n this.socket = { state: \"stopped\" };\n return result;\n }\n default: {\n // Enforce that the switch-case is exhaustive.\n const _: never = this.socket;\n return Promise.resolve();\n }\n }\n }\n\n /**\n * Create a new WebSocket after a previous `stop()`, unless `terminate()` was\n * called before.\n */\n restart(): void {\n switch (this.socket.state) {\n case \"stopped\":\n break;\n case \"terminated\":\n // If we're terminating we ignore restart\n return;\n case \"connecting\":\n case \"ready\":\n case \"disconnected\":\n throw new Error(\"`restart()` is only valid after `stop()`\");\n default: {\n // Enforce that the switch-case is exhaustive.\n const _: never = this.socket;\n }\n }\n this.connect();\n }\n\n pause(): void {\n switch (this.socket.state) {\n case \"disconnected\":\n case \"stopped\":\n case \"terminated\":\n // If already stopped or stopping ignore.\n return;\n case \"connecting\":\n case \"ready\": {\n this.socket = { ...this.socket, paused: \"yes\" };\n return;\n }\n default: {\n // Enforce that the switch-case is exhaustive.\n const _: never = this.socket;\n return;\n }\n }\n }\n\n /**\n * Resume the state machine if previously paused.\n */\n resume(): void {\n switch (this.socket.state) {\n case \"connecting\":\n this.socket = { ...this.socket, paused: \"no\" };\n return;\n case \"ready\":\n if (this.socket.paused === \"uninitialized\") {\n this.socket = { ...this.socket, paused: \"no\" };\n this.onOpen({\n connectionCount: this.connectionCount,\n lastCloseReason: this.lastCloseReason,\n });\n } else if (this.socket.paused === \"yes\") {\n this.socket = { ...this.socket, paused: \"no\" };\n this.onResume();\n }\n return;\n case \"terminated\":\n case \"stopped\":\n case \"disconnected\":\n // Ignore resume if not paused, perhaps we already resumed.\n return;\n default: {\n // Enforce that the switch-case is exhaustive.\n const _: never = this.socket;\n }\n }\n this.connect();\n }\n\n private _logVerbose(message: string) {\n if (this.verbose) {\n console.debug(`${new Date().toISOString()} ${message}`);\n }\n }\n\n private nextBackoff(): number {\n const baseBackoff = this.initialBackoff * Math.pow(2, this.retries);\n this.retries += 1;\n const actualBackoff = Math.min(baseBackoff, this.maxBackoff);\n const jitter = actualBackoff * (Math.random() - 0.5);\n return actualBackoff + jitter;\n }\n}\n", "export function newSessionId() {\n return uuidv4();\n}\n\n// From https://stackoverflow.com/a/2117523\nfunction uuidv4() {\n return \"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx\".replace(/[xy]/g, (c) => {\n const r = (Math.random() * 16) | 0,\n v = c === \"x\" ? r : (r & 0x3) | 0x8;\n return v.toString(16);\n });\n}\n", "/**\n * The code was extracted from:\n * https://github.com/davidchambers/Base64.js\n */\n\nvar chars = \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=\";\n\nfunction InvalidCharacterError(message) {\n this.message = message;\n}\n\nInvalidCharacterError.prototype = new Error();\nInvalidCharacterError.prototype.name = \"InvalidCharacterError\";\n\nfunction polyfill(input) {\n var str = String(input).replace(/=+$/, \"\");\n if (str.length % 4 == 1) {\n throw new InvalidCharacterError(\n \"'atob' failed: The string to be decoded is not correctly encoded.\"\n );\n }\n for (\n // initialize result and counters\n var bc = 0, bs, buffer, idx = 0, output = \"\";\n // get next character\n (buffer = str.charAt(idx++));\n // character found in table? initialize bit storage and add its ascii value;\n ~buffer &&\n ((bs = bc % 4 ? bs * 64 + buffer : buffer),\n // and if not first of each 4 characters,\n // convert the first 8 bits to one ascii character\n bc++ % 4) ?\n (output += String.fromCharCode(255 & (bs >> ((-2 * bc) & 6)))) :\n 0\n ) {\n // try to find character in table (0-63, not found => -1)\n buffer = chars.indexOf(buffer);\n }\n return output;\n}\n\nexport default (typeof window !== \"undefined\" &&\n window.atob &&\n window.atob.bind(window)) ||\npolyfill;", "import atob from \"./atob\";\n\nfunction b64DecodeUnicode(str) {\n return decodeURIComponent(\n atob(str).replace(/(.)/g, function(m, p) {\n var code = p.charCodeAt(0).toString(16).toUpperCase();\n if (code.length < 2) {\n code = \"0\" + code;\n }\n return \"%\" + code;\n })\n );\n}\n\nexport default function(str) {\n var output = str.replace(/-/g, \"+\").replace(/_/g, \"/\");\n switch (output.length % 4) {\n case 0:\n break;\n case 2:\n output += \"==\";\n break;\n case 3:\n output += \"=\";\n break;\n default:\n throw \"Illegal base64url string!\";\n }\n\n try {\n return b64DecodeUnicode(output);\n } catch (err) {\n return atob(output);\n }\n}", "\"use strict\";\n\nimport base64_url_decode from \"./base64_url_decode\";\n\nexport function InvalidTokenError(message) {\n this.message = message;\n}\n\nInvalidTokenError.prototype = new Error();\nInvalidTokenError.prototype.name = \"InvalidTokenError\";\n\nexport default function(token, options) {\n if (typeof token !== \"string\") {\n throw new InvalidTokenError(\"Invalid token specified\");\n }\n\n options = options || {};\n var pos = options.header === true ? 0 : 1;\n try {\n return JSON.parse(base64_url_decode(token.split(\".\")[pos]));\n } catch (e) {\n throw new InvalidTokenError(\"Invalid token specified: \" + e.message);\n }\n}", "import { LocalSyncState } from \"./local_state.js\";\nimport { AuthError, Transition } from \"./protocol.js\";\nimport jwtDecode from \"jwt-decode\";\n\n// setTimout uses 32 bit integer, so it can only\n// schedule about 24 days in the future.\nconst MAXIMUM_REFRESH_DELAY = 20 * 24 * 60 * 60 * 1000; // 20 days\n\n/**\n * An async function returning the JWT-encoded OpenID Connect Identity Token\n * if available.\n *\n * `forceRefreshToken` is `true` if the server rejected a previously\n * returned token, and the client should try to fetch a new one.\n *\n * See {@link ConvexReactClient.setAuth}.\n *\n * @public\n */\nexport type AuthTokenFetcher = (args: {\n forceRefreshToken: boolean;\n}) => Promise<string | null | undefined>;\n\n/**\n * What is provided to the client.\n */\ntype AuthConfig = {\n fetchToken: AuthTokenFetcher;\n onAuthChange: (isAuthenticated: boolean) => void;\n};\n\n/**\n * In general we take 3 steps:\n * 1. Fetch a possibly cached token\n * 2. Immediately fetch a fresh token without using a cache\n * 3. Repeat step 2 before the end of the fresh token's lifetime\n *\n * When we fetch without using a cache we know when the token\n * will expire, and can schedule refetching it.\n *\n * If we get an error before a scheduled refetch, we go back\n * to step 2.\n */\ntype AuthState =\n | { state: \"noAuth\" }\n | {\n state: \"waitingForServerConfirmationOfCachedToken\";\n config: AuthConfig;\n hasRetried: boolean;\n }\n | {\n state: \"initialRefetch\";\n config: AuthConfig;\n }\n | {\n state: \"waitingForServerConfirmationOfFreshToken\";\n config: AuthConfig;\n hadAuth: boolean;\n token: string;\n }\n | {\n state: \"waitingForScheduledRefetch\";\n config: AuthConfig;\n refetchTokenTimeoutId: ReturnType<typeof setTimeout>;\n }\n // Special/weird state when we got a valid token\n // but could not fetch a new one.\n | {\n state: \"notRefetching\";\n config: AuthConfig;\n };\n\n/**\n * Handles the state transitions for auth. The server is the source\n * of truth.\n */\nexport class AuthenticationManager {\n private authState: AuthState = { state: \"noAuth\" };\n // Used to detect races involving `setConfig` calls\n // while a token is being fetched.\n private configVersion = 0;\n // Shared by the BaseClient so that the auth manager can easily inspect it\n private readonly syncState: LocalSyncState;\n // Passed down by BaseClient, sends a message to the server\n private readonly authenticate: (token: string) => void;\n private readonly stopSocket: () => Promise<void>;\n private readonly restartSocket: () => void;\n private readonly pauseSocket: () => void;\n private readonly resumeSocket: () => void;\n // Passed down by BaseClient, sends a message to the server\n private readonly clearAuth: () => void;\n private readonly verbose: boolean;\n\n constructor(\n syncState: LocalSyncState,\n {\n authenticate,\n stopSocket,\n restartSocket,\n pauseSocket,\n resumeSocket,\n clearAuth,\n verbose,\n }: {\n authenticate: (token: string) => void;\n stopSocket: () => Promise<void>;\n restartSocket: () => void;\n pauseSocket: () => void;\n resumeSocket: () => void;\n clearAuth: () => void;\n verbose: boolean;\n },\n ) {\n this.syncState = syncState;\n this.authenticate = authenticate;\n this.stopSocket = stopSocket;\n this.restartSocket = restartSocket;\n this.pauseSocket = pauseSocket;\n this.resumeSocket = resumeSocket;\n this.clearAuth = clearAuth;\n this.verbose = verbose;\n }\n\n async setConfig(\n fetchToken: AuthTokenFetcher,\n onChange: (isAuthenticated: boolean) => void,\n ) {\n this.resetAuthState();\n this._logVerbose(\"pausing WS for auth token fetch\");\n this.pauseSocket();\n const token = await this.fetchTokenAndGuardAgainstRace(fetchToken, {\n forceRefreshToken: false,\n });\n if (token.isFromOutdatedConfig) {\n return;\n }\n if (token.value) {\n this.setAuthState({\n state: \"waitingForServerConfirmationOfCachedToken\",\n config: { fetchToken, onAuthChange: onChange },\n hasRetried: false,\n });\n this.authenticate(token.value);\n this._logVerbose(\"resuming WS after auth token fetch\");\n this.resumeSocket();\n } else {\n this.setAuthState({\n state: \"initialRefetch\",\n config: { fetchToken, onAuthChange: onChange },\n });\n // Try again with `forceRefreshToken: true`\n await this.refetchToken();\n }\n }\n\n onTransition(serverMessage: Transition) {\n if (\n !this.syncState.isCurrentOrNewerAuthVersion(\n serverMessage.endVersion.identity,\n )\n ) {\n // This is a stale transition - client has moved on to\n // a newer auth version.\n return;\n }\n if (\n serverMessage.endVersion.identity <= serverMessage.startVersion.identity\n ) {\n // This transition did not change auth - it is not a response to Authenticate.\n return;\n }\n\n if (this.authState.state === \"waitingForServerConfirmationOfCachedToken\") {\n this._logVerbose(\"server confirmed auth token is valid\");\n void this.refetchToken();\n this.authState.config.onAuthChange(true);\n return;\n }\n if (this.authState.state === \"waitingForServerConfirmationOfFreshToken\") {\n this._logVerbose(\"server confirmed new auth token is valid\");\n this.scheduleTokenRefetch(this.authState.token);\n if (!this.authState.hadAuth) {\n this.authState.config.onAuthChange(true);\n }\n }\n }\n\n onAuthError(serverMessage: AuthError) {\n const { baseVersion } = serverMessage;\n // Versioned AuthErrors are ignored if the client advanced to\n // a newer auth identity\n if (baseVersion !== null && baseVersion !== undefined) {\n // Error are reporting the previous version, since the server\n // didn't advance, hence `+ 1`.\n if (!this.syncState.isCurrentOrNewerAuthVersion(baseVersion + 1)) {\n this._logVerbose(\"ignoring auth error for previous auth attempt\");\n return;\n }\n void this.tryToReauthenticate(serverMessage);\n return;\n }\n\n // TODO: Remove after all AuthErrors are versioned\n void this.tryToReauthenticate(serverMessage);\n }\n\n // This is similar to `refetchToken` defined below, in fact we\n // don't represent them as different states, but it is different\n // in that we pause the WebSocket so that mutations\n // don't retry with bad auth.\n private async tryToReauthenticate(serverMessage: AuthError) {\n // We only retry once, to avoid infinite retries\n if (\n // No way to fetch another token, kaboom\n this.authState.state === \"noAuth\" ||\n // We failed on a fresh token, trying another one won't help\n this.authState.state === \"waitingForServerConfirmationOfFreshToken\"\n ) {\n console.error(\n `Failed to authenticate: \"${serverMessage.error}\", check your server auth config`,\n );\n if (this.syncState.hasAuth()) {\n this.syncState.clearAuth();\n }\n if (this.authState.state !== \"noAuth\") {\n this.setAndReportAuthFailed(this.authState.config.onAuthChange);\n }\n return;\n }\n this._logVerbose(\"attempting to reauthenticate\");\n await this.stopSocket();\n const token = await this.fetchTokenAndGuardAgainstRace(\n this.authState.config.fetchToken,\n {\n forceRefreshToken: true,\n },\n );\n if (token.isFromOutdatedConfig) {\n return;\n }\n\n if (token.value && this.syncState.isNewAuth(token.value)) {\n this.authenticate(token.value);\n this.setAuthState({\n state: \"waitingForServerConfirmationOfFreshToken\",\n config: this.authState.config,\n token: token.value,\n hadAuth:\n this.authState.state === \"notRefetching\" ||\n this.authState.state === \"waitingForScheduledRefetch\",\n });\n } else {\n this._logVerbose(\"reauthentication failed, could not fetch a new token\");\n if (this.syncState.hasAuth()) {\n this.syncState.clearAuth();\n }\n this.setAndReportAuthFailed(this.authState.config.onAuthChange);\n }\n this.restartSocket();\n }\n\n // Force refetch the token and schedule another refetch\n // before the token expires - an active client should never\n // need to reauthenticate.\n private async refetchToken() {\n if (this.authState.state === \"noAuth\") {\n return;\n }\n this._logVerbose(\"refetching auth token\");\n const token = await this.fetchTokenAndGuardAgainstRace(\n this.authState.config.fetchToken,\n {\n forceRefreshToken: true,\n },\n );\n if (token.isFromOutdatedConfig) {\n return;\n }\n\n if (token.value) {\n if (this.syncState.isNewAuth(token.value)) {\n this.setAuthState({\n state: \"waitingForServerConfirmationOfFreshToken\",\n hadAuth: this.syncState.hasAuth(),\n token: token.value,\n config: this.authState.config,\n });\n this.authenticate(token.value);\n } else {\n this.setAuthState({\n state: \"notRefetching\",\n config: this.authState.config,\n });\n }\n } else {\n this._logVerbose(\"refetching token failed\");\n if (this.syncState.hasAuth()) {\n this.clearAuth();\n }\n this.setAndReportAuthFailed(this.authState.config.onAuthChange);\n }\n // Resuming in case this refetch was triggered\n // by an invalid cached token.\n this._logVerbose(\n \"resuming WS after auth token fetch (if currently paused)\",\n );\n this.resumeSocket();\n }\n\n private scheduleTokenRefetch(token: string) {\n if (this.authState.state === \"noAuth\") {\n return;\n }\n const decodedToken = this.decodeToken(token);\n if (!decodedToken) {\n // This is no longer really possible, because\n // we wait on server response before scheduling token refetch,\n // and the server currently requires JWT tokens.\n console.error(\"Auth token is not a valid JWT, cannot refetch the token\");\n return;\n }\n // iat: issued at time, UTC seconds timestamp at which the JWT was issued\n // exp: expiration time, UTC seconds timestamp at which the JWT will expire\n const { iat, exp } = decodedToken as { iat?: number; exp?: number };\n if (!iat || !exp) {\n console.error(\n \"Auth token does not have required fields, cannot refetch the token\",\n );\n return;\n }\n const leewaySeconds = 2;\n // Because the client and server clocks may be out of sync,\n // we only know that the token will expire after `exp - iat`,\n // and since we just fetched a fresh one we know when that\n // will happen.\n const delay = Math.min(\n MAXIMUM_REFRESH_DELAY,\n (exp - iat - leewaySeconds) * 1000,\n );\n if (delay <= 0) {\n console.error(\n \"Auth token does not live long enough, cannot refetch the token\",\n );\n return;\n }\n const refetchTokenTimeoutId = setTimeout(() => {\n void this.refetchToken();\n }, delay);\n this.setAuthState({\n state: \"waitingForScheduledRefetch\",\n refetchTokenTimeoutId,\n config: this.authState.config,\n });\n this._logVerbose(\n `scheduled preemptive auth token refetching in ${delay}ms`,\n );\n }\n\n // Protects against simultaneous calls to `setConfig`\n // while we're fetching a token\n private async fetchTokenAndGuardAgainstRace(\n fetchToken: AuthTokenFetcher,\n fetchArgs: {\n forceRefreshToken: boolean;\n },\n ) {\n const originalConfigVersion = ++this.configVersion;\n const token = await fetchToken(fetchArgs);\n if (this.configVersion !== originalConfigVersion) {\n // This is a stale config\n return { isFromOutdatedConfig: true };\n }\n return { isFromOutdatedConfig: false, value: token };\n }\n\n stop() {\n this.resetAuthState();\n // Bump this in case we are mid-token-fetch when we get stopped\n this.configVersion++;\n }\n\n private setAndReportAuthFailed(\n onAuthChange: (authenticated: boolean) => void,\n ) {\n onAuthChange(false);\n this.resetAuthState();\n }\n\n private resetAuthState() {\n this.setAuthState({ state: \"noAuth\" });\n }\n\n private setAuthState(newAuth: AuthState) {\n if (this.authState.state === \"waitingForScheduledRefetch\") {\n clearTimeout(this.authState.refetchTokenTimeoutId);\n\n // The waitingForScheduledRefetch state is the most quiesced authed state.\n // Let the syncState know that auth is in a good state, so it can reset failure backoffs\n this.syncState.markAuthCompletion();\n }\n this.authState = newAuth;\n }\n\n private decodeToken(token: string) {\n try {\n return jwtDecode(token);\n } catch (e) {\n return null;\n }\n }\n\n private _logVerbose(message: string) {\n if (this.verbose) {\n console.debug(\n `${new Date().toISOString()} ${message} [v${this.configVersion}]`,\n );\n }\n }\n}\n", "// Marks share a global namespace with other developer code.\nconst markNames = [\n \"convexClientConstructed\",\n \"convexWebSocketOpen\",\n \"convexFirstMessageReceived\",\n] as const;\nexport type MarkName = (typeof markNames)[number];\n\n// Mark details are not reported to the server.\ntype MarkDetail = {\n sessionId: string;\n};\n\n// `PerformanceMark`s are efficient and show up in browser's performance\n// timeline. They can be cleared with `performance.clearMarks()`.\n// This is a memory leak, but a worthwhile one: automatic\n// cleanup would make in-browser debugging more difficult.\nexport function mark(name: MarkName, sessionId: string) {\n const detail: MarkDetail = { sessionId };\n // `performance` APIs exists in browsers, Node.js, Deno, and more but it\n // is not required by the Convex client.\n if (typeof performance === \"undefined\" || !performance.mark) return;\n performance.mark(name, { detail });\n}\n\n// `PerfomanceMark` has a built-in toJSON() but the return type varies\n// between implementations, e.g. Node.js returns details but Chrome does not.\nfunction performanceMarkToJson(mark: PerformanceMark): MarkJson {\n // Remove \"convex\" prefix\n let name = mark.name.slice(\"convex\".length);\n // lowercase the first letter\n name = name.charAt(0).toLowerCase() + name.slice(1);\n return {\n name,\n startTime: mark.startTime,\n };\n}\n\n// Similar to the return type of `PerformanceMark.toJson()`.\nexport type MarkJson = {\n name: string;\n // `startTime` is in milliseconds since the time origin like `performance.now()`.\n // https://developer.mozilla.org/en-US/docs/Web/API/DOMHighResTimeStamp#the_time_origin\n startTime: number;\n};\n\nexport function getMarksReport(sessionId: string): MarkJson[] {\n if (typeof performance === \"undefined\" || !performance.getEntriesByName) {\n return [];\n }\n const allMarks: PerformanceMark[] = [];\n for (const name of markNames) {\n const marks = (\n performance\n .getEntriesByName(name)\n .filter((entry) => entry.entryType === \"mark\") as PerformanceMark[]\n ).filter((mark) => mark.detail.sessionId === sessionId);\n allMarks.push(...marks);\n }\n return allMarks.map(performanceMarkToJson);\n}\n", "import { version } from \"../../index.js\";\nimport { convexToJson, Value } from \"../../values/index.js\";\nimport {\n createHybridErrorStacktrace,\n forwardData,\n logFatalError,\n} from \"../logging.js\";\nimport { LocalSyncState } from \"./local_state.js\";\nimport { RequestManager } from \"./request_manager.js\";\nimport {\n OptimisticLocalStore,\n OptimisticUpdate,\n} from \"./optimistic_updates.js\";\nimport {\n OptimisticQueryResults,\n QueryResultsMap,\n} from \"./optimistic_updates_impl.js\";\nimport {\n ActionRequest,\n MutationRequest,\n QueryId,\n QueryJournal,\n RequestId,\n ServerMessage,\n TS,\n UserIdentityAttributes,\n} from \"./protocol.js\";\nimport { RemoteQuerySet } from \"./remote_query_set.js\";\nimport { QueryToken, serializePathAndArgs } from \"./udf_path_utils.js\";\nimport { ReconnectMetadata, WebSocketManager } from \"./web_socket_manager.js\";\nimport { newSessionId } from \"./session.js\";\nimport { FunctionResult } from \"./function_result.js\";\nimport {\n AuthenticationManager,\n AuthTokenFetcher,\n} from \"./authentication_manager.js\";\nexport { type AuthTokenFetcher } from \"./authentication_manager.js\";\nimport { getMarksReport, mark, MarkName } from \"./metrics.js\";\nimport { parseArgs, validateDeploymentUrl } from \"../../common/index.js\";\nimport { ConvexError } from \"../../values/errors.js\";\n\n/**\n * Options for {@link BaseConvexClient}.\n *\n * @public\n */\nexport interface BaseConvexClientOptions {\n /**\n * Whether to prompt the user if they have unsaved changes pending\n * when navigating away or closing a web page.\n *\n * This is only possible when the `window` object exists, i.e. in a browser.\n *\n * The default value is `true` in browsers.\n */\n unsavedChangesWarning?: boolean;\n /**\n * Specifies an alternate\n * [WebSocket](https://developer.mozilla.org/en-US/docs/Web/API/WebSocket)\n * constructor to use for client communication with the Convex cloud.\n * The default behavior is to use `WebSocket` from the global environment.\n */\n webSocketConstructor?: typeof WebSocket;\n /**\n * Adds additional logging for debugging purposes.\n *\n * The default value is `false`.\n */\n verbose?: boolean;\n /**\n * Sends additional metrics to Convex for debugging purposes.\n *\n * The default value is `false`.\n */\n reportDebugInfoToConvex?: boolean;\n /**\n * Skip validating that the Convex deployment URL looks like\n * `https://happy-animal-123.convex.cloud` or localhost.\n *\n * This can be useful if running a self-hosted Convex backend that uses a different\n * URL.\n *\n * The default value is `false`\n */\n skipConvexDeploymentUrlCheck?: boolean;\n}\n\n/**\n * State describing the client's connection with the Convex backend.\n *\n * @public\n */\nexport type ConnectionState = {\n hasInflightRequests: boolean;\n isWebSocketConnected: boolean;\n timeOfOldestInflightRequest: Date | null;\n};\n\n/**\n * Options for {@link BaseConvexClient.subscribe}.\n *\n * @public\n */\nexport interface SubscribeOptions {\n /**\n * An (optional) journal produced from a previous execution of this query\n * function.\n *\n * If there is an existing subscription to a query function with the same\n * name and arguments, this journal will have no effect.\n */\n journal?: QueryJournal;\n\n /**\n * @internal\n */\n componentPath?: string;\n}\n\n/**\n * Options for {@link BaseConvexClient.mutation}.\n *\n * @public\n */\nexport interface MutationOptions {\n /**\n * An optimistic update to apply along with this mutation.\n *\n * An optimistic update locally updates queries while a mutation is pending.\n * Once the mutation completes, the update will be rolled back.\n */\n optimisticUpdate?: OptimisticUpdate<any>;\n}\n\n/**\n * Low-level client for directly integrating state management libraries\n * with Convex.\n *\n * Most developers should use higher level clients, like\n * the {@link ConvexHttpClient} or the React hook based {@link react.ConvexReactClient}.\n *\n * @public\n */\nexport class BaseConvexClient {\n private readonly address: string;\n private readonly state: LocalSyncState;\n private readonly requestManager: RequestManager;\n private readonly webSocketManager: WebSocketManager;\n private readonly authenticationManager: AuthenticationManager;\n private remoteQuerySet: RemoteQuerySet;\n private readonly optimisticQueryResults: OptimisticQueryResults;\n private readonly onTransition: (updatedQueries: QueryToken[]) => void;\n private _nextRequestId: RequestId;\n private readonly _sessionId: string;\n private firstMessageReceived = false;\n private readonly verbose: boolean;\n private readonly debug: boolean;\n private maxObservedTimestamp: TS | undefined;\n\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 onTransition - A callback receiving an array of query tokens\n * corresponding to query results that have changed.\n * @param options - See {@link BaseConvexClientOptions} for a full description.\n */\n constructor(\n address: string,\n onTransition: (updatedQueries: QueryToken[]) => void,\n options?: BaseConvexClientOptions,\n ) {\n if (typeof address === \"object\") {\n throw new Error(\n \"Passing a ClientConfig object is no longer supported. Pass the URL of the Convex deployment as a string directly.\",\n );\n }\n if (options?.skipConvexDeploymentUrlCheck !== true) {\n validateDeploymentUrl(address);\n }\n options = { ...options };\n let webSocketConstructor = options.webSocketConstructor;\n if (!webSocketConstructor && typeof WebSocket === \"undefined\") {\n throw new Error(\n \"No WebSocket global variable defined! To use Convex in an environment without WebSocket try the HTTP client: https://docs.convex.dev/api/classes/browser.ConvexHttpClient\",\n );\n }\n webSocketConstructor = webSocketConstructor || WebSocket;\n this.verbose = options.verbose ?? false;\n this.debug = options.reportDebugInfoToConvex ?? false;\n this.address = address;\n\n // Substitute http(s) with ws(s)\n const i = address.search(\"://\");\n if (i === -1) {\n throw new Error(\"Provided address was not an absolute URL.\");\n }\n const origin = address.substring(i + 3); // move past the double slash\n const protocol = address.substring(0, i);\n let wsProtocol;\n if (protocol === \"http\") {\n wsProtocol = \"ws\";\n } else if (protocol === \"https\") {\n wsProtocol = \"wss\";\n } else {\n throw new Error(`Unknown parent protocol ${protocol}`);\n }\n const wsUri = `${wsProtocol}://${origin}/api/${version}/sync`;\n\n this.state = new LocalSyncState();\n this.remoteQuerySet = new RemoteQuerySet((queryId) =>\n this.state.queryPath(queryId),\n );\n this.requestManager = new RequestManager();\n this.authenticationManager = new AuthenticationManager(this.state, {\n authenticate: (token) => {\n const message = this.state.setAuth(token);\n this.webSocketManager.sendMessage(message);\n },\n stopSocket: () => this.webSocketManager.stop(),\n restartSocket: () => this.webSocketManager.restart(),\n pauseSocket: () => this.webSocketManager.pause(),\n resumeSocket: () => this.webSocketManager.resume(),\n clearAuth: () => {\n this.clearAuth();\n },\n verbose: this.verbose,\n });\n this.optimisticQueryResults = new OptimisticQueryResults();\n this.onTransition = onTransition;\n this._nextRequestId = 0;\n this._sessionId = newSessionId();\n\n const { unsavedChangesWarning } = options;\n if (\n typeof window === \"undefined\" ||\n typeof window.addEventListener === \"undefined\"\n ) {\n if (unsavedChangesWarning === true) {\n throw new Error(\n \"unsavedChangesWarning requested, but window.addEventListener not found! Remove {unsavedChangesWarning: true} from Convex client options.\",\n );\n }\n } else if (unsavedChangesWarning !== false) {\n // Listen for tab close events and notify the user on unsaved changes.\n window.addEventListener(\"beforeunload\", (e) => {\n if (this.requestManager.hasIncompleteRequests()) {\n // There are 3 different ways to trigger this pop up so just try all of\n // them.\n\n e.preventDefault();\n // This confirmation message doesn't actually appear in most modern\n // browsers but we tried.\n const confirmationMessage =\n \"Are you sure you want to leave? Your changes may not be saved.\";\n (e || window.event).returnValue = confirmationMessage;\n return confirmationMessage;\n }\n });\n }\n\n this.webSocketManager = new WebSocketManager(\n wsUri,\n {\n onOpen: (reconnectMetadata: ReconnectMetadata) => {\n // We have a new WebSocket!\n this.mark(\"convexWebSocketOpen\");\n this.webSocketManager.sendMessage({\n ...reconnectMetadata,\n type: \"Connect\",\n sessionId: this._sessionId,\n maxObservedTimestamp: this.maxObservedTimestamp,\n });\n\n // Throw out our remote query, reissue queries\n // and outstanding mutations, and reauthenticate.\n const oldRemoteQueryResults = new Set(\n this.remoteQuerySet.remoteQueryResults().keys(),\n );\n this.remoteQuerySet = new RemoteQuerySet((queryId) =>\n this.state.queryPath(queryId),\n );\n const [querySetModification, authModification] = this.state.restart(\n oldRemoteQueryResults,\n );\n if (authModification) {\n this.webSocketManager.sendMessage(authModification);\n }\n this.webSocketManager.sendMessage(querySetModification);\n for (const message of this.requestManager.restart()) {\n this.webSocketManager.sendMessage(message);\n }\n },\n onResume: () => {\n const remoteQueryResults = new Set(\n this.remoteQuerySet.remoteQueryResults().keys(),\n );\n const [querySetModification, authModification] =\n this.state.resume(remoteQueryResults);\n if (authModification) {\n this.webSocketManager.sendMessage(authModification);\n }\n if (querySetModification) {\n this.webSocketManager.sendMessage(querySetModification);\n }\n for (const message of this.requestManager.resume()) {\n this.webSocketManager.sendMessage(message);\n }\n },\n onMessage: (serverMessage: ServerMessage) => {\n // Metrics events grow linearly with reconnection attempts so this\n // conditional prevents n^2 metrics reporting.\n if (!this.firstMessageReceived) {\n this.firstMessageReceived = true;\n this.mark(\"convexFirstMessageReceived\");\n this.reportMarks();\n }\n switch (serverMessage.type) {\n case \"Transition\": {\n this.observedTimestamp(serverMessage.endVersion.ts);\n this.authenticationManager.onTransition(serverMessage);\n this.remoteQuerySet.transition(serverMessage);\n this.state.transition(serverMessage);\n const completedRequests = this.requestManager.removeCompleted(\n this.remoteQuerySet.timestamp(),\n );\n this.notifyOnQueryResultChanges(completedRequests);\n break;\n }\n case \"MutationResponse\": {\n if (serverMessage.success) {\n this.observedTimestamp(serverMessage.ts);\n }\n const completedMutationId =\n this.requestManager.onResponse(serverMessage);\n if (completedMutationId !== null) {\n this.notifyOnQueryResultChanges(new Set([completedMutationId]));\n }\n break;\n }\n case \"ActionResponse\": {\n this.requestManager.onResponse(serverMessage);\n break;\n }\n case \"AuthError\": {\n this.authenticationManager.onAuthError(serverMessage);\n break;\n }\n case \"FatalError\": {\n const error = logFatalError(serverMessage.error);\n void this.webSocketManager.terminate();\n throw error;\n }\n case \"Ping\":\n break; // do nothing\n default: {\n const _typeCheck: never = serverMessage;\n }\n }\n\n return {\n hasSyncedPastLastReconnect: this.hasSyncedPastLastReconnect(),\n };\n },\n },\n webSocketConstructor,\n this.verbose,\n );\n this.mark(\"convexClientConstructed\");\n }\n\n /**\n * Return true if there is outstanding work from prior to the time of the most recent restart.\n * This indicates that the client has not proven itself to have gotten past the issue that\n * potentially led to the restart. Use this to influence when to reset backoff after a failure.\n */\n private hasSyncedPastLastReconnect() {\n const hasSyncedPastLastReconnect =\n this.requestManager.hasSyncedPastLastReconnect() ||\n this.state.hasSyncedPastLastReconnect();\n return hasSyncedPastLastReconnect;\n }\n\n private observedTimestamp(observedTs: TS) {\n if (\n this.maxObservedTimestamp === undefined ||\n this.maxObservedTimestamp.lessThanOrEqual(observedTs)\n ) {\n this.maxObservedTimestamp = observedTs;\n }\n }\n\n getMaxObservedTimestamp() {\n return this.maxObservedTimestamp;\n }\n\n /**\n * Compute the current query results based on the remoteQuerySet and the\n * current optimistic updates and call `onTransition` for all the changed\n * queries.\n *\n * @param completedMutations - A set of mutation IDs whose optimistic updates\n * are no longer needed.\n */\n private notifyOnQueryResultChanges(completedRequest: Set<RequestId>) {\n const remoteQueryResults: Map<QueryId, FunctionResult> =\n this.remoteQuerySet.remoteQueryResults();\n const queryTokenToValue: QueryResultsMap = new Map();\n for (const [queryId, result] of remoteQueryResults) {\n const queryToken = this.state.queryToken(queryId);\n // It's possible that we've already unsubscribed to this query but\n // the server hasn't learned about that yet. If so, ignore this one.\n\n if (queryToken !== null) {\n const query = {\n result,\n udfPath: this.state.queryPath(queryId)!,\n args: this.state.queryArgs(queryId)!,\n };\n queryTokenToValue.set(queryToken, query);\n }\n }\n\n this.onTransition(\n this.optimisticQueryResults.ingestQueryResultsFromServer(\n queryTokenToValue,\n completedRequest,\n ),\n );\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-encoded 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 void this.authenticationManager.setConfig(fetchToken, onChange);\n }\n\n hasAuth() {\n return this.state.hasAuth();\n }\n\n /** @internal */\n setAdminAuth(value: string, fakeUserIdentity?: UserIdentityAttributes) {\n const message = this.state.setAdminAuth(value, fakeUserIdentity);\n this.webSocketManager.sendMessage(message);\n }\n\n clearAuth() {\n const message = this.state.clearAuth();\n this.webSocketManager.sendMessage(message);\n }\n\n /**\n * Subscribe to a query function.\n *\n * Whenever this query's result changes, the `onTransition` callback\n * passed into the constructor will be called.\n *\n * @param name - The name of the query.\n * @param args - An arguments object for the query. If this is omitted, the\n * arguments will be `{}`.\n * @param options - A {@link SubscribeOptions} options object for this query.\n\n * @returns An object containing a {@link QueryToken} corresponding to this\n * query and an `unsubscribe` callback.\n */\n subscribe(\n name: string,\n args?: Record<string, Value>,\n options?: SubscribeOptions,\n ): { queryToken: QueryToken; unsubscribe: () => void } {\n const argsObject = parseArgs(args);\n\n const { modification, queryToken, unsubscribe } = this.state.subscribe(\n name,\n argsObject,\n options?.journal,\n options?.componentPath,\n );\n if (modification !== null) {\n this.webSocketManager.sendMessage(modification);\n }\n return {\n queryToken,\n unsubscribe: () => {\n const modification = unsubscribe();\n if (modification) {\n this.webSocketManager.sendMessage(modification);\n }\n },\n };\n }\n\n /**\n * A query result based only on the current, local state.\n *\n * The only way this will return a value is if we're already subscribed to the\n * query or its value has been set optimistically.\n */\n localQueryResult(\n udfPath: string,\n args?: Record<string, Value>,\n ): Value | undefined {\n const argsObject = parseArgs(args);\n const queryToken = serializePathAndArgs(udfPath, argsObject);\n return this.optimisticQueryResults.queryResult(queryToken);\n }\n\n /**\n * Get query result by query token based on current, local state\n *\n * The only way this will return a value is if we're already subscribed to the\n * query or its value has been set optimistically.\n *\n * @internal\n */\n localQueryResultByToken(queryToken: QueryToken): Value | undefined {\n return this.optimisticQueryResults.queryResult(queryToken);\n }\n\n /**\n * Whether local query result is available for a toke.\n *\n * This method does not throw if the result is an error.\n *\n * @internal\n */\n hasLocalQueryResultByToken(queryToken: QueryToken): boolean {\n return this.optimisticQueryResults.hasQueryResult(queryToken);\n }\n\n /**\n * @internal\n */\n localQueryLogs(\n udfPath: string,\n args?: Record<string, Value>,\n ): string[] | undefined {\n const argsObject = parseArgs(args);\n const queryToken = serializePathAndArgs(udfPath, argsObject);\n return this.optimisticQueryResults.queryLogs(queryToken);\n }\n\n /**\n * Retrieve the current {@link QueryJournal} for this query function.\n *\n * If we have not yet received a result for this query, this will be `undefined`.\n *\n * @param name - The name of the query.\n * @param args - The arguments object for this query.\n * @returns The query's {@link QueryJournal} or `undefined`.\n */\n queryJournal(\n name: string,\n args?: Record<string, Value>,\n ): QueryJournal | undefined {\n const argsObject = parseArgs(args);\n const queryToken = serializePathAndArgs(name, argsObject);\n return this.state.queryJournal(queryToken);\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 return {\n hasInflightRequests: this.requestManager.hasInflightRequests(),\n isWebSocketConnected: this.webSocketManager.socketState() === \"ready\",\n timeOfOldestInflightRequest:\n this.requestManager.timeOfOldestInflightRequest(),\n };\n }\n\n /**\n * Execute a mutation function.\n *\n * @param name - The name of the mutation.\n * @param args - An arguments object for the mutation. If this is omitted,\n * the arguments will be `{}`.\n * @param options - A {@link MutationOptions} options object for this mutation.\n\n * @returns - A promise of the mutation's result.\n */\n async mutation(\n name: string,\n args?: Record<string, Value>,\n options?: MutationOptions,\n ): Promise<any> {\n const result = await this.mutationInternal(name, args, options);\n if (!result.success) {\n if (result.errorData !== undefined) {\n throw forwardData(\n result,\n new ConvexError(\n createHybridErrorStacktrace(\"mutation\", name, result),\n ),\n );\n }\n throw new Error(createHybridErrorStacktrace(\"mutation\", name, result));\n }\n return result.value;\n }\n\n /**\n * @internal\n */\n async mutationInternal(\n udfPath: string,\n args?: Record<string, Value>,\n options?: MutationOptions,\n componentPath?: string,\n ): Promise<FunctionResult> {\n const mutationArgs = parseArgs(args);\n this.tryReportLongDisconnect();\n const requestId = this.nextRequestId;\n this._nextRequestId++;\n\n if (options !== undefined) {\n const optimisticUpdate = options.optimisticUpdate;\n if (optimisticUpdate !== undefined) {\n const wrappedUpdate = (localQueryStore: OptimisticLocalStore) => {\n optimisticUpdate(localQueryStore, mutationArgs);\n };\n\n const changedQueries =\n this.optimisticQueryResults.applyOptimisticUpdate(\n wrappedUpdate,\n requestId,\n );\n this.onTransition(changedQueries);\n }\n }\n\n const message: MutationRequest = {\n type: \"Mutation\",\n requestId,\n udfPath,\n componentPath,\n args: [convexToJson(mutationArgs)],\n };\n const mightBeSent = this.webSocketManager.sendMessage(message);\n return this.requestManager.request(message, mightBeSent);\n }\n\n /**\n * Execute an action function.\n *\n * @param name - The name of the action.\n * @param args - An 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(name: string, args?: Record<string, Value>): Promise<any> {\n const result = await this.actionInternal(name, args);\n if (!result.success) {\n if (result.errorData !== undefined) {\n throw forwardData(\n result,\n new ConvexError(createHybridErrorStacktrace(\"action\", name, result)),\n );\n }\n throw new Error(createHybridErrorStacktrace(\"action\", name, result));\n }\n return result.value;\n }\n\n /**\n * @internal\n */\n async actionInternal(\n udfPath: string,\n args?: Record<string, Value>,\n componentPath?: string,\n ): Promise<FunctionResult> {\n const actionArgs = parseArgs(args);\n const requestId = this.nextRequestId;\n this._nextRequestId++;\n this.tryReportLongDisconnect();\n\n const message: ActionRequest = {\n type: \"Action\",\n requestId,\n udfPath,\n componentPath,\n args: [convexToJson(actionArgs)],\n };\n\n const mightBeSent = this.webSocketManager.sendMessage(message);\n return this.requestManager.request(message, mightBeSent);\n }\n\n /**\n * Close any network handles associated with this client and stop all subscriptions.\n *\n * Call this method when you're done with an {@link BaseConvexClient} to\n * dispose of its sockets and resources.\n *\n * @returns A `Promise` fulfilled when the connection has been completely closed.\n */\n async close(): Promise<void> {\n this.authenticationManager.stop();\n return this.webSocketManager.terminate();\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 * @internal\n */\n get nextRequestId() {\n return this._nextRequestId;\n }\n\n /**\n * @internal\n */\n get sessionId() {\n return this._sessionId;\n }\n\n // Instance property so that `mark()` doesn't need to be called as a method.\n private mark = (name: MarkName) => {\n if (this.debug) {\n mark(name, this.sessionId);\n }\n };\n\n /**\n * Reports performance marks to the server. This should only be called when\n * we have a functional websocket.\n */\n private reportMarks() {\n if (this.debug) {\n const report = getMarksReport(this.sessionId);\n this.webSocketManager.sendMessage({\n type: \"Event\",\n eventType: \"ClientConnect\",\n event: report,\n });\n }\n }\n\n private tryReportLongDisconnect() {\n if (!this.debug) {\n return;\n }\n const timeOfOldestRequest =\n this.connectionState().timeOfOldestInflightRequest;\n if (\n timeOfOldestRequest === null ||\n Date.now() - timeOfOldestRequest.getTime() <= 60 * 1000\n ) {\n return;\n }\n const endpoint = `${this.address}/api/debug_event`;\n fetch(endpoint, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n \"Convex-Client\": `npm-${version}`,\n },\n body: JSON.stringify({ event: \"LongWebsocketDisconnect\" }),\n })\n .then((response) => {\n if (!response.ok) {\n console.warn(\n \"Analytics request failed with response:\",\n response.body,\n );\n }\n })\n .catch((error) => {\n console.warn(\"Analytics response failed with error:\", error);\n });\n }\n}\n", "import { validateDeploymentUrl } from \"../common/index.js\";\nimport {\n BaseConvexClient,\n BaseConvexClientOptions,\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 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\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-encoded 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 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 ): Promise<Awaited<FunctionReturnType<Mutation>>> {\n if (this.disabled) throw new Error(\"ConvexClient is disabled\");\n return await this.client.mutation(getFunctionName(mutation), args);\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 | Query[\"_returnType\"]\n | undefined;\n if (value !== undefined) return 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", "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 { logToConsole } from \"./logging.js\";\nimport { FunctionArgs, UserIdentityAttributes } 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\n/**\n * A Convex client that runs queries and mutations over HTTP.\n *\n * This is appropriate for server-side code (like Netlify Lambdas) or non-reactive\n * webapps.\n *\n * If you're building a React app, consider using\n * {@link react.ConvexReactClient} instead.\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\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 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 */\n constructor(address: string, skipConvexDeploymentUrlCheck?: boolean) {\n if (skipConvexDeploymentUrlCheck !== true) {\n validateDeploymentUrl(address);\n }\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 * @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 credentials: \"include\",\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 credentials: \"include\",\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 logToConsole(\"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 /**\n * Execute a Convex mutation function.\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 * @returns A promise of the mutation's result.\n */\n async mutation<Mutation extends FunctionReference<\"mutation\">>(\n mutation: Mutation,\n ...args: OptionalRestArgs<Mutation>\n ): Promise<FunctionReturnType<Mutation>> {\n const mutationArgs = parseArgs(args[0]);\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 credentials: \"include\",\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 logToConsole(\"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 /**\n * Execute a Convex action function.\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 credentials: \"include\",\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 logToConsole(\"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.\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 credentials: \"include\",\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 logToConsole(\"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
5
|
"mappings": "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",
|
|
6
6
|
"names": ["n", "value", "functionName", "version", "r", "r", "InvalidCharacterError", "message", "this", "prototype", "Error", "name", "window", "atob", "bind", "input", "str", "String", "replace", "length", "bs", "buffer", "bc", "idx", "output", "charAt", "fromCharCode", "indexOf", "decodeURIComponent", "m", "p", "code", "charCodeAt", "toString", "toUpperCase", "err", "InvalidTokenError", "token", "options", "pos", "header", "JSON", "parse", "base64_url_decode", "split", "e", "e", "mark", "e", "modification", "unsubscribeProps", "value", "e"]
|
|
7
7
|
}
|