@wishknish/knishio-client-ts 0.9.6 → 0.9.8

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.
@@ -20064,6 +20064,55 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
20064
20064
  }
20065
20065
  });
20066
20066
 
20067
+ // src/exception/SecretStorageException.ts
20068
+ exports.SecretStorageException = void 0;
20069
+ var init_SecretStorageException = __esm({
20070
+ "src/exception/SecretStorageException.ts"() {
20071
+ init_BaseException();
20072
+ exports.SecretStorageException = class _SecretStorageException extends exports.BaseException {
20073
+ constructor(message = "Secret storage operation failed", options = {}) {
20074
+ super("WALLET_CREDENTIAL_ERROR", message, {
20075
+ code: "SECRET_STORAGE_ERROR",
20076
+ ...options
20077
+ });
20078
+ }
20079
+ /**
20080
+ * Secret not found for the requested bundle hash
20081
+ */
20082
+ static notFound(bundleHash) {
20083
+ return new _SecretStorageException(`Secret not found for bundle: ${bundleHash}`, {
20084
+ code: "SECRET_NOT_FOUND",
20085
+ details: { bundleHash }
20086
+ });
20087
+ }
20088
+ /**
20089
+ * Decryption failed (wrong passphrase or corrupted payload)
20090
+ */
20091
+ static decryptionFailed(reason) {
20092
+ return new _SecretStorageException(
20093
+ `Failed to decrypt master secret: ${reason || "Invalid passphrase or corrupted ciphertext"}`,
20094
+ {
20095
+ code: "DECRYPTION_FAILED",
20096
+ details: { reason }
20097
+ }
20098
+ );
20099
+ }
20100
+ /**
20101
+ * Provider is unavailable in current platform
20102
+ */
20103
+ static unavailable(provider, reason) {
20104
+ return new _SecretStorageException(
20105
+ `Secret storage provider '${provider}' is unavailable: ${reason || "Hardware or API not accessible"}`,
20106
+ {
20107
+ code: "STORAGE_UNAVAILABLE",
20108
+ details: { provider, reason }
20109
+ }
20110
+ );
20111
+ }
20112
+ };
20113
+ }
20114
+ });
20115
+
20067
20116
  // src/exception/InvalidResponseException.ts
20068
20117
  exports.InvalidResponseException = void 0;
20069
20118
  var init_InvalidResponseException = __esm({
@@ -20526,6 +20575,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
20526
20575
  init_SignatureMismatchException();
20527
20576
  init_TransferBalanceException();
20528
20577
  init_WalletCredentialException();
20578
+ init_SecretStorageException();
20529
20579
  init_InvalidResponseException();
20530
20580
  init_BalanceInsufficientException();
20531
20581
  init_BatchIdException();
@@ -43021,7 +43071,8 @@ ${operationTypes.join("\n")}
43021
43071
  socket: external_exports.unknown().optional(),
43022
43072
  serverSdkVersion: external_exports.number().int().min(1).optional(),
43023
43073
  logging: external_exports.boolean().optional(),
43024
- defaultRequestPolicy: external_exports.enum(["cache-first", "cache-only", "network-only", "cache-and-network"]).nullable().optional()
43074
+ defaultRequestPolicy: external_exports.enum(["cache-first", "cache-only", "network-only", "cache-and-network"]).nullable().optional(),
43075
+ secretStorage: external_exports.unknown().optional()
43025
43076
  }).strict();
43026
43077
  external_exports.object({
43027
43078
  token: external_exports.string().min(1, "Auth token cannot be empty"),
@@ -48251,7 +48302,9 @@ ${operationTypes.join("\n")}
48251
48302
  // Optional default urql request policy for reads (server/sync clients pass
48252
48303
  // 'network-only'). Permitted by the strict schema so the constructor option
48253
48304
  // isn't rejected.
48254
- defaultRequestPolicy: external_exports.enum(["cache-first", "cache-only", "network-only", "cache-and-network"]).nullable().optional()
48305
+ defaultRequestPolicy: external_exports.enum(["cache-first", "cache-only", "network-only", "cache-and-network"]).nullable().optional(),
48306
+ // Pluggable hardware envelope encryption secret storage provider
48307
+ secretStorage: external_exports.unknown().optional()
48255
48308
  }).strict();
