@opendatalabs/vana-sdk 3.0.1-canary.b068ac6 → 3.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -31,7 +31,7 @@ __export(node_exports, {
31
31
  NodeECIESUint8Provider: () => NodeECIESUint8Provider
32
32
  });
33
33
  module.exports = __toCommonJS(node_exports);
34
- var import_node_crypto = require("node:crypto");
34
+ var import_crypto = require("crypto");
35
35
  var import_secp256k1 = __toESM(require("secp256k1"), 1);
36
36
  var import_base = require("./base");
37
37
  var import_viem = require("viem");
@@ -47,7 +47,7 @@ class NodeECIESUint8Provider extends import_base.BaseECIESUint8 {
47
47
  return x;
48
48
  };
49
49
  generateRandomBytes(length) {
50
- return new Uint8Array((0, import_node_crypto.randomBytes)(length));
50
+ return new Uint8Array((0, import_crypto.randomBytes)(length));
51
51
  }
52
52
  verifyPrivateKey(privateKey) {
53
53
  return secp256k1.privateKeyVerify(Buffer.from(privateKey)) === true;
@@ -91,16 +91,16 @@ class NodeECIESUint8Provider extends import_base.BaseECIESUint8 {
91
91
  }
92
92
  sha512(data) {
93
93
  return new Uint8Array(
94
- (0, import_node_crypto.createHash)("sha512").update(Buffer.from(data)).digest()
94
+ (0, import_crypto.createHash)("sha512").update(Buffer.from(data)).digest()
95
95
  );
96
96
  }
97
97
  hmacSha256(key, data) {
98
98
  return new Uint8Array(
99
- (0, import_node_crypto.createHmac)("sha256", Buffer.from(key)).update(Buffer.from(data)).digest()
99
+ (0, import_crypto.createHmac)("sha256", Buffer.from(key)).update(Buffer.from(data)).digest()
100
100
  );
101
101
  }
102
102
  async aesEncrypt(key, iv, plaintext) {
103
- const cipher = (0, import_node_crypto.createCipheriv)(
103
+ const cipher = (0, import_crypto.createCipheriv)(
104
104
  "aes-256-cbc",
105
105
  Buffer.from(key),
106
106
  Buffer.from(iv)
@@ -112,7 +112,7 @@ class NodeECIESUint8Provider extends import_base.BaseECIESUint8 {
112
112
  return new Uint8Array(encrypted);
113
113
  }
114
114
  async aesDecrypt(key, iv, ciphertext) {
115
- const decipher = (0, import_node_crypto.createDecipheriv)(
115
+ const decipher = (0, import_crypto.createDecipheriv)(
116
116
  "aes-256-cbc",
117
117
  Buffer.from(key),
118
118
  Buffer.from(iv)
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/crypto/ecies/node.ts"],"sourcesContent":["/**\n * Node.js implementation of ECIES using native secp256k1 for performance\n *\n * @remarks\n * Uses native secp256k1 bindings for all elliptic curve operations.\n * Uses Node.js crypto module for hashing and AES operations.\n * Provides Uint8Array-only interface with no Buffer exposure.\n */\n\nimport {\n randomBytes,\n createHash,\n createHmac,\n createCipheriv,\n createDecipheriv,\n} from \"node:crypto\";\nimport secp256k1Import from \"secp256k1\";\nimport { BaseECIESUint8 } from \"./base\";\nimport { toHex } from \"viem\";\n\n// Type definition for secp256k1 module\ninterface Secp256k1Module {\n privateKeyVerify(privateKey: Buffer): boolean;\n publicKeyCreate(privateKey: Buffer, compressed: boolean): Buffer;\n publicKeyVerify(publicKey: Buffer): boolean;\n publicKeyConvert(publicKey: Buffer, compressed: boolean): Buffer;\n ecdh(\n publicKey: Buffer,\n privateKey: Buffer,\n options: {\n hashfn: (x: Uint8Array, y: Uint8Array, output?: Uint8Array) => Uint8Array;\n },\n output: Buffer,\n ): Buffer;\n}\n\n// Use the imported secp256k1 module\nconst secp256k1 = secp256k1Import as unknown as Secp256k1Module;\n\n/**\n * Node.js-specific ECIES provider using native secp256k1\n *\n * @remarks\n * This implementation:\n * - Uses native secp256k1 for all EC operations (optimal performance)\n * - Uses Node.js crypto for SHA-512, HMAC, and AES operations\n * - Internally works with Uint8Array\n * - Only uses Buffer at crypto API boundaries\n */\nexport class NodeECIESUint8Provider extends BaseECIESUint8 {\n // Identity hash function for ECDH - returns raw X coordinate\n // CRITICAL: Must handle (x, y, output) signature correctly\n private readonly identityHashFn = (\n x: Uint8Array,\n _y: Uint8Array,\n output?: Uint8Array,\n ): Uint8Array => {\n // Copy x into output buffer if provided (prevents allocations)\n if (output && output.length >= 32) {\n output.set(x);\n return output;\n }\n return x;\n };\n protected generateRandomBytes(length: number): Uint8Array {\n return new Uint8Array(randomBytes(length));\n }\n\n protected verifyPrivateKey(privateKey: Uint8Array): boolean {\n // Native secp256k1 returns true for valid, false for invalid\n return secp256k1.privateKeyVerify(Buffer.from(privateKey)) === true;\n }\n\n protected createPublicKey(\n privateKey: Uint8Array,\n compressed: boolean,\n ): Uint8Array | null {\n try {\n return new Uint8Array(\n secp256k1.publicKeyCreate(Buffer.from(privateKey), compressed),\n );\n } catch {\n return null;\n }\n }\n\n protected validatePublicKey(publicKey: Uint8Array): boolean {\n // Native secp256k1 returns true for valid, false for invalid\n return secp256k1.publicKeyVerify(Buffer.from(publicKey)) === true;\n }\n\n protected decompressPublicKey(publicKey: Uint8Array): Uint8Array | null {\n try {\n // Convert to uncompressed format (65 bytes)\n return new Uint8Array(\n secp256k1.publicKeyConvert(Buffer.from(publicKey), false),\n );\n } catch {\n return null;\n }\n }\n\n protected performECDH(\n publicKey: Uint8Array,\n privateKey: Uint8Array,\n ): Uint8Array {\n try {\n // Use pre-allocated buffer for output (32 bytes)\n const output = Buffer.alloc(32);\n\n // CRITICAL: Use identity hash to get raw X coordinate\n // Default would apply SHA256 and break compatibility\n secp256k1.ecdh(\n Buffer.from(publicKey),\n Buffer.from(privateKey),\n { hashfn: this.identityHashFn },\n output,\n );\n\n return new Uint8Array(output);\n } catch (error) {\n throw new Error(\n `ECDH failed: ${error instanceof Error ? error.message : \"Unknown error\"}`,\n );\n }\n }\n\n protected sha512(data: Uint8Array): Uint8Array {\n // Use Node.js crypto for native performance\n return new Uint8Array(\n createHash(\"sha512\").update(Buffer.from(data)).digest(),\n );\n }\n\n protected hmacSha256(key: Uint8Array, data: Uint8Array): Uint8Array {\n // Use Node.js crypto for native performance\n return new Uint8Array(\n createHmac(\"sha256\", Buffer.from(key)).update(Buffer.from(data)).digest(),\n );\n }\n\n protected async aesEncrypt(\n key: Uint8Array,\n iv: Uint8Array,\n plaintext: Uint8Array,\n ): Promise<Uint8Array> {\n const cipher = createCipheriv(\n \"aes-256-cbc\",\n Buffer.from(key),\n Buffer.from(iv),\n );\n const encrypted = Buffer.concat([\n cipher.update(Buffer.from(plaintext)),\n cipher.final(),\n ]);\n return new Uint8Array(encrypted);\n }\n\n protected async aesDecrypt(\n key: Uint8Array,\n iv: Uint8Array,\n ciphertext: Uint8Array,\n ): Promise<Uint8Array> {\n const decipher = createDecipheriv(\n \"aes-256-cbc\",\n Buffer.from(key),\n Buffer.from(iv),\n );\n const decrypted = Buffer.concat([\n decipher.update(Buffer.from(ciphertext)),\n decipher.final(),\n ]);\n return new Uint8Array(decrypted);\n }\n\n // No Buffer compatibility methods - Uint8Array only public API\n\n /**\n * Normalizes a public key to uncompressed format (65 bytes with 0x04 prefix).\n * Handles compressed (33 bytes) and uncompressed (65 bytes) formats only.\n *\n * @remarks\n * Strict policy: Does not accept 64-byte raw coordinates to avoid masking\n * malformed data. Callers must provide properly formatted keys.\n *\n * @param publicKey - The public key to normalize (33 or 65 bytes)\n * @returns The normalized uncompressed public key (65 bytes)\n * @throws {Error} When public key format is invalid or decompression fails\n */\n normalizeToUncompressed(publicKey: Uint8Array): Uint8Array {\n const len = publicKey.length;\n\n // Already uncompressed\n if (len === 65 && publicKey[0] === 0x04) {\n return publicKey;\n }\n\n // Compressed - decompress using secp256k1\n if (len === 33 && (publicKey[0] === 0x02 || publicKey[0] === 0x03)) {\n const decompressed = this.decompressPublicKey(publicKey);\n if (!decompressed) {\n throw new Error(\n `Failed to decompress public key with prefix ${toHex(publicKey[0])}`,\n );\n }\n return decompressed;\n }\n\n // Reject raw coordinates (64 bytes) - require proper formatting\n if (len === 64) {\n throw new Error(\n \"Raw public key coordinates (64 bytes) are not accepted. \" +\n \"Please provide a properly formatted compressed (33 bytes) or uncompressed (65 bytes) public key.\",\n );\n }\n\n throw new Error(\n `Invalid public key format: expected compressed (33 bytes) or uncompressed (65 bytes), got ${len} bytes`,\n );\n }\n}\n"],"mappings":"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","names":["secp256k1Import"]}
1
+ {"version":3,"sources":["../../../src/crypto/ecies/node.ts"],"sourcesContent":["/**\n * Node.js implementation of ECIES using native secp256k1 for performance\n *\n * @remarks\n * Uses native secp256k1 bindings for all elliptic curve operations.\n * Uses Node.js crypto module for hashing and AES operations.\n * Provides Uint8Array-only interface with no Buffer exposure.\n */\n\nimport {\n randomBytes,\n createHash,\n createHmac,\n createCipheriv,\n createDecipheriv,\n} from \"crypto\";\nimport secp256k1Import from \"secp256k1\";\nimport { BaseECIESUint8 } from \"./base\";\nimport { toHex } from \"viem\";\n\n// Type definition for secp256k1 module\ninterface Secp256k1Module {\n privateKeyVerify(privateKey: Buffer): boolean;\n publicKeyCreate(privateKey: Buffer, compressed: boolean): Buffer;\n publicKeyVerify(publicKey: Buffer): boolean;\n publicKeyConvert(publicKey: Buffer, compressed: boolean): Buffer;\n ecdh(\n publicKey: Buffer,\n privateKey: Buffer,\n options: {\n hashfn: (x: Uint8Array, y: Uint8Array, output?: Uint8Array) => Uint8Array;\n },\n output: Buffer,\n ): Buffer;\n}\n\n// Use the imported secp256k1 module\nconst secp256k1 = secp256k1Import as unknown as Secp256k1Module;\n\n/**\n * Node.js-specific ECIES provider using native secp256k1\n *\n * @remarks\n * This implementation:\n * - Uses native secp256k1 for all EC operations (optimal performance)\n * - Uses Node.js crypto for SHA-512, HMAC, and AES operations\n * - Internally works with Uint8Array\n * - Only uses Buffer at crypto API boundaries\n */\nexport class NodeECIESUint8Provider extends BaseECIESUint8 {\n // Identity hash function for ECDH - returns raw X coordinate\n // CRITICAL: Must handle (x, y, output) signature correctly\n private readonly identityHashFn = (\n x: Uint8Array,\n _y: Uint8Array,\n output?: Uint8Array,\n ): Uint8Array => {\n // Copy x into output buffer if provided (prevents allocations)\n if (output && output.length >= 32) {\n output.set(x);\n return output;\n }\n return x;\n };\n protected generateRandomBytes(length: number): Uint8Array {\n return new Uint8Array(randomBytes(length));\n }\n\n protected verifyPrivateKey(privateKey: Uint8Array): boolean {\n // Native secp256k1 returns true for valid, false for invalid\n return secp256k1.privateKeyVerify(Buffer.from(privateKey)) === true;\n }\n\n protected createPublicKey(\n privateKey: Uint8Array,\n compressed: boolean,\n ): Uint8Array | null {\n try {\n return new Uint8Array(\n secp256k1.publicKeyCreate(Buffer.from(privateKey), compressed),\n );\n } catch {\n return null;\n }\n }\n\n protected validatePublicKey(publicKey: Uint8Array): boolean {\n // Native secp256k1 returns true for valid, false for invalid\n return secp256k1.publicKeyVerify(Buffer.from(publicKey)) === true;\n }\n\n protected decompressPublicKey(publicKey: Uint8Array): Uint8Array | null {\n try {\n // Convert to uncompressed format (65 bytes)\n return new Uint8Array(\n secp256k1.publicKeyConvert(Buffer.from(publicKey), false),\n );\n } catch {\n return null;\n }\n }\n\n protected performECDH(\n publicKey: Uint8Array,\n privateKey: Uint8Array,\n ): Uint8Array {\n try {\n // Use pre-allocated buffer for output (32 bytes)\n const output = Buffer.alloc(32);\n\n // CRITICAL: Use identity hash to get raw X coordinate\n // Default would apply SHA256 and break compatibility\n secp256k1.ecdh(\n Buffer.from(publicKey),\n Buffer.from(privateKey),\n { hashfn: this.identityHashFn },\n output,\n );\n\n return new Uint8Array(output);\n } catch (error) {\n throw new Error(\n `ECDH failed: ${error instanceof Error ? error.message : \"Unknown error\"}`,\n );\n }\n }\n\n protected sha512(data: Uint8Array): Uint8Array {\n // Use Node.js crypto for native performance\n return new Uint8Array(\n createHash(\"sha512\").update(Buffer.from(data)).digest(),\n );\n }\n\n protected hmacSha256(key: Uint8Array, data: Uint8Array): Uint8Array {\n // Use Node.js crypto for native performance\n return new Uint8Array(\n createHmac(\"sha256\", Buffer.from(key)).update(Buffer.from(data)).digest(),\n );\n }\n\n protected async aesEncrypt(\n key: Uint8Array,\n iv: Uint8Array,\n plaintext: Uint8Array,\n ): Promise<Uint8Array> {\n const cipher = createCipheriv(\n \"aes-256-cbc\",\n Buffer.from(key),\n Buffer.from(iv),\n );\n const encrypted = Buffer.concat([\n cipher.update(Buffer.from(plaintext)),\n cipher.final(),\n ]);\n return new Uint8Array(encrypted);\n }\n\n protected async aesDecrypt(\n key: Uint8Array,\n iv: Uint8Array,\n ciphertext: Uint8Array,\n ): Promise<Uint8Array> {\n const decipher = createDecipheriv(\n \"aes-256-cbc\",\n Buffer.from(key),\n Buffer.from(iv),\n );\n const decrypted = Buffer.concat([\n decipher.update(Buffer.from(ciphertext)),\n decipher.final(),\n ]);\n return new Uint8Array(decrypted);\n }\n\n // No Buffer compatibility methods - Uint8Array only public API\n\n /**\n * Normalizes a public key to uncompressed format (65 bytes with 0x04 prefix).\n * Handles compressed (33 bytes) and uncompressed (65 bytes) formats only.\n *\n * @remarks\n * Strict policy: Does not accept 64-byte raw coordinates to avoid masking\n * malformed data. Callers must provide properly formatted keys.\n *\n * @param publicKey - The public key to normalize (33 or 65 bytes)\n * @returns The normalized uncompressed public key (65 bytes)\n * @throws {Error} When public key format is invalid or decompression fails\n */\n normalizeToUncompressed(publicKey: Uint8Array): Uint8Array {\n const len = publicKey.length;\n\n // Already uncompressed\n if (len === 65 && publicKey[0] === 0x04) {\n return publicKey;\n }\n\n // Compressed - decompress using secp256k1\n if (len === 33 && (publicKey[0] === 0x02 || publicKey[0] === 0x03)) {\n const decompressed = this.decompressPublicKey(publicKey);\n if (!decompressed) {\n throw new Error(\n `Failed to decompress public key with prefix ${toHex(publicKey[0])}`,\n );\n }\n return decompressed;\n }\n\n // Reject raw coordinates (64 bytes) - require proper formatting\n if (len === 64) {\n throw new Error(\n \"Raw public key coordinates (64 bytes) are not accepted. \" +\n \"Please provide a properly formatted compressed (33 bytes) or uncompressed (65 bytes) public key.\",\n );\n }\n\n throw new Error(\n `Invalid public key format: expected compressed (33 bytes) or uncompressed (65 bytes), got ${len} bytes`,\n );\n }\n}\n"],"mappings":"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","names":["secp256k1Import"]}
@@ -4,7 +4,7 @@ import {
4
4
  createHmac,
5
5
  createCipheriv,
6
6
  createDecipheriv
7
- } from "node:crypto";
7
+ } from "crypto";
8
8
  import secp256k1Import from "secp256k1";
9
9
  import { BaseECIESUint8 } from "./base";
10
10
  import { toHex } from "viem";
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/crypto/ecies/node.ts"],"sourcesContent":["/**\n * Node.js implementation of ECIES using native secp256k1 for performance\n *\n * @remarks\n * Uses native secp256k1 bindings for all elliptic curve operations.\n * Uses Node.js crypto module for hashing and AES operations.\n * Provides Uint8Array-only interface with no Buffer exposure.\n */\n\nimport {\n randomBytes,\n createHash,\n createHmac,\n createCipheriv,\n createDecipheriv,\n} from \"node:crypto\";\nimport secp256k1Import from \"secp256k1\";\nimport { BaseECIESUint8 } from \"./base\";\nimport { toHex } from \"viem\";\n\n// Type definition for secp256k1 module\ninterface Secp256k1Module {\n privateKeyVerify(privateKey: Buffer): boolean;\n publicKeyCreate(privateKey: Buffer, compressed: boolean): Buffer;\n publicKeyVerify(publicKey: Buffer): boolean;\n publicKeyConvert(publicKey: Buffer, compressed: boolean): Buffer;\n ecdh(\n publicKey: Buffer,\n privateKey: Buffer,\n options: {\n hashfn: (x: Uint8Array, y: Uint8Array, output?: Uint8Array) => Uint8Array;\n },\n output: Buffer,\n ): Buffer;\n}\n\n// Use the imported secp256k1 module\nconst secp256k1 = secp256k1Import as unknown as Secp256k1Module;\n\n/**\n * Node.js-specific ECIES provider using native secp256k1\n *\n * @remarks\n * This implementation:\n * - Uses native secp256k1 for all EC operations (optimal performance)\n * - Uses Node.js crypto for SHA-512, HMAC, and AES operations\n * - Internally works with Uint8Array\n * - Only uses Buffer at crypto API boundaries\n */\nexport class NodeECIESUint8Provider extends BaseECIESUint8 {\n // Identity hash function for ECDH - returns raw X coordinate\n // CRITICAL: Must handle (x, y, output) signature correctly\n private readonly identityHashFn = (\n x: Uint8Array,\n _y: Uint8Array,\n output?: Uint8Array,\n ): Uint8Array => {\n // Copy x into output buffer if provided (prevents allocations)\n if (output && output.length >= 32) {\n output.set(x);\n return output;\n }\n return x;\n };\n protected generateRandomBytes(length: number): Uint8Array {\n return new Uint8Array(randomBytes(length));\n }\n\n protected verifyPrivateKey(privateKey: Uint8Array): boolean {\n // Native secp256k1 returns true for valid, false for invalid\n return secp256k1.privateKeyVerify(Buffer.from(privateKey)) === true;\n }\n\n protected createPublicKey(\n privateKey: Uint8Array,\n compressed: boolean,\n ): Uint8Array | null {\n try {\n return new Uint8Array(\n secp256k1.publicKeyCreate(Buffer.from(privateKey), compressed),\n );\n } catch {\n return null;\n }\n }\n\n protected validatePublicKey(publicKey: Uint8Array): boolean {\n // Native secp256k1 returns true for valid, false for invalid\n return secp256k1.publicKeyVerify(Buffer.from(publicKey)) === true;\n }\n\n protected decompressPublicKey(publicKey: Uint8Array): Uint8Array | null {\n try {\n // Convert to uncompressed format (65 bytes)\n return new Uint8Array(\n secp256k1.publicKeyConvert(Buffer.from(publicKey), false),\n );\n } catch {\n return null;\n }\n }\n\n protected performECDH(\n publicKey: Uint8Array,\n privateKey: Uint8Array,\n ): Uint8Array {\n try {\n // Use pre-allocated buffer for output (32 bytes)\n const output = Buffer.alloc(32);\n\n // CRITICAL: Use identity hash to get raw X coordinate\n // Default would apply SHA256 and break compatibility\n secp256k1.ecdh(\n Buffer.from(publicKey),\n Buffer.from(privateKey),\n { hashfn: this.identityHashFn },\n output,\n );\n\n return new Uint8Array(output);\n } catch (error) {\n throw new Error(\n `ECDH failed: ${error instanceof Error ? error.message : \"Unknown error\"}`,\n );\n }\n }\n\n protected sha512(data: Uint8Array): Uint8Array {\n // Use Node.js crypto for native performance\n return new Uint8Array(\n createHash(\"sha512\").update(Buffer.from(data)).digest(),\n );\n }\n\n protected hmacSha256(key: Uint8Array, data: Uint8Array): Uint8Array {\n // Use Node.js crypto for native performance\n return new Uint8Array(\n createHmac(\"sha256\", Buffer.from(key)).update(Buffer.from(data)).digest(),\n );\n }\n\n protected async aesEncrypt(\n key: Uint8Array,\n iv: Uint8Array,\n plaintext: Uint8Array,\n ): Promise<Uint8Array> {\n const cipher = createCipheriv(\n \"aes-256-cbc\",\n Buffer.from(key),\n Buffer.from(iv),\n );\n const encrypted = Buffer.concat([\n cipher.update(Buffer.from(plaintext)),\n cipher.final(),\n ]);\n return new Uint8Array(encrypted);\n }\n\n protected async aesDecrypt(\n key: Uint8Array,\n iv: Uint8Array,\n ciphertext: Uint8Array,\n ): Promise<Uint8Array> {\n const decipher = createDecipheriv(\n \"aes-256-cbc\",\n Buffer.from(key),\n Buffer.from(iv),\n );\n const decrypted = Buffer.concat([\n decipher.update(Buffer.from(ciphertext)),\n decipher.final(),\n ]);\n return new Uint8Array(decrypted);\n }\n\n // No Buffer compatibility methods - Uint8Array only public API\n\n /**\n * Normalizes a public key to uncompressed format (65 bytes with 0x04 prefix).\n * Handles compressed (33 bytes) and uncompressed (65 bytes) formats only.\n *\n * @remarks\n * Strict policy: Does not accept 64-byte raw coordinates to avoid masking\n * malformed data. Callers must provide properly formatted keys.\n *\n * @param publicKey - The public key to normalize (33 or 65 bytes)\n * @returns The normalized uncompressed public key (65 bytes)\n * @throws {Error} When public key format is invalid or decompression fails\n */\n normalizeToUncompressed(publicKey: Uint8Array): Uint8Array {\n const len = publicKey.length;\n\n // Already uncompressed\n if (len === 65 && publicKey[0] === 0x04) {\n return publicKey;\n }\n\n // Compressed - decompress using secp256k1\n if (len === 33 && (publicKey[0] === 0x02 || publicKey[0] === 0x03)) {\n const decompressed = this.decompressPublicKey(publicKey);\n if (!decompressed) {\n throw new Error(\n `Failed to decompress public key with prefix ${toHex(publicKey[0])}`,\n );\n }\n return decompressed;\n }\n\n // Reject raw coordinates (64 bytes) - require proper formatting\n if (len === 64) {\n throw new Error(\n \"Raw public key coordinates (64 bytes) are not accepted. \" +\n \"Please provide a properly formatted compressed (33 bytes) or uncompressed (65 bytes) public key.\",\n );\n }\n\n throw new Error(\n `Invalid public key format: expected compressed (33 bytes) or uncompressed (65 bytes), got ${len} bytes`,\n );\n }\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../../src/crypto/ecies/node.ts"],"sourcesContent":["/**\n * Node.js implementation of ECIES using native secp256k1 for performance\n *\n * @remarks\n * Uses native secp256k1 bindings for all elliptic curve operations.\n * Uses Node.js crypto module for hashing and AES operations.\n * Provides Uint8Array-only interface with no Buffer exposure.\n */\n\nimport {\n randomBytes,\n createHash,\n createHmac,\n createCipheriv,\n createDecipheriv,\n} from \"crypto\";\nimport secp256k1Import from \"secp256k1\";\nimport { BaseECIESUint8 } from \"./base\";\nimport { toHex } from \"viem\";\n\n// Type definition for secp256k1 module\ninterface Secp256k1Module {\n privateKeyVerify(privateKey: Buffer): boolean;\n publicKeyCreate(privateKey: Buffer, compressed: boolean): Buffer;\n publicKeyVerify(publicKey: Buffer): boolean;\n publicKeyConvert(publicKey: Buffer, compressed: boolean): Buffer;\n ecdh(\n publicKey: Buffer,\n privateKey: Buffer,\n options: {\n hashfn: (x: Uint8Array, y: Uint8Array, output?: Uint8Array) => Uint8Array;\n },\n output: Buffer,\n ): Buffer;\n}\n\n// Use the imported secp256k1 module\nconst secp256k1 = secp256k1Import as unknown as Secp256k1Module;\n\n/**\n * Node.js-specific ECIES provider using native secp256k1\n *\n * @remarks\n * This implementation:\n * - Uses native secp256k1 for all EC operations (optimal performance)\n * - Uses Node.js crypto for SHA-512, HMAC, and AES operations\n * - Internally works with Uint8Array\n * - Only uses Buffer at crypto API boundaries\n */\nexport class NodeECIESUint8Provider extends BaseECIESUint8 {\n // Identity hash function for ECDH - returns raw X coordinate\n // CRITICAL: Must handle (x, y, output) signature correctly\n private readonly identityHashFn = (\n x: Uint8Array,\n _y: Uint8Array,\n output?: Uint8Array,\n ): Uint8Array => {\n // Copy x into output buffer if provided (prevents allocations)\n if (output && output.length >= 32) {\n output.set(x);\n return output;\n }\n return x;\n };\n protected generateRandomBytes(length: number): Uint8Array {\n return new Uint8Array(randomBytes(length));\n }\n\n protected verifyPrivateKey(privateKey: Uint8Array): boolean {\n // Native secp256k1 returns true for valid, false for invalid\n return secp256k1.privateKeyVerify(Buffer.from(privateKey)) === true;\n }\n\n protected createPublicKey(\n privateKey: Uint8Array,\n compressed: boolean,\n ): Uint8Array | null {\n try {\n return new Uint8Array(\n secp256k1.publicKeyCreate(Buffer.from(privateKey), compressed),\n );\n } catch {\n return null;\n }\n }\n\n protected validatePublicKey(publicKey: Uint8Array): boolean {\n // Native secp256k1 returns true for valid, false for invalid\n return secp256k1.publicKeyVerify(Buffer.from(publicKey)) === true;\n }\n\n protected decompressPublicKey(publicKey: Uint8Array): Uint8Array | null {\n try {\n // Convert to uncompressed format (65 bytes)\n return new Uint8Array(\n secp256k1.publicKeyConvert(Buffer.from(publicKey), false),\n );\n } catch {\n return null;\n }\n }\n\n protected performECDH(\n publicKey: Uint8Array,\n privateKey: Uint8Array,\n ): Uint8Array {\n try {\n // Use pre-allocated buffer for output (32 bytes)\n const output = Buffer.alloc(32);\n\n // CRITICAL: Use identity hash to get raw X coordinate\n // Default would apply SHA256 and break compatibility\n secp256k1.ecdh(\n Buffer.from(publicKey),\n Buffer.from(privateKey),\n { hashfn: this.identityHashFn },\n output,\n );\n\n return new Uint8Array(output);\n } catch (error) {\n throw new Error(\n `ECDH failed: ${error instanceof Error ? error.message : \"Unknown error\"}`,\n );\n }\n }\n\n protected sha512(data: Uint8Array): Uint8Array {\n // Use Node.js crypto for native performance\n return new Uint8Array(\n createHash(\"sha512\").update(Buffer.from(data)).digest(),\n );\n }\n\n protected hmacSha256(key: Uint8Array, data: Uint8Array): Uint8Array {\n // Use Node.js crypto for native performance\n return new Uint8Array(\n createHmac(\"sha256\", Buffer.from(key)).update(Buffer.from(data)).digest(),\n );\n }\n\n protected async aesEncrypt(\n key: Uint8Array,\n iv: Uint8Array,\n plaintext: Uint8Array,\n ): Promise<Uint8Array> {\n const cipher = createCipheriv(\n \"aes-256-cbc\",\n Buffer.from(key),\n Buffer.from(iv),\n );\n const encrypted = Buffer.concat([\n cipher.update(Buffer.from(plaintext)),\n cipher.final(),\n ]);\n return new Uint8Array(encrypted);\n }\n\n protected async aesDecrypt(\n key: Uint8Array,\n iv: Uint8Array,\n ciphertext: Uint8Array,\n ): Promise<Uint8Array> {\n const decipher = createDecipheriv(\n \"aes-256-cbc\",\n Buffer.from(key),\n Buffer.from(iv),\n );\n const decrypted = Buffer.concat([\n decipher.update(Buffer.from(ciphertext)),\n decipher.final(),\n ]);\n return new Uint8Array(decrypted);\n }\n\n // No Buffer compatibility methods - Uint8Array only public API\n\n /**\n * Normalizes a public key to uncompressed format (65 bytes with 0x04 prefix).\n * Handles compressed (33 bytes) and uncompressed (65 bytes) formats only.\n *\n * @remarks\n * Strict policy: Does not accept 64-byte raw coordinates to avoid masking\n * malformed data. Callers must provide properly formatted keys.\n *\n * @param publicKey - The public key to normalize (33 or 65 bytes)\n * @returns The normalized uncompressed public key (65 bytes)\n * @throws {Error} When public key format is invalid or decompression fails\n */\n normalizeToUncompressed(publicKey: Uint8Array): Uint8Array {\n const len = publicKey.length;\n\n // Already uncompressed\n if (len === 65 && publicKey[0] === 0x04) {\n return publicKey;\n }\n\n // Compressed - decompress using secp256k1\n if (len === 33 && (publicKey[0] === 0x02 || publicKey[0] === 0x03)) {\n const decompressed = this.decompressPublicKey(publicKey);\n if (!decompressed) {\n throw new Error(\n `Failed to decompress public key with prefix ${toHex(publicKey[0])}`,\n );\n }\n return decompressed;\n }\n\n // Reject raw coordinates (64 bytes) - require proper formatting\n if (len === 64) {\n throw new Error(\n \"Raw public key coordinates (64 bytes) are not accepted. \" +\n \"Please provide a properly formatted compressed (33 bytes) or uncompressed (65 bytes) public key.\",\n );\n }\n\n throw new Error(\n `Invalid public key format: expected compressed (33 bytes) or uncompressed (65 bytes), got ${len} bytes`,\n );\n }\n}\n"],"mappings":"AASA;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,OAAO,qBAAqB;AAC5B,SAAS,sBAAsB;AAC/B,SAAS,aAAa;AAmBtB,MAAM,YAAY;AAYX,MAAM,+BAA+B,eAAe;AAAA;AAAA;AAAA,EAGxC,iBAAiB,CAChC,GACA,IACA,WACe;AAEf,QAAI,UAAU,OAAO,UAAU,IAAI;AACjC,aAAO,IAAI,CAAC;AACZ,aAAO;AAAA,IACT;AACA,WAAO;AAAA,EACT;AAAA,EACU,oBAAoB,QAA4B;AACxD,WAAO,IAAI,WAAW,YAAY,MAAM,CAAC;AAAA,EAC3C;AAAA,EAEU,iBAAiB,YAAiC;AAE1D,WAAO,UAAU,iBAAiB,OAAO,KAAK,UAAU,CAAC,MAAM;AAAA,EACjE;AAAA,EAEU,gBACR,YACA,YACmB;AACnB,QAAI;AACF,aAAO,IAAI;AAAA,QACT,UAAU,gBAAgB,OAAO,KAAK,UAAU,GAAG,UAAU;AAAA,MAC/D;AAAA,IACF,QAAQ;AACN,aAAO;AAAA,IACT;AAAA,EACF;AAAA,EAEU,kBAAkB,WAAgC;AAE1D,WAAO,UAAU,gBAAgB,OAAO,KAAK,SAAS,CAAC,MAAM;AAAA,EAC/D;AAAA,EAEU,oBAAoB,WAA0C;AACtE,QAAI;AAEF,aAAO,IAAI;AAAA,QACT,UAAU,iBAAiB,OAAO,KAAK,SAAS,GAAG,KAAK;AAAA,MAC1D;AAAA,IACF,QAAQ;AACN,aAAO;AAAA,IACT;AAAA,EACF;AAAA,EAEU,YACR,WACA,YACY;AACZ,QAAI;AAEF,YAAM,SAAS,OAAO,MAAM,EAAE;AAI9B,gBAAU;AAAA,QACR,OAAO,KAAK,SAAS;AAAA,QACrB,OAAO,KAAK,UAAU;AAAA,QACtB,EAAE,QAAQ,KAAK,eAAe;AAAA,QAC9B;AAAA,MACF;AAEA,aAAO,IAAI,WAAW,MAAM;AAAA,IAC9B,SAAS,OAAO;AACd,YAAM,IAAI;AAAA,QACR,gBAAgB,iBAAiB,QAAQ,MAAM,UAAU,eAAe;AAAA,MAC1E;AAAA,IACF;AAAA,EACF;AAAA,EAEU,OAAO,MAA8B;AAE7C,WAAO,IAAI;AAAA,MACT,WAAW,QAAQ,EAAE,OAAO,OAAO,KAAK,IAAI,CAAC,EAAE,OAAO;AAAA,IACxD;AAAA,EACF;AAAA,EAEU,WAAW,KAAiB,MAA8B;AAElE,WAAO,IAAI;AAAA,MACT,WAAW,UAAU,OAAO,KAAK,GAAG,CAAC,EAAE,OAAO,OAAO,KAAK,IAAI,CAAC,EAAE,OAAO;AAAA,IAC1E;AAAA,EACF;AAAA,EAEA,MAAgB,WACd,KACA,IACA,WACqB;AACrB,UAAM,SAAS;AAAA,MACb;AAAA,MACA,OAAO,KAAK,GAAG;AAAA,MACf,OAAO,KAAK,EAAE;AAAA,IAChB;AACA,UAAM,YAAY,OAAO,OAAO;AAAA,MAC9B,OAAO,OAAO,OAAO,KAAK,SAAS,CAAC;AAAA,MACpC,OAAO,MAAM;AAAA,IACf,CAAC;AACD,WAAO,IAAI,WAAW,SAAS;AAAA,EACjC;AAAA,EAEA,MAAgB,WACd,KACA,IACA,YACqB;AACrB,UAAM,WAAW;AAAA,MACf;AAAA,MACA,OAAO,KAAK,GAAG;AAAA,MACf,OAAO,KAAK,EAAE;AAAA,IAChB;AACA,UAAM,YAAY,OAAO,OAAO;AAAA,MAC9B,SAAS,OAAO,OAAO,KAAK,UAAU,CAAC;AAAA,MACvC,SAAS,MAAM;AAAA,IACjB,CAAC;AACD,WAAO,IAAI,WAAW,SAAS;AAAA,EACjC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAgBA,wBAAwB,WAAmC;AACzD,UAAM,MAAM,UAAU;AAGtB,QAAI,QAAQ,MAAM,UAAU,CAAC,MAAM,GAAM;AACvC,aAAO;AAAA,IACT;AAGA,QAAI,QAAQ,OAAO,UAAU,CAAC,MAAM,KAAQ,UAAU,CAAC,MAAM,IAAO;AAClE,YAAM,eAAe,KAAK,oBAAoB,SAAS;AACvD,UAAI,CAAC,cAAc;AACjB,cAAM,IAAI;AAAA,UACR,+CAA+C,MAAM,UAAU,CAAC,CAAC,CAAC;AAAA,QACpE;AAAA,MACF;AACA,aAAO;AAAA,IACT;AAGA,QAAI,QAAQ,IAAI;AACd,YAAM,IAAI;AAAA,QACR;AAAA,MAEF;AAAA,IACF;AAEA,UAAM,IAAI;AAAA,MACR,6FAA6F,GAAG;AAAA,IAClG;AAAA,EACF;AACF;","names":[]}
@@ -28,6 +28,7 @@ export type { ECIESProvider, ECIESEncrypted, ECIESOptions, } from "./crypto/ecie
28
28
  export { createBrowserPlatformAdapter, createPlatformAdapterSafe, } from "./platform/browser-only";
29
29
  export { generatePkceVerifier, computePkceChallenge, verifyPkceChallenge, assertValidPkceVerifier, PKCE_VERIFIER_PATTERN, PKCE_CHALLENGE_PATTERN, } from "./auth/pkce";
30
30
  export { InMemoryTokenStore, type TokenStore, type TokenRecord, } from "./auth/token-store";
31
+ export { OAuthClient, type OAuthClientConfig, type AuthorizationUrlResult, } from "./auth/oauth-client";
31
32
  export { detectPlatform, isPlatformSupported, getPlatformCapabilities, } from "./platform/utils";
32
33
  export { deriveMasterKey, deriveScopeKey, recoverServerOwner, MASTER_KEY_MESSAGE, } from "./crypto/keys/derive";
33
34
  export { encryptWithPassword, decryptWithPassword, } from "./crypto/envelope/openpgp";
@@ -29006,7 +29006,7 @@ async function buildWeb3SignedHeader(params) {
29006
29006
  }
29007
29007
 
29008
29008
  // src/storage/providers/vana-storage.ts
29009
- var DEFAULT_ENDPOINT = "https://storage.vana.com";
29009
+ var DEFAULT_ENDPOINT = "https://storage.vana.org";
29010
29010
  var BLOB_PATH_PREFIX = "/v1/blobs";
29011
29011
  var DEFAULT_TOKEN_TTL_SECONDS = 300;
29012
29012
  var VanaStorage = class {
@@ -31432,6 +31432,228 @@ var InMemoryTokenStore = class {
31432
31432
  }
31433
31433
  };
31434
31434
 
31435
+ // src/auth/oauth-client.ts
31436
+ var VERIFIER_TTL_SECONDS = 600;
31437
+ var RESERVED_AUTHORIZE_PARAMS = /* @__PURE__ */ new Set([
31438
+ "response_type",
31439
+ "client_id",
31440
+ "redirect_uri",
31441
+ "scope",
31442
+ "state",
31443
+ "code_challenge",
31444
+ "code_challenge_method"
31445
+ ]);
31446
+ var OAuthClient = class {
31447
+ #config;
31448
+ constructor(config) {
31449
+ const fetchImpl = config.fetchImpl ?? globalThis.fetch;
31450
+ if (typeof fetchImpl !== "function") {
31451
+ throw new TypeError(
31452
+ "OAuthClient requires a global `fetch` or an explicit `fetchImpl`"
31453
+ );
31454
+ }
31455
+ this.#config = {
31456
+ authorizationEndpoint: config.authorizationEndpoint,
31457
+ tokenEndpoint: config.tokenEndpoint,
31458
+ clientId: config.clientId,
31459
+ redirectUri: config.redirectUri,
31460
+ scope: config.scope,
31461
+ tokenStore: config.tokenStore ?? new InMemoryTokenStore(),
31462
+ fetchImpl,
31463
+ generateState: config.generateState ?? defaultGenerateState
31464
+ };
31465
+ }
31466
+ /** Build the authorize URL and persist the PKCE verifier keyed by `state`. */
31467
+ async buildAuthorizationUrl(opts = {}) {
31468
+ const state = opts.state ?? this.#config.generateState();
31469
+ const scope = opts.scope ?? this.#config.scope;
31470
+ const verifier = generatePkceVerifier();
31471
+ const challenge = await computePkceChallenge(verifier);
31472
+ await this.#config.tokenStore.set(this.#verifierKey(state), {
31473
+ token: verifier,
31474
+ expiresAt: Math.floor(Date.now() / 1e3) + VERIFIER_TTL_SECONDS
31475
+ });
31476
+ const params = new URLSearchParams();
31477
+ params.set("response_type", "code");
31478
+ params.set("client_id", this.#config.clientId);
31479
+ params.set("redirect_uri", this.#config.redirectUri);
31480
+ if (scope !== void 0 && scope.length > 0) {
31481
+ params.set("scope", scope);
31482
+ }
31483
+ params.set("state", state);
31484
+ params.set("code_challenge", challenge);
31485
+ params.set("code_challenge_method", "S256");
31486
+ if (opts.extraParams !== void 0) {
31487
+ for (const k of Object.keys(opts.extraParams)) {
31488
+ if (RESERVED_AUTHORIZE_PARAMS.has(k)) {
31489
+ throw new Error(
31490
+ `extraParams may not override the reserved OAuth/PKCE parameter "${k}"`
31491
+ );
31492
+ }
31493
+ }
31494
+ for (const [k, v] of Object.entries(opts.extraParams)) {
31495
+ params.set(k, v);
31496
+ }
31497
+ }
31498
+ const sep = this.#config.authorizationEndpoint.includes("?") ? "&" : "?";
31499
+ const url = `${this.#config.authorizationEndpoint}${sep}${params.toString()}`;
31500
+ return { url, state };
31501
+ }
31502
+ /**
31503
+ * Handle the redirect-callback URL. Validates `state`, retrieves the saved
31504
+ * verifier, exchanges the authorization code + verifier for tokens, and
31505
+ * persists them. Returns the access {@link TokenRecord}.
31506
+ */
31507
+ async handleCallback(callbackUrl) {
31508
+ const parsed = new URL(callbackUrl);
31509
+ const params = parsed.searchParams;
31510
+ const errorCode = params.get("error");
31511
+ if (errorCode !== null) {
31512
+ throw new Error(
31513
+ formatOAuthError({
31514
+ error: errorCode,
31515
+ error_description: params.get("error_description") ?? void 0
31516
+ })
31517
+ );
31518
+ }
31519
+ const code = params.get("code");
31520
+ const state = params.get("state");
31521
+ if (code === null || state === null) {
31522
+ throw new Error("OAuth callback is missing `code` or `state`");
31523
+ }
31524
+ const verifierRecord = await this.#config.tokenStore.get(
31525
+ this.#verifierKey(state)
31526
+ );
31527
+ if (verifierRecord === null) {
31528
+ throw new Error(
31529
+ "OAuth callback state does not match any in-flight verifier (possible CSRF or expired flow)"
31530
+ );
31531
+ }
31532
+ const body = new URLSearchParams();
31533
+ body.set("grant_type", "authorization_code");
31534
+ body.set("code", code);
31535
+ body.set("redirect_uri", this.#config.redirectUri);
31536
+ body.set("client_id", this.#config.clientId);
31537
+ body.set("code_verifier", verifierRecord.token);
31538
+ let tokens;
31539
+ try {
31540
+ tokens = await this.#tokenRequest(body);
31541
+ } finally {
31542
+ await this.#config.tokenStore.delete(this.#verifierKey(state));
31543
+ }
31544
+ return this.#persistTokens(tokens);
31545
+ }
31546
+ /**
31547
+ * Exchange a stored refresh token for a fresh access token. Throws if no
31548
+ * refresh token is available.
31549
+ */
31550
+ async refresh() {
31551
+ const refreshRecord = await this.#config.tokenStore.get(this.#refreshKey());
31552
+ if (refreshRecord === null) {
31553
+ throw new Error("OAuth refresh failed: no refresh token stored");
31554
+ }
31555
+ const body = new URLSearchParams();
31556
+ body.set("grant_type", "refresh_token");
31557
+ body.set("refresh_token", refreshRecord.token);
31558
+ body.set("client_id", this.#config.clientId);
31559
+ const tokens = await this.#tokenRequest(body);
31560
+ return this.#persistTokens(tokens, refreshRecord.token);
31561
+ }
31562
+ /**
31563
+ * Get the current access token if valid (refreshing first if expired and a
31564
+ * refresh token is available). Returns `null` when no usable token exists.
31565
+ */
31566
+ async getAccessToken() {
31567
+ const stored = await this.#config.tokenStore.get(this.#accessKey());
31568
+ if (stored !== null) return stored.token;
31569
+ const refresh = await this.#config.tokenStore.get(this.#refreshKey());
31570
+ if (refresh === null) return null;
31571
+ try {
31572
+ const refreshed = await this.refresh();
31573
+ return refreshed.token;
31574
+ } catch {
31575
+ return null;
31576
+ }
31577
+ }
31578
+ /** Forget tokens (logout). Does NOT call any remote revocation endpoint. */
31579
+ async signOut() {
31580
+ await this.#config.tokenStore.delete(this.#accessKey());
31581
+ await this.#config.tokenStore.delete(this.#refreshKey());
31582
+ }
31583
+ #accessKey() {
31584
+ return `oauth:tokens:${this.#config.clientId}`;
31585
+ }
31586
+ #refreshKey() {
31587
+ return `oauth:refresh:${this.#config.clientId}`;
31588
+ }
31589
+ #verifierKey(state) {
31590
+ return `oauth:verifier:${state}`;
31591
+ }
31592
+ async #tokenRequest(body) {
31593
+ const response = await this.#config.fetchImpl(this.#config.tokenEndpoint, {
31594
+ method: "POST",
31595
+ headers: {
31596
+ "Content-Type": "application/x-www-form-urlencoded",
31597
+ Accept: "application/json"
31598
+ },
31599
+ body: body.toString()
31600
+ });
31601
+ const text = await response.text();
31602
+ const parsed = parseJsonBody(text);
31603
+ if (!response.ok) {
31604
+ throw new Error(formatOAuthError(parsed ?? {}, response.status));
31605
+ }
31606
+ if (parsed === null || typeof parsed !== "object" || typeof parsed.access_token !== "string") {
31607
+ throw new Error(
31608
+ "OAuth token endpoint returned a response without an `access_token` string"
31609
+ );
31610
+ }
31611
+ return parsed;
31612
+ }
31613
+ async #persistTokens(tokens, previousRefreshToken) {
31614
+ const record = { token: tokens.access_token };
31615
+ if (typeof tokens.expires_in === "number" && tokens.expires_in > 0) {
31616
+ record.expiresAt = Math.floor(Date.now() / 1e3) + tokens.expires_in;
31617
+ }
31618
+ await this.#config.tokenStore.set(this.#accessKey(), record);
31619
+ const newRefresh = tokens.refresh_token ?? previousRefreshToken;
31620
+ if (newRefresh !== void 0) {
31621
+ await this.#config.tokenStore.set(this.#refreshKey(), {
31622
+ token: newRefresh
31623
+ });
31624
+ }
31625
+ return record;
31626
+ }
31627
+ };
31628
+ function defaultGenerateState() {
31629
+ const bytes = new Uint8Array(24);
31630
+ crypto.getRandomValues(bytes);
31631
+ let binary = "";
31632
+ for (let i = 0; i < bytes.length; i++) {
31633
+ binary += String.fromCharCode(bytes[i]);
31634
+ }
31635
+ return btoa(binary).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
31636
+ }
31637
+ function parseJsonBody(text) {
31638
+ if (text.length === 0) return null;
31639
+ try {
31640
+ return JSON.parse(text);
31641
+ } catch {
31642
+ return null;
31643
+ }
31644
+ }
31645
+ function formatOAuthError(body, status) {
31646
+ const parts = ["OAuth token request failed"];
31647
+ if (status !== void 0) parts.push(`(HTTP ${String(status)})`);
31648
+ if (body.error !== void 0 && body.error.length > 0) {
31649
+ parts.push(`: ${body.error}`);
31650
+ if (body.error_description !== void 0 && body.error_description.length > 0) {
31651
+ parts.push(`- ${body.error_description}`);
31652
+ }
31653
+ }
31654
+ return parts.join(" ").replace(" : ", ": ").replace(" - ", " - ");
31655
+ }
31656
+
31435
31657
  // src/platform/utils.ts
31436
31658
  function detectPlatform() {
31437
31659
  if (typeof process !== "undefined" && process.versions && process.versions.node) {
@@ -32209,6 +32431,7 @@ export {
32209
32431
  MissingAuthError,
32210
32432
  NetworkError,
32211
32433
  NonceError,
32434
+ OAuthClient,
32212
32435
  PKCE_CHALLENGE_PATTERN,
32213
32436
  PKCE_VERIFIER_PATTERN,
32214
32437
  PSError,