@partrocks/secrets 0.1.3 → 0.1.4

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.ts CHANGED
@@ -1,8 +1,13 @@
1
1
  import { type ClientOptions } from "./request.js";
2
2
  export { PartRocksError } from "./error.js";
3
3
  export type { ClientOptions } from "./request.js";
4
+ export type SecretsConfig = {
5
+ entries: Record<string, string>;
6
+ };
4
7
  export declare function createSecrets(options: ClientOptions): {
5
- getConfig: () => Promise<{
6
- entries: Record<string, string>;
7
- }>;
8
+ getConfig: () => Promise<SecretsConfig>;
9
+ get: (name: string) => Promise<string>;
10
+ require: (name: string) => Promise<string>;
11
+ refresh: () => Promise<SecretsConfig>;
12
+ invalidate: () => void;
8
13
  };
package/dist/index.js CHANGED
@@ -1,8 +1,53 @@
1
1
  import { createRequest } from "./request.js";
2
+ import { PartRocksError } from "./error.js";
2
3
  export { PartRocksError } from "./error.js";
4
+ const DEFAULT_CACHE_TTL_MS = 60_000;
5
+ function cacheTtlMs(options) {
6
+ const ttl = options.cacheTtlMs ?? DEFAULT_CACHE_TTL_MS;
7
+ if (!Number.isFinite(ttl) || ttl < 0) {
8
+ throw new RangeError("cacheTtlMs must be a finite non-negative number");
9
+ }
10
+ return ttl;
11
+ }
3
12
  export function createSecrets(options) {
4
13
  const request = createRequest(options);
14
+ const ttl = cacheTtlMs(options);
15
+ let cache;
16
+ let refreshing;
17
+ const fetchConfig = () => request("GET", "/api/v1/config");
18
+ function refresh() {
19
+ refreshing ??= fetchConfig()
20
+ .then((config) => {
21
+ cache = {
22
+ config: { entries: { ...config.entries } },
23
+ expiresAt: Date.now() + ttl,
24
+ };
25
+ return { entries: { ...cache.config.entries } };
26
+ })
27
+ .finally(() => {
28
+ refreshing = undefined;
29
+ });
30
+ return refreshing;
31
+ }
32
+ async function cachedConfig() {
33
+ if (ttl > 0 && cache !== undefined && Date.now() < cache.expiresAt) {
34
+ return cache.config;
35
+ }
36
+ return refresh();
37
+ }
5
38
  return {
6
- getConfig: () => request("GET", "/api/v1/config"),
39
+ getConfig: fetchConfig,
40
+ get: async (name) => (await cachedConfig()).entries[name],
41
+ require: async (name) => {
42
+ const value = (await cachedConfig()).entries[name];
43
+ if (value === undefined) {
44
+ throw new PartRocksError(`Secret "${name}" is not set.`, "missing_secret", 404);
45
+ }
46
+ return value;
47
+ },
48
+ refresh,
49
+ invalidate: () => {
50
+ cache = undefined;
51
+ },
7
52
  };
8
53
  }
package/dist/request.d.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  export type ClientOptions = {
2
2
  apiKey: string;
3
3
  baseUrl?: string | null;
4
+ cacheTtlMs?: number | null;
4
5
  };
5
6
  export type RequestOptions = {
6
7
  body?: unknown;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@partrocks/secrets",
3
- "version": "0.1.3",
3
+ "version": "0.1.4",
4
4
  "description": "Server-side PartRocks Secrets client",
5
5
  "type": "module",
6
6
  "license": "MIT",