offdex 1.0.2

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 ADDED
@@ -0,0 +1,52 @@
1
+ # Offdex
2
+
3
+ ID-first object storage for the browser. Offdex wraps IndexedDB with a tiny, stable API so you can drop in `{ id: <uuid>, ...data }` objects and have them shared across tabs, workers, and sessions without thinking about schema versions.
4
+
5
+ ## Why use Offdex
6
+ - Zero schema/versioning overhead: one object store keyed by `id`, no migrations to manage.
7
+ - Works everywhere IndexedDB works: tabs, workers, and other browser runtimes share the same underlying database.
8
+ - Offline by default: IndexedDB persists across reloads and disconnects.
9
+ - Typed surface: ships with TypeScript definitions for easy adoption.
10
+
11
+ ## Install
12
+ ```bash
13
+ npm install offdex
14
+ ```
15
+
16
+ ## Quick start
17
+ ```js
18
+ import { OfflineStorage } from "offdex";
19
+
20
+ const storage = new OfflineStorage();
21
+
22
+ const profile = {
23
+ id: crypto.randomUUID(), // UUIDv4 string
24
+ name: "Ada Lovelace",
25
+ role: "analyst"
26
+ };
27
+
28
+ await storage.put(profile);
29
+
30
+ const again = await storage.get(profile.id);
31
+ // -> { id: "…", name: "Ada Lovelace", role: "analyst" }
32
+
33
+ await storage.delete(profile.id);
34
+ ```
35
+
36
+ ## API
37
+ ### `class OfflineStorage`
38
+ - `constructor()` — opens (or creates) the `offline` database with the `objects` store.
39
+ - `put(object: { id: UUIDv4 } & Record<string, unknown>): Promise<void>` — upserts an object keyed by `id`.
40
+ - `get(id: UUIDv4): Promise<{ id: UUIDv4 } & Record<string, unknown> | undefined>` — fetches by `id`, returning `undefined` when missing.
41
+ - `delete(id: UUIDv4): Promise<void>` — removes an object by `id`.
42
+
43
+ ### Types
44
+ - `UUIDv4` — template literal type for UUID strings.
45
+
46
+ ## Notes
47
+ - Runs in any environment that exposes `indexedDB` (secure contexts in modern browsers).
48
+ - Data is shared per origin; open multiple tabs or workers and you will see the same store.
49
+ - There is no schema migration system; keep your stored objects backward compatible or manage migrations externally if you need them.
50
+
51
+ ## Quick manual test
52
+ Open `in-browser-testing.html` in a browser (or serve it locally) to poke at the API from DevTools: the module attaches `OfflineStorage` to `globalThis`.
package/package.json ADDED
@@ -0,0 +1,35 @@
1
+ {
2
+ "name": "offdex",
3
+ "version": "1.0.2",
4
+ "description": "ID-driven object storage wrapper for IndexedDB with zero schema/versioning overhead. Shared across all browser threads, offline-persistent, large capacity, simple API.",
5
+ "keywords": [
6
+ "indexeddb",
7
+ "offline",
8
+ "storage",
9
+ "browser-storage",
10
+ "web-storage",
11
+ "object-store",
12
+ "key-value",
13
+ "id",
14
+ "persist",
15
+ "threads",
16
+ "workers",
17
+ "shared"
18
+ ],
19
+ "license": "MIT",
20
+ "type": "module",
21
+ "main": "src/index.js",
22
+ "types": "src/index.d.ts",
23
+ "exports": {
24
+ ".": {
25
+ "types": "./src/index.d.ts",
26
+ "import": "./src/index.js"
27
+ },
28
+ "./package.json": "./package.json"
29
+ },
30
+ "files": [
31
+ "src",
32
+ "README.md"
33
+ ],
34
+ "sideEffects": false
35
+ }
package/src/index.d.ts ADDED
@@ -0,0 +1,19 @@
1
+ export type UUIDv4 = `${string}-${string}-${string}-${string}-${string}`;
2
+
3
+ export type StoredObject = { id: UUIDv4 } & Record<string, unknown>;
4
+
5
+ export class OfflineStorage {
6
+ constructor();
7
+ /**
8
+ * Persist or overwrite an object by id.
9
+ */
10
+ put(object: StoredObject): Promise<void>;
11
+ /**
12
+ * Fetch an object by id. Returns undefined when missing.
13
+ */
14
+ get(id: UUIDv4): Promise<StoredObject | undefined>;
15
+ /**
16
+ * Remove an object by id.
17
+ */
18
+ delete(id: UUIDv4): Promise<void>;
19
+ }
package/src/index.js ADDED
@@ -0,0 +1,81 @@
1
+ export class OfflineStorage {
2
+ static #idb = "offline";
3
+ static #store = "objects";
4
+
5
+ /**
6
+ * @returns {Promise<IDBDatabase>}
7
+ */
8
+ static #open() {
9
+ return new Promise((resolve, reject) => {
10
+ const request = indexedDB.open(OfflineStorage.#idb);
11
+
12
+ request.addEventListener("upgradeneeded", () => {
13
+ const db = request.result;
14
+ if (!db.objectStoreNames.contains(OfflineStorage.#store)) {
15
+ db.createObjectStore(OfflineStorage.#store, { keyPath: "id" });
16
+ }
17
+ });
18
+
19
+ request.addEventListener("success", () => {
20
+ resolve(request.result);
21
+ });
22
+
23
+ request.addEventListener("error", () => {
24
+ reject(request.error);
25
+ });
26
+ });
27
+ }
28
+
29
+ constructor() {
30
+ this.storage = OfflineStorage.#open();
31
+ }
32
+
33
+ /**
34
+ * @param {import("./types").StoredObject} object
35
+ * @returns {Promise<void>}
36
+ */
37
+ async put(object) {
38
+ const db = await this.storage;
39
+ return new Promise((resolve, reject) => {
40
+ const tx = db.transaction(OfflineStorage.#store, "readwrite");
41
+ const store = tx.objectStore(OfflineStorage.#store);
42
+ store.put(object);
43
+
44
+ tx.oncomplete = () => resolve();
45
+ tx.onerror = () => reject(new Error(`[OfflineStorage] ${tx.error}`));
46
+ });
47
+ }
48
+
49
+ /**
50
+ * @param {import("./types").UUIDv4} id
51
+ * @returns {Promise<import("./types").StoredObject | undefined>}
52
+ */
53
+ async get(id) {
54
+ const db = await this.storage;
55
+ return new Promise((resolve, reject) => {
56
+ const tx = db.transaction(OfflineStorage.#store, "readonly");
57
+ const store = tx.objectStore(OfflineStorage.#store);
58
+ const request = store.get(id);
59
+
60
+ tx.oncomplete = () => {
61
+ resolve(request.result ? request.result : undefined);
62
+ };
63
+ tx.onerror = () => reject(new Error(`[OfflineStorage] ${tx.error}`));
64
+ });
65
+ }
66
+ /**
67
+ *
68
+ * @param {import("./types").UUIDv4} id
69
+ * @returns {Promise<void>}
70
+ */
71
+ async delete(id) {
72
+ const db = await this.storage;
73
+ return new Promise((resolve, reject) => {
74
+ const tx = db.transaction(OfflineStorage.#store, "readwrite");
75
+ const store = tx.objectStore(OfflineStorage.#store);
76
+ store.delete(id);
77
+ tx.oncomplete = () => resolve();
78
+ tx.onerror = () => reject(new Error(`[OfflineStorage] ${tx.error}`));
79
+ });
80
+ }
81
+ }
package/src/types.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ export type UUIDv4 = `${string}-${string}-${string}-${string}-${string}`;
2
+
3
+ export type StoredObject = { id: UUIDv4 } & Record<string, unknown>;