idb-refined 0.0.2 → 0.0.3

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  # idb-refined
2
2
 
3
- Thin TypeScript IndexedDB helper on top of [idb](https://www.npmjs.com/package/idb): init DB with auto-version, clean by date or size, add with eviction, and delete helpers.
3
+ Minimal IndexedDB client on top of [idb](https://www.npmjs.com/package/idb). Exposes **add**, **update**, **delete**, and **removeDb**. Init, schema, cleanup and eviction run automatically.
4
4
 
5
5
  ## Install
6
6
 
@@ -12,71 +12,45 @@ npm install idb-refined
12
12
 
13
13
  ## API
14
14
 
15
- | Function | Purpose |
16
- |----------|---------|
17
- | **initDb(name, options?)** | Open or create a DB. Version is auto-detected when you pass a declarative `schema`; or use manual `version` and `upgrade`. Returns idb’s `IDBPDatabase`. |
18
- | **cleanOldEntries(db, storeName, options)** | Delete entries where `dateKey` < `before` (timestamp ms). Requires an index on `dateKey`. |
19
- | **cleanWhenTooLarge(db, storeName, options)** | Evict oldest entries (by `dateKey`) until count ≤ `maxCount`. Returns count deleted. Requires an index on `dateKey`. `maxCount` is optional. |
20
- | **putWithEviction(db, storeName, value, options)** | Put value, then if store count > `maxCount` evict oldest by `dateKey`. Options may include `expiresAt` (ms), `ttlSeconds` (seconds), and optional `maxCount`. |
21
- | **deleteByKey(db, storeName, key)** | Delete a single entry by key. |
22
- | **clearStore(db, storeName)** | Delete all entries in a store. |
23
- | **deleteDB(name)** | Re-export of idb’s `deleteDB`. |
15
+ | Export | Purpose |
16
+ |--------|---------|
17
+ | **createClient(options)** | Returns `{ set, get, update, delete, deleteDb }`. Options: `dbName` (required), `storeName` (optional). |
18
+ | **set(value)** | Store a value. Value must have an `id` property. Expiry and eviction run automatically. |
19
+ | **get(key)** | Get a value by key. Returns `undefined` if not found. |
20
+ | **update(key, value)** | Update an existing entry by key. |
21
+ | **delete(key)** | Delete an entry by key. |
22
+ | **deleteDb()** | Close the DB and delete it from disk. |
24
23
 
25
- For parameter details, behavior, and use-case explanations, see **[Advanced documentation](docs/advanced.md)**.
24
+ For details, see **[Advanced documentation](docs/advanced.md)**. Run the **[example](example/)** in the browser (see `example/README.md`).
26
25
 
27
- ## Examples
28
-
29
- ### Cache with TTL and max size
26
+ ## Example
30
27
 
31
28
  ```ts
32
- import { initDb, putWithEviction, cleanOldEntries, deleteByKey } from "idb-refined";
33
-
34
- const db = await initDb("my-cache", {
35
- schema: {
36
- stores: {
37
- cache: { keyPath: "id", indexes: ["expiresAt"] },
38
- },
39
- },
40
- });
41
-
42
- await putWithEviction(db, "cache", { id: "k1", data: "v1" }, {
43
- dateKey: "expiresAt",
44
- maxCount: 1000,
45
- ttlSeconds: 3600,
46
- });
47
-
48
- await cleanOldEntries(db, "cache", { dateKey: "expiresAt", before: Date.now() });
49
- await deleteByKey(db, "cache", "k1");
50
- ```
29
+ import { createClient } from "idb-refined";
51
30
 
52
- ### Log buffer
31
+ // Optional: type the stored value for set/get/update
32
+ type User = { id: string; name: string; createdAt?: number; expiresAt?: number };
33
+ const { set, get, update, delete: del, deleteDb } = createClient<User>({ dbName: "my-app" });
53
34
 
54
- ```ts
55
- await putWithEviction(db, "logs", { id: generateId(), message }, {
56
- dateKey: "createdAt",
57
- maxCount: 5000,
58
- });
59
- ```
60
-
61
- ### Manual eviction
62
-
63
- ```ts
64
- const deleted = await cleanWhenTooLarge(db, "cache", { dateKey: "expiresAt", maxCount: 500 });
65
- console.log(`Evicted ${deleted} entries`);
35
+ await set({ id: "1", name: "Alice" });
36
+ const value = await get("1"); // User | undefined
37
+ await update("1", { name: "Alice Updated" });
38
+ await del("1");
39
+ await deleteDb();
66
40
  ```
67
41
 
68
42
  ## Requirements
69
43
 
70
- - Stores used with `cleanOldEntries`, `cleanWhenTooLarge`, or `putWithEviction` must have an **index** on the date field (e.g. `expiresAt`, `createdAt`). Define it in your schema.
71
- - Eviction is **count-based** only (no byte-size or quota check).
44
+ - Values must include an `id` property (used as the store key).
45
+ - The library uses a single store (default name `"store"`) with indexes on `expiresAt` and `createdAt`. Cleanup and eviction run on set.
72
46
 
73
47
  ## Releasing
74
48
 
75
49
  1. Bump version: `pnpm version patch` (or `minor` / `major`).
76
50
  2. Commit and push: `git push && git push --tags`.
77
- 3. Pushing a tag matching `v*` (e.g. `v0.0.2`) triggers the [Publish to npm](.github/workflows/publish.yml) workflow, which runs build and `pnpm publish`.
51
+ 3. Pushing a tag matching `v*` triggers the [Publish to npm](.github/workflows/publish.yml) workflow.
78
52
 
79
- **Required:** Add an `NPM_TOKEN` secret in the repo (Settings → Secrets and variables → Actions). Use an npm [access token](https://www.npmjs.com/settings/~/tokens) or granular token with publish permission.
53
+ **Required:** Add an `NPM_TOKEN` secret in the repo (Settings → Secrets and variables → Actions).
80
54
 
81
55
  ## License
82
56
 
@@ -1,7 +1,8 @@
1
1
  import type { IDBPDatabase } from "idb";
2
2
  export interface CleanWhenTooLargeOptions {
3
3
  dateKey: string;
4
- maxCount: number;
4
+ /** Target max entries after eviction. */
5
+ maxCount?: number;
5
6
  }
6
7
  /**
7
8
  * Evict oldest entries (by dateKey) until store count <= maxCount.
@@ -1,9 +1,11 @@
1
+ const DEFAULT_MAX_COUNT = 1000;
1
2
  /**
2
3
  * Evict oldest entries (by dateKey) until store count <= maxCount.
3
4
  * Requires an index on dateKey. Returns the number of entries deleted.
4
5
  */
5
6
  export async function cleanWhenTooLarge(db, storeName, options) {
6
- const { dateKey, maxCount } = options;
7
+ const { dateKey } = options;
8
+ const maxCount = options.maxCount ?? DEFAULT_MAX_COUNT;
7
9
  const count = await db.count(storeName);
8
10
  if (count <= maxCount)
9
11
  return 0;
@@ -0,0 +1,21 @@
1
+ export interface CreateClientOptions {
2
+ dbName: string;
3
+ storeName?: string;
4
+ }
5
+ /** Stored value must have `id`. `createdAt` and `expiresAt` are set by the client if missing. */
6
+ export type StoredValue = Record<string, unknown> & {
7
+ id: IDBValidKey;
8
+ };
9
+ export interface IdbRefinedClient<T extends StoredValue = StoredValue> {
10
+ add: (value: T) => Promise<void>;
11
+ get: (key: IDBValidKey) => Promise<T | undefined>;
12
+ update: (key: IDBValidKey, value: Partial<T>) => Promise<void>;
13
+ delete: (key: IDBValidKey) => Promise<void>;
14
+ removeDb: () => Promise<void>;
15
+ }
16
+ /**
17
+ * Create a client that exposes add, get, update, delete, removeDb.
18
+ * Init, schema, cleanup and eviction run automatically.
19
+ * @template T - Stored value shape (must include `id`). Omit for a generic client.
20
+ */
21
+ export declare function createClient<T extends StoredValue = StoredValue>(options: CreateClientOptions): IdbRefinedClient<T>;
package/dist/client.js ADDED
@@ -0,0 +1,84 @@
1
+ import { deleteDB } from "idb";
2
+ import { initDb } from "./initDb.js";
3
+ import { cleanOldEntries } from "./cleanOldEntries.js";
4
+ import { cleanWhenTooLarge } from "./cleanWhenTooLarge.js";
5
+ const DEFAULT_STORE_NAME = "store";
6
+ const DEFAULT_KEY_PATH = "id";
7
+ const DATE_INDEXES = ["expiresAt", "createdAt"];
8
+ const DEFAULT_TTL_MS = 3600 * 1000;
9
+ const DEFAULT_MAX_COUNT = 1000;
10
+ const dbCache = new Map();
11
+ function getDefaultSchema(storeName) {
12
+ return {
13
+ stores: {
14
+ [storeName]: {
15
+ keyPath: DEFAULT_KEY_PATH,
16
+ indexes: DATE_INDEXES,
17
+ },
18
+ },
19
+ };
20
+ }
21
+ async function getDb(dbName, storeName) {
22
+ let db = dbCache.get(dbName);
23
+ if (db != null)
24
+ return db;
25
+ const schema = getDefaultSchema(storeName);
26
+ db = await initDb(dbName, { schema });
27
+ dbCache.set(dbName, db);
28
+ return db;
29
+ }
30
+ function setExpiryFields(value) {
31
+ const now = Date.now();
32
+ if (value.createdAt === undefined)
33
+ value.createdAt = now;
34
+ if (value.expiresAt === undefined)
35
+ value.expiresAt = now + DEFAULT_TTL_MS;
36
+ }
37
+ /**
38
+ * Create a client that exposes add, get, update, delete, removeDb.
39
+ * Init, schema, cleanup and eviction run automatically.
40
+ * @template T - Stored value shape (must include `id`). Omit for a generic client.
41
+ */
42
+ export function createClient(options) {
43
+ const { dbName } = options;
44
+ const storeName = options.storeName ?? DEFAULT_STORE_NAME;
45
+ return {
46
+ async add(value) {
47
+ const db = await getDb(dbName, storeName);
48
+ setExpiryFields(value);
49
+ await db.put(storeName, value);
50
+ const count = await db.count(storeName);
51
+ if (count > DEFAULT_MAX_COUNT) {
52
+ await cleanWhenTooLarge(db, storeName, {
53
+ dateKey: "createdAt",
54
+ maxCount: DEFAULT_MAX_COUNT,
55
+ });
56
+ }
57
+ await cleanOldEntries(db, storeName, {
58
+ dateKey: "expiresAt",
59
+ before: Date.now(),
60
+ });
61
+ },
62
+ async get(key) {
63
+ const db = await getDb(dbName, storeName);
64
+ return (await db.get(storeName, key));
65
+ },
66
+ async update(key, value) {
67
+ const db = await getDb(dbName, storeName);
68
+ const withKey = { ...value, [DEFAULT_KEY_PATH]: key };
69
+ await db.put(storeName, withKey);
70
+ },
71
+ async delete(key) {
72
+ const db = await getDb(dbName, storeName);
73
+ await db.delete(storeName, key);
74
+ },
75
+ async removeDb() {
76
+ const db = dbCache.get(dbName);
77
+ if (db != null) {
78
+ db.close();
79
+ dbCache.delete(dbName);
80
+ }
81
+ await deleteDB(dbName);
82
+ },
83
+ };
84
+ }
package/dist/index.d.ts CHANGED
@@ -1,13 +1,2 @@
1
- export { initDb } from "./initDb.js";
2
- export type { InitDbOptions } from "./initDb.js";
3
- export { cleanOldEntries } from "./cleanOldEntries.js";
4
- export type { CleanOldEntriesOptions } from "./cleanOldEntries.js";
5
- export { cleanWhenTooLarge } from "./cleanWhenTooLarge.js";
6
- export type { CleanWhenTooLargeOptions } from "./cleanWhenTooLarge.js";
7
- export { putWithEviction } from "./putWithEviction.js";
8
- export type { PutWithEvictionOptions } from "./putWithEviction.js";
9
- export { deleteByKey, clearStore } from "./delete.js";
10
- export { deleteDB } from "idb";
11
- export type { IDBPDatabase, DBSchema } from "idb";
12
- export type { SchemaDef, StoreDef } from "./schema.js";
13
- export { fingerprint, applySchema } from "./schema.js";
1
+ export { createClient } from "./client.js";
2
+ export type { CreateClientOptions, IdbRefinedClient, StoredValue, } from "./client.js";
package/dist/index.js CHANGED
@@ -1,7 +1 @@
1
- export { initDb } from "./initDb.js";
2
- export { cleanOldEntries } from "./cleanOldEntries.js";
3
- export { cleanWhenTooLarge } from "./cleanWhenTooLarge.js";
4
- export { putWithEviction } from "./putWithEviction.js";
5
- export { deleteByKey, clearStore } from "./delete.js";
6
- export { deleteDB } from "idb";
7
- export { fingerprint, applySchema } from "./schema.js";
1
+ export { createClient } from "./client.js";
@@ -2,7 +2,8 @@ import type { IDBPDatabase } from "idb";
2
2
  export interface PutWithEvictionOptions {
3
3
  key?: IDBValidKey;
4
4
  dateKey: string;
5
- maxCount: number;
5
+ /** Evict oldest when store count exceeds this. */
6
+ maxCount?: number;
6
7
  /** Absolute expiry timestamp (ms). If set, used for the dateKey field on the value. */
7
8
  expiresAt?: number;
8
9
  /** Relative expiry in seconds. Used when expiresAt is not set; then dateKey = now + ttlSeconds * 1000. */
@@ -1,19 +1,22 @@
1
1
  import { cleanWhenTooLarge } from "./cleanWhenTooLarge.js";
2
2
  const DEFAULT_TTL_SECONDS = 3600;
3
+ const DEFAULT_MAX_COUNT = 1000;
3
4
  /**
4
5
  * Put a value in the store, then if count > maxCount evict oldest entries (by dateKey).
5
6
  * Optionally set the dateKey field from expiresAt (absolute ms) or ttlSeconds (relative seconds).
6
7
  * Value must include the keyPath field, or pass options.key.
7
8
  */
8
9
  export async function putWithEviction(db, storeName, value, options) {
9
- const { key, dateKey, maxCount, expiresAt, ttlSeconds } = options;
10
+ const { key, dateKey, expiresAt, ttlSeconds } = options;
11
+ const maxCount = options.maxCount ?? DEFAULT_MAX_COUNT;
10
12
  if (typeof value === "object" && value !== null) {
11
13
  const valueRecord = value;
12
14
  if (expiresAt !== undefined) {
13
15
  valueRecord[dateKey] = expiresAt;
14
16
  }
15
17
  else {
16
- valueRecord[dateKey] = Date.now() + (ttlSeconds ?? DEFAULT_TTL_SECONDS) * 1000;
18
+ valueRecord[dateKey] =
19
+ Date.now() + (ttlSeconds ?? DEFAULT_TTL_SECONDS) * 1000;
17
20
  }
18
21
  }
19
22
  await db.put(storeName, value, key);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "idb-refined",
3
- "version": "0.0.2",
3
+ "version": "0.0.3",
4
4
  "description": "Thin TypeScript IndexedDB helper: initDb (auto-version), clean by date/size, add with eviction, delete helpers",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",