@konemono/nostr-login 1.7.35 → 1.7.37

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.
@@ -1,59 +1,34 @@
1
1
  import NDK, { NDKEvent, NDKFilter, NDKNip46Signer, NDKNostrRpc, NDKRpcRequest, NDKRpcResponse, NDKSubscription, NDKSubscriptionCacheUsage, NostrEvent } from '@nostr-dev-kit/ndk';
2
2
  import { validateEvent, verifySignature } from 'nostr-tools';
3
3
  import { PrivateKeySigner } from './Signer';
4
- import { NIP46_TIMEOUT } from '../const';
5
- import ProcessManager from './ProcessManager';
6
4
 
7
5
  class NostrRpc extends NDKNostrRpc {
8
- protected processManager?: ProcessManager;
9
6
  protected _ndk: NDK;
10
7
  protected _signer: PrivateKeySigner;
11
8
  protected requests: Set<string> = new Set();
12
- protected requestTimeouts: Map<string, NodeJS.Timeout> = new Map();
13
9
  private sub?: NDKSubscription;
14
10
  protected _useNip44: boolean = false;
15
11
 
16
- public cleanupTimersAndRequests() {
17
- this.clearAllTimeouts(); // private/protected なメソッドを呼び出す
18
- this.requests.clear(); // requests Setをクリア
19
- }
20
-
21
- public constructor(ndk: NDK, signer: PrivateKeySigner, processManager?: ProcessManager) {
12
+ public constructor(ndk: NDK, signer: PrivateKeySigner) {
22
13
  super(ndk, signer, ndk.debug.extend('nip46:signer:rpc'));
23
14
  this._ndk = ndk;
24
15
  this._signer = signer;
25
- this.processManager = processManager;
26
16
  }
27
17
 
28
18
  public async subscribe(filter: NDKFilter): Promise<NDKSubscription> {
19
+ // NOTE: fixing ndk
29
20
  filter.kinds = filter.kinds?.filter(k => k === 24133);
30
21
  this.sub = await super.subscribe(filter);
31
22
  return this.sub;
32
23
  }
33
24
 
34
25
  public stop() {
35
- this.clearAllTimeouts();
36
26
  if (this.sub) {
37
27
  this.sub.stop();
38
28
  this.sub = undefined;
39
29
  }
40
30
  }
41
31
 
42
- protected clearAllTimeouts() {
43
- for (const timeout of this.requestTimeouts.values()) {
44
- clearTimeout(timeout);
45
- }
46
- this.requestTimeouts.clear();
47
- }
48
-
49
- protected clearTimeout(id: string) {
50
- const timeout = this.requestTimeouts.get(id);
51
- if (timeout) {
52
- clearTimeout(timeout);
53
- this.requestTimeouts.delete(id);
54
- }
55
- }
56
-
57
32
  public setUseNip44(useNip44: boolean) {
58
33
  this._useNip44 = useNip44;
59
34
  }
@@ -64,6 +39,7 @@ class NostrRpc extends NDKNostrRpc {
64
39
  return ciphertext[l - 28] === '?' && ciphertext[l - 27] === 'i' && ciphertext[l - 26] === 'v' && ciphertext[l - 25] === '=';
65
40
  }
66
41
 
42
+ // override to auto-decrypt nip04/nip44
67
43
  public async parseEvent(event: NDKEvent): Promise<NDKRpcRequest | NDKRpcResponse> {
68
44
  const remoteUser = this._ndk.getUser({ pubkey: event.pubkey });
69
45
  remoteUser.ndk = this._ndk;
@@ -92,6 +68,9 @@ class NostrRpc extends NDKNostrRpc {
92
68
  }
93
69
  }
94
70
 
71
+ // ndk doesn't support nostrconnect:
72
+ // we just listed to an unsolicited reply to
73
+ // our pubkey and if it's ack/secret - we're fine
95
74
  public async listen(nostrConnectSecret: string): Promise<string> {
96
75
  const pubkey = this._signer.pubkey;
97
76
  console.log('nostr-login listening for conn to', pubkey);
@@ -100,45 +79,40 @@ class NostrRpc extends NDKNostrRpc {
100
79
  '#p': [pubkey],
101
80
  });
102
81
  return new Promise<string>((ok, err) => {
103
- const timeoutId = setTimeout(() => {
104
- this.stop();
105
- err(new Error('NIP46 listen timeout'));
106
- }, NIP46_TIMEOUT);
107
-
108
82
  sub.on('event', async (event: NDKEvent) => {
109
83
  try {
110
84
  const parsedEvent = await this.parseEvent(event);
85
+ // console.log('ack parsedEvent', parsedEvent);
111
86
  if (!(parsedEvent as NDKRpcRequest).method) {
112
87
  const response = parsedEvent as NDKRpcResponse;
113
88
 
89
+ // ignore
114
90
  if (response.result === 'auth_url') return;
115
91
 
92
+ // FIXME for now accept 'ack' replies, later on only
93
+ // accept secrets
116
94
  if (response.result === 'ack' || response.result === nostrConnectSecret) {
117
- clearTimeout(timeoutId);
118
95
  ok(event.pubkey);
119
96
  } else {
120
- clearTimeout(timeoutId);
121
97
  err(response.error);
122
98
  }
123
99
  }
124
100
  } catch (e) {
125
101
  console.log('error parsing event', e, event.rawEvent());
126
102
  }
103
+ // done
127
104
  this.stop();
128
105
  });
129
106
  });
130
107
  }
131
108
 
109
+ // since ndk doesn't yet support perms param
110
+ // we reimplement the 'connect' call here
111
+ // instead of await signer.blockUntilReady();
132
112
  public async connect(pubkey: string, token?: string, perms?: string) {
133
113
  return new Promise<void>((ok, err) => {
134
114
  const connectParams = [pubkey!, token || '', perms || ''];
135
-
136
- const timeoutId = setTimeout(() => {
137
- err(new Error('NIP46 connect timeout'));
138
- }, NIP46_TIMEOUT);
139
-
140
115
  this.sendRequest(pubkey!, 'connect', connectParams, 24133, (response: NDKRpcResponse) => {
141
- clearTimeout(timeoutId);
142
116
  if (response.result === 'ack') {
143
117
  ok();
144
118
  } else {
@@ -152,112 +126,24 @@ class NostrRpc extends NDKNostrRpc {
152
126
  return Math.random().toString(36).substring(7);
153
127
  }
154
128
 
155
- protected async ensureConnected(): Promise<void> {
156
- const relays = Array.from(this._ndk.pool.relays.values());
157
- console.log(
158
- 'Checking relay connections:',
159
- relays.map(r => ({ url: r.url, status: r.status })),
160
- );
161
-
162
- const connectedRelays = relays.filter(r => r.status === 1);
163
- console.log('connected relays', connectedRelays);
164
-
165
- if (connectedRelays.length === 0) {
166
- console.log('No connected relays, forcing reconnection...');
167
-
168
- // 既存の接続を全てクリーンアップ
169
- for (const relay of relays) {
170
- try {
171
- await relay.disconnect();
172
- } catch (e) {
173
- console.log('Error disconnecting relay:', relay.url, e);
174
- }
175
- }
176
-
177
- // 再接続
178
- await this._ndk.connect();
179
-
180
- // 接続確立を待つ
181
- await new Promise<void>((resolve, reject) => {
182
- const timeout = setTimeout(() => {
183
- const status = Array.from(this._ndk.pool.relays.values()).map(r => ({ url: r.url, status: r.status }));
184
- console.error('Failed to reconnect to relays within 10s. Status:', status);
185
- reject(new Error('Failed to reconnect to relays'));
186
- }, 10000);
187
-
188
- const checkConnection = () => {
189
- const connected = Array.from(this._ndk.pool.relays.values()).filter(r => r.status === 1);
190
- if (connected.length > 0) {
191
- clearTimeout(timeout);
192
- console.log(
193
- 'Successfully reconnected to',
194
- connected.length,
195
- 'relays:',
196
- connected.map(r => r.url),
197
- );
198
- resolve();
199
- } else {
200
- setTimeout(checkConnection, 200);
201
- }
202
- };
203
- checkConnection();
204
- });
205
- } else {
206
- console.log(
207
- 'Already connected to',
208
- connectedRelays.length,
209
- 'relays:',
210
- connectedRelays.map(r => r.url),
211
- );
212
- }
213
- }
214
-
215
129
  public async sendRequest(remotePubkey: string, method: string, params: string[] = [], kind = 24133, cb?: (res: NDKRpcResponse) => void): Promise<NDKRpcResponse> {
216
- console.log('sendRequest called:', method, 'to', remotePubkey);
217
-
218
- try {
219
- this.processManager?.pause();
220
- await this.ensureConnected();
221
- } catch (e) {
222
- console.error('Failed to ensure connection:', e);
223
- if (cb) {
224
- cb({
225
- id: '',
226
- result: '',
227
- error: 'Failed to connect to relays: ' + (e as Error).message,
228
- event: undefined as any,
229
- });
230
- }
231
- throw e;
232
- } finally {
233
- this.processManager?.resume();
234
- }
235
-
236
130
  const id = this.getId();
237
131
 
132
+ // response handler will deduplicate auth urls and responses
238
133
  this.setResponseHandler(id, cb);
239
134
 
135
+ // create and sign request
240
136
  const event = await this.createRequestEvent(id, remotePubkey, method, params, kind);
241
- console.log('sendRequest event created', { event, method, remotePubkey, params });
137
+ console.log("sendRequest", { event, method, remotePubkey, params });
242
138
 
243
- try {
244
- await event.publish();
245
- console.log('sendRequest event published successfully');
246
- } catch (e) {
247
- console.error('Failed to publish event:', e);
248
- this.clearTimeout(id);
249
- this.requests.delete(id);
250
- if (cb) {
251
- cb({
252
- id,
253
- result: '',
254
- error: 'Failed to publish event: ' + (e as Error).message,
255
- event: undefined as any,
256
- });
257
- }
258
- throw e;
259
- }
139
+ // send to relays
140
+ await event.publish();
260
141
 
142
+ // NOTE: ndk returns a promise that never resolves and
143
+ // in fact REQUIRES cb to be provided (otherwise no way
144
+ // to consume the result), we've already stepped on the bug
145
+ // of waiting for this unresolvable result, so now we return
146
+ // undefined to make sure waiters fail, not hang.
261
147
  // @ts-ignore
262
148
  return undefined as NDKRpcResponse;
263
149
  }
@@ -265,26 +151,6 @@ class NostrRpc extends NDKNostrRpc {
265
151
  protected setResponseHandler(id: string, cb?: (res: NDKRpcResponse) => void) {
266
152
  let authUrlSent = false;
267
153
  const now = Date.now();
268
-
269
- const timeoutId = setTimeout(() => {
270
- if (this.requests.has(id)) {
271
- clearTimeout(timeoutId);
272
- this.requests.delete(id);
273
- this.requestTimeouts.delete(id);
274
- console.log('NIP46 request timeout for', id);
275
- if (cb) {
276
- cb({
277
- id,
278
- result: '',
279
- error: 'NIP46 request timeout',
280
- event: undefined as any,
281
- });
282
- }
283
- }
284
- }, NIP46_TIMEOUT);
285
-
286
- this.requestTimeouts.set(id, timeoutId);
287
-
288
154
  return new Promise<NDKRpcResponse>(() => {
289
155
  const responseHandler = (response: NDKRpcResponse) => {
290
156
  if (response.result === 'auth_url') {
@@ -295,7 +161,6 @@ class NostrRpc extends NDKNostrRpc {
295
161
  }
296
162
  } else if (cb) {
297
163
  if (this.requests.has(id)) {
298
- this.clearTimeout(id);
299
164
  this.requests.delete(id);
300
165
  console.log('nostr-login processed nip46 request in', Date.now() - now, 'ms');
301
166
  cb(response);
@@ -310,14 +175,6 @@ class NostrRpc extends NDKNostrRpc {
310
175
  protected async createRequestEvent(id: string, remotePubkey: string, method: string, params: string[] = [], kind = 24133) {
311
176
  this.requests.add(id);
312
177
  const localUser = await this._signer.user();
313
-
314
- if (!localUser.pubkey) {
315
- throw new Error('CORRUPTION: Missing local pubkey. Signer state compromised.');
316
- }
317
- if (!remotePubkey) {
318
- throw new Error('CORRUPTION: Missing remote pubkey. Signer state compromised.');
319
- }
320
-
321
178
  const remoteUser = this._ndk.getUser({ pubkey: remotePubkey });
322
179
  const request = { id, method, params };
323
180
 
@@ -354,6 +211,7 @@ export class IframeNostrRpc extends NostrRpc {
354
211
  this._ndk,
355
212
  {},
356
213
  {
214
+ // don't send to relay
357
215
  closeOnEose: true,
358
216
  cacheUsage: NDKSubscriptionCacheUsage.ONLY_CACHE,
359
217
  },
@@ -365,6 +223,7 @@ export class IframeNostrRpc extends NostrRpc {
365
223
 
366
224
  this.iframePort = port;
367
225
 
226
+ // to make sure Chrome doesn't terminate the channel
368
227
  setInterval(() => {
369
228
  console.log('iframe-nip46 ping');
370
229
  this.iframePort!.postMessage('ping');
@@ -379,6 +238,7 @@ export class IframeNostrRpc extends NostrRpc {
379
238
  return;
380
239
  }
381
240
 
241
+ // a copy-paste from rpc.subscribe
382
242
  try {
383
243
  const event = ev.data;
384
244
 
@@ -386,6 +246,7 @@ export class IframeNostrRpc extends NostrRpc {
386
246
  if (!verifySignature(event)) throw new Error('Invalid event signature from iframe');
387
247
  const nevent = new NDKEvent(this._ndk, event);
388
248
  const parsedEvent = await this.parseEvent(nevent);
249
+ // we're only implementing client-side rpc
389
250
  if (!(parsedEvent as NDKRpcRequest).method) {
390
251
  console.log('parsed response', parsedEvent);
391
252
  this.emit(`response-${parsedEvent.id}`, parsedEvent);
@@ -397,60 +258,31 @@ export class IframeNostrRpc extends NostrRpc {
397
258
  }
398
259
 
399
260
  public async sendRequest(remotePubkey: string, method: string, params: string[] = [], kind = 24133, cb?: (res: NDKRpcResponse) => void): Promise<NDKRpcResponse> {
400
- console.log('IframeNostrRpc.sendRequest called:', method, 'iframePort:', !!this.iframePort);
401
-
402
- if (!this.iframePort) {
403
- try {
404
- console.log(this.processManager);
405
- this.processManager?.pause();
406
- await this.ensureConnected();
407
- } catch (e) {
408
- console.error('Failed to ensure connection:', e);
409
- if (cb) {
410
- cb({
411
- id: '',
412
- result: '',
413
- error: 'Failed to connect to relays: ' + (e as Error).message,
414
- event: undefined as any,
415
- });
416
- }
417
- throw e;
418
- } finally {
419
- this.processManager?.resume();
420
- }
421
- }
422
-
423
261
  const id = this.getId();
424
262
 
263
+ // create and sign request event
425
264
  const event = await this.createRequestEvent(id, remotePubkey, method, params, kind);
426
265
 
266
+ // set response handler, it will dedup auth urls,
267
+ // and also dedup response handlers - we're sending
268
+ // to relays and to iframe
427
269
  this.setResponseHandler(id, cb);
428
270
 
429
271
  if (this.iframePort) {
272
+ // map request event id to request id, if iframe
273
+ // has no key it will reply with error:event_id (it can't
274
+ // decrypt the request id without keys)
430
275
  this.iframeRequests.set(event.id, { id, pubkey: remotePubkey });
431
276
 
277
+ // send to iframe
432
278
  console.log('iframe-nip46 sending request to', this.peerOrigin, event.rawEvent());
433
279
  this.iframePort.postMessage(event.rawEvent());
434
280
  } else {
435
- try {
436
- await event.publish();
437
- console.log('Request published to relays successfully');
438
- } catch (e) {
439
- console.error('Failed to publish event:', e);
440
- this.clearTimeout(id);
441
- this.requests.delete(id);
442
- if (cb) {
443
- cb({
444
- id,
445
- result: '',
446
- error: 'Failed to publish event: ' + (e as Error).message,
447
- event: undefined as any,
448
- });
449
- }
450
- throw e;
451
- }
281
+ // send to relays
282
+ await event.publish();
452
283
  }
453
284
 
285
+ // see notes in 'super'
454
286
  // @ts-ignore
455
287
  return undefined as NDKRpcResponse;
456
288
  }
@@ -467,11 +299,14 @@ export class ReadyListener {
467
299
  this.promise = new Promise<any>(ok => {
468
300
  console.log(new Date(), 'started listener for', this.messages);
469
301
 
302
+ // ready message handler
470
303
  const onReady = async (e: MessageEvent) => {
471
304
  const originHostname = new URL(origin!).hostname;
472
305
  const messageHostname = new URL(e.origin).hostname;
306
+ // same host or subdomain
473
307
  const validHost = messageHostname === originHostname || messageHostname.endsWith('.' + originHostname);
474
308
  if (!validHost || !Array.isArray(e.data) || !e.data.length || !this.messages.includes(e.data[0])) {
309
+ // console.log(new Date(), 'got invalid ready message', e.origin, e.data);
475
310
  return;
476
311
  }
477
312
 
@@ -486,6 +321,17 @@ export class ReadyListener {
486
321
  async wait(): Promise<any> {
487
322
  console.log(new Date(), 'waiting for', this.messages);
488
323
  const r = await this.promise;
324
+ // NOTE: timer here doesn't help bcs it must be activated when
325
+ // user "confirms", but that's happening on a different
326
+ // origin and we can't really know.
327
+ // await new Promise<any>((ok, err) => {
328
+ // // 10 sec should be more than enough
329
+ // setTimeout(() => err(new Date() + ' timeout for ' + this.message), 10000);
330
+
331
+ // // if promise already resolved or will resolve in the future
332
+ // this.promise.then(ok);
333
+ // });
334
+
489
335
  console.log(new Date(), 'finished waiting for', this.messages, r);
490
336
  return r;
491
337
  }
@@ -498,8 +344,9 @@ export class Nip46Signer extends NDKNip46Signer {
498
344
  constructor(ndk: NDK, localSigner: PrivateKeySigner, signerPubkey: string, iframeOrigin?: string) {
499
345
  super(ndk, signerPubkey, localSigner);
500
346
 
347
+ // override with our own rpc implementation
501
348
  this._rpc = new IframeNostrRpc(ndk, localSigner, iframeOrigin);
502
- this._rpc.setUseNip44(true);
349
+ this._rpc.setUseNip44(true); // !!this.params.optionsModal.dev);
503
350
  this._rpc.on('authUrl', (url: string) => {
504
351
  this.emit('authUrl', url);
505
352
  });
@@ -512,29 +359,20 @@ export class Nip46Signer extends NDKNip46Signer {
512
359
  }
513
360
 
514
361
  private async setSignerPubkey(signerPubkey: string, sameAsUser: boolean = false) {
515
- console.log('setSignerPubkey', signerPubkey);
362
+ console.log("setSignerPubkey", signerPubkey);
516
363
 
364
+ // ensure it's set
517
365
  this.remotePubkey = signerPubkey;
518
366
 
367
+ // when we're sure it's known
519
368
  this._rpc.on(`iframeRestart-${signerPubkey}`, () => {
520
369
  this.emit('iframeRestart');
521
370
  });
522
371
 
372
+ // now call getPublicKey and swap remotePubkey w/ that
523
373
  await this.initUserPubkey(sameAsUser ? signerPubkey : '');
524
374
  }
525
375
 
526
- public forceResetState() {
527
- console.log('Nip46Signer state reset due to connection failure or timeout.');
528
-
529
- // 1. ユーザー公開鍵をクリア
530
- this._userPubkey = '';
531
-
532
- // 2. リモート公開鍵をクリア
533
- this.remotePubkey = ''; // 親クラスのプロパティをクリア
534
-
535
- // 3. RPC側のタイマーとリクエストを、公開メソッド経由でクリア
536
- (this._rpc as NostrRpc).cleanupTimersAndRequests();
537
- }
538
376
  public async initUserPubkey(hintPubkey?: string) {
539
377
  if (this._userPubkey) throw new Error('Already called initUserPubkey');
540
378
 
@@ -546,19 +384,9 @@ export class Nip46Signer extends NDKNip46Signer {
546
384
  this._userPubkey = await new Promise<string>((ok, err) => {
547
385
  if (!this.remotePubkey) throw new Error('Signer pubkey not set');
548
386
 
549
- console.log('get_public_key', this.remotePubkey);
550
-
551
- const timeoutId = setTimeout(() => {
552
- err(new Error('NIP46 get_public_key timeout'));
553
- }, NIP46_TIMEOUT);
554
-
387
+ console.log("get_public_key", this.remotePubkey);
555
388
  this._rpc.sendRequest(this.remotePubkey, 'get_public_key', [], 24133, (response: NDKRpcResponse) => {
556
- clearTimeout(timeoutId);
557
- if (response.error) {
558
- err(new Error(response.error));
559
- } else {
560
- ok(response.result);
561
- }
389
+ ok(response.result);
562
390
  });
563
391
  });
564
392
  }
@@ -580,21 +408,15 @@ export class Nip46Signer extends NDKNip46Signer {
580
408
  }
581
409
 
582
410
  public async createAccount2({ bunkerPubkey, name, domain, perms = '' }: { bunkerPubkey: string; name: string; domain: string; perms?: string }) {
583
- const params = [name, domain, '', perms];
584
-
585
- const r = await new Promise<NDKRpcResponse>((ok, err) => {
586
- const timeoutId = setTimeout(() => {
587
- err(new Error('NIP46 create_account timeout'));
588
- }, NIP46_TIMEOUT);
589
-
590
- this.rpc.sendRequest(bunkerPubkey, 'create_account', params, undefined, response => {
591
- clearTimeout(timeoutId);
592
- if (response.error) {
593
- err(new Error(response.error));
594
- } else {
595
- ok(response);
596
- }
597
- });
411
+ const params = [
412
+ name,
413
+ domain,
414
+ '', // email
415
+ perms,
416
+ ];
417
+
418
+ const r = await new Promise<NDKRpcResponse>(ok => {
419
+ this.rpc.sendRequest(bunkerPubkey, 'create_account', params, undefined, ok);
598
420
  });
599
421
 
600
422
  console.log('create_account pubkey', r);
@@ -1,4 +1,4 @@
1
- import { Info } from 'nostr-login-components';
1
+ import { Info } from 'nostr-login-components/dist/types/types';
2
2
 
3
3
  export interface Signer {
4
4
  signEvent: (event: any) => Promise<any>;
@@ -1,4 +1,4 @@
1
- import { Info } from 'nostr-login-components';
1
+ import { Info } from 'nostr-login-components/dist/types/types';
2
2
  import { NostrLoginOptions } from '../types';
3
3
 
4
4
  class NostrParams {
@@ -2,7 +2,6 @@ import { EventEmitter } from 'tseep';
2
2
  import { CALL_TIMEOUT } from '../const';
3
3
 
4
4
  class ProcessManager extends EventEmitter {
5
- private paused = false;
6
5
  private callCount: number = 0;
7
6
  private callTimer: NodeJS.Timeout | undefined;
8
7
 
@@ -11,41 +10,22 @@ class ProcessManager extends EventEmitter {
11
10
  }
12
11
 
13
12
  public onAuthUrl() {
14
- console.log('ProcessManager.onAuthUrl called, resetting timer');
15
- this.resetTimer();
13
+ if (Boolean(this.callTimer)) {
14
+ clearTimeout(this.callTimer);
15
+ }
16
16
  }
17
17
 
18
18
  public onIframeUrl() {
19
- console.log('ProcessManager.onIframeUrl called, resetting timer');
20
- this.resetTimer();
21
- }
22
-
23
- private resetTimer() {
24
- // 既存のタイマーがあればクリア
25
- if (this.callTimer) {
19
+ if (Boolean(this.callTimer)) {
26
20
  clearTimeout(this.callTimer);
27
- this.callTimer = undefined; // IDをクリア
28
- console.log('ProcessManager: timer reset');
29
- }
30
-
31
- // 監視対象が残っていて、かつ一時停止中でなければ、新しいタイマーを設定
32
- if (this.callCount > 0 && !this.paused) {
33
- this.callTimer = setTimeout(() => {
34
- console.log('ProcessManager: timeout reached, emitting onCallTimeout');
35
- this.callTimer = undefined; // タイムアウト時にIDをクリア
36
- this.emit('onCallTimeout');
37
- }, CALL_TIMEOUT);
38
- console.log(`ProcessManager: new timer set for ${CALL_TIMEOUT} ms`);
39
21
  }
40
22
  }
41
23
 
42
24
  public async wait<T>(cb: () => Promise<T>): Promise<T> {
43
- console.log('ProcessManager.wait called, callTimer exists:', !!this.callTimer, 'callCount:', this.callCount);
25
+ // FIXME only allow 1 parallel req
44
26
 
45
- // 修正点: タイマーの初期設定を resetTimer に任せる
46
- if (!this.callTimer && this.callCount === 0) {
47
- // waitの最初の呼び出し時のみ、タイマーを初期設定
48
- this.resetTimer();
27
+ if (!this.callTimer) {
28
+ this.callTimer = setTimeout(() => this.emit('onCallTimeout'), CALL_TIMEOUT);
49
29
  }
50
30
 
51
31
  if (!this.callCount) {
@@ -54,52 +34,33 @@ class ProcessManager extends EventEmitter {
54
34
 
55
35
  this.callCount++;
56
36
 
57
- let error: any;
58
- let result: any;
37
+ let error;
38
+ let result;
59
39
 
60
- // 非同期処理の実行
61
40
  try {
62
41
  result = await cb();
63
42
  } catch (e) {
64
43
  error = e;
65
44
  }
66
45
 
67
- // ★ 修正点: クリーンアップロジックを resetTimer に置き換え
68
- // ProcessManagerの呼び出しカウントをデクリメント
69
46
  this.callCount--;
70
- this.emit('onCallEnd');
71
-
72
- // リクエスト完了後、タイマーをリセットし、callCountに応じて再設定
73
- this.resetTimer();
74
47
 
75
- // エラーがあればスローし、呼び出し元に伝播させる
76
- if (error) {
77
- throw error;
78
- }
79
-
80
- // @ts-ignore
81
- return result as T;
82
- }
48
+ this.emit('onCallEnd');
83
49
 
84
- public pause() {
85
- console.log('ProcessManager: PAUSING timer...');
86
50
  if (this.callTimer) {
87
51
  clearTimeout(this.callTimer);
88
52
  }
89
- this.callTimer = undefined; // タイマーをクリア
90
- this.paused = true;
91
- this.emit('onCallPause');
92
- }
93
53
 
94
- public resume() {
95
- console.log('ProcessManager: RESUMING timer...');
96
- this.paused = false;
54
+ this.callTimer = undefined;
97
55
 
98
- // ★ 修正点: pause解除後、監視対象が残っていればタイマーを再設定 (resetTimerを呼び出す)
99
- if (this.callCount > 0 && !this.callTimer) {
100
- this.resetTimer();
56
+ if (error) {
57
+ throw error;
101
58
  }
102
- this.emit('onCallResume');
59
+
60
+ // we can't return undefined bcs an exception is
61
+ // thrown above on error
62
+ // @ts-ignore
63
+ return result;
103
64
  }
104
65
  }
105
66