@konemono/nostr-login 1.7.56 → 1.7.58

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.56",
3
+ "version": "1.7.58",
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,40 @@ 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, result: string) {
56
+ const resolve = this.pendingResolves.get(id);
57
+ if (resolve) {
58
+ console.log('Resolving pending Amber promise', id);
59
+ resolve(result);
60
+ this.pendingResolves.delete(id);
61
+ return true;
62
+ }
63
+ return false;
64
+ }
65
+
55
66
  async signEvent(event: any): Promise<any> {
56
67
  const content = JSON.stringify(event);
57
68
  const cached = this.checkCache(content, 'sign_event');
58
69
  if (cached) {
59
- return JSON.parse(cached);
70
+ return JSON.parse(cached);
60
71
  }
61
72
 
62
73
  const id = Math.random().toString(36).substring(7);
63
74
  this.setPending(id, content, 'sign_event');
64
75
  const url = this.generateUrl(content, 'sign_event', id);
65
76
  window.location.href = url;
66
- // This will never resolve because of page reload
67
- return new Promise(() => {});
77
+ return new Promise((resolve) => {
78
+ AmberDirectSigner.pendingResolves.set(id, (res) => resolve(JSON.parse(res)));
79
+ });
80
+ }
81
+
82
+ async getPublicKey(): Promise<string> {
83
+ const id = Math.random().toString(36).substring(7);
84
+ const url = this.generateUrl('', 'get_public_key', id);
85
+ window.location.href = url;
86
+ return new Promise((resolve) => {
87
+ AmberDirectSigner.pendingResolves.set(id, resolve);
88
+ });
68
89
  }
69
90
 
