offdex 3.0.0 → 4.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 CHANGED
@@ -1,25 +1,26 @@
1
1
  # Offdex
2
2
 
3
- IndexedDB-backed object storage for browsers and workers. Store
4
- structured-clone JS values (objects, arrays, and primitives limited to
5
- msgpack-compatible types) by key, read them back directly, and share data across
6
- tabs and workers without schema migrations.
3
+ IndexedDB-backed envelope storage for browsers and workers. Store AES-GCM
4
+ envelopes (12-byte IV + ciphertext ArrayBuffer) by base64url identifier and
5
+ read them back directly. The store is shared per origin across tabs and workers.
7
6
 
8
7
  ## Why use Offdex
9
8
 
10
- - Simple `put/get/head/delete/list` API in browser contexts.
11
- - Object storage for msgpack-safe structured-clone JS values: primitives,
12
- arrays, plain objects, Date, and typed arrays.
13
- - Single object store keyed by string; no migrations to manage.
14
- - Data shared per origin across tabs and workers (instance per JavaScript realm).
9
+ - Minimal `put/get/has/delete` API for encrypted payload envelopes.
10
+ - Fixed-width base64url identifiers (43 chars, 32 random bytes).
11
+ - Single object store keyed by identifier; no migrations to manage.
12
+ - Data shared per origin across tabs and workers (instance per realm).
15
13
  - Offline persistence via IndexedDB.
16
14
  - TypeScript-first.
17
- - Singleton-only API: one shared `storage` instance per JavaScript realm (per thread).
18
15
 
19
16
  ## Install
20
17
 
21
18
  ```bash
22
19
  npm install offdex
20
+ # or
21
+ pnpm add offdex
22
+ # or
23
+ yarn add offdex
23
24
  ```
24
25
 
25
26
  ## Quick start
@@ -27,16 +28,33 @@ npm install offdex
27
28
  ```js
28
29
  import storage from "offdex";
29
30
 
30
- await storage.put("profile:ada", { greeting: "hello from IndexedDB" });
31
-
32
- const object = await storage.get("profile:ada");
33
- if (object) {
34
- console.log(object);
31
+ const makeId = () => {
32
+ const bytes = crypto.getRandomValues(new Uint8Array(32));
33
+ let binary = "";
34
+ for (let i = 0; i < bytes.length; i += 1) {
35
+ binary += String.fromCharCode(bytes[i]);
36
+ }
37
+ return btoa(binary)
38
+ .replace(/\+/g, "-")
39
+ .replace(/\//g, "_")
40
+ .replace(/=+$/, "");
41
+ };
42
+
43
+ const envelope = {
44
+ iv: crypto.getRandomValues(new Uint8Array(12)),
45
+ ciphertext: new Uint8Array([1, 2, 3]).buffer,
46
+ };
47
+
48
+ const key = makeId();
49
+
50
+ await storage.put(key, envelope);
51
+
52
+ const stored = await storage.get(key);
53
+ if (stored) {
54
+ console.log(stored.iv, stored.ciphertext);
35
55
  }
36
56
 
37
- await storage.put("bytes", new Uint8Array([1, 2, 3]));
38
- const bytes = await storage.get("bytes");
39
- console.log(bytes instanceof Uint8Array, bytes);
57
+ await storage.delete(key);
40
58
  ```
41
59
 
42
60
  ## API
@@ -44,36 +62,29 @@ console.log(bytes instanceof Uint8Array, bytes);
44
62
  ### `storage` (default export)
45
63
 
46
64
  Singleton storage instance per JavaScript realm backed by the `offdex` database
47
- and `blobs` object store. The underlying store is shared per origin across tabs
48
- and workers.
65
+ and `envelopes` object store. The underlying store is shared per origin across
66
+ tabs and workers.
49
67
 
50
68
  ### Methods
51
69
 
52
- - `put(key, value, options?)` -> `Promise<void>`
53
- - `get(key, options?)` -> `Promise<unknown | null>`
54
- - `head(key)` -> `Promise<boolean>`
70
+ - `put(key, envelope)` -> `Promise<void>`
71
+ - `get(key)` -> `Promise<OffdexEnvelope | null>`
72
+ - `has(key)` -> `Promise<boolean>`
55
73
  - `delete(key)` -> `Promise<void>`
56
- - `list(options?)` -> `Promise<{ objects: { key: string }[] }>`
74
+ - `destroy()` -> `Promise<void>`
57
75
 
