@wishknish/knishio-client-ts 0.9.6 → 0.9.7

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/dist/index.cjs CHANGED
@@ -527,6 +527,55 @@ var init_TransferBalanceException = __esm({
527
527
  }
528
528
  });
529
529
 
530
+ // src/exception/SecretStorageException.ts
531
+ exports.SecretStorageException = void 0;
532
+ var init_SecretStorageException = __esm({
533
+ "src/exception/SecretStorageException.ts"() {
534
+ init_BaseException();
535
+ exports.SecretStorageException = class _SecretStorageException extends exports.BaseException {
536
+ constructor(message = "Secret storage operation failed", options = {}) {
537
+ super("WALLET_CREDENTIAL_ERROR", message, {
538
+ code: "SECRET_STORAGE_ERROR",
539
+ ...options
540
+ });
541
+ }
542
+ /**
543
+ * Secret not found for the requested bundle hash
544
+ */
545
+ static notFound(bundleHash) {
546
+ return new _SecretStorageException(`Secret not found for bundle: ${bundleHash}`, {
547
+ code: "SECRET_NOT_FOUND",
548
+ details: { bundleHash }
549
+ });
550
+ }
551
+ /**
552
+ * Decryption failed (wrong passphrase or corrupted payload)
553
+ */
554
+ static decryptionFailed(reason) {
555
+ return new _SecretStorageException(
556
+ `Failed to decrypt master secret: ${reason || "Invalid passphrase or corrupted ciphertext"}`,
557
+ {
558
+ code: "DECRYPTION_FAILED",
559
+ details: { reason }
560
+ }
561
+ );
562
+ }
563
+ /**
564
+ * Provider is unavailable in current platform
565
+ */
566
+ static unavailable(provider, reason) {
567
+ return new _SecretStorageException(
568
+ `Secret storage provider '${provider}' is unavailable: ${reason || "Hardware or API not accessible"}`,
569
+ {
570
+ code: "STORAGE_UNAVAILABLE",
571
+ details: { provider, reason }
572
+ }
573
+ );
574
+ }
575
+ };
576
+ }
577
+ });
578
+
530
579
  // src/exception/InvalidResponseException.ts
531
580
  exports.InvalidResponseException = void 0;
