memory.ts 1.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354
  1. /**
  2. * In-memory settings provider fixture: the smallest real subclass of the seam,
  3. * used by the base-class behavior suite in place of a file- or network-backed
  4. * provider. Kept in `tests/` because production providers live in their own
  5. * packages.
  6. */
  7. import { Settings, type SettingsNamespace } from '../src/index.ts'
  8. /** In-memory provider exposing the protected seam hooks to tests. */
  9. export class MemorySettings extends Settings {
  10. /** Raw document the provider "storage" currently holds. */
  11. doc: Record<string, unknown>
  12. /** Every persist() call observed, in order. */
  13. persisted: Array<{ ns: SettingsNamespace; section: Record<string, unknown> }> = []
  14. /** When false, update() must reject before reaching persist(). */
  15. writableFlag: boolean
  16. /** Artificial persist latency so tests can interleave concurrent updates. */
  17. persistDelayMs: number
  18. constructor(ctx: ConstructorParameters<typeof Settings>[0], options?: {
  19. doc?: Record<string, unknown>
  20. writable?: boolean
  21. persistDelayMs?: number
  22. }) {
  23. super(ctx)
  24. this.doc = structuredClone(options?.doc ?? {})
  25. this.writableFlag = options?.writable ?? true
  26. this.persistDelayMs = options?.persistDelayMs ?? 0
  27. }
  28. get writable(): boolean {
  29. return this.writableFlag
  30. }
  31. protected load(): Promise<Record<string, unknown>> {
  32. return Promise.resolve(structuredClone(this.doc))
  33. }
  34. protected async persist(ns: SettingsNamespace, section: Record<string, unknown>): Promise<void> {
  35. if (this.persistDelayMs > 0) {
  36. await new Promise(resolve => setTimeout(resolve, this.persistDelayMs))
  37. }
  38. this.persisted.push({ ns, section: structuredClone(section) })
  39. this.doc[ns] = structuredClone(section)
  40. }
  41. /** Simulate an external storage change reaching the provider. */
  42. pushExternal(doc: Record<string, unknown>): void {
  43. this.doc = structuredClone(doc)
  44. this.publish(structuredClone(doc))
  45. }
  46. }