{"id":19356867,"url":"https://github.com/alexfigliolia/enhanced-stores","last_synced_at":"2026-04-17T06:02:44.346Z","repository":{"id":184913938,"uuid":"672621899","full_name":"alexfigliolia/enhanced-stores","owner":"alexfigliolia","description":"An enhancer library for svelte stores that supports middleware","archived":false,"fork":false,"pushed_at":"2024-04-30T00:06:30.000Z","size":403,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-02-06T18:11:43.714Z","etag":null,"topics":["derived","enhancers","middleware","readable","state","stores","svelte","writable"],"latest_commit_sha":null,"homepage":"https://www.npmjs.com/package/@figliolia/enhanced-stores","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/alexfigliolia.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-07-30T17:46:53.000Z","updated_at":"2024-04-30T00:06:33.000Z","dependencies_parsed_at":"2024-01-13T06:07:15.151Z","dependency_job_id":"43e9cdcb-ad9c-4ad9-bd45-ca7e4d06977b","html_url":"https://github.com/alexfigliolia/enhanced-stores","commit_stats":null,"previous_names":["alexfigliolia/enhanced-stores"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alexfigliolia%2Fenhanced-stores","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alexfigliolia%2Fenhanced-stores/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alexfigliolia%2Fenhanced-stores/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alexfigliolia%2Fenhanced-stores/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/alexfigliolia","download_url":"https://codeload.github.com/alexfigliolia/enhanced-stores/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":240473290,"owners_count":19807113,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["derived","enhancers","middleware","readable","state","stores","svelte","writable"],"created_at":"2024-11-10T07:05:43.505Z","updated_at":"2026-04-17T06:02:39.323Z","avatar_url":"https://github.com/alexfigliolia.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Enhanced Stores\nAn extension of Svelte's `store` API's that support the usage of middleware enhancers! \n\n# Getting Started\n\n## Installation\n```bash\nnpm install --save @figliolia/enhanced-stores\n# or\nyarn add @figliolia/enhanced-stores\n```\n\n## Background \nSvelte Stores are a great way to manage isolated slices of state in your Svelte projects. Their only shortcoming is that they lack some of the convenient API's of more seasoned state management libraries such as Redux, MobX, and *__insert library here__*. \n\nThis library is designed to allow developers to polyfill their own features into their Svelte stores through a familiar middleware API.\n\nThis library wraps each stores provided by Svelte and **fully** implements their API's. \n\nThis means, you can drop in this library anywhere you're currently using `Svelte` stores - with no refactoring required!\n\n## Basic Usage\nTo begin using and creating middleware for your Svelte stores, simply import an `EnhancedWritable`, `EnhancedReadable`, or `EnhancedDerived`. Each of these instances work identically to `Svelte` stores and support `get()` and `$value` syntax:\n\n#### Creating Stores\n\n##### `EnhancedWriteable`\nThe `EnhancedWritable` is a `writable` instance that exposes a `registerMiddleware` method\n```typescript\nimport { EnhancedWritable } from \"@figliolia/enhanced-stores\";\n\nconst listItems = new EnhancedWritable(\"List Items\", [1, 2, 3]);\n/* \n  Enhanced Stores require a string as their first parameter\n\n  This string represents a name for this piece of state and \n  is used to identify specific stores from within your middleware\n\n  The parameters following the name are identical to Svelte's writable\n*/\n\nlistItems.set([1, 2, 3, 4]);\nlistItems.update(v =\u003e [...v, 4]);\nlistItems.subscribe((v) =\u003e {});\nlistItems.registerMiddleware(/* ...middleware */);\n\n$listItems // [1, 2, 3, 4]\nget(listItems) // [1, 2, 3, 4]\n```\n\n##### `EnhancedDerived`\nThe `EnhancedDerived` is a `derived` instance that exposes a `registerMiddleware` method\n```typescript\nimport { \n  EnhancedDerived,\n  EnhancedWritable, \n} from \"@figliolia/enhanced-stores\";\n\nconst base = new EnhancedWritable(\"Base Items\", [1, 2, 3]);\n// Create a derived instance from an EnhancedWritable or Svelte writable\nconst listItems = new EnhancedDerived(\n  \"List Items\",\n  base, \n  (v) =\u003e v.map(el =\u003e el + 1)\n);\n\nlistItems.subscribe((v) =\u003e {});\nlistItems.registerMiddleware(/* ...middleware */);\n\n$listItems // [2, 3, 4]\nget(listItems) // [2, 3, 4]\n```\n\n##### `EnhancedReadable`\nThe `EnhancedReadable` is a `readable` instance that exposes a `registerMiddleware` method\n```typescript\nimport { EnhancedReadable } from \"@figliolia/enhanced-stores\";\n\nconst time = new EnhancedReadable(\"Time\", Date.now(), set =\u003e {\n  const interval = setInterval(() =\u003e {\n    set(Date.now());\n  }, 1000);\n \n  return function stop() {\n    clearInterval(interval);\n  };\n});\n\nlistItems.subscribe((v) =\u003e {});\nlistItems.registerMiddleware(/* ...middleware */);\n\n$listItems // Unix time stamp\nget(listItems) // Unix time stamp\n```\n\n## Using Middleware\nThe primary purpose of this library and the stores it exposes is for creating enhancements to the default behavior of Svelte stores.\n\nLet's look at some useful examples\n\n\n### Logging Middleware \nThis library comes with a redux-like logging middleware for your stores. To enable it, import the `Logger` and one of the `Enhanced*` stores:\n\n```typescript\nimport { EnhancedWritable, Logger } from \"@figliolia/enhanced-stores\";\n\nconst ListItems = new EnhancedWritable(\"List Items\", [1, 2, 3]);\n\nif(process.env.NODE_ENV === \"development\") {\n  // Enable logging!\n  ListItems.registerMiddleware(new Logger());\n}\n\n// Set state using `set` or `update`\nListItems.set([1, 2, 3, 4]);\n// or\nListItems.update(v =\u003e [...v, 4]);\n```\nJust like that, you now have a history of your `writable's` state updates in your console during development mode.\n\n![Logs](images/Logging.png)\n\n\n#### Profiling Middleware\nIn addition to logging, this library comes with one of my more favored middlewares - a profiler for inefficient state updates. This middleware, will issue a warning to the console anytime it detects a bottleneck in one of your stores:\n\n```typescript\nimport { EnhancedWritable, Profiler } from \"@figliolia/enhanced-stores\";\n\nconst ListItems = new EnhancedWritable(\"List Items\", [1, 2, 3]);\n\nif(process.env.NODE_ENV === \"development\") {\n\t// Enable profiling!\n  ListItems.registerMiddleware(new Profiler());\n}\n\n// Set state \nListItems.update(v =\u003e {\n  // intentional bottleneck\n  for(let i = 0; i \u003c 100000000; i++) {};\n  return [...v, 4];\n});\n```\nWhen bottlenecks are identified in your `writable` or `derived` state updates, you'll receive warnings like this one:\n\n![Logs](images/Profiling.png)\n\n### Building Your Own Middleware\nTo build your own middleware, simply extend the `Middleware` class provided by this library and override its methods:\n\n```typescript\nimport { Middleware } from \"@figliolia/enhanced-stores\";\n\nclass MyMiddleware\u003cT\u003e extends Middleware\u003cT\u003e {\n  public override onInitialize(name: string, state: T) {\n    // Execute logic on initialization of a store\n  }\n  public override onBeforeUpdate(name: string, state: T) {\n    // Execute logic before updates take place\n  }\n\n  public override onUpdate(name: string, state: T) {\n    // Execute logic after state updates\n  }\n} \n```\nEach method found above receives the name of the `writable`, `readable`, or `derived` store along with its current value.\n\n#### A Real World Example - Profiling\nTo better demonstrate how to build useful tools using the middleware API, let's build the `Profiling Middleware` found in this library:\n\n```typescript\nimport { Middleware } from \"@figliolia/enhanced-stores\";\n\n// Extend the Base class\nexport class Profiler\u003cT\u003e extends Middleware\u003cT\u003e {\n  public threshold: number;\n  private lastUpdate: number | null = null;\n\t// Accept a threshold parameter\n  constructor(threshold: number = 16) {\n    this.threshold = threshold;\n  }\n  // Capture a high-res timestamp before each update\n  public override onBeforeUpdate(name: string, state: T) {\n    this.lastUpdate = performance.now();\n  }\n\n  // Compare the current high-res timestamp with the previous\n  public override onUpdate(name: string, state: T) {\n    if(performance.now() - this.lastUpdate \u003e this.threshold) {\n      // Issue a warning if a state update exceeds the threshold\n      console.warn(\"Slow state update detected on\", name);\n    }\n  }\n} \n```\n\n#### A Real World Example - Testing\nTesting stores using their update history can be a meaningful way to ensure that certain side-effects occur in your test cases. Let's create a middleware that tracks each update to your stores and provides a means for making assertions:\n\n```typescript\nimport { Middleware } from \"@figliolia/enhanced-stores\";\n\n// Extend the Base class\nexport class Testing\u003cT\u003e extends Middleware\u003cT\u003e {\n  public history: T[] = [];\n\n  // Push the initial value to the history array\n  public override onInitialization(name: string, state: T) {\n    this.history.push(state);\n  }\n\n  // Push each state update to the history array\n  public override onUpdate(name: string, state: T) {\n    this.history.push(state);\n  }\n\n  // Expose a method for asserting that the store's\n  // update history matches the input\n  public assert(history: T[]) {\n    const { length } = this.history;\n    for(let i = 0; i \u003c length; i++) {\n      if(this.history[i] !== history[i]) {\n        return false;\n      }\n    }\n    return true;\n  }\n} \n```\n\nSimply register this middleware on your stores in testing environments and make assertions based on the store's update history\n\n## Factories\nIn your application, you may find yourself registering the same middleware to each new store you create. To reduce the amount of boiler plate required to enhance your stores, this library comes with an `EnhancerFactory`.\n\nEnhancer Factories are factories that are constructed with one or more middleware. From your factories, you can spawn, `readable`, `writable`, and `derived` stores with your middleware already registered to them:\n\n```typescript\nimport { EnhancerFactory, Logger, Profiler } from \"@figliolia/enhanced-stores\";\n\nconst Factory = new EnhancerFactory(\n  new Logger(), \n  new Profiler()\n  // ...and so on\n);\n\nconst writable = Factory.createWritable(/* enhanced store arguments*/);\nconst derived = Factory.createDerived(/* enhanced derived arguments*/);\nconst readable = Factory.createReadable(/* enhanced readable arguments*/);\n```\nEach of the `create` methods found on the `Factory` will return an `enhanced` readable, writable, or derived instance with the `Logger` and `Profiler` registered to it.\n\n## Contributing\nThis library was built with the intention of adding some useful mechanisms for extending the behavior of Svelte stores. It's designed to help Svelte Stores reach some feature-parity with popular state management tools that have become prolific in the frontend world.\n\nIf you see identify a bug or a better way of achieving this, your contributions and welcome and supported.","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Falexfigliolia%2Fenhanced-stores","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Falexfigliolia%2Fenhanced-stores","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Falexfigliolia%2Fenhanced-stores/lists"}