nostr-double-ratchet 0.0.28 → 0.0.30

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/src/UserRecord.ts CHANGED
@@ -17,15 +17,6 @@ export class UserRecord {
17
17
  private deviceRecords: Map<string, DeviceRecord> = new Map();
18
18
  private isStale: boolean = false;
19
19
  private staleTimestamp?: number;
20
- /**
21
- * Temporary store for sessions when the corresponding deviceId is unknown.
22
- *
23
- * SessionManager currently operates at a per-user granularity (it is not
24
- * yet aware of individual devices). Until full Sesame device handling is
25
- * implemented we keep sessions in this simple list so that
26
- * SessionManager.getActiveSessions / getAllSessions work as expected.
27
- */
28
- private extraSessions: Session[] = [];
29
20
 
30
21
  constructor(
31
22
  public _userId: string,
@@ -53,18 +44,7 @@ export class UserRecord {
53
44
  * Inserts a new session for a device, making it the active session
54
45
  */
55
46
  public insertSession(deviceId: string, session: Session): void {
56
- const record = this.deviceRecords.get(deviceId);
57
- if (!record) {
58
- throw new Error(`No device record found for ${deviceId}`);
59
- }
60
-
61
- // Move current active session to inactive list if it exists
62
- if (record.activeSession) {
63
- record.inactiveSessions.unshift(record.activeSession);
64
- }
65
-
66
- // Set new session as active
67
- record.activeSession = session;
47
+ this.upsertSession(deviceId, session)
68
48
  }
69
49
 
70
50
  /**
@@ -194,22 +174,14 @@ export class UserRecord {
194
174
  // Helper methods used by SessionManager (WIP):
195
175
  // ---------------------------------------------------------------------------
196
176
 
197
- /**
198
- * Add a session without associating it with a specific device.
199
- * This is mainly used by SessionManager which does not yet keep track of
200
- * device identifiers. The session will be considered active.
201
- */
202
- public addSession(session: Session): void {
203
- this.extraSessions.push(session);
204
- }
205
-
206
177
  /**
207
178
  * Return all sessions that are currently considered *active*.
208
179
  * For now this means any session in a non-stale device record as well as
209
180
  * all sessions added through `addSession`.
181
+ * Prioritizes initiator sessions (can send first message) over responder sessions.
210
182
  */
211
183
  public getActiveSessions(): Session[] {
212
- const sessions: Session[] = [...this.extraSessions];
184
+ const sessions: Session[] = [];
213
185
 
214
186
  for (const record of this.deviceRecords.values()) {
215
187
  if (!record.isStale && record.activeSession) {
@@ -217,6 +189,15 @@ export class UserRecord {
217
189
  }
218
190
  }
219
191
 
192
+ sessions.sort((a, b) => {
193
+ const aCanSend = !!(a.state?.theirNextNostrPublicKey && a.state?.ourCurrentNostrKey);
194
+ const bCanSend = !!(b.state?.theirNextNostrPublicKey && b.state?.ourCurrentNostrKey);
195
+
196
+ if (aCanSend && !bCanSend) return -1; // a comes first
197
+ if (!aCanSend && bCanSend) return 1; // b comes first
198
+ return 0; // equal priority
199
+ });
200
+
220
201
  return sessions;
221
202
  }
222
203
 
@@ -226,7 +207,7 @@ export class UserRecord {
226
207
  * listeners to existing sessions.
227
208
  */
228
209
  public getAllSessions(): Session[] {
229
- const sessions: Session[] = [...this.extraSessions];
210
+ const sessions: Session[] = [];
230
211
 
231
212
  for (const record of this.deviceRecords.values()) {
232
213
  if (record.activeSession) {
@@ -237,4 +218,32 @@ export class UserRecord {
237
218
 
238
219
  return sessions;
239
220
  }
221
+
222
+ /**
223
+ * Unified helper that either associates the session with a device record
224
+ * (if deviceId provided **and** the record exists) or falls back to the
225
+ * legacy extraSessions list.
226
+ */
227
+ public upsertSession(deviceId: string | undefined, session: Session) {
228
+ if (!deviceId) {
229
+ deviceId = 'unknown'
230
+ }
231
+
232
+ let record = this.deviceRecords.get(deviceId)
233
+ if (!record) {
234
+ record = {
235
+ publicKey: session.state?.theirNextNostrPublicKey || '',
236
+ inactiveSessions: [],
237
+ isStale: false
238
+ }
239
+ this.deviceRecords.set(deviceId, record)
240
+ }
241
+
242
+ if (record.activeSession) {
243
+ record.inactiveSessions.unshift(record.activeSession)
244
+ }
245
+ // Ensure session name matches deviceId for easier identification
246
+ session.name = deviceId
247
+ record.activeSession = session
248
+ }
240
249
  }
package/src/index.ts CHANGED
@@ -1,4 +1,5 @@
1
- export * from "./Session.ts"
1
+ export * from "./Session"
2
2
  export * from "./Invite"
3
3
  export * from "./types"
4
- export * from "./utils"
4
+ export * from "./utils"
5
+ export * from "./SessionManager"
package/src/types.ts CHANGED
@@ -74,7 +74,8 @@ export type Rumor = UnsignedEvent & { id: string }
74
74
 
75
75
  /**
76
76
  * Callback function for handling decrypted messages
77
- * @param message - The decrypted message object
77
+ * @param _event - The decrypted message object (Rumor)
78
+ * @param _outerEvent - The outer Nostr event (VerifiedEvent)
78
79
  */
79
80
  export type EventCallback = (_event: Rumor, _outerEvent: VerifiedEvent) => void;
80
81