58
- ### Value requirements (msgpack-compatible)
76
+ ### Identifier requirements
59
77
 
60
- - `value` must be a structured-clone JS value encodable by `@msgpack/msgpack`
61
- with default options.
62
- - Allowed: `null`/`undefined`, booleans, numbers, strings, arrays, plain
63
- objects, `Date`, and `ArrayBufferView` (typed arrays/DataView).
64
- - Not allowed: `BigInt`, `Map`, `Set`, `RegExp`, `Error`, `Blob`/`File`,
65
- `ArrayBuffer`, functions, symbols, or circular references.
66
- - `put` throws a `TypeError` if a value is not msgpack-compatible.
67
- - MessagePack note: `undefined` decodes as `null`, and binary decodes as
68
- `Uint8Array`.
78
+ - `key` must be a base64url string, exactly 43 chars (32 random bytes, no
79
+ padding).
80
+ - `put/get/has/delete` throw a `TypeError` if the identifier is invalid.
69
81
 
70
- ## Compatibility notes
82
+ ### Envelope requirements
71
83
 
72
- - Method names mirror Cloudflare R2 (`put/get/head/delete/list`), but return
73
- values are simplified for direct value access.
74
- - Offdex does not use MessagePack internally; it just validates compatibility.
75
- - `options` arguments are accepted for signature compatibility but not used.
76
- - `list` currently returns all keys; prefix/limit/cursor options are ignored.
84
+ - `envelope` must be an object with:
85
+ - `iv`: `Uint8Array` exactly 12 bytes (AES-GCM nonce).
86
+ - `ciphertext`: non-empty `ArrayBuffer`.
87
+ - `put` throws a `TypeError` if the envelope is invalid.
77
88
 
78
89
  ## Build
79
90
 
@@ -88,7 +99,16 @@ npx playwright install
88
99
  npm test
89
100
  ```
90
101
 
91
- Playwright runs Chromium, Firefox, WebKit, plus mobile emulation projects.
102
+ Unit, integration, and end-to-end runs are available as well:
103
+
104
+ ```bash
105
+ npm run test:unit
106
+ npm run test:integration
107
+ npm run test:e2e
108
+ ```
109
+
110
+ Playwright runs Chromium, Firefox, WebKit, plus mobile emulation projects for
111
+ integration and end-to-end coverage.
92
112
 
93
113
  ## Benchmarks
94
114
 
@@ -97,24 +117,23 @@ npx playwright install
97
117
  npm run bench
98
118
  ```
99
119
 
100
- The benchmark runs in Chromium via Playwright and times a batch of msgpack-safe
101
- `put/head/get/list/delete` operations.
120
+ The benchmark runs in Chromium via Playwright and times a batch of envelope
121
+ `put/has/get/delete` operations.
102
122
 
103
123
  ```text
104
- [bench] put 200 items: 148.6ms
105
- [bench] head 200 items: 101.6ms
106
- [bench] get 200 items: 100.3ms
107
- [bench] list 200 items: 2.7ms
108
- [bench] delete 200 items: 123.8ms
124
+ [bench] put 200 envelopes: 148.6ms
125
+ [bench] has 200 envelopes: 101.6ms
126
+ [bench] get 200 envelopes: 100.3ms
127
+ [bench] delete 200 envelopes: 123.8ms
109
128
  ```
110
129
 
111
130
  ## Manual browser check
112
131
 
113
132
  - Run `npm run build`, open `in-browser-testing.html`, then use `storage` from
114
- the console with msgpack-compatible structured-clone values.
133
+ the console with envelope values.
115
134
 
116
135
  ## Notes
117
136
 
118
137
  - Requires `indexedDB` (modern browsers / worker runtimes).
119
138
  - Data is scoped per origin; all tabs/workers on the same origin share the same
