@konemono/nostr-login 1.7.57 → 1.7.59

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@konemono/nostr-login",
3
- "version": "1.7.57",
3
+ "version": "1.7.59",
4
4
  "description": "",
5
5
  "main": "./dist/index.esm.js",
6
6
  "types": "./dist/index.d.ts",
@@ -1,8 +1,8 @@
1
- import { NDKUser } from '@nostr-dev-kit/ndk';
2
1
  import { Signer } from './Nostr';
3
2
 
4
3
  export class AmberDirectSigner implements Signer {
5
4
  private _pubkey: string = '';
5
+ private static pendingResolves: Map<string, (result: any) => void> = new Map();
6
6
 
7
7
  constructor(pubkey?: string) {
8
8
  this._pubkey = pubkey || '';
@@ -29,9 +29,9 @@ export class AmberDirectSigner implements Signer {
29
29
  private getHash(content: string): string {
30
30
  let hash = 0;
31
31
  for (let i = 0; i < content.length; i++) {
32
- const char = content.charCodeAt(i);
33
- hash = (hash << 5) - hash + char;
34
- hash |= 0;
32
+ const char = content.charCodeAt(i);
33
+ hash = (hash << 5) - hash + char;
34
+ hash |= 0;
35
35
  }
36
36
  return hash.toString(36);
37
37
  }
@@ -41,8 +41,8 @@ export class AmberDirectSigner implements Signer {
41
41
  const cacheKey = `amber_result_${type}_${hash}`;
42
42
  const cached = sessionStorage.getItem(cacheKey);
43
43
  if (cached) {
44
- sessionStorage.removeItem(cacheKey);
45
- return cached;
44
+ sessionStorage.removeItem(cacheKey);
45
+ return cached;
46
46
  }
47
47
  return null;
48
48
  }
@@ -52,19 +52,58 @@ export class AmberDirectSigner implements Signer {
52
52
  sessionStorage.setItem(`amber_pending_${id}`, JSON.stringify({ hash, type }));
53
53
  }
54
54
 
55
+ public static resolvePending(id: string, type: string, result: string) {
56
+ // Try resolving by ID first
57
+ let resolve = this.pendingResolves.get(id);
58
+
59
+ // Fallback: If no ID match, try resolving by type if only one is pending of that type
60
+ if (!resolve) {
61
+ console.log('No direct ID match for Amber resolve, searching by type', { id, type });
62
+ for (const [pendingId, pendingResolve] of this.pendingResolves.entries()) {
63
+ const pending = sessionStorage.getItem(`amber_pending_${pendingId}`);
64
+ if (pending) {
65
+ const { type: pendingType } = JSON.parse(pending);
66
+ if (pendingType === type) {
67
+ resolve = pendingResolve;
68
+ id = pendingId;
69
+ break;
70
+ }
71
+ }
72
+ }
73
+ }
74
+
75
+ if (resolve) {
76
+ console.log('Resolving pending Amber promise', { id, type });
77
+ resolve(result);
78
+ this.pendingResolves.delete(id);
79
+ return true;
80
+ }
81
+ return false;
82
+ }
83
+
55
84
  async signEvent(event: any): Promise<any> {
56
85
  const content = JSON.stringify(event);
57
86
  const cached = this.checkCache(content, 'sign_event');
58
87
  if (cached) {
59
- return JSON.parse(cached);
88
+ return JSON.parse(cached);
60
89
  }
61
90
 
62
91
  const id = Math.random().toString(36).substring(7);
63
92
  this.setPending(id, content, 'sign_event');
64
93
  const url = this.generateUrl(content, 'sign_event', id);
65
94
  window.location.href = url;
66
- // This will never resolve because of page reload
67
- return new Promise(() => {});
95
+ return new Promise((resolve) => {
96
+ AmberDirectSigner.pendingResolves.set(id, (res) => resolve(JSON.parse(res)));
97
+ });
98
+ }
99
+
100
+ async getPublicKey(): Promise<string> {
101
+ const id = Math.random().toString(36).substring(7);
102
+ const url = this.generateUrl('', 'get_public_key', id);
103
+ window.location.href = url;
104
+ return new Promise((resolve) => {
105
+ AmberDirectSigner.pendingResolves.set(id, resolve);
106
+ });
68
107
  }
69
108
 
70
109
  async encrypt04(pubkey: string, plaintext: string): Promise<string> {
@@ -75,7 +114,9 @@ export class AmberDirectSigner implements Signer {
75
114
  this.setPending(id, plaintext, 'nip04_encrypt');
76
115
  const url = this.generateUrl(plaintext, 'nip04_encrypt', id, pubkey);
77
116
  window.location.href = url;
78
- return new Promise(() => {});
117
+ return new Promise((resolve) => {
118
+ AmberDirectSigner.pendingResolves.set(id, resolve);
119
+ });
79
120
  }
80
121
 
81
122
  async decrypt04(pubkey: string, ciphertext: string): Promise<string> {
@@ -86,7 +127,9 @@ export class AmberDirectSigner implements Signer {
86
127
  this.setPending(id, ciphertext, 'nip04_decrypt');
87
128
  const url = this.generateUrl(ciphertext, 'nip04_decrypt', id, pubkey);
88
129
  window.location.href = url;
89
- return new Promise(() => {});
130
+ return new Promise((resolve) => {
131
+ AmberDirectSigner.pendingResolves.set(id, resolve);
132
+ });
90
133
  }
91
134
 
92
135
  async encrypt44(pubkey: string, plaintext: string): Promise<string> {
@@ -97,7 +140,9 @@ export class AmberDirectSigner implements Signer {
97
140
  this.setPending(id, plaintext, 'nip44_encrypt');
98
141
  const url = this.generateUrl(plaintext, 'nip44_encrypt', id, pubkey);
99
142
  window.location.href = url;
100
- return new Promise(() => {});
143
+ return new Promise((resolve) => {
144
+ AmberDirectSigner.pendingResolves.set(id, resolve);
145
+ });
101
146
  }
102
147
 
103
148
  async decrypt44(pubkey: string, ciphertext: string): Promise<string> {
@@ -108,30 +153,40 @@ export class AmberDirectSigner implements Signer {
108
153
  this.setPending(id, ciphertext, 'nip44_decrypt');
109
154
  const url = this.generateUrl(ciphertext, 'nip44_decrypt', id, pubkey);
110
155
  window.location.href = url;
111
- return new Promise(() => {});
112
- }
113
-
114
- public async getPublicKey(): Promise<string> {
115
- const id = Math.random().toString(36).substring(7);
116
- const url = this.generateUrl('', 'get_public_key', id);
117
- window.location.href = url;
118
- return new Promise(() => {});
156
+ return new Promise((resolve) => {
157
+ AmberDirectSigner.pendingResolves.set(id, resolve);
158
+ });
119
159
  }
120
160
 
121
161
  private generateUrl(content: string, type: string, id: string, recipient?: string): string {
122
- const url = new URL(window.location.origin + window.location.pathname);
123
- url.searchParams.set('amberType', type);
124
- url.searchParams.set('amberId', id);
162
+ const callbackUrl = new URL(window.location.origin + window.location.pathname);
163
+
164
+ // Preserve other relevant current URL params if necessary, but avoid amber internal ones
165
+ const currentParams = new URLSearchParams(window.location.search);
166
+ currentParams.forEach((value, key) => {
167
+ if (!['amberType', 'amberId', 'signature', 'result', 'pubKey', 'pubkey'].includes(key)) {
168
+ callbackUrl.searchParams.set(key, value);
169
+ }
170
+ });
171
+
172
+ callbackUrl.searchParams.set('amberType', type);
173
+ callbackUrl.searchParams.set('amberId', id);
174
+
175
+ const name = document.title || window.location.hostname || 'Nostr Login';
125
176
 
126
177
  const params = new URLSearchParams();
127
178
  params.set('type', type);
128
179
  params.set('id', id);
129
- params.set('callbackUrl', url.toString());
130
- params.set('name', document.title || window.location.hostname || 'Nostr Login');
180
+ params.set('callbackUrl', callbackUrl.toString());
181
+ params.set('name', name);
182
+ params.set('app_name', name); // Alias just in case
183
+
131
184
  if (recipient) {
132
- params.set('pubkey', recipient);
185
+ params.set('pubkey', recipient);
186
+ params.set('pubKey', recipient); // Alias
133
187
  } else if (this._pubkey) {
134
- params.set('pubkey', this._pubkey);
188
+ params.set('pubkey', this._pubkey);
189
+ params.set('pubKey', this._pubkey); // Alias
135
190
  }
136
191
 
137
192
  const dataPart = content ? encodeURIComponent(content) : '/';
@@ -143,19 +198,25 @@ export class AmberDirectSigner implements Signer {
143
198
  const params = new URLSearchParams(url.search);
144
199
  const hashParams = new URLSearchParams(url.hash.substring(1));
145
200
 
146
- let type = params.get('amberType') || hashParams.get('amberType');
147
- let id = params.get('amberId') || hashParams.get('amberId');
148
- let result = params.get('signature') || params.get('result') || params.get('pubKey') ||
149
- hashParams.get('signature') || hashParams.get('result') || hashParams.get('pubKey');
201
+ const getParam = (name: string) => params.get(name) || hashParams.get(name);
202
+
203
+ const type = getParam('amberType') || getParam('type');
204
+ const id = getParam('amberId') || getParam('id');
205
+ const result = getParam('signature') || getParam('result') || getParam('pubKey') || getParam('pubkey');
206
+
207
+ if (type && result) {
208
+ // ID might be missing in some older redirect cases, but we need it for precise resolution
209
+ const finalId = id || '';
150
210
 
151
- if (type && id && result) {
152
- // Clean up URL
153
- const newUrl = new URL(window.location.href);
154
- ['amberType', 'amberId', 'signature', 'result', 'pubKey'].forEach(p => newUrl.searchParams.delete(p));
155
- newUrl.hash = '';
156
- window.history.replaceState({}, '', newUrl.toString());
211
+ // Clean up URL
212
+ const newUrl = new URL(window.location.href);
213
+ ['amberType', 'amberId', 'signature', 'result', 'pubKey', 'pubkey', 'type', 'id'].forEach(p => {
214
+ newUrl.searchParams.delete(p);
215
+ });
216
+ newUrl.hash = '';
217
+ window.history.replaceState({}, '', newUrl.toString());
157
218
 
158
- return { type, id, result };
219
+ return { type, id: finalId, result };
159
220
  }
160
221
  return null;
161
222
  }
@@ -98,6 +98,10 @@ class AuthNostrService extends EventEmitter implements Signer {
98
98
  const response = AmberDirectSigner.parseResponse();
99
99
  if (response) {
100
100
  console.log('Amber response detected', response);
101
+
102
+ // Resolve pending promises if any (for non-reload cases)
103
+ AmberDirectSigner.resolvePending(response.id, response.type, response.result);
104
+
101
105
  if (response.type === 'get_public_key') {
102
106
  const info: Info = {
103
107
  pubkey: response.result,