@me2em/react 0.1.0-alpha.1 → 0.1.0-alpha.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 +35 -6
- package/dist/index.d.ts +1 -1
- package/package.json +4 -3
- package/src/react/index.ts +3 -0
- package/src/headless/context-key-store.ts +0 -124
package/README.md
CHANGED
|
@@ -1,10 +1,8 @@
|
|
|
1
|
-
|
|
1
|
+
[](https://www.npmjs.com/package/@me2em/react)
|
|
2
|
+
[](./LICENSE)
|
|
3
|
+
[](https://react.me2em.com)
|
|
2
4
|
|
|
3
|
-
|
|
4
|
-
places only: your paper and transient memory during login. This
|
|
5
|
-
package stores only *derived, encrypted context caches* — losing your
|
|
6
|
-
browser data never loses your identity, because your identity lives
|
|
7
|
-
in your head.
|
|
5
|
+
## 📦 @me2em/react — React bindings
|
|
8
6
|
|
|
9
7
|
React bindings for the Me2em protocol: identity lifecycle, seed phrase UX, and hierarchical handle derivation.
|
|
10
8
|
|
|
@@ -16,6 +14,13 @@ pnpm add @me2em/react react
|
|
|
16
14
|
|
|
17
15
|
Requires React >= 18.0.0 as a peer dependency.
|
|
18
16
|
|
|
17
|
+
> 💡 This package requires [`@me2em/core`](../core/README.md) (peer
|
|
18
|
+
> dependency via workspace) and React ≥ 18. It is self-contained —
|
|
19
|
+
> for E2EE channels, X3DH, and Argon2id see
|
|
20
|
+
> [`@me2em/crypto`](../crypto/README.md). All three packages are
|
|
21
|
+
> designed to work together — see the root
|
|
22
|
+
> [README](../../README.md) for the full package map.
|
|
23
|
+
|
|
19
24
|
## Quick Start
|
|
20
25
|
|
|
21
26
|
```tsx
|
|
@@ -69,6 +74,30 @@ const state = headless.identityFlowReducer(headless.initialIdentityFlowState, {
|
|
|
69
74
|
});
|
|
70
75
|
```
|
|
71
76
|
|
|
77
|
+
---
|
|
78
|
+
|
|
79
|
+
## 📖 Terminology (selected)
|
|
80
|
+
|
|
81
|
+
Protocol terms are **domain-neutral**. The terms most relevant to
|
|
82
|
+
this package:
|
|
83
|
+
|
|
84
|
+
| Term | Definition |
|
|
85
|
+
|------|------------|
|
|
86
|
+
| **Identity** | Root cryptographic identity derived from a seed phrase. Constant forever. |
|
|
87
|
+
| **Handle** | A derived, attested, named key representing a distinct identity context. |
|
|
88
|
+
| **Session** | A stateless signed authorization token. |
|
|
89
|
+
| **Transient material** | Key bytes existing only in RAM at the moment of use. |
|
|
90
|
+
| **Context cache** | Per-identity encrypted storage of derived Handle context. |
|
|
91
|
+
|
|
92
|
+
Full glossary (including Attestation, SubHandle, Ephemeral material):
|
|
93
|
+
see the [root README](../../README.md).
|
|
94
|
+
|
|
95
|
+
**This package never persists your seed.** The seed phrase exists in
|
|
96
|
+
two places only — your paper and transient memory during login. What
|
|
97
|
+
this package stores is derived, encrypted context caches. Losing your
|
|
98
|
+
browser data never loses your identity, because your identity lives
|
|
99
|
+
in your head.
|
|
100
|
+
|
|
72
101
|
## Components
|
|
73
102
|
|
|
74
103
|
### SeedPhraseDisplay
|
package/dist/index.d.ts
CHANGED
|
@@ -364,4 +364,4 @@ declare namespace index {
|
|
|
364
364
|
export { type index_ContextEnvelope as ContextEnvelope, type index_DisplayEvent as DisplayEvent, type index_DisplayState as DisplayState, type index_DisplayStatus as DisplayStatus, type index_IdentityContextData as IdentityContextData, index_IdentityContextIDBStorage as IdentityContextIDBStorage, type index_IdentityContextStorage as IdentityContextStorage, type index_IdentityFlowEvent as IdentityFlowEvent, type index_IdentityFlowState as IdentityFlowState, type index_IdentityFlowStatus as IdentityFlowStatus, type index_ImportEvent as ImportEvent, type index_ImportState as ImportState, type index_ImportStatus as ImportStatus, type index_VerifyEvent as VerifyEvent, type index_VerifyState as VerifyState, type index_VerifyStatus as VerifyStatus, index_buildVerificationGrid as buildVerificationGrid, index_decryptContext as decryptContext, index_deriveCacheKey as deriveCacheKey, index_displayFlowReducer as displayFlowReducer, index_encryptContext as encryptContext, index_identityFlowReducer as identityFlowReducer, index_importFlowReducer as importFlowReducer, index_initImportState as initImportState, index_initVerifyState as initVerifyState, index_initialDisplayState as initialDisplayState, index_initialIdentityFlowState as initialIdentityFlowState, index_isGridSelectionCorrect as isGridSelectionCorrect, index_shuffleWithSeed as shuffleWithSeed, index_verifyFlowReducer as verifyFlowReducer };
|
|
365
365
|
}
|
|
366
366
|
|
|
367
|
-
export { Me2emProvider, PassphraseInput, type PassphraseInputProps, SeedPhraseDisplay, type SeedPhraseDisplayProps, SeedPhraseImport, type SeedPhraseImportProps, SeedPhraseVerify, type SeedPhraseVerifyProps, type UseIdentityContextResult, type UseSessionOptions, type UseSessionResult, index as headless, useCreateIdentity, useHandle, useIdentityContext, useImportSeed, useMe2emContext, useSession, useSubHandle };
|
|
367
|
+
export { type Me2emContextValue, Me2emProvider, PassphraseInput, type PassphraseInputProps, SeedPhraseDisplay, type SeedPhraseDisplayProps, SeedPhraseImport, type SeedPhraseImportProps, SeedPhraseVerify, type SeedPhraseVerifyProps, type UseCreateIdentityResult, type UseIdentityContextResult, type UseImportSeedResult, type UseSessionOptions, type UseSessionResult, index as headless, useCreateIdentity, useHandle, useIdentityContext, useImportSeed, useMe2emContext, useSession, useSubHandle };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@me2em/react",
|
|
3
|
-
"version": "0.1.0-alpha.
|
|
3
|
+
"version": "0.1.0-alpha.2",
|
|
4
4
|
"description": "React bindings for the Me2em protocol: identity lifecycle, seed phrase UX, hierarchical handles",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
"access": "public"
|
|
23
23
|
},
|
|
24
24
|
"dependencies": {
|
|
25
|
-
"@me2em/core": "0.7.0-alpha.
|
|
25
|
+
"@me2em/core": "^0.7.0-alpha.2"
|
|
26
26
|
},
|
|
27
27
|
"peerDependencies": {
|
|
28
28
|
"react": ">=18.0.0"
|
|
@@ -46,6 +46,7 @@
|
|
|
46
46
|
"build": "tsup",
|
|
47
47
|
"test": "vitest run",
|
|
48
48
|
"lint": "eslint src",
|
|
49
|
-
"typecheck": "tsc --noEmit"
|
|
49
|
+
"typecheck": "tsc --noEmit",
|
|
50
|
+
"build-docs": "typedoc"
|
|
50
51
|
}
|
|
51
52
|
}
|
package/src/react/index.ts
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
export { Me2emProvider } from './Me2emProvider.js';
|
|
2
2
|
export { useMe2emContext } from './context.js';
|
|
3
|
+
export type { Me2emContextValue } from './context.js';
|
|
3
4
|
export { useCreateIdentity } from './useCreateIdentity.js';
|
|
5
|
+
export type { UseCreateIdentityResult } from './useCreateIdentity.js';
|
|
4
6
|
export { useImportSeed } from './useImportSeed.js';
|
|
7
|
+
export type { UseImportSeedResult } from './useImportSeed.js';
|
|
5
8
|
export { useHandle } from './useHandle.js';
|
|
6
9
|
export { useSubHandle } from './useSubHandle.js';
|
|
7
10
|
export { SeedPhraseDisplay } from './SeedPhraseDisplay.js';
|
|
@@ -1,124 +0,0 @@
|
|
|
1
|
-
// packages/react/src/headless/context-key-store.ts
|
|
2
|
-
import type { IdentityContextData } from './identity-context-storage.js';
|
|
3
|
-
|
|
4
|
-
const KEYS_PREFIX = '__keys:';
|
|
5
|
-
|
|
6
|
-
export interface ContextKeyStore {
|
|
7
|
-
/** Save a persisted CryptoKey for later use. */
|
|
8
|
-
setCacheKey(key: CryptoKey): Promise<void>;
|
|
9
|
-
/** Retrieve the persisted CryptoKey, or null if not found. */
|
|
10
|
-
getCacheKey(): Promise<CryptoKey | null>;
|
|
11
|
-
/** Delete the persisted CryptoKey (called on logout). */
|
|
12
|
-
deleteCacheKey(): Promise<void>;
|
|
13
|
-
/** Persist the CryptoKey to IndexedDB for warm return after browser restart. */
|
|
14
|
-
persistCacheKey(): Promise<void>;
|
|
15
|
-
/** Load a previously persisted CryptoKey from IndexedDB. */
|
|
16
|
-
loadPersistedKey(): Promise<CryptoKey | null>;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
/**
|
|
20
|
-
* IndexedDB-backed key store. CryptoKey objects are structured-cloned
|
|
21
|
-
* into an object store 'cryptoKeys' so they survive browser restarts.
|
|
22
|
-
*/
|
|
23
|
-
export class InMemoryKeyStore implements ContextKeyStore {
|
|
24
|
-
private db: IDBDatabase | null = null;
|
|
25
|
-
|
|
26
|
-
private getDbName(identityId: string): string {
|
|
27
|
-
return `${KEYS_PREFIX}${identityId}`;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
private async openOrCreate(): Promise<IDBDatabase> {
|
|
31
|
-
if (this.db) return this.db;
|
|
32
|
-
|
|
33
|
-
const name = this.getDbName('default');
|
|
34
|
-
return new Promise<IDBDatabase>((resolve, reject) => {
|
|
35
|
-
const request = indexedDB.open(name, 1);
|
|
36
|
-
|
|
37
|
-
request.onupgradeneeded = () => {
|
|
38
|
-
const db = request.result;
|
|
39
|
-
if (!db.objectStoreNames.contains('keys')) {
|
|
40
|
-
db.createObjectStore('keys', { keyPath: 'key' });
|
|
41
|
-
}
|
|
42
|
-
if (!db.objectStoreNames.contains('cryptoKeys')) {
|
|
43
|
-
db.createObjectStore('cryptoKeys', { keyPath: 'key' });
|
|
44
|
-
}
|
|
45
|
-
};
|
|
46
|
-
|
|
47
|
-
request.onsuccess = () => {
|
|
48
|
-
this.db = request.result;
|
|
49
|
-
resolve(request.result);
|
|
50
|
-
};
|
|
51
|
-
|
|
52
|
-
request.onerror = () => reject(new Error('Keys DB open failed'));
|
|
53
|
-
});
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
async setCacheKey(key: CryptoKey): Promise<void> {
|
|
57
|
-
this.cacheKey = key;
|
|
58
|
-
const db = await this.openOrCreate();
|
|
59
|
-
return new Promise<void>((resolve, reject) => {
|
|
60
|
-
const tx = db.transaction('cryptoKeys', 'readwrite');
|
|
61
|
-
const store = tx.objectStore('cryptoKeys');
|
|
62
|
-
store.put({ key: 'cacheKey', cryptoKey: key });
|
|
63
|
-
|
|
64
|
-
tx.oncomplete = () => resolve();
|
|
65
|
-
tx.onerror = () => reject(new Error('setCacheKey failed: ' + tx.error?.message));
|
|
66
|
-
});
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
private cacheKey: CryptoKey | null = null;
|
|
70
|
-
|
|
71
|
-
async getCacheKey(): Promise<CryptoKey | null> {
|
|
72
|
-
if (this.cacheKey) return this.cacheKey;
|
|
73
|
-
return this.loadPersistedKey();
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
async deleteCacheKey(): Promise<void> {
|
|
77
|
-
this.cacheKey = null;
|
|
78
|
-
const db = await this.openOrCreate();
|
|
79
|
-
return new Promise<void>((resolve, reject) => {
|
|
80
|
-
const tx = db.transaction('cryptoKeys', 'readwrite');
|
|
81
|
-
const store = tx.objectStore('cryptoKeys');
|
|
82
|
-
store.delete('cacheKey');
|
|
83
|
-
|
|
84
|
-
tx.oncomplete = () => resolve();
|
|
85
|
-
tx.onerror = () => reject(new Error('deleteCacheKey failed: ' + tx.error?.message));
|
|
86
|
-
});
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
async persistCacheKey(): Promise<void> {
|
|
90
|
-
const key = this.cacheKey;
|
|
91
|
-
if (!key) {
|
|
92
|
-
throw new Error('No cache key to persist');
|
|
93
|
-
}
|
|
94
|
-
const db = await this.openOrCreate();
|
|
95
|
-
return new Promise<void>((resolve, reject) => {
|
|
96
|
-
const tx = db.transaction('cryptoKeys', 'readwrite');
|
|
97
|
-
const store = tx.objectStore('cryptoKeys');
|
|
98
|
-
store.put({ key: 'cacheKey', cryptoKey: key });
|
|
99
|
-
|
|
100
|
-
tx.oncomplete = () => resolve();
|
|
101
|
-
tx.onerror = () => reject(new Error('persistCacheKey failed: ' + tx.error?.message));
|
|
102
|
-
});
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
async loadPersistedKey(): Promise<CryptoKey | null> {
|
|
106
|
-
const db = await this.openOrCreate();
|
|
107
|
-
return new Promise<CryptoKey | null>((resolve, reject) => {
|
|
108
|
-
const tx = db.transaction('cryptoKeys', 'readonly');
|
|
109
|
-
const store = tx.objectStore('cryptoKeys');
|
|
110
|
-
const request = store.get('cacheKey');
|
|
111
|
-
|
|
112
|
-
request.onsuccess = () => {
|
|
113
|
-
const record = request.result;
|
|
114
|
-
if (!record || !record.cryptoKey) {
|
|
115
|
-
resolve(null);
|
|
116
|
-
return;
|
|
117
|
-
}
|
|
118
|
-
resolve(record.cryptoKey);
|
|
119
|
-
};
|
|
120
|
-
|
|
121
|
-
request.onerror = () => resolve(null);
|
|
122
|
-
});
|
|
123
|
-
}
|
|
124
|
-
}
|