120
- store.
139
+ store.
@@ -0,0 +1,12 @@
1
+ import type { OffdexEnvelope, OffdexIdentifier } from "./types.js";
2
+ export type { OffdexEnvelope, OffdexIdentifier };
3
+ export declare class OffdexEnvelopeStorage {
4
+ #private;
5
+ static open(): Promise<OffdexEnvelopeStorage>;
6
+ static destroy(): Promise<void>;
7
+ static put(key: OffdexIdentifier, value: OffdexEnvelope): Promise<void>;
8
+ static has(key: OffdexIdentifier): Promise<boolean>;
9
+ static get(key: OffdexIdentifier): Promise<OffdexEnvelope | null>;
10
+ static delete(key: OffdexIdentifier): Promise<void>;
11
+ }
12
+ //# sourceMappingURL=class.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"class.d.ts","sourceRoot":"","sources":["../../src/OffdexEnvelopeStorage/class.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAGnE,YAAY,EAAE,cAAc,EAAE,gBAAgB,EAAE,CAAC;AAOjD,qBAAa,qBAAqB;;WAKnB,IAAI,IAAI,OAAO,CAAC,qBAAqB,CAAC;WAmBtC,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;WAsBxB,GAAG,CACd,GAAG,EAAE,gBAAgB,EACrB,KAAK,EAAE,cAAc,GACpB,OAAO,CAAC,IAAI,CAAC;WAeH,GAAG,CAAC,GAAG,EAAE,gBAAgB,GAAG,OAAO,CAAC,OAAO,CAAC;WAiB5C,GAAG,CAAC,GAAG,EAAE,gBAAgB,GAAG,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC;WAgB1D,MAAM,CAAC,GAAG,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC;CAa1D"}
@@ -0,0 +1,88 @@
1
+ import { assertEnvelope, assertIdentifier } from "./validation.js";
2
+ export class OffdexEnvelopeStorage {
3
+ static #dbName = "offdex";
4
+ static #storeName = "envelopes";
5
+ static #db = null;
6
+ static async open() {
7
+ if (this.#db)
8
+ return OffdexEnvelopeStorage;
9
+ this.#db = await new Promise((resolve, reject) => {
10
+ const request = indexedDB.open(this.#dbName, 1);
11
+ request.onupgradeneeded = () => {
12
+ const db = request.result;
13
+ if (!db.objectStoreNames.contains(this.#storeName)) {
14
+ db.createObjectStore(this.#storeName, { keyPath: "key" });
15
+ }
16
+ };
17
+ request.onsuccess = () => resolve(request.result);
18
+ request.onerror = () => reject(request.error);
19
+ });
20
+ return OffdexEnvelopeStorage;
21
+ }
22
+ static async destroy() {
23
+ if (this.#db) {
24
+ this.#db.close();
25
+ this.#db = null;
26
+ }
27
+ await new Promise((resolve, reject) => {
28
+ const req = indexedDB.deleteDatabase(this.#dbName);
29
+ req.onsuccess = () => resolve();
30
+ req.onerror = () => reject(req.error);
31
+ req.onblocked = () => reject(new Error("{offdex} database deletion blocked"));
32
+ });
33
+ }
34
+ static #requireDb() {
35
+ if (!this.#db) {
36
+ throw new Error("{offdex} storage not opened; call open() first");
37
+ }
38
+ return this.#db;
39
+ }
40
+ static async put(key, value) {
41
+ assertIdentifier(key);
42
+ assertEnvelope(value);
43
+ const db = this.#requireDb();
44
+ await new Promise((resolve, reject) => {
45
+ const tx = db.transaction(this.#storeName, "readwrite");
46
+ tx.objectStore(this.#storeName).put({ key, value });
47
+ tx.oncomplete = () => resolve();
48
+ tx.onerror = () => reject(tx.error);
49
+ tx.onabort = () => reject(tx.error);
50
+ });
51
+ }
52
+ static async has(key) {
53
+ assertIdentifier(key);
54
+ const db = this.#requireDb();
55
+ return new Promise((resolve, reject) => {
56
+ const tx = db.transaction(this.#storeName, "readonly");
57
+ const store = tx.objectStore(this.#storeName);
58
+ const req = typeof store.getKey === "function" ? store.getKey(key) : store.get(key);
59
+ tx.oncomplete = () => resolve(req.result !== undefined);
60
+ tx.onerror = () => reject(tx.error);
61
+ tx.onabort = () => reject(tx.error);
62
+ });
63
+ }
64
+ static async get(key) {
65
+ assertIdentifier(key);
66
+ const db = this.#requireDb();
67
+ const row = await new Promise((resolve, reject) => {
68
+ const tx = db.transaction(this.#storeName, "readonly");
69
+ const req = tx.objectStore(this.#storeName).get(key);
70
+ tx.oncomplete = () => resolve(req.result);
71
+ tx.onerror = () => reject(tx.error);
72
+ tx.onabort = () => reject(tx.error);
73
+ });
74
+ return row ? row.value : null;
75
+ }
76
+ static async delete(key) {
77
+ assertIdentifier(key);
78
+ const db = this.#requireDb();
79
+ await new Promise((resolve, reject) => {
80
+ const tx = db.transaction(this.#storeName, "readwrite");
81
+ tx.objectStore(this.#storeName).delete(key);
82
+ tx.oncomplete = () => resolve();
83
+ tx.onerror = () => reject(tx.error);
84
+ tx.onabort = () => reject(tx.error);
85
+ });
86
+ }
87
+ }
88
+ //# sourceMappingURL=class.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"class.js","sourceRoot":"","sources":["../../src/OffdexEnvelopeStorage/class.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ export type OffdexIdentifier = Base64URLString; /** 43 chars, no padding */
2
+ export type OffdexEnvelope = {
3
+ iv: Uint8Array;
4
+ ciphertext: ArrayBuffer;
5
+ };
6
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/OffdexEnvelopeStorage/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,gBAAgB,GAAG,eAAe,CAAC,CAAC,2BAA2B;AAE3E,MAAM,MAAM,cAAc,GAAG;IAC3B,EAAE,EAAE,UAAU,CAAC;IACf,UAAU,EAAE,WAAW,CAAC;CACzB,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/OffdexEnvelopeStorage/types.ts"],"names":[],"mappings":""}
@@ -0,0 +1,4 @@
1
+ import type { OffdexEnvelope, OffdexIdentifier } from "./types.js";
2
+ export declare const assertIdentifier: (key: string) => asserts key is OffdexIdentifier;
3
+ export declare const assertEnvelope: (value: unknown) => asserts value is OffdexEnvelope;
4
+ //# sourceMappingURL=validation.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validation.d.ts","sourceRoot":"","sources":["../../src/OffdexEnvelopeStorage/validation.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAEnE,eAAO,MAAM,gBAAgB,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,GAAG,IAAI,gBAQ9D,CAAC;AAEF,eAAO,MAAM,cAAc,EAAE,CAC3B,KAAK,EAAE,OAAO,KACX,OAAO,CAAC,KAAK,IAAI,cAmBrB,CAAC"}
@@ -0,0 +1,22 @@
1
+ export const assertIdentifier = (key) => {
2
+ if (key.length !== 43) {
3
+ throw new TypeError("{offdex} identifier must be exactly 43 chars");
4
+ }
5
+ if (!/^[A-Za-z0-9_-]+$/.test(key)) {
6
+ throw new TypeError("{offdex} identifier must be base64url (no padding)");
7
+ }
8
+ };
9
+ export const assertEnvelope = (value) => {
10
+ if (typeof value !== "object" || value === null) {
11
+ throw new TypeError("{offdex} envelope must be an object");
12
+ }
13
+ const env = value;
14
+ if (!(env.iv instanceof Uint8Array) || env.iv.byteLength !== 12) {
15
+ throw new TypeError("{offdex} iv must be 12-byte Uint8Array (AES-GCM)");
16
+ }
17
+ if (!(env.ciphertext instanceof ArrayBuffer) ||
18
+ env.ciphertext.byteLength === 0) {
19
+ throw new TypeError("{offdex} ciphertext must be non-empty ArrayBuffer");
20
+ }
21
+ };
22
+ //# sourceMappingURL=validation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validation.js","sourceRoot":"","sources":["../../src/OffdexEnvelopeStorage/validation.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,gBAAgB,GAC3B,CAAC,GAAW,EAAmC,EAAE;IACjD,IAAI,GAAG,CAAC,MAAM,KAAK,EAAE,EAAE,CAAC;QACtB,MAAM,IAAI,SAAS,CAAC,8CAA8C,CAAC,CAAC;IACtE,CAAC;IACD,IAAI,CAAC,kBAAkB,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;QAClC,MAAM,IAAI,SAAS,CAAC,oDAAoD,CAAC,CAAC;IAC5E,CAAC;AACH,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,cAAc,GAEY,CACrC,KAAc,EACmB,EAAE;IACnC,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;QAChD,MAAM,IAAI,SAAS,CAAC,qCAAqC,CAAC,CAAC;IAC7D,CAAC;IAED,MAAM,GAAG,GAAG,KAAgC,CAAC;IAE7C,IAAI,CAAC,CAAC,GAAG,CAAC,EAAE,YAAY,UAAU,CAAC,IAAI,GAAG,CAAC,EAAE,CAAC,UAAU,KAAK,EAAE,EAAE,CAAC;QAChE,MAAM,IAAI,SAAS,CAAC,kDAAkD,CAAC,CAAC;IAC1E,CAAC;IAED,IACE,CAAC,CAAC,GAAG,CAAC,UAAU,YAAY,WAAW,CAAC;QACxC,GAAG,CAAC,UAAU,CAAC,UAAU,KAAK,CAAC,EAC/B,CAAC;QACD,MAAM,IAAI,SAAS,CAAC,mDAAmD,CAAC,CAAC;IAC3E,CAAC;AACH,CAAC,CAAC"}
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { ObjectStorage } from "./ObjectStorage/class.js";
2
- declare const _default: ObjectStorage;
3
- export default _default;
1
+ import { OffdexEnvelopeStorage } from "./OffdexEnvelopeStorage/class.js";
2
+ declare const offdex: OffdexEnvelopeStorage;
3
+ export default offdex;
4
4
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;;AAEzD,wBAAmC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAE,MAAM,kCAAkC,CAAC;AACzE,QAAA,MAAM,MAAM,uBAAqC,CAAC;AAClD,eAAe,MAAM,CAAC"}
package/dist/index.js CHANGED
@@ -1,3 +1,4 @@
1
- import { ObjectStorage } from "./ObjectStorage/class.js";
2
- export default new ObjectStorage();
1
+ import { OffdexEnvelopeStorage } from "./OffdexEnvelopeStorage/class.js";
2
+ const offdex = await OffdexEnvelopeStorage.open();
3
+ export default offdex;
3
4
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAEzD,eAAe,IAAI,aAAa,EAAE,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAE,MAAM,kCAAkC,CAAC;AACzE,MAAM,MAAM,GAAG,MAAM,qBAAqB,CAAC,IAAI,EAAE,CAAC;AAClD,eAAe,MAAM,CAAC"}
package/package.json CHANGED
@@ -1,19 +1,17 @@
1
1
  {
2
2
  "name": "offdex",
3
- "version": "3.0.0",
4
- "description": "IndexedDB-backed object storage for structured-clone JS values (msgpack-compatible) in browsers and workers.",
3
+ "version": "4.0.0",
4
+ "description": "IndexedDB-backed envelope storage for AES-GCM payloads in browsers and workers.",
5
5
  "keywords": [
6
6
  "indexeddb",
7
- "structured-clone",
8
- "msgpack",
9
- "binary",
10
- "object",
7
+ "envelope",
8
+ "ciphertext",
9
+ "crypto",
10
+ "aes-gcm",
11
+ "base64url",
11
12
  "storage",
12
13
  "browser-storage",
13
14
  "web-storage",
14
- "r2",
15
- "cloudflare",
16
- "bucket",
17
15
  "offline",
18
16
  "worker",
19
17
  "persist"
@@ -24,12 +22,12 @@
24
22
  "types": "dist/index.d.ts",
25
23
  "repository": {
26
24
  "type": "git",
27
- "url": "git+https://github.com/jortsupetterson/offdex.git"
25
+ "url": "git+https://github.com/z-base/offdex.git"
28
26
  },
29
27
  "bugs": {
30
- "url": "https://github.com/jortsupetterson/offdex/issues"
28
+ "url": "https://github.com/z-base/offdex/issues"
31
29
  },
32
- "homepage": "https://github.com/jortsupetterson/offdex#readme",
30
+ "homepage": "https://github.com/z-base/offdex#readme",
33
31
  "exports": {
34
32
  ".": {
35
33
  "types": "./dist/index.d.ts",
@@ -46,14 +44,15 @@
46
44
  "scripts": {
47
45
  "build": "tsc -p tsconfig.build.json",
48
46
  "test": "npm run build && playwright test",
47
+ "test:unit": "playwright test --project=unit",
48
+ "test:integration": "npm run build && playwright test --project=chromium --project=firefox --project=webkit --project=chromium-mobile --project=webkit-mobile tests/integration",
49
+ "test:e2e": "npm run build && playwright test --project=chromium --project=firefox --project=webkit --project=chromium-mobile --project=webkit-mobile tests/e2e",
49
50
  "bench": "npm run build && playwright test -c playwright.bench.config.ts",
50
51
  "prepublishOnly": "npm run build"
51
52
  },
52
- "dependencies": {
53
- "@cloudflare/workers-types": "^4.20260101.0"
54
- },
55
53
  "devDependencies": {
56
54
  "@playwright/test": "^1.57.0",
55
+ "@types/node": "^25.0.9",
57
56
  "typescript": "^5.9.3"
58
57
  }
59
58
  }