vaultkeeper 0.5.3 → 0.6.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.
package/dist/index.d.cts CHANGED
@@ -134,9 +134,43 @@ declare class IdentityMismatchError extends VaultError {
134
134
  readonly currentHash: string;
135
135
  constructor(message: string, previousHash: string, currentHash: string);
136
136
  }
137
+ /**
138
+ * Thrown when a delegated `exec()` call fails due to a process-level error
139
+ * (e.g. the command binary is not found or cannot be spawned).
140
+ *
141
+ * @public
142
+ */
143
+ declare class ExecError extends VaultError {
144
+ /**
145
+ * The command that failed to execute.
146
+ */
147
+ readonly command: string;
148
+ constructor(message: string, command: string);
149
+ }
150
+ /**
151
+ * Thrown when a JWE string cannot be parsed because it is structurally
152
+ * malformed (e.g. wrong number of segments, invalid Base64URL header,
153
+ * or unparseable JSON header).
154
+ *
155
+ * @public
156
+ */
157
+ declare class InvalidTokenError extends VaultError {
158
+ constructor(message: string);
159
+ }
160
+ /**
161
+ * Thrown when `SecretAccessor.read()` is called after the accessor has
162
+ * already been consumed.
163
+ *
164
+ * @public
165
+ */
166
+ declare class AccessorConsumedError extends VaultError {
167
+ constructor(message: string);
168
+ }
137
169
  /**
138
170
  * Thrown when a caller requests a signing/verification algorithm that is not
139
171
  * in the allowed set (e.g. `'md5'`).
172
+ *
173
+ * @public
140
174
  */