70
91
  async encrypt04(pubkey: string, plaintext: string): Promise<string> {
@@ -75,7 +96,9 @@ export class AmberDirectSigner implements Signer {
75
96
  this.setPending(id, plaintext, 'nip04_encrypt');
76
97
  const url = this.generateUrl(plaintext, 'nip04_encrypt', id, pubkey);
77
98
  window.location.href = url;
78
- return new Promise(() => {});
99
+ return new Promise((resolve) => {
100
+ AmberDirectSigner.pendingResolves.set(id, resolve);
101
+ });
79
102
  }
80
103
 
81
104
  async decrypt04(pubkey: string, ciphertext: string): Promise<string> {
@@ -86,7 +109,9 @@ export class AmberDirectSigner implements Signer {
86
109
  this.setPending(id, ciphertext, 'nip04_decrypt');
87
110
  const url = this.generateUrl(ciphertext, 'nip04_decrypt', id, pubkey);
88
111
  window.location.href = url;
89
- return new Promise(() => {});
112
+ return new Promise((resolve) => {
113
+ AmberDirectSigner.pendingResolves.set(id, resolve);
114
+ });
90
115
  }
91
116
 
92
117
  async encrypt44(pubkey: string, plaintext: string): Promise<string> {
@@ -97,7 +122,9 @@ export class AmberDirectSigner implements Signer {
97
122
  this.setPending(id, plaintext, 'nip44_encrypt');
98
123
  const url = this.generateUrl(plaintext, 'nip44_encrypt', id, pubkey);
99
124
  window.location.href = url;
100
- return new Promise(() => {});
125
+ return new Promise((resolve) => {
126
+ AmberDirectSigner.pendingResolves.set(id, resolve);
127
+ });
101
128
  }
102
129
 
103
130
  async decrypt44(pubkey: string, ciphertext: string): Promise<string> {
@@ -108,67 +135,59 @@ export class AmberDirectSigner implements Signer {
108
135
  this.setPending(id, ciphertext, 'nip44_decrypt');
109
136
  const url = this.generateUrl(ciphertext, 'nip44_decrypt', id, pubkey);
110
137
  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(() => {});
138
+ return new Promise((resolve) => {
139
+ AmberDirectSigner.pendingResolves.set(id, resolve);
140
+ });
119
141
  }
120
142
 
121
143
  private generateUrl(content: string, type: string, id: string, recipient?: string): string {
122
- const url = new URL(window.location.href);
123
- const searchParams = url.searchParams;
124
- searchParams.delete('amberType');
125
- searchParams.delete('amberId');
126
- searchParams.delete('signature');
127
- searchParams.delete('result');
128
- url.hash = ''; // Amber/Android may not handle hash in callbackUrl well
129
-
130
- url.searchParams.set('amberType', type);
131
- url.searchParams.set('amberId', id);
132
-
133
- const params = new URLSearchParams();
134
- params.set('type', type);
135
- params.set('id', id);
136
- params.set('callbackUrl', url.toString());
137
- params.set('name', document.location.host);
144
+ const callbackUrl = new URL(window.location.origin + window.location.pathname);
145
+ callbackUrl.searchParams.set('amberType', type);
146
+ callbackUrl.searchParams.set('amberId', id);
147
+
148
+ const action = `com.greenart7c3.nostrsigner.${type.toUpperCase()}`;
149
+ const name = document.title || window.location.hostname || 'Nostr Login';
150
+
151
+ const params = [
152
+ `S.type=${encodeURIComponent(type)}`,
153
+ `S.name=${encodeURIComponent(name)}`,
154
+ `S.callbackUrl=${encodeURIComponent(callbackUrl.toString())}`,
155
+ `S.id=${encodeURIComponent(id)}`
156
+ ];
157
+
138
158
  if (recipient) {
139
- params.set('pubkey', recipient);
159
+ params.push(`S.pubKey=${encodeURIComponent(recipient)}`);
140
160
  } else if (this._pubkey) {
141
- params.set('pubkey', this._pubkey);
161
+ params.push(`S.pubKey=${encodeURIComponent(this._pubkey)}`);
142
162
  }
143
163
 
144
- return `nostrsigner:${encodeURIComponent(content)}?${params.toString()}`;
164
+ if (type === 'sign_event') {
165
+ params.push(`S.event=${encodeURIComponent(content)}`);
166
+ } else {
167
+ params.push(`S.content=${encodeURIComponent(content)}`);
168
+ }
169
+
170
+ return `intent:#Intent;action=${action};package=com.greenart7c3.nostrsigner;${params.join(';')};end`;
145
171
  }
146
172
 
147
173
  public static parseResponse(): { type: string; id: string; result: string } | null {
148
- const params = new URLSearchParams(window.location.search);
149
- let type = params.get('amberType');
150
- let id = params.get('amberId');
151
- let result = params.get('signature') || params.get('result'); // Amber uses signature for events, result for others?
152
-
153
- // Also check hash
154
- if (!type || !id || !result) {
155
- const hashParams = new URLSearchParams(window.location.hash.substring(1));
156
- type = type || hashParams.get('amberType');
157
- id = id || hashParams.get('amberId');
158
- result = result || hashParams.get('signature') || hashParams.get('result');
159
- }
174
+ const url = new URL(window.location.href);
175
+ const params = new URLSearchParams(url.search);
176
+ const hashParams = new URLSearchParams(url.hash.substring(1));
177
+
178
+ const type = params.get('amberType') || hashParams.get('amberType');
179
+ const id = params.get('amberId') || hashParams.get('amberId');
180
+ const result = params.get('signature') || params.get('result') || params.get('pubKey') || params.get('pubkey') ||
181
+ hashParams.get('signature') || hashParams.get('result') || hashParams.get('pubKey') || hashParams.get('pubkey');
160
182
 
161
183
  if (type && id && result) {
162
- // Clean up URL
163
- const newUrl = new URL(window.location.href);
164
- newUrl.searchParams.delete('amberType');
165
- newUrl.searchParams.delete('amberId');
166
- newUrl.searchParams.delete('signature');
167
- newUrl.searchParams.delete('result');
168
- newUrl.hash = ''; // Clear hash too
169
- window.history.replaceState({}, '', newUrl.toString());
170
-
171
- return { type, id, result };
184
+ // Clean up URL
185
+ const newUrl = new URL(window.location.href);
186
+ ['amberType', 'amberId', 'signature', 'result', 'pubKey', 'pubkey'].forEach(p => newUrl.searchParams.delete(p));
187
+ newUrl.hash = '';
188
+ window.history.replaceState({}, '', newUrl.toString());
189
+
190
+ return { type, id, result };
172
191
  }
173
192
  return null;
174
193
  }
@@ -86,9 +86,10 @@ class AuthNostrService extends EventEmitter implements Signer {
86
86
  decrypt: this.decrypt44.bind(this),
87
87
  };
88
88
 
89
- setTimeout(() => this.checkAmberResponse(), 500);
89
+ setTimeout(() => this.checkAmberResponse(), 100);
90
90
 
91
91
  window.addEventListener('focus', () => {
92
+ console.log('Window focused, checking Amber response');
92
93
  this.checkAmberResponse();
93
94
  });
94
95
  }
@@ -96,11 +97,17 @@ class AuthNostrService extends EventEmitter implements Signer {
96
97
  private checkAmberResponse() {
97
98
  const response = AmberDirectSigner.parseResponse();
98
99
  if (response) {
100
+ console.log('Amber response detected', response);
101
+
102
+ // Resolve pending promises if any (for non-reload cases)
103
+ AmberDirectSigner.resolvePending(response.id, response.result);
104
+
99
105
  if (response.type === 'get_public_key') {
100
106
  const info: Info = {
101
107
  pubkey: response.result,
102
108
  authMethod: 'amber' as any,
103
109
  };
110
+ console.log('Amber login success', info);
104
111
  this.onAuth('login', info);
105
112
  } else {
106
113
  const pendingKey = `amber_pending_${response.id}`;