@rezwanul7/settings 1.0.0 → 2.0.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/README.md +174 -60
- package/dist/index.cjs +332 -1
- package/dist/index.d.cts +278 -14
- package/dist/index.d.ts +278 -14
- package/dist/index.js +330 -2
- package/dist/prisma.cjs +4 -1
- package/dist/prisma.d.cts +10 -10
- package/dist/prisma.d.ts +10 -10
- package/dist/prisma.js +4 -1
- package/package.json +2 -1
package/dist/index.d.ts
CHANGED
|
@@ -76,11 +76,43 @@ interface SettingsDefinition<T = unknown, SingleOwner extends boolean = boolean>
|
|
|
76
76
|
/** Whether the Scope has exactly one Owner, stored with the id `"default"`. */
|
|
77
77
|
readonly singleOwner: SingleOwner;
|
|
78
78
|
}
|
|
79
|
+
/** The settings type of a Settings definition. Internal: not exported from the package entry. */
|
|
80
|
+
type SettingsOf<D> = D extends SettingsDefinition<infer T> ? T : never;
|
|
81
|
+
/** Counts down the depth {@link NonJsonPaths} still walks, so a recursive settings type can't recurse forever. */
|
|
82
|
+
type Depth = [never, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
|
|
83
|
+
/** Whether an object type has a method, as a `Date`, `Map`, `Set` or class instance does. */
|
|
84
|
+
type HasMethod<T> = true extends {
|
|
85
|
+
[K in keyof T]-?: 0 extends 1 & T[K] ? false : T[K] extends (...args: never[]) => unknown ? true : false;
|
|
86
|
+
}[keyof T] ? true : false;
|
|
87
|
+
/**
|
|
88
|
+
* The dot paths in `T` whose values can't be kept as JSON, such as a `Date`, `Map`, `Set`, `bigint` or class
|
|
89
|
+
* instance; `never` when every value can. An array's elements are named `path[]`. `unknown` and `any` pass, since
|
|
90
|
+
* the runtime check covers them, and so does anything deeper than the walk goes.
|
|
91
|
+
*/
|
|
92
|
+
type NonJsonPaths<T, P extends string, D extends number = 10> = [D] extends [
|
|
93
|
+
never
|
|
94
|
+
] ? never : 0 extends 1 & T ? never : unknown extends T ? never : T extends string | number | boolean | null | undefined ? never : T extends bigint | symbol | ((...args: never[]) => unknown) ? P : T extends readonly (infer E)[] ? NonJsonPaths<E, `${P}[]`, Depth[D]> : T extends object ? HasMethod<T> extends true ? P : {
|
|
95
|
+
[K in keyof T & string]-?: NonJsonPaths<T[K], P extends "" ? K : `${P}.${K}`, Depth[D]>;
|
|
96
|
+
}[keyof T & string] : P;
|
|
97
|
+
/**
|
|
98
|
+
* Nothing extra when the schema's output can be kept as JSON. Otherwise a property no schema has, whose name states
|
|
99
|
+
* the rule and whose type names the offending paths, so the compile error at `schema` reads as the reason.
|
|
100
|
+
*/
|
|
101
|
+
type JsonOutputCheck<Schema extends StandardSchemaV1> = [
|
|
102
|
+
NonJsonPaths<StandardSchemaV1.InferOutput<Schema>, "">
|
|
103
|
+
] extends [never] ? unknown : {
|
|
104
|
+
readonly "Not a JSON value, so it can't be stored at": NonJsonPaths<StandardSchemaV1.InferOutput<Schema>, ""> extends "" ? "(the whole settings)" : NonJsonPaths<StandardSchemaV1.InferOutput<Schema>, "">;
|
|
105
|
+
};
|
|
79
106
|
/**
|
|
80
107
|
* Declares a Scope's Settings definition. The settings type is inferred from the schema's output type, and
|
|
81
108
|
* `defaults` must be a complete value of it; optional schema fields may be left out. Any Standard Schema works, such
|
|
82
109
|
* as one from Zod, Valibot or ArkType.
|
|
83
110
|
*
|
|
111
|
+
* Overrides are kept as JSON, so a schema whose output has a value that isn't, such as a `Date` from
|
|
112
|
+
* `z.coerce.date()`, a `Map`, a `Set`, a `bigint` or a class instance, is a compile error at `schema` that names the
|
|
113
|
+
* path. Store a date as its string and convert it where the setting is used. Output typed `unknown` or `any` passes;
|
|
114
|
+
* writes still check their values at runtime.
|
|
115
|
+
*
|
|
84
116
|
* The defaults are checked against the schema on the first operation on the Scope, because Standard Schema
|
|
85
117
|
* validation may be async; `createSettings` throws `SettingsDefinitionError` there if they fail.
|
|
86
118
|
*
|
|
@@ -88,27 +120,27 @@ interface SettingsDefinition<T = unknown, SingleOwner extends boolean = boolean>
|
|
|
88
120
|
* @returns The Settings definition, to pass to `createSettings` under its Scope name.
|
|
89
121
|
*
|
|
90
122
|
* @example
|
|
91
|
-
* const
|
|
123
|
+
* const userDefinition = defineSettings({
|
|
92
124
|
* schema: z.object({ theme: z.enum(["light", "dark"]), language: z.string() }),
|
|
93
125
|
* defaults: { theme: "light", language: "en" },
|
|
94
126
|
* });
|
|
95
|
-
* const
|
|
127
|
+
* const globalDefinition = defineSettings({
|
|
96
128
|
* schema: z.object({ maintenanceBanner: z.string().nullable() }),
|
|
97
129
|
* defaults: { maintenanceBanner: null },
|
|
98
130
|
* singleOwner: true,
|
|
99
131
|
* });
|
|
100
132
|
*/
|
|
101
133
|
declare function defineSettings<Schema extends StandardSchemaV1, SingleOwner extends boolean = false>(definition: {
|
|
102
|
-
/** The Standard Schema every Owner's Effective settings must pass. */
|
|
103
|
-
readonly schema: Schema
|
|
134
|
+
/** The Standard Schema every Owner's Effective settings must pass. Its output must be JSON. */
|
|
135
|
+
readonly schema: Schema & JsonOutputCheck<Schema>;
|
|
104
136
|
/** The complete settings used where an Owner has no Override. */
|
|
105
137
|
readonly defaults: StandardSchemaV1.InferOutput<Schema>;
|
|
106
138
|
/** `true` for a Scope with exactly one Owner, which takes no id. Defaults to `false`. */
|
|
107
139
|
readonly singleOwner?: SingleOwner;
|
|
108
140
|
}): SettingsDefinition<StandardSchemaV1.InferOutput<Schema>, SingleOwner>;
|
|
109
141
|
|
|
110
|
-
/** Objects whose keys a dot path walks through; arrays
|
|
111
|
-
type Walkable<T> = T extends readonly unknown[] |
|
|
142
|
+
/** Objects whose keys a dot path walks through; arrays and functions are values, never walked into. */
|
|
143
|
+
type Walkable<T> = T extends readonly unknown[] | ((...args: never[]) => unknown) ? never : T extends object ? T : never;
|
|
112
144
|
/**
|
|
113
145
|
* The union of dot paths through the nested plain objects of `T`, such as `"theme" | "notifications" |
|
|
114
146
|
* "notifications.email"`. A path never descends into an array: an array is one value, set and reset as a whole.
|
|
@@ -128,11 +160,11 @@ type Path<T> = [Walkable<T>] extends [never] ? never : {
|
|
|
128
160
|
type PathValue<T, P extends string> = P extends keyof Walkable<T> ? Walkable<T>[P] : P extends `${infer K}.${infer Rest}` ? K extends keyof Walkable<T> ? PathValue<NonNullable<Walkable<T>[K]>, Rest> | (null extends Walkable<T>[K] ? undefined : never) | (undefined extends Walkable<T>[K] ? undefined : never) : never : never;
|
|
129
161
|
/**
|
|
130
162
|
* A partial of `T` at any depth, for `update`: every key of a nested plain object may be left out or `undefined`.
|
|
131
|
-
* Arrays
|
|
163
|
+
* Arrays and functions are whole values, never partial.
|
|
132
164
|
*
|
|
133
165
|
* @typeParam T - The settings type.
|
|
134
166
|
*/
|
|
135
|
-
type DeepPartial<T> = T extends readonly unknown[] |
|
|
167
|
+
type DeepPartial<T> = T extends readonly unknown[] | ((...args: never[]) => unknown) ? T : T extends object ? {
|
|
136
168
|
[K in keyof T]?: DeepPartial<T[K]> | undefined;
|
|
137
169
|
} : T;
|
|
138
170
|
|
|
@@ -152,6 +184,10 @@ interface SettingsOptions<Definitions extends Record<string, SettingsDefinition>
|
|
|
152
184
|
* next successful write drops them. Writes read the Overrides first, so it can also be called during a write, again
|
|
153
185
|
* on each retry. Without it, ignored Overrides are dropped silently.
|
|
154
186
|
*
|
|
187
|
+
* It isn't awaited, and it can't change the result of the read or write that calls it: if it throws or returns a
|
|
188
|
+
* rejected promise, the operation goes on as if it had succeeded, and the failure goes to `console.warn` the first
|
|
189
|
+
* time only for each {@link createSettings} result.
|
|
190
|
+
*
|
|
155
191
|
* @param owner - The Owner whose Overrides were ignored.
|
|
156
192
|
* @param issues - The Standard Schema issues the Effective settings failed with, naming the ignored paths.
|
|
157
193
|
*/
|
|
@@ -259,8 +295,6 @@ interface ScopedSettings<T> {
|
|
|
259
295
|
*/
|
|
260
296
|
reset(): Promise<void>;
|
|
261
297
|
}
|
|
262
|
-
/** The settings type of a Settings definition. */
|
|
263
|
-
type SettingsOf<D> = D extends SettingsDefinition<infer T> ? T : never;
|
|
264
298
|
/** The id argument of `scope()`: none for a single-owner Scope, a string for any other. */
|
|
265
299
|
type OwnerIdArgs<D> = D extends SettingsDefinition<unknown, true> ? [] : [id: string];
|
|
266
300
|
/**
|
|
@@ -279,7 +313,10 @@ type OwnerIdArgs<D> = D extends SettingsDefinition<unknown, true> ? [] : [id: st
|
|
|
279
313
|
* @throws `RangeError` If `maxRetries` isn't a whole number, 0 or more.
|
|
280
314
|
*
|
|
281
315
|
* @example
|
|
282
|
-
* const settings = createSettings({
|
|
316
|
+
* const settings = createSettings({
|
|
317
|
+
* definitions: { user: userDefinition, global: globalDefinition },
|
|
318
|
+
* store: new MemoryStore(),
|
|
319
|
+
* });
|
|
283
320
|
* const theme = await settings.scope("user", "1").get("theme");
|
|
284
321
|
* await settings.scope("global").set("maintenanceBanner", "Back at 10:00");
|
|
285
322
|
*/
|
|
@@ -288,8 +325,11 @@ declare function createSettings<Definitions extends Record<string, SettingsDefin
|
|
|
288
325
|
* Returns the settings of one Owner of the Scope `name`.
|
|
289
326
|
*
|
|
290
327
|
* @param name - The Scope name, a key of `definitions`.
|
|
291
|
-
* @param id - The Owner's id; left out for a single-owner Scope.
|
|
328
|
+
* @param id - The Owner's id, any non-empty string; left out for a single-owner Scope. The package doesn't interpret
|
|
329
|
+
* it, so ids that differ in any way, such as `"1"` and `" 1"`, are different Owners.
|
|
292
330
|
* @throws {@link SettingsDefinitionError} If `name` isn't a key of `definitions`.
|
|
331
|
+
* @throws `TypeError` If `id` is the empty string, is missing for a normal Scope, or is given for a single-owner
|
|
332
|
+
* Scope.
|
|
293
333
|
*/
|
|
294
334
|
scope<Name extends keyof Definitions & string>(name: Name, ...id: OwnerIdArgs<Definitions[Name]>): ScopedSettings<SettingsOf<Definitions[Name]>>;
|
|
295
335
|
};
|
|
@@ -302,7 +342,7 @@ declare function createSettings<Definitions extends Record<string, SettingsDefin
|
|
|
302
342
|
* write that read a version before a delete is a conflict; the Store remembers one number per Owner it ever stored.
|
|
303
343
|
*
|
|
304
344
|
* @example
|
|
305
|
-
* const settings = createSettings({ definitions: { user }, store: new MemoryStore() });
|
|
345
|
+
* const settings = createSettings({ definitions: { user: userDefinition }, store: new MemoryStore() });
|
|
306
346
|
*/
|
|
307
347
|
declare class MemoryStore implements SettingsStore {
|
|
308
348
|
#private;
|
|
@@ -314,6 +354,230 @@ declare class MemoryStore implements SettingsStore {
|
|
|
314
354
|
delete(owner: Owner): Promise<void>;
|
|
315
355
|
}
|
|
316
356
|
|
|
357
|
+
/**
|
|
358
|
+
* The part of a Secret Vault `Vault` that {@link SealedStore} uses, so this package doesn't depend on Secret Vault.
|
|
359
|
+
* A `Vault` fits.
|
|
360
|
+
*/
|
|
361
|
+
interface SealingVault {
|
|
362
|
+
/**
|
|
363
|
+
* Seals a JSON value.
|
|
364
|
+
*
|
|
365
|
+
* @param value - The value to seal.
|
|
366
|
+
* @param context - Where the Sealed value is stored.
|
|
367
|
+
* @returns The Sealed value.
|
|
368
|
+
*/
|
|
369
|
+
encryptJson(value: unknown, context: string): Promise<string>;
|
|
370
|
+
/**
|
|
371
|
+
* Opens a Sealed value made by `encryptJson`; rejects when it doesn't open.
|
|
372
|
+
*
|
|
373
|
+
* @param sealed - The Sealed value.
|
|
374
|
+
* @param context - The Context it was sealed under.
|
|
375
|
+
* @returns The Plaintext value.
|
|
376
|
+
*/
|
|
377
|
+
decryptJson(sealed: string, context: string): Promise<unknown>;
|
|
378
|
+
/**
|
|
379
|
+
* Whether a stored value is a Sealed value rather than plain text still stored at a listed path. Optional: a Secret
|
|
380
|
+
* Vault `Vault` has `isSealed` only as a static method, so without it `SealedStore` treats a string starting with
|
|
381
|
+
* `vault:` as sealed.
|
|
382
|
+
*
|
|
383
|
+
* @param value - A stored value.
|
|
384
|
+
*/
|
|
385
|
+
isSealed?(value: unknown): boolean;
|
|
386
|
+
}
|
|
387
|
+
/**
|
|
388
|
+
* The paths to keep sealed, by Scope name, each checked against its Scope's settings type, such as
|
|
389
|
+
* `{ organization: ["smtp.password"] }`. A Scope may be left out.
|
|
390
|
+
*
|
|
391
|
+
* @typeParam Definitions - The Settings definitions by Scope name.
|
|
392
|
+
*/
|
|
393
|
+
type SealedPaths<Definitions extends Record<string, SettingsDefinition>> = {
|
|
394
|
+
readonly [Scope in keyof Definitions & string]?: readonly Path<SettingsOf<Definitions[Scope]>>[];
|
|
395
|
+
};
|
|
396
|
+
/**
|
|
397
|
+
* Options of {@link SealedStore}.
|
|
398
|
+
*
|
|
399
|
+
* @typeParam Definitions - The Settings definitions by Scope name, the same ones passed to `createSettings`.
|
|
400
|
+
*/
|
|
401
|
+
interface SealedStoreOptions<Definitions extends Record<string, SettingsDefinition>> {
|
|
402
|
+
/** The Store that keeps the Sealed values. */
|
|
403
|
+
readonly store: SettingsStore;
|
|
404
|
+
/** Seals and opens values; a Secret Vault `Vault` fits. */
|
|
405
|
+
readonly vault: SealingVault;
|
|
406
|
+
/**
|
|
407
|
+
* Each Scope's Settings definition, by Scope name: the same object passed to `createSettings`. Only used to check
|
|
408
|
+
* `paths`.
|
|
409
|
+
*/
|
|
410
|
+
readonly definitions: Definitions;
|
|
411
|
+
/**
|
|
412
|
+
* Dot paths into the settings to keep sealed, by Scope name, such as `{ organization: ["smtp.password"] }`. A path
|
|
413
|
+
* may name an object, which is sealed whole as JSON. No path may be inside another of the same Scope; two Scopes may
|
|
414
|
+
* list the same path. A Scope left out has nothing sealed: a Sealed value stored there reads back as its raw
|
|
415
|
+
* `vault:…` string.
|
|
416
|
+
*/
|
|
417
|
+
readonly paths: NoInfer<SealedPaths<Definitions>>;
|
|
418
|
+
}
|
|
419
|
+
/**
|
|
420
|
+
* A Store that keeps the Overrides at the listed paths as Sealed values in the Store it wraps, and hands the core
|
|
421
|
+
* their Plaintext. The schema validates the Plaintext, and the app calls `set` and `get` with plain values.
|
|
422
|
+
*
|
|
423
|
+
* Every write seals again with the Vault's current secret, which finishes a Rotation for that Owner. A Sealed value
|
|
424
|
+
* that doesn't open makes the read throw: it is never ignored as a stale Override, because the next write would
|
|
425
|
+
* replace the secret with its default. A plain value at a listed path reads as it is and is sealed on the Owner's next
|
|
426
|
+
* write. Values at unlisted paths are never opened.
|
|
427
|
+
*
|
|
428
|
+
* Paths are listed per Scope and checked against each Scope's settings type, so a misspelled path doesn't compile. Only
|
|
429
|
+
* the paths listed for an Owner's Scope are sealed and opened; the same path in another Scope stays plain.
|
|
430
|
+
*
|
|
431
|
+
* Nest it outermost, around a {@link CachedStore}, so the cache holds only Sealed values.
|
|
432
|
+
*
|
|
433
|
+
* @typeParam Definitions - The Settings definitions by Scope name.
|
|
434
|
+
*
|
|
435
|
+
* @example
|
|
436
|
+
* const store = new SealedStore({
|
|
437
|
+
* store: new PrismaStore({ delegate: prisma.setting }),
|
|
438
|
+
* vault,
|
|
439
|
+
* definitions: { user, organization },
|
|
440
|
+
* paths: { organization: ["smtp.password"] },
|
|
441
|
+
* });
|
|
442
|
+
*/
|
|
443
|
+
declare class SealedStore<Definitions extends Record<string, SettingsDefinition> = Record<string, SettingsDefinition>> implements SettingsStore {
|
|
444
|
+
#private;
|
|
445
|
+
/**
|
|
446
|
+
* @param options - The Store to wrap, the Vault, the Settings definitions and the sealed paths by Scope.
|
|
447
|
+
* @throws `TypeError` when no Scope lists a path, a Scope in `paths` isn't in `definitions`, a path is empty, or a
|
|
448
|
+
* path is inside another of the same Scope.
|
|
449
|
+
*/
|
|
450
|
+
constructor(options: SealedStoreOptions<Definitions>);
|
|
451
|
+
/** {@inheritDoc SettingsStore.read} */
|
|
452
|
+
read(owner: Owner): Promise<StoredOverrides | null>;
|
|
453
|
+
/** {@inheritDoc SettingsStore.write} */
|
|
454
|
+
write(owner: Owner, overrides: Record<string, unknown>, expectedVersion: number | null): Promise<number | null>;
|
|
455
|
+
/**
|
|
456
|
+
* Removes one Sealed value that won't open, so the Owner can read its settings and set a new secret again; its
|
|
457
|
+
* other Sealed values stay sealed and aren't opened, and a plain value at another listed path is sealed, as on any
|
|
458
|
+
* write. Its other Overrides stay as they are. A value that opens, a
|
|
459
|
+
* plain value and an empty path are left alone, so running it again after the Owner set a new secret changes
|
|
460
|
+
* nothing. Any rejection from `decryptJson` counts as not opening.
|
|
461
|
+
*
|
|
462
|
+
* **Check the Vault secret first.** With a wrong or missing secret every Sealed value fails to open, so `discard`
|
|
463
|
+
* would remove secrets that fixing the configuration would have recovered.
|
|
464
|
+
*
|
|
465
|
+
* It reads the wrapped Store and writes with the version it read. On a conflict it reads again and retries, up to 3
|
|
466
|
+
* times; a {@link CachedStore} underneath evicts on the conflict, so the retry reads fresh Overrides.
|
|
467
|
+
*
|
|
468
|
+
* @param owner - The Owner whose Sealed value to remove.
|
|
469
|
+
* @param path - A path listed for the Owner's Scope, such as `"smtp.password"`.
|
|
470
|
+
* @returns `true` when a Sealed value that won't open was removed, `false` when nothing was changed.
|
|
471
|
+
* @throws `TypeError` when `path` isn't listed for the Owner's Scope.
|
|
472
|
+
* @throws {@link SettingsConflictError} when every write lost the version race to another write.
|
|
473
|
+
*/
|
|
474
|
+
discard(owner: Owner, path: string): Promise<boolean>;
|
|
475
|
+
/** {@inheritDoc SettingsStore.delete} */
|
|
476
|
+
delete(owner: Owner): Promise<void>;
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
/**
|
|
480
|
+
* A cache of strings with a time to live, which {@link CachedStore} keeps Overrides in. {@link MemoryCache} fits;
|
|
481
|
+
* so does a thin wrapper around Redis or Keyv.
|
|
482
|
+
*/
|
|
483
|
+
interface SettingsCache {
|
|
484
|
+
/**
|
|
485
|
+
* Reads an entry.
|
|
486
|
+
*
|
|
487
|
+
* @param key - The cache key.
|
|
488
|
+
* @returns The value, or `undefined` when there is none or it expired.
|
|
489
|
+
*/
|
|
490
|
+
get(key: string): Promise<string | undefined>;
|
|
491
|
+
/**
|
|
492
|
+
* Stores an entry, replacing any under the key.
|
|
493
|
+
*
|
|
494
|
+
* @param key - The cache key.
|
|
495
|
+
* @param value - The string to keep.
|
|
496
|
+
* @param ttlSeconds - Seconds until the entry expires.
|
|
497
|
+
*/
|
|
498
|
+
set(key: string, value: string, ttlSeconds: number): Promise<void>;
|
|
499
|
+
/**
|
|
500
|
+
* Removes an entry; removing a missing one does nothing.
|
|
501
|
+
*
|
|
502
|
+
* @param key - The cache key.
|
|
503
|
+
*/
|
|
504
|
+
delete(key: string): Promise<void>;
|
|
505
|
+
}
|
|
506
|
+
/** Options of {@link CachedStore}. */
|
|
507
|
+
interface CachedStoreOptions {
|
|
508
|
+
/** The Store to read through. */
|
|
509
|
+
readonly store: SettingsStore;
|
|
510
|
+
/** Where to keep what the Store returns. */
|
|
511
|
+
readonly cache: SettingsCache;
|
|
512
|
+
/** Seconds an entry stays cached. */
|
|
513
|
+
readonly ttl: number;
|
|
514
|
+
/** Starts every cache key. Defaults to `"settings"`. */
|
|
515
|
+
readonly prefix?: string;
|
|
516
|
+
/**
|
|
517
|
+
* Called with an error a cache method threw; the Store then answers instead.
|
|
518
|
+
*
|
|
519
|
+
* It isn't awaited, and it can't change the result of the read, write or delete that calls it: if it throws or
|
|
520
|
+
* returns a rejected promise, the operation goes on as if it had succeeded, so a write still returns the wrapped
|
|
521
|
+
* Store's result. The failure goes to `console.warn` the first time only for each {@link CachedStore}.
|
|
522
|
+
*/
|
|
523
|
+
readonly onError?: (error: unknown) => void;
|
|
524
|
+
}
|
|
525
|
+
/**
|
|
526
|
+
* A Store that keeps what the Store it wraps returns in a cache for `ttl` seconds, an Owner with nothing stored
|
|
527
|
+
* included. Every write, conflict and delete evicts the Owner, so a conflicting write retries against fresh Overrides,
|
|
528
|
+
* and a write on this instance is read back at once by this instance, even when one of its reads of that Owner was in
|
|
529
|
+
* flight during the write: a read that an eviction overtook returns what it read but doesn't cache it. A cache that
|
|
530
|
+
* throws is reported to `onError` and the Store answers instead.
|
|
531
|
+
*
|
|
532
|
+
* With a per-process cache and several instances, another instance can read Overrides up to `ttl` seconds old. Share
|
|
533
|
+
* a cache, such as Redis, to avoid most of it. Even then, a read on another instance that was in flight during the
|
|
534
|
+
* write can still cache the old Overrides, which are then read for up to `ttl` seconds.
|
|
535
|
+
*
|
|
536
|
+
* @example
|
|
537
|
+
* const store = new CachedStore({ store: prismaStore, cache: new MemoryCache(), ttl: 60 });
|
|
538
|
+
*/
|
|
539
|
+
declare class CachedStore implements SettingsStore {
|
|
540
|
+
#private;
|
|
541
|
+
/**
|
|
542
|
+
* @param options - The Store to wrap, the cache and the TTL.
|
|
543
|
+
* @throws `RangeError` when `ttl` isn't a positive number.
|
|
544
|
+
*/
|
|
545
|
+
constructor(options: CachedStoreOptions);
|
|
546
|
+
/** {@inheritDoc SettingsStore.read} */
|
|
547
|
+
read(owner: Owner): Promise<StoredOverrides | null>;
|
|
548
|
+
/** {@inheritDoc SettingsStore.write} */
|
|
549
|
+
write(owner: Owner, overrides: Record<string, unknown>, expectedVersion: number | null): Promise<number | null>;
|
|
550
|
+
/** {@inheritDoc SettingsStore.delete} */
|
|
551
|
+
delete(owner: Owner): Promise<void>;
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
/** Options of {@link MemoryCache}. */
|
|
555
|
+
interface MemoryCacheOptions {
|
|
556
|
+
/** Most entries kept; the oldest are evicted past it. Defaults to 1000. */
|
|
557
|
+
readonly maxEntries?: number;
|
|
558
|
+
}
|
|
559
|
+
/**
|
|
560
|
+
* A {@link SettingsCache} in process memory. Entries expire after their TTL and the oldest are evicted past
|
|
561
|
+
* `maxEntries`. It is per process: instances don't share it.
|
|
562
|
+
*
|
|
563
|
+
* @example
|
|
564
|
+
* const cache = new MemoryCache({ maxEntries: 5000 });
|
|
565
|
+
*/
|
|
566
|
+
declare class MemoryCache implements SettingsCache {
|
|
567
|
+
#private;
|
|
568
|
+
/**
|
|
569
|
+
* @param options - The size limit.
|
|
570
|
+
* @throws `RangeError` when `maxEntries` isn't a positive integer.
|
|
571
|
+
*/
|
|
572
|
+
constructor(options?: MemoryCacheOptions);
|
|
573
|
+
/** {@inheritDoc SettingsCache.get} */
|
|
574
|
+
get(key: string): Promise<string | undefined>;
|
|
575
|
+
/** {@inheritDoc SettingsCache.set} */
|
|
576
|
+
set(key: string, value: string, ttlSeconds: number): Promise<void>;
|
|
577
|
+
/** {@inheritDoc SettingsCache.delete} */
|
|
578
|
+
delete(key: string): Promise<void>;
|
|
579
|
+
}
|
|
580
|
+
|
|
317
581
|
/**
|
|
318
582
|
* A write would make an Owner's Effective settings fail its Scope's schema, so nothing was stored. `issues` are the
|
|
319
583
|
* Standard Schema issues, with paths into the Effective settings, for showing next to a form field.
|
|
@@ -358,4 +622,4 @@ declare class SettingsDefinitionError extends Error {
|
|
|
358
622
|
constructor(message: string, scope: string, issues?: ReadonlyArray<StandardSchemaV1.Issue>);
|
|
359
623
|
}
|
|
360
624
|
|
|
361
|
-
export { MemoryStore, Owner, type Path, type PathValue, type ScopedSettings, SettingsConflictError, type SettingsDefinition, SettingsDefinitionError, type SettingsOptions, SettingsStore, SettingsValidationError, StoredOverrides, createSettings, defineSettings };
|
|
625
|
+
export { CachedStore, type CachedStoreOptions, MemoryCache, type MemoryCacheOptions, MemoryStore, Owner, type Path, type PathValue, type ScopedSettings, type SealedPaths, SealedStore, type SealedStoreOptions, type SealingVault, type SettingsCache, SettingsConflictError, type SettingsDefinition, SettingsDefinitionError, type SettingsOptions, SettingsStore, SettingsValidationError, StoredOverrides, createSettings, defineSettings };
|