@burgantech/context-store 0.1.0 → 0.1.1

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.
Files changed (2) hide show
  1. package/README.md +205 -0
  2. package/package.json +3 -2
package/README.md ADDED
@@ -0,0 +1,205 @@
1
+ # @burgantech/context-store
2
+
3
+ Centralized, boundary-based state management SDK for web applications. Framework-agnostic — works with Angular, React, Vue, or plain TypeScript.
4
+
5
+ ## Features
6
+
7
+ - **Boundary isolation** — `device`, `user`, and `subject` scopes keep data cleanly separated
8
+ - **Multiple storage backends** — `secureStorage`, `secureStorageEncrypted`, `memory`, `localStorage`
9
+ - **Envelope metadata** — every entry is wrapped with `createdAt`, `updatedAt`, `expiry`, `appName`, `appVersion`, `sdkVersion`
10
+ - **TTL & auto-expiry** — time-to-live with lazy cleanup on read and proactive `cleanup()` sweeps
11
+ - **Server time sync** — pluggable HTTP delegate fetches authoritative time; falls back to device time on failure
12
+ - **Encryption** — AES-256-GCM spec; encryption key held in memory only, never persisted
13
+ - **Observability** — `observeData` (Observable) and `addListener` / `removeListener` (callback) — no framework dependency
14
+ - **Nested access** — `dataPath` option for deep property read/write (e.g. `profile.address.city`)
15
+ - **Batch operations** — `batchSet`, `batchGet` for bulk reads and writes
16
+ - **Export / Import** — `exportData` and `importData` for migration and backup
17
+ - **Zero dependencies**
18
+
19
+ ## Installation
20
+
21
+ ```bash
22
+ npm install @burgantech/context-store
23
+ ```
24
+
25
+ ## Quick Start
26
+
27
+ ```typescript
28
+ import { ContextStore, Boundary, Storage } from '@burgantech/context-store';
29
+
30
+ const store = ContextStore.create({
31
+ timeServerUrls: ['https://your-api.com/time'],
32
+ onRequestServerTime: async (url, timeout) => {
33
+ const res = await fetch(url, { method: 'HEAD', signal: AbortSignal.timeout(timeout) });
34
+ const d = res.headers.get('date');
35
+ return d ? new Date(d) : null;
36
+ },
37
+ onLog: (level, message) => console.log(`[${level}] ${message}`),
38
+ });
39
+
40
+ // Identity
41
+ store.activeUser = 'user-42';
42
+ store.activeSubject = 'customer-7';
43
+
44
+ // Write
45
+ store.setData(Boundary.user, 'profile', { name: 'Ada', role: 'admin' });
46
+
47
+ // Read
48
+ const profile = store.getData(Boundary.user, 'profile');
49
+
50
+ // Nested access
51
+ store.setData(Boundary.user, 'profile', 'Lovelace', { dataPath: 'surname' });
52
+ const surname = store.getData(Boundary.user, 'profile', { dataPath: 'surname' });
53
+
54
+ // TTL (expires in 5 minutes)
55
+ store.setData(Boundary.user, 'otp', '123456', { ttl: 5 * 60_000 });
56
+
57
+ // Observe changes
58
+ const sub = store.observeData(Boundary.user, 'profile').subscribe((value) => {
59
+ console.log('profile changed:', value);
60
+ });
61
+ // later: sub.unsubscribe();
62
+
63
+ // Listener
64
+ store.addListener('my-listener', Boundary.user, 'profile', (value) => {
65
+ console.log('listener fired:', value);
66
+ });
67
+ store.removeListener('my-listener');
68
+ ```
69
+
70
+ ## Encryption
71
+
72
+ The SDK accepts an encryption key at runtime for `secureStorageEncrypted` storage. The key is held in memory only and never written to disk.
73
+
74
+ ```typescript
75
+ // After authenticating, set the key provided by your backend
76
+ store.setEncryptionKey('backend-provided-key');
77
+
78
+ // Write encrypted
79
+ store.setData(Boundary.user, 'secret', { pin: '1234' }, { storage: Storage.secureStorageEncrypted });
80
+
81
+ // Read encrypted
82
+ const secret = store.getData(Boundary.user, 'secret', { storage: Storage.secureStorageEncrypted });
83
+
84
+ // On logout
85
+ store.revokeEncryptionKey();
86
+ ```
87
+
88
+ ## Server Time
89
+
90
+ The SDK never trusts device time for TTL calculations. It fetches authoritative time via a delegate you provide and caches the result.
91
+
92
+ ```typescript
93
+ const serverTime = await store.getServerTime();
94
+ ```
95
+
96
+ | Option | Default | Description |
97
+ |--------|---------|-------------|
98
+ | `timeServerUrls` | — | URL list for HEAD requests |
99
+ | `onRequestServerTime` | — | Async delegate: `(url, timeout) => Promise<Date \| null>` |
100
+ | `serverTimeTtl` | 1 800 000 (30 min) | Cache duration in ms |
101
+ | `requestServerTimeTimeout` | 5 000 | Per-request timeout in ms |
102
+
103
+ If all fetches fail, the SDK falls back to device time and reports the error via `onLog`.
104
+
105
+ ## API Overview
106
+
107
+ ### Identity
108
+
109
+ | Property / Method | Type | Description |
110
+ |---|---|---|
111
+ | `activeDevice` | `string \| null` | Read-only. SDK-generated per session (web) or from platform API (native). |
112
+ | `activeUser` | `string \| null` | Get/set. Application-managed user identity. |
113
+ | `activeSubject` | `string \| null` | Get/set. Sub-user scope (customer, tenant, etc.). |
114
+ | `getServerTime()` | `Promise<Date>` | Authoritative time; re-fetches when cache expires. |
115
+
116
+ ### Data Operations
117
+
118
+ | Method | Description |
119
+ |---|---|
120
+ | `setData(boundary, key, value, options?)` | Write data. Options: `storage`, `ttl`, `dataPath`. |
121
+ | `getData<T>(boundary, key, options?)` | Read data. Returns `undefined` if missing or expired. |
122
+ | `getDataMetadata(boundary, key, options?)` | Read full envelope (metadata + data). |
123
+ | `deleteData(boundary, key, options?)` | Delete a key. Supports `dataPath` for nested removal. |
124
+ | `batchSet(operations)` | Bulk write. |
125
+ | `batchGet(operations)` | Bulk read. |
126
+
127
+ ### Observability
128
+
129
+ | Method | Description |
130
+ |---|---|
131
+ | `observeData(boundary, key, options?)` | Returns `Observable<T>`. Emits on every `setData` for that key. |
132
+ | `addListener(id, boundary, key, callback, options?)` | Register a named callback. |
133
+ | `removeListener(id)` | Remove a named callback. |
134
+ | `clearAllListeners()` | Remove all callbacks. |
135
+
136
+ ### Housekeeping
137
+
138
+ | Method | Description |
139
+ |---|---|
140
+ | `findKeys(boundary, partialKey, options?)` | Search keys by prefix. |
141
+ | `clearData(boundary, options?)` | Clear data for a boundary. Optional `partialKey` filter. |
142
+ | `exportData(boundary, options?)` | Export raw envelopes as a record. |
143
+ | `importData(boundary, data, options?)` | Import envelopes. `overwrite` flag controls conflict resolution. |
144
+ | `cleanup(options?)` | Remove expired entries. Filterable by `boundary` and `storage`. |
145
+
146
+ ### Encryption Key
147
+
148
+ | Method | Description |
149
+ |---|---|
150
+ | `setEncryptionKey(key)` | Set the encryption key (in-memory only). |
151
+ | `isEncryptionKeySet` | `boolean` — whether a key is currently loaded. |
152
+ | `revokeEncryptionKey()` | Clear the key from memory. |
153
+
154
+ ## Enums
155
+
156
+ ```typescript
157
+ enum Boundary {
158
+ device = 'device',
159
+ user = 'user',
160
+ subject = 'subject',
161
+ }
162
+
163
+ enum Storage {
164
+ secureStorage = 'secureStorage',
165
+ secureStorageEncrypted = 'secureStorageEncrypted',
166
+ memory = 'memory',
167
+ localStorage = 'localStorage',
168
+ }
169
+ ```
170
+
171
+ ## Types
172
+
173
+ ```typescript
174
+ type Envelope = {
175
+ data: any;
176
+ expiry: string | null;
177
+ createdAt: string;
178
+ updatedAt: string;
179
+ appName: string;
180
+ appVersion: string;
181
+ sdkVersion: string;
182
+ };
183
+
184
+ type Subscription = { unsubscribe(): void };
185
+ type Observable<T> = { subscribe(callback: (value: T) => void): Subscription };
186
+ ```
187
+
188
+ ## Error Behaviour
189
+
190
+ | Scenario | Behaviour |
191
+ |---|---|
192
+ | `secureStorageEncrypted` access without key | Returns `undefined`, logs warning |
193
+ | Invalid key or boundary | Returns `undefined` |
194
+ | Storage write failure | Logs error via `onLog` |
195
+ | Server time fetch failure | Falls back to device time, logs error |
196
+ | Decryption with wrong key | Returns `undefined`, logs error |
197
+
198
+ ## Requirements
199
+
200
+ - TypeScript ≥ 5.4
201
+ - ES2022 target (uses `crypto.randomUUID`, `structuredClone`)
202
+
203
+ ## License
204
+
205
+ UNLICENSED — proprietary software.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@burgantech/context-store",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "Centralized state store SDK — boundary-based, encrypted, observable",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -12,7 +12,8 @@
12
12
  }
13
13
  },
14
14
  "files": [
15
- "dist"
15
+ "dist",
16
+ "README.md"
16
17
  ],
17
18
  "scripts": {
18
19
  "build": "tsc",