@droponair/sdk-js 0.31.0 → 0.32.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/CHANGELOG.md +27 -0
- package/README.md +28 -0
- package/dist/core/types.d.ts +13 -0
- package/dist/index.js +5 -3
- package/dist/storage/indexeddb-key-storage.d.ts +20 -0
- package/dist/storage/indexeddb-key-storage.js +25 -3
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,32 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.32.0
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
|
|
7
|
+
- **Run a second identity alongside the first.** `initialize` now takes a name, and
|
|
8
|
+
each named instance gets its own connection, its own token, and its own key
|
|
9
|
+
storage. The identities are not linkable to each other by anyone observing
|
|
10
|
+
them, which a single instance could not offer: every message carries the
|
|
11
|
+
publisher's user id to its recipients, so one identity meant one visible
|
|
12
|
+
identity everywhere the app spoke.
|
|
13
|
+
|
|
14
|
+
Use it when an app needs a long-lived identity for the user's own
|
|
15
|
+
conversations plus a short-lived or anonymous one for an ephemeral context.
|
|
16
|
+
|
|
17
|
+
```ts
|
|
18
|
+
const mine = await initialize({ ...opts });
|
|
19
|
+
const anon = await initialize({ ...opts, instanceName: 'nearby' });
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
A `storage` adapter you supply yourself is used exactly as given, so give each
|
|
23
|
+
instance its own; only the default storage is namespaced for you.
|
|
24
|
+
|
|
25
|
+
Existing code is unaffected. Calls without a name use the instance named
|
|
26
|
+
`default`, which keeps the key storage an app already has, so upgrading does
|
|
27
|
+
not change the identity a device has been using.
|
|
28
|
+
|
|
29
|
+
|
|
3
30
|
## 0.31.0
|
|
4
31
|
|
|
5
32
|
### Fixed
|
package/README.md
CHANGED
|
@@ -681,6 +681,34 @@ client.onGroupCallEvent((evt) => {
|
|
|
681
681
|
- Mute is intentionally a signaling hint: WebRTC media tracks can't be muted from outside the producing client. Remove is server-enforced - the target SDK receives `GROUP_CALL_PARTICIPANT_REMOVED` and the others receive `PARTICIPANT_LEFT`.
|
|
682
682
|
- Availability depends on your plan. See the [pricing page](https://www.droponair.com/pricing) and your dashboard Subscription page for what's enabled on your app.
|
|
683
683
|
|
|
684
|
+
## Two identities at once
|
|
685
|
+
|
|
686
|
+
Every message carries the publisher's user id to whoever receives it, so a single
|
|
687
|
+
identity is a single visible identity everywhere the app speaks. When that is not
|
|
688
|
+
what you want, name a second instance. Each named instance has its own
|
|
689
|
+
connection, its own token, and its own key storage, so nobody observing them can
|
|
690
|
+
tell the two identities belong to one device.
|
|
691
|
+
|
|
692
|
+
The usual shape is a long-lived identity for the user's own conversations plus a
|
|
693
|
+
short-lived or anonymous one for an ephemeral context, running side by side.
|
|
694
|
+
|
|
695
|
+
```ts
|
|
696
|
+
const mine = await initialize({ ...options });
|
|
697
|
+
const anon = await initialize({ ...options, instanceName: 'nearby' });
|
|
698
|
+
|
|
699
|
+
await anon.publishBroadcast(channelId, 'hello');
|
|
700
|
+
```
|
|
701
|
+
|
|
702
|
+
| Option | Description |
|
|
703
|
+
|---|---|
|
|
704
|
+
| `instanceName` | Names this instance. Defaults to `'default'`. |
|
|
705
|
+
|
|
706
|
+
Only the default key storage is namespaced for you. A `storage` adapter you
|
|
707
|
+
supply yourself is used exactly as given, so give each instance its own.
|
|
708
|
+
|
|
709
|
+
Calls without a name use the instance named `default`, which keeps the key
|
|
710
|
+
storage an app already has. Upgrading changes nothing for existing code.
|
|
711
|
+
|
|
684
712
|
## Security
|
|
685
713
|
|
|
686
714
|
- **X25519 ECDH** key agreement for shared secrets
|
package/dist/core/types.d.ts
CHANGED
|
@@ -381,6 +381,19 @@ export interface InitializeOptions {
|
|
|
381
381
|
*/
|
|
382
382
|
defaultPushPayload?: PushPayload;
|
|
383
383
|
fetchFn?: typeof fetch;
|
|
384
|
+
/**
|
|
385
|
+
* Names this instance, so an app can run a second identity alongside the first.
|
|
386
|
+
*
|
|
387
|
+
* Each named instance gets key storage of its own, so the two identities are
|
|
388
|
+
* not linkable to each other by anyone observing them. A typical use is a
|
|
389
|
+
* long-lived identity for the user's own conversations plus a short-lived one
|
|
390
|
+
* for an anonymous or ephemeral context. Only the default key storage is
|
|
391
|
+
* namespaced for you; a `storage` adapter you supply yourself is used exactly
|
|
392
|
+
* as given, so give each instance its own.
|
|
393
|
+
*
|
|
394
|
+
* Defaults to `'default'`, which keeps the storage an existing app already has.
|
|
395
|
+
*/
|
|
396
|
+
instanceName?: string;
|
|
384
397
|
storage?: KeyStorageAdapter;
|
|
385
398
|
/**
|
|
386
399
|
* Owns the identity keypair instead of {@link storage}, when the consumer wants
|
package/dist/index.js
CHANGED
|
@@ -12,11 +12,13 @@ var version_1 = require("./version");
|
|
|
12
12
|
Object.defineProperty(exports, "SDK_VERSION", { enumerable: true, get: function () { return version_1.SDK_VERSION; } });
|
|
13
13
|
Object.defineProperty(exports, "PROTOCOL_VERSION", { enumerable: true, get: function () { return version_1.PROTOCOL_VERSION; } });
|
|
14
14
|
Object.defineProperty(exports, "PAYLOAD_FORMAT_VERSION", { enumerable: true, get: function () { return version_1.PAYLOAD_FORMAT_VERSION; } });
|
|
15
|
-
function resolveStorage(adapter) {
|
|
15
|
+
function resolveStorage(adapter, instanceName) {
|
|
16
16
|
if (adapter) {
|
|
17
|
+
// A supplied adapter is used exactly as given: namespacing it here would
|
|
18
|
+
// silently move the caller's own keys somewhere they did not ask for.
|
|
17
19
|
return adapter;
|
|
18
20
|
}
|
|
19
|
-
return new indexeddb_key_storage_1.IndexedDbKeyStorage();
|
|
21
|
+
return new indexeddb_key_storage_1.IndexedDbKeyStorage(instanceName);
|
|
20
22
|
}
|
|
21
23
|
/**
|
|
22
24
|
* An identity whose private key script cannot read, or `null` where the platform
|
|
@@ -48,7 +50,7 @@ async function createSecureIdentity(store) {
|
|
|
48
50
|
return new webcrypto_identity_provider_1.WebCryptoIdentityProvider(recordStore);
|
|
49
51
|
}
|
|
50
52
|
async function initialize(options) {
|
|
51
|
-
const storage = resolveStorage(options.storage);
|
|
53
|
+
const storage = resolveStorage(options.storage, options.instanceName);
|
|
52
54
|
const sessionManager = new session_manager_1.SessionManager();
|
|
53
55
|
// An explicitly supplied identity provider owns the key agreement; otherwise
|
|
54
56
|
// the storage adapter does, exactly as in every previous release.
|
|
@@ -1,6 +1,26 @@
|
|
|
1
1
|
import { KeyStorageAdapter } from '../core/types';
|
|
2
|
+
export declare const DEFAULT_INSTANCE = "default";
|
|
3
|
+
/**
|
|
4
|
+
* The database backing an instance's keys.
|
|
5
|
+
*
|
|
6
|
+
* Exported so the rule can be tested directly: if two instances ever resolve to
|
|
7
|
+
* one database they share a keypair, publish the same public key under both user
|
|
8
|
+
* ids, and become linkable, with nothing visible to say so.
|
|
9
|
+
*/
|
|
10
|
+
export declare function dbNameFor(instanceName?: string): string;
|
|
2
11
|
export declare class IndexedDbKeyStorage implements KeyStorageAdapter {
|
|
3
12
|
private readonly fallback;
|
|
13
|
+
private readonly dbName;
|
|
14
|
+
/**
|
|
15
|
+
* Each named instance gets a database of its own. Two identities sharing one
|
|
16
|
+
* database would share one messaging keypair, which publishes the same public
|
|
17
|
+
* key under both user ids and links them to anyone who looks, defeating the
|
|
18
|
+
* point of running a second identity at all.
|
|
19
|
+
*
|
|
20
|
+
* The default instance keeps the original database name, so an app upgrading
|
|
21
|
+
* to a version with named instances keeps the identity it already had.
|
|
22
|
+
*/
|
|
23
|
+
constructor(instanceName?: string);
|
|
4
24
|
get(key: string): Promise<string | null>;
|
|
5
25
|
set(key: string, value: string): Promise<void>;
|
|
6
26
|
remove(key: string): Promise<void>;
|
|
@@ -1,13 +1,35 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.IndexedDbKeyStorage = void 0;
|
|
3
|
+
exports.IndexedDbKeyStorage = exports.DEFAULT_INSTANCE = void 0;
|
|
4
|
+
exports.dbNameFor = dbNameFor;
|
|
4
5
|
const memory_key_storage_1 = require("./memory-key-storage");
|
|
5
6
|
const DB_NAME = 'droponair_sdk';
|
|
6
7
|
const STORE_NAME = 'secure_keys';
|
|
7
8
|
const DB_VERSION = 1;
|
|
9
|
+
exports.DEFAULT_INSTANCE = 'default';
|
|
10
|
+
/**
|
|
11
|
+
* The database backing an instance's keys.
|
|
12
|
+
*
|
|
13
|
+
* Exported so the rule can be tested directly: if two instances ever resolve to
|
|
14
|
+
* one database they share a keypair, publish the same public key under both user
|
|
15
|
+
* ids, and become linkable, with nothing visible to say so.
|
|
16
|
+
*/
|
|
17
|
+
function dbNameFor(instanceName = exports.DEFAULT_INSTANCE) {
|
|
18
|
+
return instanceName === exports.DEFAULT_INSTANCE ? DB_NAME : `${DB_NAME}_${instanceName}`;
|
|
19
|
+
}
|
|
8
20
|
class IndexedDbKeyStorage {
|
|
9
|
-
|
|
21
|
+
/**
|
|
22
|
+
* Each named instance gets a database of its own. Two identities sharing one
|
|
23
|
+
* database would share one messaging keypair, which publishes the same public
|
|
24
|
+
* key under both user ids and links them to anyone who looks, defeating the
|
|
25
|
+
* point of running a second identity at all.
|
|
26
|
+
*
|
|
27
|
+
* The default instance keeps the original database name, so an app upgrading
|
|
28
|
+
* to a version with named instances keeps the identity it already had.
|
|
29
|
+
*/
|
|
30
|
+
constructor(instanceName = exports.DEFAULT_INSTANCE) {
|
|
10
31
|
this.fallback = new memory_key_storage_1.MemoryKeyStorage();
|
|
32
|
+
this.dbName = dbNameFor(instanceName);
|
|
11
33
|
}
|
|
12
34
|
async get(key) {
|
|
13
35
|
if (!this.isIndexedDbAvailable()) {
|
|
@@ -55,7 +77,7 @@ class IndexedDbKeyStorage {
|
|
|
55
77
|
}
|
|
56
78
|
async openDb() {
|
|
57
79
|
return new Promise((resolve, reject) => {
|
|
58
|
-
const request = indexedDB.open(
|
|
80
|
+
const request = indexedDB.open(this.dbName, DB_VERSION);
|
|
59
81
|
request.onupgradeneeded = () => {
|
|
60
82
|
const db = request.result;
|
|
61
83
|
if (!db.objectStoreNames.contains(STORE_NAME)) {
|
package/dist/version.d.ts
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* MINOR, additive feature (e.g. multi-device payloads, new call event type)
|
|
8
8
|
* PATCH, bug-fix / perf improvement with no wire or API change
|
|
9
9
|
*/
|
|
10
|
-
export declare const SDK_VERSION = "0.
|
|
10
|
+
export declare const SDK_VERSION = "0.32.0";
|
|
11
11
|
/**
|
|
12
12
|
* Binary encrypted-payload format version.
|
|
13
13
|
* Included as the first byte of every encrypted payload so receivers can
|
package/dist/version.js
CHANGED
|
@@ -10,7 +10,7 @@ exports.PROTOCOL_VERSION = exports.PAYLOAD_FORMAT_VERSION = exports.SDK_VERSION
|
|
|
10
10
|
* MINOR, additive feature (e.g. multi-device payloads, new call event type)
|
|
11
11
|
* PATCH, bug-fix / perf improvement with no wire or API change
|
|
12
12
|
*/
|
|
13
|
-
exports.SDK_VERSION = '0.
|
|
13
|
+
exports.SDK_VERSION = '0.32.0';
|
|
14
14
|
/**
|
|
15
15
|
* Binary encrypted-payload format version.
|
|
16
16
|
* Included as the first byte of every encrypted payload so receivers can
|
package/package.json
CHANGED