@konemono/nostr-login 1.7.70 → 1.8.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/dist/index.esm.js +10 -12
- package/dist/index.esm.js.map +1 -1
- package/dist/modules/AmberDirectSigner.d.ts +1 -0
- package/dist/modules/AuthNostrService.d.ts +5 -5
- package/dist/modules/Nip46.d.ts +47 -31
- package/dist/modules/NostrExtensionService.d.ts +5 -0
- package/dist/modules/Signer.d.ts +11 -4
- package/dist/modules/nip46/Nip46Adapter.d.ts +26 -0
- package/dist/modules/nip46/Nip46Client.d.ts +52 -0
- package/dist/modules/nip46/types.d.ts +24 -0
- package/dist/unpkg.js +10 -12
- package/dist/utils/index.d.ts +2 -3
- package/package.json +7 -4
- package/src/index.ts +1 -1
- package/src/modules/AmberDirectSigner.ts +205 -162
- package/src/modules/AuthNostrService.ts +151 -122
- package/src/modules/Nip46.iframe.test.ts +124 -0
- package/src/modules/Nip46.test.ts +31 -0
- package/src/modules/Nip46.ts +212 -261
- package/src/modules/NostrExtensionService.ts +6 -0
- package/src/modules/Signer.ts +39 -8
- package/src/modules/nip46/Nip46Adapter.ts +123 -0
- package/src/modules/nip46/Nip46Client.ts +248 -0
- package/src/modules/nip46/types.ts +26 -0
- package/src/utils/index.ts +63 -22
- package/tsconfig.json +2 -2
- package/vitest.config.ts +9 -0
package/dist/utils/index.d.ts
CHANGED
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
import { Info, RecentType } from 'nostr-login-components/dist/types/types';
|
|
2
|
-
import NDK, { NDKSigner } from '@nostr-dev-kit/ndk';
|
|
3
2
|
import { NostrLoginOptions } from '../types';
|
|
4
3
|
export declare const localStorageSetItem: (key: string, value: string) => void;
|
|
5
4
|
export declare const localStorageGetItem: (key: string) => any;
|
|
6
5
|
export declare const localStorageRemoveItem: (key: string) => void;
|
|
7
|
-
export declare const fetchProfile: (info: Info,
|
|
6
|
+
export declare const fetchProfile: (info: Info, profileNdkOrRelays?: any) => Promise<any>;
|
|
8
7
|
export declare const prepareSignupRelays: (signupRelays?: string) => string[];
|
|
9
|
-
export declare const createProfile: (info: Info,
|
|
8
|
+
export declare const createProfile: (info: Info, signer: any, signupRelays?: string, outboxRelays?: string[]) => Promise<void>;
|
|
10
9
|
export declare const bunkerUrlToInfo: (bunkerUrl: string, sk?: string) => Info;
|
|
11
10
|
export declare const isBunkerUrl: (value: string) => boolean;
|
|
12
11
|
export declare const getBunkerUrl: (value: string, optionsModal: NostrLoginOptions) => Promise<string>;
|
package/package.json
CHANGED
|
@@ -1,17 +1,18 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@konemono/nostr-login",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.8.0",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "./dist/index.esm.js",
|
|
6
6
|
"types": "./dist/index.d.ts",
|
|
7
7
|
"type": "module",
|
|
8
8
|
"scripts": {
|
|
9
9
|
"build": "rollup -c",
|
|
10
|
-
"format": "npx prettier --write src"
|
|
10
|
+
"format": "npx prettier --write src",
|
|
11
|
+
"test": "vitest run",
|
|
12
|
+
"test:watch": "vitest"
|
|
11
13
|
},
|
|
12
14
|
"author": "a-fralou",
|
|
13
15
|
"dependencies": {
|
|
14
|
-
"@nostr-dev-kit/ndk": "^2.3.1",
|
|
15
16
|
"nostr-tools": "^1.17.0",
|
|
16
17
|
"tseep": "^1.2.1"
|
|
17
18
|
},
|
|
@@ -22,7 +23,9 @@
|
|
|
22
23
|
"nostr-login-components": "^1.0.3",
|
|
23
24
|
"prettier": "^3.2.2",
|
|
24
25
|
"rollup": "^4.9.6",
|
|
25
|
-
"rollup-plugin-typescript2": "^0.36.0"
|
|
26
|
+
"rollup-plugin-typescript2": "^0.36.0",
|
|
27
|
+
"vitest": "^1.0.0",
|
|
28
|
+
"@types/node": "^18.0.0"
|
|
26
29
|
},
|
|
27
30
|
"license": "MIT"
|
|
28
31
|
}
|
package/src/index.ts
CHANGED
|
@@ -149,7 +149,7 @@ export class NostrLoginInitializer {
|
|
|
149
149
|
|
|
150
150
|
private openPopup(url: string) {
|
|
151
151
|
if (url.startsWith('nostrsigner:')) {
|
|
152
|
-
window.
|
|
152
|
+
window.open(url, '_blank', 'width=400,height=600');
|
|
153
153
|
} else {
|
|
154
154
|
this.popupManager.openPopup(url);
|
|
155
155
|
}
|
|
@@ -2,184 +2,227 @@ import { AmberResponse } from '../types';
|
|
|
2
2
|
import { Signer } from './Nostr';
|
|
3
3
|
|
|
4
4
|
export class AmberDirectSigner implements Signer {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
5
|
+
private _pubkey: string;
|
|
6
|
+
private static pendingResolves: Map<string, { resolve: (result: string) => void; timer: NodeJS.Timeout | null }> = new Map();
|
|
7
|
+
|
|
8
|
+
constructor(pubkey: string = '') {
|
|
9
|
+
this._pubkey = pubkey;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
get pubkey() {
|
|
13
|
+
return this._pubkey;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
set pubkey(v: string) {
|
|
17
|
+
this._pubkey = v;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
public nip04 = {
|
|
21
|
+
encrypt: (pubkey: string, plaintext: string) => this.encrypt04(pubkey, plaintext),
|
|
22
|
+
decrypt: (pubkey: string, ciphertext: string) => this.decrypt04(pubkey, ciphertext),
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
public nip44 = {
|
|
26
|
+
encrypt: (pubkey: string, plaintext: string) => this.encrypt44(pubkey, plaintext),
|
|
27
|
+
decrypt: (pubkey: string, ciphertext: string) => this.decrypt44(pubkey, ciphertext),
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
public async getPublicKey(id?: string): Promise<string> {
|
|
31
|
+
id = id || Math.random().toString(36).substring(7);
|
|
32
|
+
const url = this.generateUrl('', 'get_public_key', id);
|
|
33
|
+
console.log('Amber redirecting to:', url);
|
|
34
|
+
window.open(url, '_blank', 'width=400,height=600');
|
|
35
|
+
return new Promise((resolve, reject) => {
|
|
36
|
+
const timer = setTimeout(() => {
|
|
37
|
+
AmberDirectSigner.pendingResolves.delete(id!);
|
|
38
|
+
reject(new Error('AmberDirectSigner timeout'));
|
|
39
|
+
}, 20000);
|
|
40
|
+
AmberDirectSigner.pendingResolves.set(id!, { resolve, timer });
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
public async signEvent(event: any, id?: string): Promise<any> {
|
|
45
|
+
id = id || Math.random().toString(36).substring(7);
|
|
46
|
+
const url = this.generateUrl(JSON.stringify(event), 'sign_event', id);
|
|
47
|
+
console.log('Amber redirecting to:', url);
|
|
48
|
+
window.open(url, '_blank', 'width=400,height=600');
|
|
49
|
+
return new Promise((resolve, reject) => {
|
|
50
|
+
const timer = setTimeout(() => {
|
|
51
|
+
AmberDirectSigner.pendingResolves.delete(id!);
|
|
52
|
+
reject(new Error('AmberDirectSigner timeout'));
|
|
53
|
+
}, 20000);
|
|
54
|
+
AmberDirectSigner.pendingResolves.set(id!, {
|
|
55
|
+
resolve: (result: string) => {
|
|
56
|
+
try {
|
|
57
|
+
resolve(JSON.parse(result));
|
|
58
|
+
} catch (e) {
|
|
59
|
+
resolve(result as any);
|
|
60
|
+
}
|
|
61
|
+
},
|
|
62
|
+
timer,
|
|
63
|
+
});
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
public async encrypt04(pubkey: string, plaintext: string, id?: string): Promise<string> {
|
|
68
|
+
id = id || Math.random().toString(36).substring(7);
|
|
69
|
+
const url = this.generateUrl(plaintext, 'nip04_encrypt', id, pubkey);
|
|
70
|
+
console.log('Amber redirecting to:', url);
|
|
71
|
+
window.open(url, '_blank', 'width=400,height=600');
|
|
72
|
+
return new Promise((resolve, reject) => {
|
|
73
|
+
const timer = setTimeout(() => {
|
|
74
|
+
AmberDirectSigner.pendingResolves.delete(id!);
|
|
75
|
+
reject(new Error('AmberDirectSigner timeout'));
|
|
76
|
+
}, 20000);
|
|
77
|
+
AmberDirectSigner.pendingResolves.set(id!, { resolve, timer });
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
public async decrypt04(pubkey: string, ciphertext: string, id?: string): Promise<string> {
|
|
82
|
+
id = id || Math.random().toString(36).substring(7);
|
|
83
|
+
const url = this.generateUrl(ciphertext, 'nip04_decrypt', id, pubkey);
|
|
84
|
+
console.log('Amber redirecting to:', url);
|
|
85
|
+
window.open(url, '_blank', 'width=400,height=600');
|
|
86
|
+
return new Promise((resolve, reject) => {
|
|
87
|
+
const timer = setTimeout(() => {
|
|
88
|
+
AmberDirectSigner.pendingResolves.delete(id!);
|
|
89
|
+
reject(new Error('AmberDirectSigner timeout'));
|
|
90
|
+
}, 20000);
|
|
91
|
+
AmberDirectSigner.pendingResolves.set(id!, { resolve, timer });
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
public async encrypt44(pubkey: string, plaintext: string, id?: string): Promise<string> {
|
|
96
|
+
id = id || Math.random().toString(36).substring(7);
|
|
97
|
+
const url = this.generateUrl(plaintext, 'nip44_encrypt', id, pubkey);
|
|
98
|
+
console.log('Amber redirecting to:', url);
|
|
99
|
+
window.open(url, '_blank', 'width=400,height=600');
|
|
100
|
+
return new Promise((resolve, reject) => {
|
|
101
|
+
const timer = setTimeout(() => {
|
|
102
|
+
AmberDirectSigner.pendingResolves.delete(id!);
|
|
103
|
+
reject(new Error('AmberDirectSigner timeout'));
|
|
104
|
+
}, 20000);
|
|
105
|
+
AmberDirectSigner.pendingResolves.set(id!, { resolve, timer });
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
public async decrypt44(pubkey: string, ciphertext: string, id?: string): Promise<string> {
|
|
110
|
+
id = id || Math.random().toString(36).substring(7);
|
|
111
|
+
const url = this.generateUrl(ciphertext, 'nip44_decrypt', id, pubkey);
|
|
112
|
+
console.log('Amber redirecting to:', url);
|
|
113
|
+
window.open(url, '_blank', 'width=400,height=600');
|
|
114
|
+
return new Promise((resolve, reject) => {
|
|
115
|
+
const timer = setTimeout(() => {
|
|
116
|
+
AmberDirectSigner.pendingResolves.delete(id!);
|
|
117
|
+
reject(new Error('AmberDirectSigner timeout'));
|
|
118
|
+
}, 20000);
|
|
119
|
+
AmberDirectSigner.pendingResolves.set(id!, { resolve, timer });
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
public generateUrl(content: string, type: string, id: string, pubkey?: string): string {
|
|
124
|
+
const callbackUrl = window.location.href.split('#')[0].split('?')[0];
|
|
125
|
+
const encodedContent = encodeURIComponent(content || '');
|
|
126
|
+
const encodedCallback = encodeURIComponent(callbackUrl);
|
|
127
|
+
|
|
128
|
+
localStorage.setItem('amber_last_type', type);
|
|
129
|
+
localStorage.setItem('amber_last_id', id);
|
|
130
|
+
localStorage.setItem('amber_last_timestamp', Date.now().toString());
|
|
131
|
+
|
|
132
|
+
// NIP-55準拠: nostrsigner: スキーム
|
|
133
|
+
let url = `nostrsigner:${encodedContent}`;
|
|
134
|
+
const params = new URLSearchParams();
|
|
135
|
+
params.append('compressionType', 'none');
|
|
136
|
+
params.append('returnType', 'signature');
|
|
137
|
+
params.append('type', type);
|
|
138
|
+
params.append('callbackUrl', callbackUrl);
|
|
139
|
+
|
|
140
|
+
// 三重の冗長性でアプリ名を渡す
|
|
141
|
+
const appName = document.title || window.location.hostname;
|
|
142
|
+
params.append('name', appName);
|
|
143
|
+
params.append('appName', appName);
|
|
144
|
+
params.append('app', appName);
|
|
145
|
+
|
|
146
|
+
// NIP-46互換のmetadata形式も追加
|
|
147
|
+
const metadata = {
|
|
148
|
+
name: appName,
|
|
149
|
+
url: window.location.origin,
|
|
150
|
+
description: 'Nostr Login provided by nostr-login library',
|
|
23
151
|
};
|
|
152
|
+
params.append('metadata', JSON.stringify(metadata));
|
|
24
153
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
decrypt: (pubkey: string, ciphertext: string) => this.decrypt44(pubkey, ciphertext),
|
|
28
|
-
};
|
|
29
|
-
|
|
30
|
-
public async getPublicKey(id?: string): Promise<string> {
|
|
31
|
-
id = id || Math.random().toString(36).substring(7);
|
|
32
|
-
const url = this.generateUrl('', 'get_public_key', id);
|
|
33
|
-
console.log('Amber redirecting to:', url);
|
|
34
|
-
window.location.assign(url);
|
|
35
|
-
return new Promise((resolve) => {
|
|
36
|
-
AmberDirectSigner.pendingResolves.set(id!, resolve);
|
|
37
|
-
});
|
|
38
|
-
}
|
|
154
|
+
if (pubkey) params.append('pubkey', pubkey);
|
|
155
|
+
if (this._pubkey) params.append('current_user', this._pubkey);
|
|
39
156
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
const url = this.generateUrl(JSON.stringify(event), 'sign_event', id);
|
|
43
|
-
console.log('Amber redirecting to:', url);
|
|
44
|
-
window.location.assign(url);
|
|
45
|
-
return new Promise((resolve) => {
|
|
46
|
-
AmberDirectSigner.pendingResolves.set(id!, (result: string) => {
|
|
47
|
-
resolve(JSON.parse(result));
|
|
48
|
-
});
|
|
49
|
-
});
|
|
50
|
-
}
|
|
157
|
+
return `${url}?${params.toString()}`;
|
|
158
|
+
}
|
|
51
159
|
|
|
52
|
-
|
|
53
|
-
id = id || Math.random().toString(36).substring(7);
|
|
54
|
-
const url = this.generateUrl(plaintext, 'nip04_encrypt', id, pubkey);
|
|
55
|
-
console.log('Amber redirecting to:', url);
|
|
56
|
-
window.location.assign(url);
|
|
57
|
-
return new Promise((resolve) => {
|
|
58
|
-
AmberDirectSigner.pendingResolves.set(id!, resolve);
|
|
59
|
-
});
|
|
60
|
-
}
|
|
160
|
+
// AmberDirectSigner.ts の parseResponse を拡張
|
|
61
161
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
const url = this.generateUrl(ciphertext, 'nip04_decrypt', id, pubkey);
|
|
65
|
-
console.log('Amber redirecting to:', url);
|
|
66
|
-
window.location.assign(url);
|
|
67
|
-
return new Promise((resolve) => {
|
|
68
|
-
AmberDirectSigner.pendingResolves.set(id!, resolve);
|
|
69
|
-
});
|
|
70
|
-
}
|
|
162
|
+
static parseResponse(): AmberResponse | null {
|
|
163
|
+
const url = new URL(window.location.href);
|
|
71
164
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
const url = this.generateUrl(plaintext, 'nip44_encrypt', id, pubkey);
|
|
75
|
-
console.log('Amber redirecting to:', url);
|
|
76
|
-
window.location.assign(url);
|
|
77
|
-
return new Promise((resolve) => {
|
|
78
|
-
AmberDirectSigner.pendingResolves.set(id!, resolve);
|
|
79
|
-
});
|
|
80
|
-
}
|
|
165
|
+
// パターン1: NIP-55標準 (?event=...)
|
|
166
|
+
let result = url.searchParams.get('event');
|
|
81
167
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
168
|
+
// パターン2: パス末尾にhexId (/<hexId>)
|
|
169
|
+
if (!result) {
|
|
170
|
+
const pathParts = url.pathname.split('/').filter(Boolean);
|
|
171
|
+
if (pathParts.length > 0) {
|
|
172
|
+
const lastPart = pathParts[pathParts.length - 1];
|
|
173
|
+
// hexIdっぽい(64文字の16進数)
|
|
174
|
+
if (/^[0-9a-f]{64}$/i.test(lastPart)) {
|
|
175
|
+
result = lastPart;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
90
178
|
}
|
|
91
179
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
localStorage.
|
|
99
|
-
|
|
100
|
-
localStorage.setItem('amber_last_timestamp', Date.now().toString());
|
|
101
|
-
|
|
102
|
-
// NIP-55準拠: nostrsigner: スキーム
|
|
103
|
-
let url = `nostrsigner:${encodedContent}`;
|
|
104
|
-
const params = new URLSearchParams();
|
|
105
|
-
params.append('compressionType', 'none');
|
|
106
|
-
params.append('returnType', 'signature');
|
|
107
|
-
params.append('type', type);
|
|
108
|
-
params.append('callbackUrl', callbackUrl);
|
|
109
|
-
|
|
110
|
-
// 三重の冗長性でアプリ名を渡す
|
|
111
|
-
const appName = document.title || window.location.hostname;
|
|
112
|
-
params.append('name', appName);
|
|
113
|
-
params.append('appName', appName);
|
|
114
|
-
params.append('app', appName);
|
|
115
|
-
|
|
116
|
-
// NIP-46互換のmetadata形式も追加
|
|
117
|
-
const metadata = {
|
|
118
|
-
name: appName,
|
|
119
|
-
url: window.location.origin,
|
|
120
|
-
description: 'Nostr Login provided by nostr-login library'
|
|
121
|
-
};
|
|
122
|
-
params.append('metadata', JSON.stringify(metadata));
|
|
123
|
-
|
|
124
|
-
if (pubkey) params.append('pubkey', pubkey);
|
|
125
|
-
if (this._pubkey) params.append('current_user', this._pubkey);
|
|
126
|
-
|
|
127
|
-
return `${url}?${params.toString()}`;
|
|
180
|
+
if (result) {
|
|
181
|
+
console.log('Amber response detection:', {
|
|
182
|
+
href: window.location.href,
|
|
183
|
+
eventParam: url.searchParams.get('event'),
|
|
184
|
+
pathResult: result,
|
|
185
|
+
sessionId: localStorage.getItem('amber_last_id'),
|
|
186
|
+
sessionType: localStorage.getItem('amber_last_type'),
|
|
187
|
+
});
|
|
128
188
|
}
|
|
129
189
|
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
static parseResponse(): AmberResponse | null {
|
|
133
|
-
const url = new URL(window.location.href);
|
|
190
|
+
if (!result) return null;
|
|
134
191
|
|
|
135
|
-
|
|
136
|
-
|
|
192
|
+
const id = localStorage.getItem('amber_last_id');
|
|
193
|
+
const type = localStorage.getItem('amber_last_type');
|
|
137
194
|
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
if (pathParts.length > 0) {
|
|
142
|
-
const lastPart = pathParts[pathParts.length - 1];
|
|
143
|
-
// hexIdっぽい(64文字の16進数)
|
|
144
|
-
if (/^[0-9a-f]{64}$/i.test(lastPart)) {
|
|
145
|
-
result = lastPart;
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
if (result) {
|
|
151
|
-
console.log('Amber response detection:', {
|
|
152
|
-
href: window.location.href,
|
|
153
|
-
eventParam: url.searchParams.get('event'),
|
|
154
|
-
pathResult: result,
|
|
155
|
-
sessionId: localStorage.getItem('amber_last_id'),
|
|
156
|
-
sessionType: localStorage.getItem('amber_last_type')
|
|
157
|
-
});
|
|
158
|
-
}
|
|
195
|
+
localStorage.removeItem('amber_last_id');
|
|
196
|
+
localStorage.removeItem('amber_last_type');
|
|
197
|
+
localStorage.removeItem('amber_last_timestamp');
|
|
159
198
|
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
const type = localStorage.getItem('amber_last_type');
|
|
164
|
-
|
|
165
|
-
localStorage.removeItem('amber_last_id');
|
|
166
|
-
localStorage.removeItem('amber_last_type');
|
|
167
|
-
localStorage.removeItem('amber_last_timestamp');
|
|
199
|
+
if (id && type) {
|
|
200
|
+
return { id, type, result };
|
|
201
|
+
}
|
|
168
202
|
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
}
|
|
203
|
+
return null;
|
|
204
|
+
}
|
|
172
205
|
|
|
173
|
-
|
|
206
|
+
static resolvePending(id: string, type: string, result: string): boolean {
|
|
207
|
+
const entry = this.pendingResolves.get(id);
|
|
208
|
+
if (entry) {
|
|
209
|
+
this.pendingResolves.delete(id);
|
|
210
|
+
if (entry.timer) clearTimeout(entry.timer);
|
|
211
|
+
entry.resolve(result);
|
|
212
|
+
return true;
|
|
174
213
|
}
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
214
|
+
return false;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
static cleanupPending() {
|
|
218
|
+
for (const [id, entry] of this.pendingResolves) {
|
|
219
|
+
try {
|
|
220
|
+
if (entry.timer) clearTimeout(entry.timer);
|
|
221
|
+
entry.resolve('');
|
|
222
|
+
} catch (e) {
|
|
223
|
+
// ignore
|
|
224
|
+
}
|
|
184
225
|
}
|
|
226
|
+
this.pendingResolves.clear();
|
|
227
|
+
}
|
|
185
228
|
}
|