141
175
  declare class InvalidAlgorithmError extends VaultError {
142
176
  /**
@@ -609,6 +643,45 @@ declare class CapabilityToken {
609
643
  toString(): string;
610
644
  }
611
645
 
646
+ /**
647
+ * Platform detection utilities.
648
+ */
649
+ /**
650
+ * The OS platform identifier used for platform-specific behavior.
651
+ * @public
652
+ */
653
+ type Platform = 'darwin' | 'win32' | 'linux';
654
+
655
+ /**
656
+ * Doctor runner: orchestrates platform-appropriate checks and aggregates results.
657
+ */
658
+
659
+ /**
660
+ * Options for running the doctor.
661
+ * @public
662
+ */
663
+ interface RunDoctorOptions {
664
+ /** Override the platform detection (useful for testing). */
665
+ platform?: Platform;
666
+ /**
667
+ * When provided, doctor checks are scoped to the given backends.
668
+ * Platform-native dependency checks (e.g. `secret-tool`, `security`,
669
+ * `powershell`) are demoted from required to optional when the
670
+ * corresponding backend is not enabled. Plugin tool checks (`op`,
671
+ * `ykman`) are promoted from optional to required when their backend
672
+ * (`1password`, `yubikey`) is explicitly enabled.
673
+ *
674
+ * When omitted, all platform-default checks are treated as required
675
+ * (backward-compatible behavior).
676
+ */
677
+ backends?: BackendConfig[];
678
+ }
679
+ /**
680
+ * Run all platform-appropriate preflight checks and aggregate the results.
681
+ * @public
682
+ */
683
+ declare function runDoctor(options?: RunDoctorOptions): Promise<PreflightResult>;
684
+
612
685
  /**
613
686
  * VaultKeeper main class — wires together all vaultkeeper subsystems.
614
687
  */
@@ -650,13 +723,37 @@ declare class VaultKeeper {
650
723
  /**
651
724
  * Run doctor checks without full initialization.
652
725
  *
653
- * Uses conservative platform defaults — all platform-native dependency
654
- * checks are treated as required regardless of any backend configuration.
655
- * For config-aware scoping, call `runDoctor({ backends })` directly.
726
+ * When called without arguments, uses conservative platform defaults —
727
+ * all platform-native dependency checks are treated as required. Pass
728
+ * `{ backends }` to scope checks to only the backends you plan to use.
729
+ *
730
+ * @param options - Optional doctor options (e.g. `{ backends }` to scope checks).
731
+ */
732
+ static doctor(options?: RunDoctorOptions): Promise<PreflightResult>;
733
+ /**
734
+ * Store a secret in the configured backend.
735
+ *
736
+ * This is a convenience method that delegates to the active backend's
737
+ * `store()` method. If a secret with the same name already exists, it is
738
+ * overwritten.
739
+ *
740
+ * @param name - Identifier for the secret.
741
+ * @param value - The secret value to store.
742
+ * @public
743
+ */
744
+ store(name: string, value: string): Promise<void>;
745
+ /**
746
+ * Delete a secret from the configured backend.
747
+ *
748
+ * This is a convenience method that delegates to the active backend's
749
+ * `delete()` method.
750
+ *
751
+ * @param name - Identifier for the secret to delete.
752
+ * @public
656
753
  */
657
- static doctor(): Promise<PreflightResult>;
754
+ delete(name: string): Promise<void>;
658
755
  /**
659
- * Retrieve a secret from the backend and return a JWE token that encapsulates it.
756
+ * Read a stored secret from the backend and mint a JWE token that encapsulates it.
660
757
  *
661
758
  * @param secretName - Identifier for the secret
662
759
  * @param options - Setup options
@@ -668,11 +765,14 @@ declare class VaultKeeper {
668
765
  * an opaque CapabilityToken.
669
766
  *
670
767
  * @param jwe - Compact JWE string from setup()
671
- * @returns Opaque capability token for use with fetch/exec/getSecret
768
+ * @returns Object containing an opaque {@link CapabilityToken} for use with
769
+ * fetch/exec/getSecret, and a {@link VaultResponse} describing key status.
770
+ * When the JWE was decrypted with a non-current key,
771
+ * `vaultResponse.rotatedJwt` contains a re-encrypted JWE for the current key.
672
772
  */
673
773
  authorize(jwe: string): Promise<{
674
774
  token: CapabilityToken;
675
- response: VaultResponse;
775
+ vaultResponse: VaultResponse;
676
776
  }>;
677
777
  /**
678
778
  * Execute a delegated HTTP fetch, injecting the secret from the token.
@@ -799,43 +899,4 @@ declare class VaultKeeper {
799
899
  setDevelopmentMode(executablePath: string, enabled: boolean): Promise<void>;
800
900
  }
801
901
 
802
- /**
803
- * Platform detection utilities.
804
- */
805
- /**
806
- * The OS platform identifier used for platform-specific behavior.
807
- * @public
808
- */
809
- type Platform = 'darwin' | 'win32' | 'linux';
810
-
811
- /**
812
- * Doctor runner: orchestrates platform-appropriate checks and aggregates results.
813
- */
814
-
815
- /**
816
- * Options for running the doctor.
817
- * @public
818
- */
819
- interface RunDoctorOptions {
820
- /** Override the platform detection (useful for testing). */
821
- platform?: Platform;
822
- /**
823
- * When provided, doctor checks are scoped to the given backends.
824
- * Platform-native dependency checks (e.g. `secret-tool`, `security`,
825
- * `powershell`) are demoted from required to optional when the
826
- * corresponding backend is not enabled. Plugin tool checks (`op`,
827
- * `ykman`) are promoted from optional to required when their backend
828
- * (`1password`, `yubikey`) is explicitly enabled.
829
- *
830
- * When omitted, all platform-default checks are treated as required
831
- * (backward-compatible behavior).
832
- */
833
- backends?: BackendConfig[];
834
- }
835
- /**
836
- * Run all platform-appropriate preflight checks and aggregate the results.
837
- * @public
838
- */
839
- declare function runDoctor(options?: RunDoctorOptions): Promise<PreflightResult>;
840
-
841
- export { AuthorizationDeniedError, type BackendConfig, type BackendFactory, BackendLockedError, BackendRegistry, type BackendSetupFactory, BackendUnavailableError, CapabilityToken, DeviceNotPresentError, type ExecRequest, type ExecResult, type FetchRequest, FilesystemError, IdentityMismatchError, InvalidAlgorithmError, KeyRevokedError, KeyRotatedError, type KeyStatus, type ListableBackend, type Platform, PluginNotFoundError, type PreflightCheck, type PreflightCheckStatus, type PreflightResult, RotationInProgressError, type RunDoctorOptions, type SecretAccessor, type SecretBackend, SecretNotFoundError, type SetupChoice, SetupError, type SetupOptions, type SetupQuestion, type SetupResult, type SignRequest, type SignResult, TokenExpiredError, TokenRevokedError, type TrustTier, UsageLimitExceededError, type VaultConfig, VaultError, VaultKeeper, type VaultKeeperOptions, type VaultResponse, type VerifyRequest, isListableBackend, runDoctor };
902
+ export { AccessorConsumedError, AuthorizationDeniedError, type BackendConfig, type BackendFactory, BackendLockedError, BackendRegistry, type BackendSetupFactory, BackendUnavailableError, CapabilityToken, DeviceNotPresentError, ExecError, type ExecRequest, type ExecResult, type FetchRequest, FilesystemError, IdentityMismatchError, InvalidAlgorithmError, InvalidTokenError, KeyRevokedError, KeyRotatedError, type KeyStatus, type ListableBackend, type Platform, PluginNotFoundError, type PreflightCheck, type PreflightCheckStatus, type PreflightResult, RotationInProgressError, type RunDoctorOptions, type SecretAccessor, type SecretBackend, SecretNotFoundError, type SetupChoice, SetupError, type SetupOptions, type SetupQuestion, type SetupResult, type SignRequest, type SignResult, TokenExpiredError, TokenRevokedError, type TrustTier, UsageLimitExceededError, type VaultConfig, VaultError, VaultKeeper, type VaultKeeperOptions, type VaultResponse, type VerifyRequest, isListableBackend, runDoctor };
package/dist/index.d.ts CHANGED
@@ -134,9 +134,43 @@ declare class IdentityMismatchError extends VaultError {
134
134
  readonly currentHash: string;
135
135
  constructor(message: string, previousHash: string, currentHash: string);
136
136
  }
137
+ /**
138
+ * Thrown when a delegated `exec()` call fails due to a process-level error
139
+ * (e.g. the command binary is not found or cannot be spawned).
140
+ *
141
+ * @public
142
+ */
143
+ declare class ExecError extends VaultError {
144
+ /**
145
+ * The command that failed to execute.
146
+ */
147
+ readonly command: string;
148
+ constructor(message: string, command: string);
149
+ }
150
+ /**
151
+ * Thrown when a JWE string cannot be parsed because it is structurally
152
+ * malformed (e.g. wrong number of segments, invalid Base64URL header,
153
+ * or unparseable JSON header).
154
+ *
155
+ * @public
156
+ */
157
+ declare class InvalidTokenError extends VaultError {
158
+ constructor(message: string);
159
+ }
160
+ /**
161
+ * Thrown when `SecretAccessor.read()` is called after the accessor has
162
+ * already been consumed.
163
+ *
164
+ * @public
165
+ */
166
+ declare class AccessorConsumedError extends VaultError {
167
+ constructor(message: string);
168
+ }
137
169
  /**
138
170
  * Thrown when a caller requests a signing/verification algorithm that is not
139
171
  * in the allowed set (e.g. `'md5'`).
172
+ *
173
+ * @public
140
174
  */
141
175
  declare class InvalidAlgorithmError extends VaultError {
142
176
  /**
@@ -609,6 +643,45 @@ declare class CapabilityToken {
609
643
  toString(): string;
610
644
  }
611
645
 
646
+ /**
647
+ * Platform detection utilities.
648
+ */
649
+ /**
650
+ * The OS platform identifier used for platform-specific behavior.
651
+ * @public
652
+ */
653
+ type Platform = 'darwin' | 'win32' | 'linux';
654
+
655
+ /**
656
+ * Doctor runner: orchestrates platform-appropriate checks and aggregates results.
657
+ */
658
+
659
+ /**
660
+ * Options for running the doctor.
661
+ * @public
662
+ */
663
+ interface RunDoctorOptions {
664
+ /** Override the platform detection (useful for testing). */
665
+ platform?: Platform;
666
+ /**
667
+ * When provided, doctor checks are scoped to the given backends.
668
+ * Platform-native dependency checks (e.g. `secret-tool`, `security`,
669
+ * `powershell`) are demoted from required to optional when the
670
+ * corresponding backend is not enabled. Plugin tool checks (`op`,
671
+ * `ykman`) are promoted from optional to required when their backend
672
+ * (`1password`, `yubikey`) is explicitly enabled.
673
+ *
674
+ * When omitted, all platform-default checks are treated as required
675
+ * (backward-compatible behavior).
676
+ */
677
+ backends?: BackendConfig[];
678
+ }
679
+ /**
680
+ * Run all platform-appropriate preflight checks and aggregate the results.
681
+ * @public
682
+ */
683
+ declare function runDoctor(options?: RunDoctorOptions): Promise<PreflightResult>;
684
+
612
685
  /**
613
686
  * VaultKeeper main class — wires together all vaultkeeper subsystems.
614
687
  */
@@ -650,13 +723,37 @@ declare class VaultKeeper {
650
723
  /**
651
724
  * Run doctor checks without full initialization.
652
725
  *
653
- * Uses conservative platform defaults — all platform-native dependency
654
- * checks are treated as required regardless of any backend configuration.
655
- * For config-aware scoping, call `runDoctor({ backends })` directly.
726
+ * When called without arguments, uses conservative platform defaults —
727
+ * all platform-native dependency checks are treated as required. Pass
728
+ * `{ backends }` to scope checks to only the backends you plan to use.
729
+ *
730
+ * @param options - Optional doctor options (e.g. `{ backends }` to scope checks).
731
+ */
732
+ static doctor(options?: RunDoctorOptions): Promise<PreflightResult>;
733
+ /**
734
+ * Store a secret in the configured backend.
735
+ *
736
+ * This is a convenience method that delegates to the active backend's
737
+ * `store()` method. If a secret with the same name already exists, it is
738
+ * overwritten.
739
+ *
740
+ * @param name - Identifier for the secret.
741
+ * @param value - The secret value to store.
742
+ * @public
743
+ */
744
+ store(name: string, value: string): Promise<void>;
745
+ /**
746
+ * Delete a secret from the configured backend.
747
+ *
748
+ * This is a convenience method that delegates to the active backend's
749
+ * `delete()` method.
750
+ *
751
+ * @param name - Identifier for the secret to delete.
752
+ * @public
656
753
  */
657
- static doctor(): Promise<PreflightResult>;
754
+ delete(name: string): Promise<void>;
658
755
  /**
659
- * Retrieve a secret from the backend and return a JWE token that encapsulates it.
756
+ * Read a stored secret from the backend and mint a JWE token that encapsulates it.
660
757
  *
661
758
  * @param secretName - Identifier for the secret
662
759
  * @param options - Setup options
@@ -668,11 +765,14 @@ declare class VaultKeeper {
668
765
  * an opaque CapabilityToken.
669
766
  *
670
767
  * @param jwe - Compact JWE string from setup()
671
- * @returns Opaque capability token for use with fetch/exec/getSecret
768
+ * @returns Object containing an opaque {@link CapabilityToken} for use with
769
+ * fetch/exec/getSecret, and a {@link VaultResponse} describing key status.
770
+ * When the JWE was decrypted with a non-current key,
771
+ * `vaultResponse.rotatedJwt` contains a re-encrypted JWE for the current key.
672
772
  */
673
773
  authorize(jwe: string): Promise<{
674
774
  token: CapabilityToken;
675
- response: VaultResponse;
775
+ vaultResponse: VaultResponse;
676
776
  }>;
677
777
  /**
678
778
  * Execute a delegated HTTP fetch, injecting the secret from the token.
@@ -799,43 +899,4 @@ declare class VaultKeeper {
799
899
  setDevelopmentMode(executablePath: string, enabled: boolean): Promise<void>;
800
900
  }
801
901
 
802
- /**
803
- * Platform detection utilities.
804
- */
805
- /**
806
- * The OS platform identifier used for platform-specific behavior.
807
- * @public
808
- */
809
- type Platform = 'darwin' | 'win32' | 'linux';
810
-
811
- /**
812
- * Doctor runner: orchestrates platform-appropriate checks and aggregates results.
813
- */
814
-
815
- /**
816
- * Options for running the doctor.
817
- * @public
818
- */
819
- interface RunDoctorOptions {
820
- /** Override the platform detection (useful for testing). */
821
- platform?: Platform;
822
- /**
823
- * When provided, doctor checks are scoped to the given backends.
824
- * Platform-native dependency checks (e.g. `secret-tool`, `security`,
825
- * `powershell`) are demoted from required to optional when the
826
- * corresponding backend is not enabled. Plugin tool checks (`op`,
827
- * `ykman`) are promoted from optional to required when their backend
828
- * (`1password`, `yubikey`) is explicitly enabled.
829
- *
830
- * When omitted, all platform-default checks are treated as required
831
- * (backward-compatible behavior).
832
- */
833
- backends?: BackendConfig[];
834
- }
835
- /**
836
- * Run all platform-appropriate preflight checks and aggregate the results.
837
- * @public
838
- */
839
- declare function runDoctor(options?: RunDoctorOptions): Promise<PreflightResult>;
840
-
841
- export { AuthorizationDeniedError, type BackendConfig, type BackendFactory, BackendLockedError, BackendRegistry, type BackendSetupFactory, BackendUnavailableError, CapabilityToken, DeviceNotPresentError, type ExecRequest, type ExecResult, type FetchRequest, FilesystemError, IdentityMismatchError, InvalidAlgorithmError, KeyRevokedError, KeyRotatedError, type KeyStatus, type ListableBackend, type Platform, PluginNotFoundError, type PreflightCheck, type PreflightCheckStatus, type PreflightResult, RotationInProgressError, type RunDoctorOptions, type SecretAccessor, type SecretBackend, SecretNotFoundError, type SetupChoice, SetupError, type SetupOptions, type SetupQuestion, type SetupResult, type SignRequest, type SignResult, TokenExpiredError, TokenRevokedError, type TrustTier, UsageLimitExceededError, type VaultConfig, VaultError, VaultKeeper, type VaultKeeperOptions, type VaultResponse, type VerifyRequest, isListableBackend, runDoctor };
902
+ export { AccessorConsumedError, AuthorizationDeniedError, type BackendConfig, type BackendFactory, BackendLockedError, BackendRegistry, type BackendSetupFactory, BackendUnavailableError, CapabilityToken, DeviceNotPresentError, ExecError, type ExecRequest, type ExecResult, type FetchRequest, FilesystemError, IdentityMismatchError, InvalidAlgorithmError, InvalidTokenError, KeyRevokedError, KeyRotatedError, type KeyStatus, type ListableBackend, type Platform, PluginNotFoundError, type PreflightCheck, type PreflightCheckStatus, type PreflightResult, RotationInProgressError, type RunDoctorOptions, type SecretAccessor, type SecretBackend, SecretNotFoundError, type SetupChoice, SetupError, type SetupOptions, type SetupQuestion, type SetupResult, type SignRequest, type SignResult, TokenExpiredError, TokenRevokedError, type TrustTier, UsageLimitExceededError, type VaultConfig, VaultError, VaultKeeper, type VaultKeeperOptions, type VaultResponse, type VerifyRequest, isListableBackend, runDoctor };
package/dist/index.js CHANGED
@@ -139,6 +139,29 @@ var IdentityMismatchError = class extends VaultError {
139
139
  this.currentHash = currentHash;
140
140
  }
141
141
  };
142
+ var ExecError = class extends VaultError {
143
+ /**
144
+ * The command that failed to execute.
145
+ */
146
+ command;
147
+ constructor(message, command) {
148
+ super(message);
149
+ this.name = "ExecError";
150
+ this.command = command;
151
+ }
152
+ };
153
+ var InvalidTokenError = class extends VaultError {
154
+ constructor(message) {
155
+ super(message);
156
+ this.name = "InvalidTokenError";
157
+ }
158
+ };
159
+ var AccessorConsumedError = class extends VaultError {
160
+ constructor(message) {
161
+ super(message);
162
+ this.name = "AccessorConsumedError";
163
+ }
164
+ };
142
165
  var InvalidAlgorithmError = class extends VaultError {
143
166
  /**
144
167
  * The algorithm that was requested.
@@ -470,7 +493,17 @@ function execCommandFull(command, args, options) {
470
493
  resolve2({ stdout, stderr, exitCode: code ?? 1 });
471
494
  });
472
495
  proc.on("error", (error) => {
473
- reject(error);
496
+ if ("code" in error && error.code === "ENOENT") {
497
+ reject(
498
+ new PluginNotFoundError(
499
+ `'${command}' is not installed or not found in PATH`,
500
+ command,
501
+ ""
502
+ )
503
+ );
504
+ } else {
505
+ reject(error);
506
+ }
474
507
  });
475
508
  });
476
509
  }
@@ -1810,40 +1843,40 @@ async function decryptToken(key, jwe) {
1810
1843
  plaintext = result.plaintext;
1811
1844
  } catch (err) {
1812
1845
  const message = err instanceof Error ? err.message : String(err);
1813
- throw new VaultError(`JWE decryption failed: ${message}`);
1846
+ throw new InvalidTokenError(`JWE decryption failed: ${message}`);
1814
1847
  }
1815
1848
  let parsed;
1816
1849
  try {
1817
1850
  parsed = JSON.parse(new TextDecoder().decode(plaintext));
1818
1851
  } catch {
1819
- throw new VaultError("JWE payload is not valid JSON");
1852
+ throw new InvalidTokenError("JWE payload is not valid JSON");
1820
1853
  }
1821
1854
  const claims = parseVaultClaims(parsed);
1822
1855
  if (claims === void 0) {
1823
- throw new VaultError("JWE payload does not match VaultClaims schema");
1856
+ throw new InvalidTokenError("JWE payload does not match VaultClaims schema");
1824
1857
  }
1825
1858
  return claims;
1826
1859
  }
1827
1860
  function extractKid(jwe) {
1828
1861
  const parts = jwe.split(".");
1829
1862
  if (parts.length !== 5) {
1830
- throw new VaultError("Invalid JWE compact serialization: expected 5 parts");
1863
+ throw new InvalidTokenError("Invalid JWE compact serialization: expected 5 parts");
1831
1864
  }
1832
1865
  const headerSegment = parts[0];
1833
1866
  if (headerSegment === void 0 || headerSegment === "") {
1834
- throw new VaultError("Invalid JWE compact serialization: missing header segment");
1867
+ throw new InvalidTokenError("Invalid JWE compact serialization: missing header segment");
1835
1868
  }
1836
1869
  let headerJson;
1837
1870
  try {
1838
1871
  headerJson = Buffer.from(headerSegment, "base64url").toString("utf-8");
1839
1872
  } catch {
1840
- throw new VaultError("Invalid JWE compact serialization: header is not valid Base64URL");
1873
+ throw new InvalidTokenError("Invalid JWE compact serialization: header is not valid Base64URL");
1841
1874
  }
1842
1875
  let header;
1843
1876
  try {
1844
1877
  header = JSON.parse(headerJson);
1845
1878
  } catch {
1846
- throw new VaultError("Invalid JWE compact serialization: header is not valid JSON");
1879
+ throw new InvalidTokenError("Invalid JWE compact serialization: header is not valid JSON");
1847
1880
  }
1848
1881
  if (!isObject2(header)) {
1849
1882
  return void 0;
@@ -1958,6 +1991,12 @@ function replaceInRecord2(record, secret) {
1958
1991
  return result;
1959
1992
  }
1960
1993
  function delegatedExec(secret, request) {
1994
+ if (request.command.includes(PLACEHOLDER2)) {
1995
+ throw new ExecError(
1996
+ `The {{secret}} placeholder is not supported in the command field. Use args or env instead.`,
1997
+ request.command
1998
+ );
1999
+ }
1961
2000
  const args = (request.args ?? []).map((arg) => replacePlaceholder2(arg, secret));
1962
2001
  const env = request.env !== void 0 ? replaceInRecord2(request.env, secret) : void 0;
1963
2002
  return new Promise((resolve2, reject) => {
@@ -1983,7 +2022,22 @@ function delegatedExec(secret, request) {
1983
2022
  resolve2({ stdout, stderr, exitCode: code ?? 1 });
1984
2023
  });
1985
2024
  proc.on("error", (error) => {
1986
- reject(error);
2025
+ const isEnoent = error instanceof Error && "code" in error && error.code === "ENOENT";
2026
+ if (isEnoent) {
2027
+ reject(
2028
+ new ExecError(
2029
+ `Command not found: ${request.command}. Verify the command exists and is in PATH.`,
2030
+ request.command
2031
+ )
2032
+ );
2033
+ } else {
2034
+ reject(
2035
+ new ExecError(
2036
+ `Failed to execute command: ${request.command}. ${error instanceof Error ? error.message : String(error)}`,
2037
+ request.command
2038
+ )
2039
+ );
2040
+ }
1987
2041
  });
1988
2042
  });
1989
2043
  }
@@ -2002,7 +2056,7 @@ function createSecretAccessor(secretValue) {
2002
2056
  let consumed = false;
2003
2057
  function readImpl(callback) {
2004
2058
  if (consumed) {
2005
- throw new Error("SecretAccessor has already been consumed \u2014 call getSecret() again to obtain a new accessor");
2059
+ throw new AccessorConsumedError("SecretAccessor has already been consumed \u2014 call getSecret() again to obtain a new accessor");
2006
2060
  }
2007
2061
  consumed = true;
2008
2062
  const buf = Buffer.from(secretValue, "utf8");
@@ -2276,16 +2330,15 @@ async function runDoctor(options) {
2276
2330
  const warnings = [];
2277
2331
  const nextSteps = [];
2278
2332
  for (const { required, result } of resolved) {
2333
+ const reasonSuffix = result.reason !== void 0 ? ` \u2014 ${result.reason}` : "";
2279
2334
  if (result.status === "missing") {
2280
2335
  if (required) {
2281
- nextSteps.push(`Install missing required dependency: ${result.name}`);
2336
+ nextSteps.push(`Install missing required dependency: ${result.name}${reasonSuffix}`);
2282
2337
  } else {
2283
- warnings.push(
2284
- `Optional dependency not found: ${result.name}${result.reason !== void 0 ? ` \u2014 ${result.reason}` : ""}`
2285
- );
2338
+ warnings.push(`Optional dependency not found: ${result.name}${reasonSuffix}`);
2286
2339
  }
2287
2340
  } else if (result.status === "version-unsupported") {
2288
- const msg = `${result.name} version is unsupported${result.reason !== void 0 ? `: ${result.reason}` : ""}`;
2341
+ const msg = `${result.name} version is unsupported${reasonSuffix}`;
2289
2342
  if (required) {
2290
2343
  nextSteps.push(`Upgrade required dependency: ${msg}`);
2291
2344
  } else {
@@ -2372,21 +2425,54 @@ var VaultKeeper = class _VaultKeeper {
2372
2425
  /**
2373
2426
  * Run doctor checks without full initialization.
2374
2427
  *
2375
- * Uses conservative platform defaults — all platform-native dependency
2376
- * checks are treated as required regardless of any backend configuration.
2377
- * For config-aware scoping, call `runDoctor({ backends })` directly.
2428
+ * When called without arguments, uses conservative platform defaults —
2429
+ * all platform-native dependency checks are treated as required. Pass
2430
+ * `{ backends }` to scope checks to only the backends you plan to use.
2431
+ *
2432
+ * @param options - Optional doctor options (e.g. `{ backends }` to scope checks).
2433
+ */
2434
+ static async doctor(options) {
2435
+ return runDoctor(options);
2436
+ }
2437
+ /**
2438
+ * Store a secret in the configured backend.
2439
+ *
2440
+ * This is a convenience method that delegates to the active backend's
2441
+ * `store()` method. If a secret with the same name already exists, it is
2442
+ * overwritten.
2443
+ *
2444
+ * @param name - Identifier for the secret.
2445
+ * @param value - The secret value to store.
2446
+ * @public
2447
+ */
2448
+ async store(name, value) {
2449
+ _VaultKeeper.#validateSecretName(name);
2450
+ const backend = this.#requireBackend();
2451
+ await backend.store(name, value);
2452
+ }
2453
+ /**
2454
+ * Delete a secret from the configured backend.
2455
+ *
2456
+ * This is a convenience method that delegates to the active backend's
2457
+ * `delete()` method.
2458
+ *
2459
+ * @param name - Identifier for the secret to delete.
2460
+ * @public
2378
2461
  */
2379
- static async doctor() {
2380
- return runDoctor();
2462
+ async delete(name) {
2463
+ _VaultKeeper.#validateSecretName(name);
2464
+ const backend = this.#requireBackend();
2465
+ await backend.delete(name);
2381
2466
  }
2382
2467
  /**
2383
- * Retrieve a secret from the backend and return a JWE token that encapsulates it.
2468
+ * Read a stored secret from the backend and mint a JWE token that encapsulates it.
2384
2469
  *
2385
2470
  * @param secretName - Identifier for the secret
2386
2471
  * @param options - Setup options
2387
2472
  * @returns Compact JWE string
2388
2473
  */
2389
2474
  async setup(secretName, options) {
2475
+ _VaultKeeper.#validateSecretName(secretName);
2390
2476
  const backend = this.#requireBackend();
2391
2477
  const backendType = options?.backendType ?? backend.type;
2392
2478
  const ttlMinutes = options?.ttlMinutes ?? this.#config.defaults.ttlMinutes;
@@ -2431,7 +2517,10 @@ var VaultKeeper = class _VaultKeeper {
2431
2517
  * an opaque CapabilityToken.
2432
2518
  *
2433
2519
  * @param jwe - Compact JWE string from setup()
2434
- * @returns Opaque capability token for use with fetch/exec/getSecret
2520
+ * @returns Object containing an opaque {@link CapabilityToken} for use with
2521
+ * fetch/exec/getSecret, and a {@link VaultResponse} describing key status.
2522
+ * When the JWE was decrypted with a non-current key,
2523
+ * `vaultResponse.rotatedJwt` contains a re-encrypted JWE for the current key.
2435
2524
  */
2436
2525
  async authorize(jwe) {
2437
2526
  const kid = extractKid(jwe);
@@ -2451,13 +2540,13 @@ var VaultKeeper = class _VaultKeeper {
2451
2540
  }
2452
2541
  }
2453
2542
  const token = createCapabilityToken(claims);
2454
- const response = { keyStatus };
2543
+ const vaultResponse = { keyStatus };
2455
2544
  if (keyStatus === "previous") {
2456
2545
  const currentKey = this.#keyManager.getCurrentKey();
2457
2546
  const rotatedJwt = await createToken(currentKey.key, claims, { kid: currentKey.id });
2458
- response.rotatedJwt = rotatedJwt;
2547
+ vaultResponse.rotatedJwt = rotatedJwt;
2459
2548
  }
2460
- return { token, response };
2549
+ return { token, vaultResponse };
2461
2550
  }
2462
2551
  /**
2463
2552
  * Execute a delegated HTTP fetch, injecting the secret from the token.
@@ -2625,6 +2714,11 @@ var VaultKeeper = class _VaultKeeper {
2625
2714
  // ---------------------------------------------------------------------------
2626
2715
  // Private helpers
2627
2716
  // ---------------------------------------------------------------------------
2717
+ static #validateSecretName(name) {
2718
+ if (name.trim() === "") {
2719
+ throw new VaultError("Secret name must not be empty");
2720
+ }
2721
+ }
2628
2722
  #resolveBackend() {
2629
2723
  const enabledBackends = this.#config.backends.filter((b) => b.enabled);
2630
2724
  if (enabledBackends.length === 0) {
@@ -2683,6 +2777,6 @@ var VaultKeeper = class _VaultKeeper {
2683
2777
  }
2684
2778
  };
2685
2779
 
2686
- export { AuthorizationDeniedError, BackendLockedError, BackendRegistry, BackendUnavailableError, CapabilityToken, DeviceNotPresentError, FilesystemError, IdentityMismatchError, InvalidAlgorithmError, KeyRevokedError, KeyRotatedError, PluginNotFoundError, RotationInProgressError, SecretNotFoundError, SetupError, TokenExpiredError, TokenRevokedError, UsageLimitExceededError, VaultError, VaultKeeper, isListableBackend, runDoctor };
2780
+ export { AccessorConsumedError, AuthorizationDeniedError, BackendLockedError, BackendRegistry, BackendUnavailableError, CapabilityToken, DeviceNotPresentError, ExecError, FilesystemError, IdentityMismatchError, InvalidAlgorithmError, InvalidTokenError, KeyRevokedError, KeyRotatedError, PluginNotFoundError, RotationInProgressError, SecretNotFoundError, SetupError, TokenExpiredError, TokenRevokedError, UsageLimitExceededError, VaultError, VaultKeeper, isListableBackend, runDoctor };
2687
2781
  //# sourceMappingURL=index.js.map
2688
2782
  //# sourceMappingURL=index.js.map