{"_id":"@burgantech/context-store","_rev":"2-5776b6c3fc16e91045f817723de0065d","name":"@burgantech/context-store","dist-tags":{"latest":"0.1.1"},"versions":{"0.1.0":{"name":"@burgantech/context-store","version":"0.1.0","license":"UNLICENSED","_id":"@burgantech/context-store@0.1.0","maintainers":[{"name":"ukaratas","email":"ukaratas@rocketmail.com"}],"homepage":"https://github.com/burgan-tech/vnext-client-data-manager#readme","bugs":{"url":"https://github.com/burgan-tech/vnext-client-data-manager/issues"},"dist":{"shasum":"a7c7350d34cf3da7eafdd1034c58a8110b030afc","tarball":"https://registry.npmjs.org/@burgantech/context-store/-/context-store-0.1.0.tgz","fileCount":11,"integrity":"sha512-fzVeWdIMM9BGGy1nA9UqrtKx0ivro1r5oYdKKBGB87RvImKRhDYuGV0X/jUy4LSYI3PThUuSqtxw1AZGfWCrGA==","signatures":[{"sig":"MEQCICDKgwb83T5kAV9EU8FQvW4+/Aa6CviRIc7bMg1MSDflAiA5AP2uv4zHowhX0Di6nbGIMgoHhJQYTWszJaYVQ+BvvQ==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":33893},"main":"dist/index.js","type":"module","types":"dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"gitHead":"76e5609d61da9b197973e75817a74271fb810b41","scripts":{"dev":"tsc --watch","test":"vitest run","build":"tsc","test:watch":"vitest","prepublishOnly":"npm run build"},"_npmUser":{"name":"ukaratas","email":"ukaratas@rocketmail.com"},"repository":{"url":"git+https://github.com/burgan-tech/vnext-client-data-manager.git","type":"git","directory":"core/ts-context-store"},"_npmVersion":"10.9.4","description":"Centralized state store SDK — boundary-based, encrypted, observable","directories":{},"_nodeVersion":"22.22.1","publishConfig":{"access":"public","registry":"https://registry.npmjs.org"},"_hasShrinkwrap":false,"devDependencies":{"vitest":"^3.0.0","happy-dom":"^20.8.4","typescript":"^5.4.0"},"_npmOperationalInternal":{"tmp":"tmp/context-store_0.1.0_1773757906274_0.4748360640511953","host":"s3://npm-registry-packages-npm-production"}},"0.1.1":{"name":"@burgantech/context-store","version":"0.1.1","description":"Centralized state store SDK — boundary-based, encrypted, observable","type":"module","main":"dist/index.js","types":"dist/index.d.ts","exports":{".":{"import":"./dist/index.js","types":"./dist/index.d.ts"}},"scripts":{"build":"tsc","dev":"tsc --watch","test":"vitest run","test:watch":"vitest","prepublishOnly":"npm run build"},"repository":{"type":"git","url":"git+https://github.com/burgan-tech/vnext-client-data-manager.git","directory":"core/ts-context-store"},"publishConfig":{"access":"public","registry":"https://registry.npmjs.org"},"license":"UNLICENSED","devDependencies":{"happy-dom":"^20.8.4","typescript":"^5.4.0","vitest":"^3.0.0"},"_id":"@burgantech/context-store@0.1.1","gitHead":"8b269e36f350605a771e699707b91803abfbbb5f","bugs":{"url":"https://github.com/burgan-tech/vnext-client-data-manager/issues"},"homepage":"https://github.com/burgan-tech/vnext-client-data-manager#readme","_nodeVersion":"22.22.1","_npmVersion":"10.9.4","dist":{"integrity":"sha512-OdiyZteU2+Yxuxug9EPt7EAgtddh8Cne8/TVc9pPDBVP3ptGsuVeq5S5ZHFxcIwbFEqtgaYMQ1wakkwY/oDZCA==","shasum":"e5de1da634fc0008273a16c42b4de21d57da9382","tarball":"https://registry.npmjs.org/@burgantech/context-store/-/context-store-0.1.1.tgz","fileCount":12,"unpackedSize":41024,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEYCIQCvz+K1SGzQ6VeBtbduaP1S+xQMtrwmJMxCWqeCWuWpTwIhAMMDJicoL4YKLjcLxAl83+z5lPwFYQnFuHiA28/kWZUu"}]},"_npmUser":{"name":"ukaratas","email":"ukaratas@rocketmail.com"},"directories":{},"maintainers":[{"name":"ukaratas","email":"ukaratas@rocketmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/context-store_0.1.1_1773758681577_0.8843384222177177"},"_hasShrinkwrap":false}},"time":{"created":"2026-03-17T14:31:46.164Z","modified":"2026-03-17T14:44:42.145Z","0.1.0":"2026-03-17T14:31:46.434Z","0.1.1":"2026-03-17T14:44:41.717Z"},"bugs":{"url":"https://github.com/burgan-tech/vnext-client-data-manager/issues"},"license":"UNLICENSED","homepage":"https://github.com/burgan-tech/vnext-client-data-manager#readme","repository":{"type":"git","url":"git+https://github.com/burgan-tech/vnext-client-data-manager.git","directory":"core/ts-context-store"},"description":"Centralized state store SDK — boundary-based, encrypted, observable","maintainers":[{"name":"ukaratas","email":"ukaratas@rocketmail.com"}],"readme":"# @burgantech/context-store\n\nCentralized, boundary-based state management SDK for web applications. Framework-agnostic — works with Angular, React, Vue, or plain TypeScript.\n\n## Features\n\n- **Boundary isolation** — `device`, `user`, and `subject` scopes keep data cleanly separated\n- **Multiple storage backends** — `secureStorage`, `secureStorageEncrypted`, `memory`, `localStorage`\n- **Envelope metadata** — every entry is wrapped with `createdAt`, `updatedAt`, `expiry`, `appName`, `appVersion`, `sdkVersion`\n- **TTL & auto-expiry** — time-to-live with lazy cleanup on read and proactive `cleanup()` sweeps\n- **Server time sync** — pluggable HTTP delegate fetches authoritative time; falls back to device time on failure\n- **Encryption** — AES-256-GCM spec; encryption key held in memory only, never persisted\n- **Observability** — `observeData` (Observable) and `addListener` / `removeListener` (callback) — no framework dependency\n- **Nested access** — `dataPath` option for deep property read/write (e.g. `profile.address.city`)\n- **Batch operations** — `batchSet`, `batchGet` for bulk reads and writes\n- **Export / Import** — `exportData` and `importData` for migration and backup\n- **Zero dependencies**\n\n## Installation\n\n```bash\nnpm install @burgantech/context-store\n```\n\n## Quick Start\n\n```typescript\nimport { ContextStore, Boundary, Storage } from '@burgantech/context-store';\n\nconst store = ContextStore.create({\n  timeServerUrls: ['https://your-api.com/time'],\n  onRequestServerTime: async (url, timeout) => {\n    const res = await fetch(url, { method: 'HEAD', signal: AbortSignal.timeout(timeout) });\n    const d = res.headers.get('date');\n    return d ? new Date(d) : null;\n  },\n  onLog: (level, message) => console.log(`[${level}] ${message}`),\n});\n\n// Identity\nstore.activeUser = 'user-42';\nstore.activeSubject = 'customer-7';\n\n// Write\nstore.setData(Boundary.user, 'profile', { name: 'Ada', role: 'admin' });\n\n// Read\nconst profile = store.getData(Boundary.user, 'profile');\n\n// Nested access\nstore.setData(Boundary.user, 'profile', 'Lovelace', { dataPath: 'surname' });\nconst surname = store.getData(Boundary.user, 'profile', { dataPath: 'surname' });\n\n// TTL (expires in 5 minutes)\nstore.setData(Boundary.user, 'otp', '123456', { ttl: 5 * 60_000 });\n\n// Observe changes\nconst sub = store.observeData(Boundary.user, 'profile').subscribe((value) => {\n  console.log('profile changed:', value);\n});\n// later: sub.unsubscribe();\n\n// Listener\nstore.addListener('my-listener', Boundary.user, 'profile', (value) => {\n  console.log('listener fired:', value);\n});\nstore.removeListener('my-listener');\n```\n\n## Encryption\n\nThe SDK accepts an encryption key at runtime for `secureStorageEncrypted` storage. The key is held in memory only and never written to disk.\n\n```typescript\n// After authenticating, set the key provided by your backend\nstore.setEncryptionKey('backend-provided-key');\n\n// Write encrypted\nstore.setData(Boundary.user, 'secret', { pin: '1234' }, { storage: Storage.secureStorageEncrypted });\n\n// Read encrypted\nconst secret = store.getData(Boundary.user, 'secret', { storage: Storage.secureStorageEncrypted });\n\n// On logout\nstore.revokeEncryptionKey();\n```\n\n## Server Time\n\nThe SDK never trusts device time for TTL calculations. It fetches authoritative time via a delegate you provide and caches the result.\n\n```typescript\nconst serverTime = await store.getServerTime();\n```\n\n| Option | Default | Description |\n|--------|---------|-------------|\n| `timeServerUrls` | — | URL list for HEAD requests |\n| `onRequestServerTime` | — | Async delegate: `(url, timeout) => Promise<Date \\| null>` |\n| `serverTimeTtl` | 1 800 000 (30 min) | Cache duration in ms |\n| `requestServerTimeTimeout` | 5 000 | Per-request timeout in ms |\n\nIf all fetches fail, the SDK falls back to device time and reports the error via `onLog`.\n\n## API Overview\n\n### Identity\n\n| Property / Method | Type | Description |\n|---|---|---|\n| `activeDevice` | `string \\| null` | Read-only. SDK-generated per session (web) or from platform API (native). |\n| `activeUser` | `string \\| null` | Get/set. Application-managed user identity. |\n| `activeSubject` | `string \\| null` | Get/set. Sub-user scope (customer, tenant, etc.). |\n| `getServerTime()` | `Promise<Date>` | Authoritative time; re-fetches when cache expires. |\n\n### Data Operations\n\n| Method | Description |\n|---|---|\n| `setData(boundary, key, value, options?)` | Write data. Options: `storage`, `ttl`, `dataPath`. |\n| `getData<T>(boundary, key, options?)` | Read data. Returns `undefined` if missing or expired. |\n| `getDataMetadata(boundary, key, options?)` | Read full envelope (metadata + data). |\n| `deleteData(boundary, key, options?)` | Delete a key. Supports `dataPath` for nested removal. |\n| `batchSet(operations)` | Bulk write. |\n| `batchGet(operations)` | Bulk read. |\n\n### Observability\n\n| Method | Description |\n|---|---|\n| `observeData(boundary, key, options?)` | Returns `Observable<T>`. Emits on every `setData` for that key. |\n| `addListener(id, boundary, key, callback, options?)` | Register a named callback. |\n| `removeListener(id)` | Remove a named callback. |\n| `clearAllListeners()` | Remove all callbacks. |\n\n### Housekeeping\n\n| Method | Description |\n|---|---|\n| `findKeys(boundary, partialKey, options?)` | Search keys by prefix. |\n| `clearData(boundary, options?)` | Clear data for a boundary. Optional `partialKey` filter. |\n| `exportData(boundary, options?)` | Export raw envelopes as a record. |\n| `importData(boundary, data, options?)` | Import envelopes. `overwrite` flag controls conflict resolution. |\n| `cleanup(options?)` | Remove expired entries. Filterable by `boundary` and `storage`. |\n\n### Encryption Key\n\n| Method | Description |\n|---|---|\n| `setEncryptionKey(key)` | Set the encryption key (in-memory only). |\n| `isEncryptionKeySet` | `boolean` — whether a key is currently loaded. |\n| `revokeEncryptionKey()` | Clear the key from memory. |\n\n## Enums\n\n```typescript\nenum Boundary {\n  device = 'device',\n  user   = 'user',\n  subject = 'subject',\n}\n\nenum Storage {\n  secureStorage          = 'secureStorage',\n  secureStorageEncrypted = 'secureStorageEncrypted',\n  memory                 = 'memory',\n  localStorage           = 'localStorage',\n}\n```\n\n## Types\n\n```typescript\ntype Envelope = {\n  data: any;\n  expiry: string | null;\n  createdAt: string;\n  updatedAt: string;\n  appName: string;\n  appVersion: string;\n  sdkVersion: string;\n};\n\ntype Subscription = { unsubscribe(): void };\ntype Observable<T> = { subscribe(callback: (value: T) => void): Subscription };\n```\n\n## Error Behaviour\n\n| Scenario | Behaviour |\n|---|---|\n| `secureStorageEncrypted` access without key | Returns `undefined`, logs warning |\n| Invalid key or boundary | Returns `undefined` |\n| Storage write failure | Logs error via `onLog` |\n| Server time fetch failure | Falls back to device time, logs error |\n| Decryption with wrong key | Returns `undefined`, logs error |\n\n## Requirements\n\n- TypeScript ≥ 5.4\n- ES2022 target (uses `crypto.randomUUID`, `structuredClone`)\n\n## License\n\nUNLICENSED — proprietary software.\n","readmeFilename":"README.md"}