48256
48309
  var EnvironmentConfigSchema = external_exports.object({
48257
48310
  NODE_ENV: external_exports.enum(["development", "production", "test"]).optional(),
@@ -50849,6 +50902,13 @@ ${operationTypes.join("\n")}
50849
50902
  molecule() {
50850
50903
  return this.$__molecule.toJSON ? this.$__molecule.toJSON() : this.$__molecule;
50851
50904
  }
50905
+ /**
50906
+ * Fills the molecule with specific mutation data.
50907
+ * Subclasses override to build domain-specific atoms.
50908
+ * Default implementation is a no-op for pre-assembled molecules.
50909
+ */
50910
+ fillMolecule(_params) {
50911
+ }
50852
50912
  };
50853
50913
 
50854
50914
  // src/response/ResponseCreateToken.ts
@@ -51827,9 +51887,134 @@ ${operationTypes.join("\n")}
51827
51887
 
51828
51888
  // src/KnishIOClient.ts
51829
51889
  init_exception();
51890
+
51891
+ // src/storage/MemorySecretStorageProvider.ts
51892
+ init_SecretStorageException();
51893
+
51894
+ // src/libraries/secureMemory.ts
51895
+ var textEncoder = new TextEncoder();
51896
+ function zeroizeBytes(buffer) {
51897
+ if (buffer instanceof Uint8Array) {
51898
+ buffer.fill(0);
51899
+ } else if (Array.isArray(buffer)) {
51900
+ for (let i4 = 0; i4 < buffer.length; i4++) {
51901
+ buffer[i4] = 0;
51902
+ }
51903
+ }
51904
+ }
51905
+ async function withSecureBytes(bytes, fn) {
51906
+ try {
51907
+ return await fn(bytes);
51908
+ } finally {
51909
+ zeroizeBytes(bytes);
51910
+ }
51911
+ }
51912
+ async function withSecureString(secret, fn) {
51913
+ const bytes = textEncoder.encode(secret);
51914
+ try {
51915
+ return await fn(secret);
51916
+ } finally {
51917
+ zeroizeBytes(bytes);
51918
+ }
51919
+ }
51920
+ function constantTimeCompare(a3, b2) {
51921
+ const bytesA = typeof a3 === "string" ? textEncoder.encode(a3) : a3;
51922
+ const bytesB = typeof b2 === "string" ? textEncoder.encode(b2) : b2;
51923
+ let result = bytesA.length === bytesB.length ? 0 : 1;
51924
+ const len = Math.min(bytesA.length, bytesB.length);
51925
+ for (let i4 = 0; i4 < len; i4++) {
51926
+ const byteA = bytesA[i4] ?? 0;
51927
+ const byteB = bytesB[i4] ?? 0;
51928
+ result |= byteA ^ byteB;
51929
+ }
51930
+ if (typeof a3 === "string") zeroizeBytes(bytesA);
51931
+ if (typeof b2 === "string") zeroizeBytes(bytesB);
51932
+ return result === 0;
51933
+ }
51934
+
51935
+ // src/storage/MemorySecretStorageProvider.ts
51936
+ var MemorySecretStorageProvider = class {
51937
+ providerType = "memory";
51938
+ secrets = /* @__PURE__ */ new Map();
51939
+ /**
51940
+ * Memory storage is not hardware backed
51941
+ */
51942
+ isHardwareBacked() {
51943
+ return false;
51944
+ }
51945
+ /**
51946
+ * Memory storage is always available
51947
+ */
51948
+ async isAvailable() {
51949
+ return true;
51950
+ }
51951
+ /**
51952
+ * Store a secret in memory
51953
+ */
51954
+ async storeSecret(bundleHash, secret, options) {
51955
+ if (!bundleHash) {
51956
+ throw new exports.SecretStorageException("Bundle hash cannot be empty");
51957
+ }
51958
+ if (!secret) {
51959
+ throw new exports.SecretStorageException("Secret cannot be empty");
51960
+ }
51961
+ const metadata = {
51962
+ bundleHash,
51963
+ label: options?.label,
51964
+ createdAt: Date.now(),
51965
+ hardwareBacked: false,
51966
+ providerType: this.providerType
51967
+ };
51968
+ this.secrets.set(bundleHash, { secret, metadata });
51969
+ }
51970
+ /**
51971
+ * Retrieve a secret from memory
51972
+ */
51973
+ async retrieveSecret(bundleHash) {
51974
+ const entry = this.secrets.get(bundleHash);
51975
+ return entry ? entry.secret : null;
51976
+ }
51977
+ /**
51978
+ * Delete a stored secret
51979
+ */
51980
+ async deleteSecret(bundleHash) {
51981
+ return this.secrets.delete(bundleHash);
51982
+ }
51983
+ /**
51984
+ * Check if a secret exists
51985
+ */
51986
+ async hasSecret(bundleHash) {
51987
+ return this.secrets.has(bundleHash);
51988
+ }
51989
+ /**
51990
+ * List all stored secret metadata
51991
+ */
51992
+ async listSecrets() {
51993
+ return Array.from(this.secrets.values()).map((entry) => ({ ...entry.metadata }));
51994
+ }
51995
+ /**
51996
+ * Execute callback with unwrapped secret and ensure cleanup
51997
+ */
51998
+ async withSecret(bundleHash, fn) {
51999
+ const entry = this.secrets.get(bundleHash);
52000
+ if (!entry) {
52001
+ throw exports.SecretStorageException.notFound(bundleHash);
52002
+ }
52003
+ return withSecureString(entry.secret, fn);
52004
+ }
52005
+ /**
52006
+ * Clear all secrets from memory
52007
+ */
52008
+ clear() {
52009
+ this.secrets.clear();
52010
+ }
52011
+ };
52012
+
52013
+ // src/KnishIOClient.ts
51830
52014
  var KnishIOClient = class {
51831
52015
  $__secret = "";
51832
52016
  $__bundle = "";
52017
+ $__secretStorage = null;
51833
52018
  $__cellSlug = null;
51834
52019
  $__encrypt = false;
51835
52020
  $__uris = [];
@@ -51889,6 +52074,9 @@ ${operationTypes.join("\n")}
51889
52074
  logging,
51890
52075
  defaultRequestPolicy
51891
52076
  });