532
581
  var init_InvalidResponseException = __esm({
@@ -989,6 +1038,7 @@ var init_exception = __esm({
989
1038
  init_SignatureMismatchException();
990
1039
  init_TransferBalanceException();
991
1040
  init_WalletCredentialException();
1041
+ init_SecretStorageException();
992
1042
  init_InvalidResponseException();
993
1043
  init_BalanceInsufficientException();
994
1044
  init_BatchIdException();
@@ -4115,7 +4165,8 @@ zod.z.object({
4115
4165
  socket: zod.z.unknown().optional(),
4116
4166
  serverSdkVersion: zod.z.number().int().min(1).optional(),
4117
4167
  logging: zod.z.boolean().optional(),
4118
- defaultRequestPolicy: zod.z.enum(["cache-first", "cache-only", "network-only", "cache-and-network"]).nullable().optional()
4168
+ defaultRequestPolicy: zod.z.enum(["cache-first", "cache-only", "network-only", "cache-and-network"]).nullable().optional(),
4169
+ secretStorage: zod.z.unknown().optional()
4119
4170
  }).strict();
4120
4171
  zod.z.object({
4121
4172
  token: zod.z.string().min(1, "Auth token cannot be empty"),
@@ -6915,7 +6966,9 @@ var KnishIOClientConfigSchema2 = zod.z.object({
6915
6966
  // Optional default urql request policy for reads (server/sync clients pass
6916
6967
  // 'network-only'). Permitted by the strict schema so the constructor option
6917
6968
  // isn't rejected.
6918
- defaultRequestPolicy: zod.z.enum(["cache-first", "cache-only", "network-only", "cache-and-network"]).nullable().optional()
6969
+ defaultRequestPolicy: zod.z.enum(["cache-first", "cache-only", "network-only", "cache-and-network"]).nullable().optional(),
6970
+ // Pluggable hardware envelope encryption secret storage provider
6971
+ secretStorage: zod.z.unknown().optional()
6919
6972
  }).strict();
6920
6973
  var EnvironmentConfigSchema = zod.z.object({
6921
6974
  NODE_ENV: zod.z.enum(["development", "production", "test"]).optional(),
@@ -10453,9 +10506,134 @@ var ActiveSessionSubscribe = class extends Subscribe {
10453
10506
 
10454
10507
  // src/KnishIOClient.ts
10455
10508
  init_exception();
10509
+
10510
+ // src/storage/MemorySecretStorageProvider.ts
10511
+ init_SecretStorageException();
10512
+
10513
+ // src/libraries/secureMemory.ts
10514
+ var textEncoder = new TextEncoder();
10515
+ function zeroizeBytes(buffer) {
10516
+ if (buffer instanceof Uint8Array) {
10517
+ buffer.fill(0);
10518
+ } else if (Array.isArray(buffer)) {
10519
+ for (let i = 0; i < buffer.length; i++) {
10520
+ buffer[i] = 0;
10521
+ }
10522
+ }
10523
+ }
10524
+ async function withSecureBytes(bytes, fn) {
10525
+ try {
10526
+ return await fn(bytes);
10527
+ } finally {
10528
+ zeroizeBytes(bytes);
10529
+ }
10530
+ }
10531
+ async function withSecureString(secret, fn) {
10532
+ const bytes = textEncoder.encode(secret);
10533
+ try {
10534
+ return await fn(secret);
10535
+ } finally {
10536
+ zeroizeBytes(bytes);
10537
+ }
10538
+ }
10539
+ function constantTimeCompare(a, b) {
10540
+ const bytesA = typeof a === "string" ? textEncoder.encode(a) : a;
10541
+ const bytesB = typeof b === "string" ? textEncoder.encode(b) : b;
10542
+ let result = bytesA.length === bytesB.length ? 0 : 1;
10543
+ const len = Math.min(bytesA.length, bytesB.length);
10544
+ for (let i = 0; i < len; i++) {
10545
+ const byteA = bytesA[i] ?? 0;
10546
+ const byteB = bytesB[i] ?? 0;
10547
+ result |= byteA ^ byteB;
10548
+ }
10549
+ if (typeof a === "string") zeroizeBytes(bytesA);
10550
+ if (typeof b === "string") zeroizeBytes(bytesB);
10551
+ return result === 0;
10552
+ }
10553
+
10554
+ // src/storage/MemorySecretStorageProvider.ts
10555
+ var MemorySecretStorageProvider = class {
10556
+ providerType = "memory";
10557
+ secrets = /* @__PURE__ */ new Map();
10558
+ /**
10559
+ * Memory storage is not hardware backed
10560
+ */
10561
+ isHardwareBacked() {
10562
+ return false;
10563
+ }
10564
+ /**
10565
+ * Memory storage is always available
10566
+ */
10567
+ async isAvailable() {
10568
+ return true;
10569
+ }
10570
+ /**
10571
+ * Store a secret in memory
10572
+ */
10573
+ async storeSecret(bundleHash, secret, options) {
10574
+ if (!bundleHash) {
10575
+ throw new exports.SecretStorageException("Bundle hash cannot be empty");
10576
+ }
10577
+ if (!secret) {
10578
+ throw new exports.SecretStorageException("Secret cannot be empty");
10579
+ }
10580
+ const metadata = {
10581
+ bundleHash,
10582
+ label: options?.label,
10583
+ createdAt: Date.now(),
10584
+ hardwareBacked: false,
10585
+ providerType: this.providerType
10586
+ };
10587
+ this.secrets.set(bundleHash, { secret, metadata });
10588
+ }
10589
+ /**
10590
+ * Retrieve a secret from memory
10591
+ */
10592
+ async retrieveSecret(bundleHash) {
10593
+ const entry = this.secrets.get(bundleHash);
10594
+ return entry ? entry.secret : null;
10595
+ }
10596
+ /**
10597
+ * Delete a stored secret
10598
+ */
10599
+ async deleteSecret(bundleHash) {
10600
+ return this.secrets.delete(bundleHash);
10601
+ }
10602
+ /**
10603
+ * Check if a secret exists
10604
+ */
10605
+ async hasSecret(bundleHash) {
10606
+ return this.secrets.has(bundleHash);
10607
+ }
10608
+ /**
10609
+ * List all stored secret metadata
10610
+ */
10611
+ async listSecrets() {
10612
+ return Array.from(this.secrets.values()).map((entry) => ({ ...entry.metadata }));
10613
+ }
10614
+ /**
10615
+ * Execute callback with unwrapped secret and ensure cleanup
10616
+ */
10617
+ async withSecret(bundleHash, fn) {
10618
+ const entry = this.secrets.get(bundleHash);
10619
+ if (!entry) {
10620
+ throw exports.SecretStorageException.notFound(bundleHash);
10621
+ }
10622
+ return withSecureString(entry.secret, fn);
10623
+ }
10624
+ /**
10625
+ * Clear all secrets from memory
10626
+ */
10627
+ clear() {
10628
+ this.secrets.clear();
10629
+ }
10630
+ };
10631
+
10632
+ // src/KnishIOClient.ts
10456
10633
  var KnishIOClient = class {
10457
10634
  $__secret = "";
10458
10635
  $__bundle = "";
10636
+ $__secretStorage = null;
10459
10637
  $__cellSlug = null;
10460
10638
  $__encrypt = false;
10461
10639
  $__uris = [];
@@ -10515,6 +10693,9 @@ var KnishIOClient = class {
10515
10693
  logging,
10516
10694
  defaultRequestPolicy
10517
10695
  });
10696
+ if (config.secretStorage) {
10697
+ this.$__secretStorage = config.secretStorage;
10698
+ }
10518
10699
  }
10519
10700
  /**
10520
10701
  * Initializes a new Knish.IO client session
@@ -10616,6 +10797,7 @@ var KnishIOClient = class {
10616
10797
  reset() {
10617
10798
  this.$__secret = "";
10618
10799
  this.$__bundle = "";
10800
+ this.$__secretStorage = null;
10619
10801
  this.$__encrypt = false;
10620
10802
  this.$__cellSlug = null;
10621
10803
  this.$__authToken = null;
@@ -10677,7 +10859,7 @@ var KnishIOClient = class {
10677
10859
  * Returns whether a secret is stored for this session
10678
10860
  */
10679
10861
  hasSecret() {
10680
- return !!this.$__secret && this.$__secret.length > 0;
10862
+ return !!this.$__secret && this.$__secret.length > 0 || !!this.$__secretStorage && !!this.$__bundle && this.$__bundle.length > 0;
10681
10863
  }
10682
10864
  /**
10683
10865
  * Returns the stored secret
@@ -10688,6 +10870,33 @@ var KnishIOClient = class {
10688
10870
  }
10689
10871
  return this.$__secret;
10690
10872
  }
10873
+ /**
10874
+ * Sets the secret storage provider and optionally sets the bundle hash
10875
+ */
10876
+ setSecretStorage(storage, bundleHash) {
10877
+ this.$__secretStorage = storage;
10878
+ if (bundleHash) {
10879
+ this.$__bundle = bundleHash;
10880
+ }
10881
+ }
10882
+ /**
10883
+ * Returns current secret storage provider
10884
+ */
10885
+ getSecretStorage() {
10886
+ return this.$__secretStorage;
10887
+ }
10888
+ /**
10889
+ * Asynchronously retrieves the secret from storage or returns in-memory secret
10890
+ */
10891
+ async retrieveSecret(options) {
10892
+ if (this.$__secret && this.$__secret.length > 0) {
10893
+ return this.$__secret;
10894
+ }
10895
+ if (this.$__secretStorage && this.$__bundle && this.$__bundle.length > 0) {
10896
+ return await this.$__secretStorage.retrieveSecret(this.$__bundle, options);
10897
+ }
10898
+ return null;
10899
+ }
10691
10900
  /**
10692
10901
  * Returns whether a bundle hash is being stored for this session
10693
10902
  */
@@ -10726,6 +10935,13 @@ var KnishIOClient = class {
10726
10935
  remainderWallet = null
10727
10936
  } = {}) {
10728
10937
  this.log("info", "KnishIOClient::createMolecule() - Creating a new molecule...");
10938
+ if (!secret) {
10939
+ if (this.$__secret && this.$__secret.length > 0) {
10940
+ secret = this.getSecret();
10941
+ } else if (this.$__secretStorage && this.$__bundle && this.$__bundle.length > 0) {
10942
+ secret = await this.$__secretStorage.retrieveSecret(this.$__bundle);
10943
+ }
10944
+ }
10729
10945
  secret = secret || this.getSecret();
10730
10946
  bundle = bundle || this.getBundle();
10731
10947
  let continuIdPosition = null;
@@ -10755,6 +10971,7 @@ var KnishIOClient = class {
10755
10971
  }));
10756
10972
  return new Molecule({
10757
10973
  secret,
10974
+ bundle,
10758
10975
  sourceWallet,
10759
10976
  remainderWallet: this.getRemainderWallet(),
10760
10977
  cellSlug: this.getCellSlug(),
@@ -10801,8 +11018,9 @@ var KnishIOClient = class {
10801
11018
  async executeQuery(query, variables = null, context = {}) {
10802
11019
  if (this.$__authToken && this.$__authToken.isExpired() && !this.$__authInProcess) {
10803
11020
  this.log("info", "KnishIOClient::executeQuery() - Access token is expired. Getting new one...");
11021
+ const authSecret = this.$__secret || await this.retrieveSecret() || "";
10804
11022
  await this.requestAuthToken({
10805
- secret: this.$__secret,
11023
+ secret: authSecret,
10806
11024
  cellSlug: this.$__cellSlug,
10807
11025
  encrypt: this.$__encrypt
10808
11026
  });
@@ -10842,6 +11060,13 @@ var KnishIOClient = class {
10842
11060
  setSecret(secret) {
10843
11061
  this.$__secret = secret;
10844
11062
  this.$__bundle = generateBundleHash(secret);
11063
+ if (!this.$__secretStorage) {
11064
+ const memStorage = new MemorySecretStorageProvider();
11065
+ memStorage.storeSecret(this.$__bundle, secret);
11066
+ this.$__secretStorage = memStorage;
11067
+ } else {
11068
+ this.$__secretStorage.storeSecret(this.$__bundle, secret);
11069
+ }
10845
11070
  }
10846
11071
  /**
10847
11072
  * Sets the auth token for this session
@@ -11025,6 +11250,9 @@ var KnishIOClient = class {
11025
11250
  if (secret === null && seed) {
11026
11251
  secret = generateSecret(seed);
11027
11252
  }
11253
+ if (secret === null && this.$__secretStorage && this.$__bundle) {
11254
+ secret = await this.$__secretStorage.retrieveSecret(this.$__bundle);
11255
+ }
11028
11256
  if (cellSlug) {
11029
11257
  this.setCellSlug(cellSlug);
11030
11258
  }
@@ -12162,7 +12390,297 @@ var KnishIOClient = class {
12162
12390
  // src/index.ts
12163
12391
  init_Response();
12164
12392
  init_exception();
12165
- var SDK_VERSION = "0.9.6";
12393
+
12394
+ // src/storage/WebCryptoSecretStorageProvider.ts
12395
+ init_SecretStorageException();
12396
+ var MemoryStorageBackend = class {
12397
+ store = /* @__PURE__ */ new Map();
12398
+ getItem(key) {
12399
+ return this.store.get(key) ?? null;
12400
+ }
12401
+ setItem(key, value) {
12402
+ this.store.set(key, value);
12403
+ }
12404
+ removeItem(key) {
12405
+ return this.store.delete(key);
12406
+ }
12407
+ keys() {
12408
+ return Array.from(this.store.keys());
12409
+ }
12410
+ };
12411
+ function uint8ArrayToBase64(bytes) {
12412
+ let binary = "";
12413
+ const len = bytes.byteLength;
12414
+ for (let i = 0; i < len; i++) {
12415
+ const byte = bytes[i];
12416
+ if (byte !== void 0) {
12417
+ binary += String.fromCharCode(byte);
12418
+ }
12419
+ }
12420
+ return btoa(binary);
12421
+ }
12422
+ function base64ToUint8Array(base64) {
12423
+ const binary = atob(base64);
12424
+ const len = binary.length;
12425
+ const bytes = new Uint8Array(len);
12426
+ for (let i = 0; i < len; i++) {
12427
+ bytes[i] = binary.charCodeAt(i);
12428
+ }
12429
+ return bytes;
12430
+ }
12431
+ var textEncoder2 = new TextEncoder();
12432
+ var textDecoder = new TextDecoder();
12433
+ var KEY_PREFIX = "knishio:secret:";
12434
+ var DEFAULT_ITERATIONS = 1e5;
12435
+ var WebCryptoSecretStorageProvider = class {
12436
+ providerType = "webcrypto-aes-gcm";
12437
+ backend;
12438
+ defaultPassphrase;
12439
+ hardwareBacked;
12440
+ constructor(options = {}) {
12441
+ this.backend = options.backend ?? new MemoryStorageBackend();
12442
+ this.defaultPassphrase = options.defaultPassphrase;
12443
+ this.hardwareBacked = options.hardwareBacked ?? false;
12444
+ }
12445
+ /**
12446
+ * Whether this provider is backed by hardware (e.g. WebAuthn PRF wrapping)
12447
+ */
12448
+ isHardwareBacked() {
12449
+ return this.hardwareBacked;
12450
+ }
12451
+ /**
12452
+ * Check if WebCrypto subtle API is available
12453
+ */
12454
+ async isAvailable() {
12455
+ return typeof globalThis.crypto !== "undefined" && typeof globalThis.crypto.subtle !== "undefined";
12456
+ }
12457
+ /**
12458
+ * Derive an AES-GCM CryptoKey from a passphrase and salt using PBKDF2
12459
+ */
12460
+ async deriveKey(passphrase, salt, iterations = DEFAULT_ITERATIONS) {
12461
+ if (!await this.isAvailable()) {
12462
+ throw exports.SecretStorageException.unavailable(this.providerType, "WebCrypto API is not available");
12463
+ }
12464
+ const passphraseBytes = textEncoder2.encode(passphrase);
12465
+ try {
12466
+ const baseKey = await globalThis.crypto.subtle.importKey(
12467
+ "raw",
12468
+ passphraseBytes,
12469
+ "PBKDF2",
12470
+ false,
12471
+ ["deriveKey"]
12472
+ );
12473
+ return await globalThis.crypto.subtle.deriveKey(
12474
+ {
12475
+ name: "PBKDF2",
12476
+ salt,
12477
+ iterations,
12478
+ hash: "SHA-256"
12479
+ },
12480
+ baseKey,
12481
+ { name: "AES-GCM", length: 256 },
12482
+ false,
12483
+ ["encrypt", "decrypt"]
12484
+ );
12485
+ } finally {
12486
+ zeroizeBytes(passphraseBytes);
12487
+ }
12488
+ }
12489
+ /**
12490
+ * Store and encrypt a master secret
12491
+ */
12492
+ async storeSecret(bundleHash, secret, options) {
12493
+ if (!bundleHash) {
12494
+ throw new exports.SecretStorageException("Bundle hash cannot be empty");
12495
+ }
12496
+ if (!secret) {
12497
+ throw new exports.SecretStorageException("Secret cannot be empty");
12498
+ }
12499
+ const passphrase = options?.passphrase ?? this.defaultPassphrase;
12500
+ if (!passphrase) {
12501
+ throw new exports.SecretStorageException("Passphrase required for envelope encryption");
12502
+ }
12503
+ const salt = new Uint8Array(16);
12504
+ const iv = new Uint8Array(12);
12505
+ globalThis.crypto.getRandomValues(salt);
12506
+ globalThis.crypto.getRandomValues(iv);
12507
+ const key = await this.deriveKey(passphrase, salt, DEFAULT_ITERATIONS);
12508
+ const secretBytes = textEncoder2.encode(secret);
12509
+ try {
12510
+ const encryptedBuffer = await globalThis.crypto.subtle.encrypt(
12511
+ {
12512
+ name: "AES-GCM",
12513
+ iv
12514
+ },
12515
+ key,
12516
+ secretBytes
12517
+ );
12518
+ const ciphertext = uint8ArrayToBase64(new Uint8Array(encryptedBuffer));
12519
+ const metadata = {
12520
+ bundleHash,
12521
+ label: options?.label,
12522
+ createdAt: Date.now(),
12523
+ hardwareBacked: this.hardwareBacked,
12524
+ providerType: this.providerType
12525
+ };
12526
+ const payload = {
12527
+ version: 1,
12528
+ ciphertext,
12529
+ iv: uint8ArrayToBase64(iv),
12530
+ salt: uint8ArrayToBase64(salt),
12531
+ algorithm: "AES-GCM",
12532
+ iterations: DEFAULT_ITERATIONS,
12533
+ metadata
12534
+ };
12535
+ await this.backend.setItem(`${KEY_PREFIX}${bundleHash}`, JSON.stringify(payload));
12536
+ } catch (err) {
12537
+ const msg = err instanceof Error ? err.message : String(err);
12538
+ throw new exports.SecretStorageException(`Encryption failed: ${msg}`);
12539
+ } finally {
12540
+ zeroizeBytes(secretBytes);
12541
+ }
12542
+ }
12543
+ /**
12544
+ * Retrieve and decrypt the master secret
12545
+ */
12546
+ async retrieveSecret(bundleHash, options) {
12547
+ const raw = await this.backend.getItem(`${KEY_PREFIX}${bundleHash}`);
12548
+ if (!raw) {
12549
+ return null;
12550
+ }
12551
+ let payload;
12552
+ try {
12553
+ payload = JSON.parse(raw);
12554
+ } catch {
12555
+ throw exports.SecretStorageException.decryptionFailed("Corrupted payload format");
12556
+ }
12557
+ const passphrase = options?.passphrase ?? this.defaultPassphrase;
12558
+ if (!passphrase) {
12559
+ throw new exports.SecretStorageException("Passphrase required for secret decryption");
12560
+ }
12561
+ const salt = base64ToUint8Array(payload.salt);
12562
+ const iv = base64ToUint8Array(payload.iv);
12563
+ const ciphertext = base64ToUint8Array(payload.ciphertext);
12564
+ try {
12565
+ const key = await this.deriveKey(passphrase, salt, payload.iterations ?? DEFAULT_ITERATIONS);
12566
+ const decryptedBuffer = await globalThis.crypto.subtle.decrypt(
12567
+ {
12568
+ name: "AES-GCM",
12569
+ iv
12570
+ },
12571
+ key,
12572
+ ciphertext
12573
+ );
12574
+ const decryptedBytes = new Uint8Array(decryptedBuffer);
12575
+ try {
12576
+ return textDecoder.decode(decryptedBytes);
12577
+ } finally {
12578
+ zeroizeBytes(decryptedBytes);
12579
+ }
12580
+ } catch (err) {
12581
+ const msg = err instanceof Error ? err.message : String(err);
12582
+ throw exports.SecretStorageException.decryptionFailed(msg);
12583
+ }
12584
+ }
12585
+ /**
12586
+ * Delete a stored secret
12587
+ */
12588
+ async deleteSecret(bundleHash) {
12589
+ const key = `${KEY_PREFIX}${bundleHash}`;
12590
+ const result = await this.backend.removeItem(key);
12591
+ return result !== false;
12592
+ }
12593
+ /**
12594
+ * Check if a secret exists
12595
+ */
12596
+ async hasSecret(bundleHash) {
12597
+ const raw = await this.backend.getItem(`${KEY_PREFIX}${bundleHash}`);
12598
+ return raw !== null;
12599
+ }
12600
+ /**
12601
+ * List all stored secret metadata
12602
+ */
12603
+ async listSecrets() {
12604
+ const keys = await this.backend.keys();
12605
+ const matchingKeys = keys.filter((k) => k.startsWith(KEY_PREFIX));
12606
+ const results = [];
12607
+ for (const key of matchingKeys) {
12608
+ const raw = await this.backend.getItem(key);
12609
+ if (raw) {
12610
+ try {
12611
+ const payload = JSON.parse(raw);
12612
+ if (payload.metadata) {
12613
+ results.push(payload.metadata);
12614
+ }
12615
+ } catch {
12616
+ }
12617
+ }
12618
+ }
12619
+ return results;
12620
+ }
12621
+ /**
12622
+ * Execute callback with unwrapped secret, zeroizing the decrypted buffer upon completion
12623
+ */
12624
+ async withSecret(bundleHash, fn, options) {
12625
+ const raw = await this.backend.getItem(`${KEY_PREFIX}${bundleHash}`);
12626
+ if (!raw) {
12627
+ throw exports.SecretStorageException.notFound(bundleHash);
12628
+ }
12629
+ let payload;
12630
+ try {
12631
+ payload = JSON.parse(raw);
12632
+ } catch {
12633
+ throw exports.SecretStorageException.decryptionFailed("Corrupted payload format");
12634
+ }
12635
+ const passphrase = options?.passphrase ?? this.defaultPassphrase;
12636
+ if (!passphrase) {
12637
+ throw new exports.SecretStorageException("Passphrase required for secret decryption");
12638
+ }
12639
+ const salt = base64ToUint8Array(payload.salt);
12640
+ const iv = base64ToUint8Array(payload.iv);
12641
+ const ciphertext = base64ToUint8Array(payload.ciphertext);
12642
+ try {
12643
+ const key = await this.deriveKey(passphrase, salt, payload.iterations ?? DEFAULT_ITERATIONS);
12644
+ const decryptedBuffer = await globalThis.crypto.subtle.decrypt(
12645
+ {
12646
+ name: "AES-GCM",
12647
+ iv
12648
+ },
12649
+ key,
12650
+ ciphertext
12651
+ );
12652
+ const decryptedBytes = new Uint8Array(decryptedBuffer);
12653
+ return await withSecureBytes(decryptedBytes, async (bytes) => {
12654
+ const secretString = textDecoder.decode(bytes);
12655
+ return await fn(secretString);
12656
+ });
12657
+ } catch (err) {
12658
+ if (err instanceof exports.SecretStorageException) {
12659
+ throw err;
12660
+ }
12661
+ const msg = err instanceof Error ? err.message : String(err);
12662
+ throw exports.SecretStorageException.decryptionFailed(msg);
12663
+ }
12664
+ }
12665
+ };
12666
+
12667
+ // src/storage/index.ts
12668
+ function createDefaultSecretStorage(options = {}) {
12669
+ if (options.type === "memory") {
12670
+ return new MemorySecretStorageProvider();
12671
+ }
12672
+ if (typeof globalThis.crypto !== "undefined" && typeof globalThis.crypto.subtle !== "undefined") {
12673
+ return new WebCryptoSecretStorageProvider({
12674
+ backend: options.backend,
12675
+ defaultPassphrase: options.defaultPassphrase,
12676
+ hardwareBacked: options.hardwareBacked
12677
+ });
12678
+ }
12679
+ return new MemorySecretStorageProvider();
12680
+ }
12681
+
12682
+ // src/index.ts
12683
+ var SDK_VERSION = "0.9.7";
12166
12684
  var SDK_NAME = "KnishIO-Client-TS";
12167
12685
  var COMPATIBLE_SERVER_VERSIONS = [4, 5];
12168
12686
  var SDK_INFO = {
@@ -12263,6 +12781,8 @@ exports.EXTENDED_COMPATIBILITY_TEST_VECTORS = EXTENDED_COMPATIBILITY_TEST_VECTOR
12263
12781
  exports.GraphQLClient = GraphQLClient;
12264
12782
  exports.KnishIO = KnishIO;
12265
12783
  exports.KnishIOClient = KnishIOClient;
12784
+ exports.MemorySecretStorageProvider = MemorySecretStorageProvider;
12785
+ exports.MemoryStorageBackend = MemoryStorageBackend;
12266
12786
  exports.Meta = Meta;
12267
12787
  exports.Molecule = Molecule;
12268
12788
  exports.Mutation = Mutation;
@@ -12308,6 +12828,7 @@ exports.SDK_NAME = SDK_NAME;
12308
12828
  exports.SDK_VERSION = SDK_VERSION;
12309
12829
  exports.TokenUnit = TokenUnit;
12310
12830
  exports.Wallet = Wallet;
12831
+ exports.WebCryptoSecretStorageProvider = WebCryptoSecretStorageProvider;
12311
12832
  exports.base64ToHex = base64ToHex;
12312
12833
  exports.bufferToHexString = bufferToHexString;
12313
12834
  exports.capitalize = capitalize;
@@ -12315,8 +12836,10 @@ exports.charsetBaseConvert = charsetBaseConvert;
12315
12836
  exports.chunkArray = chunkArray;
12316
12837
  exports.chunkSubstr = chunkSubstr;
12317
12838
  exports.configureSDK = configureSDK;
12839
+ exports.constantTimeCompare = constantTimeCompare;
12318
12840
  exports.convertToBase17 = convertToBase17;
12319
12841
  exports.createBundleHash = createBundleHash;
12842
+ exports.createDefaultSecretStorage = createDefaultSecretStorage;
12320
12843
  exports.createMolecularHash = createMolecularHash;
12321
12844
  exports.createPosition = createPosition;
12322
12845
  exports.createTokenSlug = createTokenSlug;
@@ -12358,5 +12881,8 @@ exports.validatePosition = validatePosition;
12358
12881
  exports.validateSecret = validateSecret;
12359
12882
  exports.validateWalletAddress = validateWalletAddress;
12360
12883
  exports.verifyOTSSignature = verifyOTSSignature;
12884
+ exports.withSecureBytes = withSecureBytes;
12885
+ exports.withSecureString = withSecureString;
12886
+ exports.zeroizeBytes = zeroizeBytes;
12361
12887
  //# sourceMappingURL=index.cjs.map
12362
12888
  //# sourceMappingURL=index.cjs.map