52077
+ if (config2.secretStorage) {
52078
+ this.$__secretStorage = config2.secretStorage;
52079
+ }
51892
52080
  }
51893
52081
  /**
51894
52082
  * Initializes a new Knish.IO client session
@@ -51990,6 +52178,7 @@ ${operationTypes.join("\n")}
51990
52178
  reset() {
51991
52179
  this.$__secret = "";
51992
52180
  this.$__bundle = "";
52181
+ this.$__secretStorage = null;
51993
52182
  this.$__encrypt = false;
51994
52183
  this.$__cellSlug = null;
51995
52184
  this.$__authToken = null;
@@ -52051,7 +52240,7 @@ ${operationTypes.join("\n")}
52051
52240
  * Returns whether a secret is stored for this session
52052
52241
  */
52053
52242
  hasSecret() {
52054
- return !!this.$__secret && this.$__secret.length > 0;
52243
+ return !!this.$__secret && this.$__secret.length > 0 || !!this.$__secretStorage && !!this.$__bundle && this.$__bundle.length > 0;
52055
52244
  }
52056
52245
  /**
52057
52246
  * Returns the stored secret
@@ -52062,6 +52251,33 @@ ${operationTypes.join("\n")}
52062
52251
  }
52063
52252
  return this.$__secret;
52064
52253
  }
52254
+ /**
52255
+ * Sets the secret storage provider and optionally sets the bundle hash
52256
+ */
52257
+ setSecretStorage(storage, bundleHash) {
52258
+ this.$__secretStorage = storage;
52259
+ if (bundleHash) {
52260
+ this.$__bundle = bundleHash;
52261
+ }
52262
+ }
52263
+ /**
52264
+ * Returns current secret storage provider
52265
+ */
52266
+ getSecretStorage() {
52267
+ return this.$__secretStorage;
52268
+ }
52269
+ /**
52270
+ * Asynchronously retrieves the secret from storage or returns in-memory secret
52271
+ */
52272
+ async retrieveSecret(options) {
52273
+ if (this.$__secret && this.$__secret.length > 0) {
52274
+ return this.$__secret;
52275
+ }
52276
+ if (this.$__secretStorage && this.$__bundle && this.$__bundle.length > 0) {
52277
+ return await this.$__secretStorage.retrieveSecret(this.$__bundle, options);
52278
+ }
52279
+ return null;
52280
+ }
52065
52281
  /**
52066
52282
  * Returns whether a bundle hash is being stored for this session
52067
52283
  */
@@ -52100,6 +52316,13 @@ ${operationTypes.join("\n")}
52100
52316
  remainderWallet = null
52101
52317
  } = {}) {
52102
52318
  this.log("info", "KnishIOClient::createMolecule() - Creating a new molecule...");
52319
+ if (!secret) {
52320
+ if (this.$__secret && this.$__secret.length > 0) {
52321
+ secret = this.getSecret();
52322
+ } else if (this.$__secretStorage && this.$__bundle && this.$__bundle.length > 0) {
52323
+ secret = await this.$__secretStorage.retrieveSecret(this.$__bundle);
52324
+ }
52325
+ }
52103
52326
  secret = secret || this.getSecret();
52104
52327
  bundle = bundle || this.getBundle();
52105
52328
  let continuIdPosition = null;
@@ -52129,6 +52352,7 @@ ${operationTypes.join("\n")}
52129
52352
  }));
52130
52353
  return new Molecule({
52131
52354
  secret,
52355
+ bundle,
52132
52356
  sourceWallet,
52133
52357
  remainderWallet: this.getRemainderWallet(),
52134
52358
  cellSlug: this.getCellSlug(),
@@ -52175,8 +52399,9 @@ ${operationTypes.join("\n")}
52175
52399
  async executeQuery(query, variables = null, context = {}) {
52176
52400
  if (this.$__authToken && this.$__authToken.isExpired() && !this.$__authInProcess) {
52177
52401
  this.log("info", "KnishIOClient::executeQuery() - Access token is expired. Getting new one...");
52402
+ const authSecret = this.$__secret || await this.retrieveSecret() || "";
52178
52403
  await this.requestAuthToken({
52179
- secret: this.$__secret,
52404
+ secret: authSecret,
52180
52405
  cellSlug: this.$__cellSlug,
52181
52406
  encrypt: this.$__encrypt
52182
52407
  });
@@ -52216,6 +52441,13 @@ ${operationTypes.join("\n")}
52216
52441
  setSecret(secret) {
52217
52442
  this.$__secret = secret;
52218
52443
  this.$__bundle = generateBundleHash(secret);
52444
+ if (!this.$__secretStorage) {
52445
+ const memStorage = new MemorySecretStorageProvider();
52446
+ memStorage.storeSecret(this.$__bundle, secret);
52447
+ this.$__secretStorage = memStorage;
52448
+ } else {
52449
+ this.$__secretStorage.storeSecret(this.$__bundle, secret);
52450
+ }
52219
52451
  }
52220
52452
  /**
52221
52453
  * Sets the auth token for this session
@@ -52399,6 +52631,9 @@ ${operationTypes.join("\n")}
52399
52631
  if (secret === null && seed) {
52400
52632
  secret = generateSecret(seed);
52401
52633
  }
52634
+ if (secret === null && this.$__secretStorage && this.$__bundle) {
52635
+ secret = await this.$__secretStorage.retrieveSecret(this.$__bundle);
52636
+ }
52402
52637
  if (cellSlug) {
52403
52638
  this.setCellSlug(cellSlug);
52404
52639
  }
@@ -53244,15 +53479,30 @@ ${operationTypes.join("\n")}
53244
53479
  async createPolicy({
53245
53480
  metaType,
53246
53481
  metaId,
53247
- policy = null
53482
+ policy = {}
53248
53483
  }) {
53249
53484
  this.log("info", `KnishIOClient::createPolicy() - Creating policy for ${metaType}:${metaId}...`);
53250
- return this.createMeta({
53485
+ const molecule = await this.createMolecule({});
53486
+ molecule.addPolicyAtom({
53251
53487
  metaType,
53252
53488
  metaId,
53253
- meta: null,
53254
- policy
53489
+ meta: {},
53490
+ policy: policy || {}
53255
53491
  });
53492
+ molecule.addContinuIdAtom();
53493
+ molecule.sign({
53494
+ bundle: this.getBundle()
53495
+ });
53496
+ molecule.check();
53497
+ const query = await this.createMoleculeMutation({
53498
+ mutationClass: MutationProposeMolecule,
53499
+ molecule
53500
+ });
53501
+ const response = await this.executeQuery(query);
53502
+ if (!response) {
53503
+ throw new CodeException("Policy creation failed");
53504
+ }
53505
+ return response;
53256
53506
  }
53257
53507
  /**
53258
53508
  * Create an identifier
@@ -53536,7 +53786,297 @@ ${operationTypes.join("\n")}
53536
53786
  // src/index.ts
53537
53787
  init_Response();
53538
53788
  init_exception();
53539
- var SDK_VERSION = "0.9.6";
53789
+
53790
+ // src/storage/WebCryptoSecretStorageProvider.ts
53791
+ init_SecretStorageException();
53792
+ var MemoryStorageBackend = class {
53793
+ store = /* @__PURE__ */ new Map();
53794
+ getItem(key) {
53795
+ return this.store.get(key) ?? null;
53796
+ }
53797
+ setItem(key, value2) {
53798
+ this.store.set(key, value2);
53799
+ }
53800
+ removeItem(key) {
53801
+ return this.store.delete(key);
53802
+ }
53803
+ keys() {
53804
+ return Array.from(this.store.keys());
53805
+ }
53806
+ };
53807
+ function uint8ArrayToBase642(bytes) {
53808
+ let binary = "";
53809
+ const len = bytes.byteLength;
53810
+ for (let i4 = 0; i4 < len; i4++) {
53811
+ const byte = bytes[i4];
53812
+ if (byte !== void 0) {
53813
+ binary += String.fromCharCode(byte);
53814
+ }
53815
+ }
53816
+ return btoa(binary);
53817
+ }
53818
+ function base64ToUint8Array2(base643) {
53819
+ const binary = atob(base643);
53820
+ const len = binary.length;
53821
+ const bytes = new Uint8Array(len);
53822
+ for (let i4 = 0; i4 < len; i4++) {
53823
+ bytes[i4] = binary.charCodeAt(i4);
53824
+ }
53825
+ return bytes;
53826
+ }
53827
+ var textEncoder2 = new TextEncoder();
53828
+ var textDecoder = new TextDecoder();
53829
+ var KEY_PREFIX = "knishio:secret:";
53830
+ var DEFAULT_ITERATIONS = 1e5;
53831
+ var WebCryptoSecretStorageProvider = class {
53832
+ providerType = "webcrypto-aes-gcm";
53833
+ backend;
53834
+ defaultPassphrase;
53835
+ hardwareBacked;
53836
+ constructor(options = {}) {
53837
+ this.backend = options.backend ?? new MemoryStorageBackend();
53838
+ this.defaultPassphrase = options.defaultPassphrase;
53839
+ this.hardwareBacked = options.hardwareBacked ?? false;
53840
+ }
53841
+ /**
53842
+ * Whether this provider is backed by hardware (e.g. WebAuthn PRF wrapping)
53843
+ */
53844
+ isHardwareBacked() {
53845
+ return this.hardwareBacked;
53846
+ }
53847
+ /**
53848
+ * Check if WebCrypto subtle API is available
53849
+ */
53850
+ async isAvailable() {
53851
+ return typeof globalThis.crypto !== "undefined" && typeof globalThis.crypto.subtle !== "undefined";
53852
+ }
53853
+ /**
53854
+ * Derive an AES-GCM CryptoKey from a passphrase and salt using PBKDF2
53855
+ */
53856
+ async deriveKey(passphrase, salt, iterations = DEFAULT_ITERATIONS) {
53857
+ if (!await this.isAvailable()) {
53858
+ throw exports.SecretStorageException.unavailable(this.providerType, "WebCrypto API is not available");
53859
+ }
53860
+ const passphraseBytes = textEncoder2.encode(passphrase);
53861
+ try {
53862
+ const baseKey = await globalThis.crypto.subtle.importKey(
53863
+ "raw",
53864
+ passphraseBytes,
53865
+ "PBKDF2",
53866
+ false,
53867
+ ["deriveKey"]
53868
+ );
53869
+ return await globalThis.crypto.subtle.deriveKey(
53870
+ {
53871
+ name: "PBKDF2",
53872
+ salt,
53873
+ iterations,
53874
+ hash: "SHA-256"
53875
+ },
53876
+ baseKey,
53877
+ { name: "AES-GCM", length: 256 },
53878
+ false,
53879
+ ["encrypt", "decrypt"]
53880
+ );
53881
+ } finally {
53882
+ zeroizeBytes(passphraseBytes);
53883
+ }
53884
+ }
53885
+ /**
53886
+ * Store and encrypt a master secret
53887
+ */
53888
+ async storeSecret(bundleHash, secret, options) {
53889
+ if (!bundleHash) {
53890
+ throw new exports.SecretStorageException("Bundle hash cannot be empty");
53891
+ }
53892
+ if (!secret) {
53893
+ throw new exports.SecretStorageException("Secret cannot be empty");
53894
+ }
53895
+ const passphrase = options?.passphrase ?? this.defaultPassphrase;
53896
+ if (!passphrase) {
53897
+ throw new exports.SecretStorageException("Passphrase required for envelope encryption");
53898
+ }
53899
+ const salt = new Uint8Array(16);
53900
+ const iv = new Uint8Array(12);
53901
+ globalThis.crypto.getRandomValues(salt);
53902
+ globalThis.crypto.getRandomValues(iv);
53903
+ const key = await this.deriveKey(passphrase, salt, DEFAULT_ITERATIONS);
53904
+ const secretBytes = textEncoder2.encode(secret);
53905
+ try {
53906
+ const encryptedBuffer = await globalThis.crypto.subtle.encrypt(
53907
+ {
53908
+ name: "AES-GCM",
53909
+ iv
53910
+ },
53911
+ key,
53912
+ secretBytes
53913
+ );
53914
+ const ciphertext = uint8ArrayToBase642(new Uint8Array(encryptedBuffer));
53915
+ const metadata = {
53916
+ bundleHash,
53917
+ label: options?.label,
53918
+ createdAt: Date.now(),
53919
+ hardwareBacked: this.hardwareBacked,
53920
+ providerType: this.providerType
53921
+ };
53922
+ const payload = {
53923
+ version: 1,
53924
+ ciphertext,
53925
+ iv: uint8ArrayToBase642(iv),
53926
+ salt: uint8ArrayToBase642(salt),
53927
+ algorithm: "AES-GCM",
53928
+ iterations: DEFAULT_ITERATIONS,
53929
+ metadata
53930
+ };
53931
+ await this.backend.setItem(`${KEY_PREFIX}${bundleHash}`, JSON.stringify(payload));
53932
+ } catch (err) {
53933
+ const msg = err instanceof Error ? err.message : String(err);
53934
+ throw new exports.SecretStorageException(`Encryption failed: ${msg}`);
53935
+ } finally {
53936
+ zeroizeBytes(secretBytes);
53937
+ }
53938
+ }
53939
+ /**
53940
+ * Retrieve and decrypt the master secret
53941
+ */
53942
+ async retrieveSecret(bundleHash, options) {
53943
+ const raw = await this.backend.getItem(`${KEY_PREFIX}${bundleHash}`);
53944
+ if (!raw) {
53945
+ return null;
53946
+ }
53947
+ let payload;
53948
+ try {
53949
+ payload = JSON.parse(raw);
53950
+ } catch {
53951
+ throw exports.SecretStorageException.decryptionFailed("Corrupted payload format");
53952
+ }
53953
+ const passphrase = options?.passphrase ?? this.defaultPassphrase;
53954
+ if (!passphrase) {
53955
+ throw new exports.SecretStorageException("Passphrase required for secret decryption");
53956
+ }
53957
+ const salt = base64ToUint8Array2(payload.salt);
53958
+ const iv = base64ToUint8Array2(payload.iv);
53959
+ const ciphertext = base64ToUint8Array2(payload.ciphertext);
53960
+ try {
53961
+ const key = await this.deriveKey(passphrase, salt, payload.iterations ?? DEFAULT_ITERATIONS);
53962
+ const decryptedBuffer = await globalThis.crypto.subtle.decrypt(
53963
+ {
53964
+ name: "AES-GCM",
53965
+ iv
53966
+ },
53967
+ key,
53968
+ ciphertext
53969
+ );
53970
+ const decryptedBytes = new Uint8Array(decryptedBuffer);
53971
+ try {
53972
+ return textDecoder.decode(decryptedBytes);
53973
+ } finally {
53974
+ zeroizeBytes(decryptedBytes);
53975
+ }
53976
+ } catch (err) {
53977
+ const msg = err instanceof Error ? err.message : String(err);
53978
+ throw exports.SecretStorageException.decryptionFailed(msg);
53979
+ }
53980
+ }
53981
+ /**
53982
+ * Delete a stored secret
53983
+ */
53984
+ async deleteSecret(bundleHash) {
53985
+ const key = `${KEY_PREFIX}${bundleHash}`;
53986
+ const result = await this.backend.removeItem(key);
53987
+ return result !== false;
53988
+ }
53989
+ /**
53990
+ * Check if a secret exists
53991
+ */
53992
+ async hasSecret(bundleHash) {
53993
+ const raw = await this.backend.getItem(`${KEY_PREFIX}${bundleHash}`);
53994
+ return raw !== null;
53995
+ }
53996
+ /**
53997
+ * List all stored secret metadata
53998
+ */
53999
+ async listSecrets() {
54000
+ const keys = await this.backend.keys();
54001
+ const matchingKeys = keys.filter((k2) => k2.startsWith(KEY_PREFIX));
54002
+ const results = [];
54003
+ for (const key of matchingKeys) {
54004
+ const raw = await this.backend.getItem(key);
54005
+ if (raw) {
54006
+ try {
54007
+ const payload = JSON.parse(raw);
54008
+ if (payload.metadata) {
54009
+ results.push(payload.metadata);
54010
+ }
54011
+ } catch {
54012
+ }
54013
+ }
54014
+ }
54015
+ return results;
54016
+ }
54017
+ /**
54018
+ * Execute callback with unwrapped secret, zeroizing the decrypted buffer upon completion
54019
+ */
54020
+ async withSecret(bundleHash, fn, options) {
54021
+ const raw = await this.backend.getItem(`${KEY_PREFIX}${bundleHash}`);
54022
+ if (!raw) {
54023
+ throw exports.SecretStorageException.notFound(bundleHash);
54024
+ }
54025
+ let payload;
54026
+ try {
54027
+ payload = JSON.parse(raw);
54028
+ } catch {
54029
+ throw exports.SecretStorageException.decryptionFailed("Corrupted payload format");
54030
+ }
54031
+ const passphrase = options?.passphrase ?? this.defaultPassphrase;
54032
+ if (!passphrase) {
54033
+ throw new exports.SecretStorageException("Passphrase required for secret decryption");
54034
+ }
54035
+ const salt = base64ToUint8Array2(payload.salt);
54036
+ const iv = base64ToUint8Array2(payload.iv);
54037
+ const ciphertext = base64ToUint8Array2(payload.ciphertext);
54038
+ try {
54039
+ const key = await this.deriveKey(passphrase, salt, payload.iterations ?? DEFAULT_ITERATIONS);
54040
+ const decryptedBuffer = await globalThis.crypto.subtle.decrypt(
54041
+ {
54042
+ name: "AES-GCM",
54043
+ iv
54044
+ },
54045
+ key,
54046
+ ciphertext
54047
+ );
54048
+ const decryptedBytes = new Uint8Array(decryptedBuffer);
54049
+ return await withSecureBytes(decryptedBytes, async (bytes) => {
54050
+ const secretString = textDecoder.decode(bytes);
54051
+ return await fn(secretString);
54052
+ });
54053
+ } catch (err) {
54054
+ if (err instanceof exports.SecretStorageException) {
54055
+ throw err;
54056
+ }
54057
+ const msg = err instanceof Error ? err.message : String(err);
54058
+ throw exports.SecretStorageException.decryptionFailed(msg);
54059
+ }
54060
+ }
54061
+ };
54062
+
54063
+ // src/storage/index.ts
54064
+ function createDefaultSecretStorage(options = {}) {
54065
+ if (options.type === "memory") {
54066
+ return new MemorySecretStorageProvider();
54067
+ }
54068
+ if (typeof globalThis.crypto !== "undefined" && typeof globalThis.crypto.subtle !== "undefined") {
54069
+ return new WebCryptoSecretStorageProvider({
54070
+ backend: options.backend,
54071
+ defaultPassphrase: options.defaultPassphrase,
54072
+ hardwareBacked: options.hardwareBacked
54073
+ });
54074
+ }
54075
+ return new MemorySecretStorageProvider();
54076
+ }
54077
+
54078
+ // src/index.ts
54079
+ var SDK_VERSION = "0.9.8";
53540
54080
  var SDK_NAME = "KnishIO-Client-TS";
53541
54081
  var COMPATIBLE_SERVER_VERSIONS = [4, 5];
53542
54082
  var SDK_INFO = {
@@ -53647,6 +54187,8 @@ ${operationTypes.join("\n")}
53647
54187
  exports.GraphQLClient = GraphQLClient;
53648
54188
  exports.KnishIO = KnishIO;
53649
54189
  exports.KnishIOClient = KnishIOClient;
54190
+ exports.MemorySecretStorageProvider = MemorySecretStorageProvider;
54191
+ exports.MemoryStorageBackend = MemoryStorageBackend;
53650
54192
  exports.Meta = Meta;
53651
54193
  exports.Molecule = Molecule;
53652
54194
  exports.Mutation = Mutation;
@@ -53692,6 +54234,7 @@ ${operationTypes.join("\n")}
53692
54234
  exports.SDK_VERSION = SDK_VERSION;
53693
54235
  exports.TokenUnit = TokenUnit;
53694
54236
  exports.Wallet = Wallet;
54237
+ exports.WebCryptoSecretStorageProvider = WebCryptoSecretStorageProvider;
53695
54238
  exports.base64ToHex = base64ToHex;
53696
54239
  exports.bufferToHexString = bufferToHexString;
53697
54240
  exports.capitalize = capitalize;
@@ -53699,8 +54242,10 @@ ${operationTypes.join("\n")}
53699
54242
  exports.chunkArray = chunkArray;
53700
54243
  exports.chunkSubstr = chunkSubstr;
53701
54244
  exports.configureSDK = configureSDK;
54245
+ exports.constantTimeCompare = constantTimeCompare;
53702
54246
  exports.convertToBase17 = convertToBase17;
53703
54247
  exports.createBundleHash = createBundleHash;
54248
+ exports.createDefaultSecretStorage = createDefaultSecretStorage;
53704
54249
  exports.createMolecularHash = createMolecularHash;
53705
54250
  exports.createPosition = createPosition;
53706
54251
  exports.createTokenSlug = createTokenSlug;
@@ -53742,6 +54287,9 @@ ${operationTypes.join("\n")}
53742
54287
  exports.validateSecret = validateSecret;
53743
54288
  exports.validateWalletAddress = validateWalletAddress;
53744
54289
  exports.verifyOTSSignature = verifyOTSSignature;
54290
+ exports.withSecureBytes = withSecureBytes;
54291
+ exports.withSecureString = withSecureString;
54292
+ exports.zeroizeBytes = zeroizeBytes;
53745
54293
 
53746
54294
  return exports;
53747
54295