@juzi/wechaty 1.0.60 → 1.0.62

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.
Files changed (45) hide show
  1. package/dist/cjs/src/package-json.d.ts.map +1 -1
  2. package/dist/cjs/src/package-json.js +3 -2
  3. package/dist/cjs/src/package-json.js.map +1 -1
  4. package/dist/cjs/src/user-modules/room.d.ts.map +1 -1
  5. package/dist/cjs/src/user-modules/room.js +1 -0
  6. package/dist/cjs/src/user-modules/room.js.map +1 -1
  7. package/dist/cjs/src/wechaty/wechaty-base.d.ts +31 -0
  8. package/dist/cjs/src/wechaty/wechaty-base.d.ts.map +1 -1
  9. package/dist/cjs/src/wechaty/wechaty-base.spec.js +75 -2
  10. package/dist/cjs/src/wechaty/wechaty-base.spec.js.map +1 -1
  11. package/dist/cjs/src/wechaty-mixins/login-mixin.d.ts +4 -0
  12. package/dist/cjs/src/wechaty-mixins/login-mixin.d.ts.map +1 -1
  13. package/dist/cjs/src/wechaty-mixins/misc-mixin.d.ts +4 -0
  14. package/dist/cjs/src/wechaty-mixins/misc-mixin.d.ts.map +1 -1
  15. package/dist/cjs/src/wechaty-mixins/plugin-mixin.d.ts +6 -0
  16. package/dist/cjs/src/wechaty-mixins/plugin-mixin.d.ts.map +1 -1
  17. package/dist/cjs/src/wechaty-mixins/puppet-mixin.d.ts +12 -12
  18. package/dist/cjs/src/wechaty-mixins/puppet-mixin.d.ts.map +1 -1
  19. package/dist/cjs/src/wechaty-mixins/puppet-mixin.js +49 -3
  20. package/dist/cjs/src/wechaty-mixins/puppet-mixin.js.map +1 -1
  21. package/dist/esm/src/package-json.d.ts.map +1 -1
  22. package/dist/esm/src/package-json.js +3 -2
  23. package/dist/esm/src/package-json.js.map +1 -1
  24. package/dist/esm/src/user-modules/room.d.ts.map +1 -1
  25. package/dist/esm/src/user-modules/room.js +1 -0
  26. package/dist/esm/src/user-modules/room.js.map +1 -1
  27. package/dist/esm/src/wechaty/wechaty-base.d.ts +31 -0
  28. package/dist/esm/src/wechaty/wechaty-base.d.ts.map +1 -1
  29. package/dist/esm/src/wechaty/wechaty-base.spec.js +75 -2
  30. package/dist/esm/src/wechaty/wechaty-base.spec.js.map +1 -1
  31. package/dist/esm/src/wechaty-mixins/login-mixin.d.ts +4 -0
  32. package/dist/esm/src/wechaty-mixins/login-mixin.d.ts.map +1 -1
  33. package/dist/esm/src/wechaty-mixins/misc-mixin.d.ts +4 -0
  34. package/dist/esm/src/wechaty-mixins/misc-mixin.d.ts.map +1 -1
  35. package/dist/esm/src/wechaty-mixins/plugin-mixin.d.ts +6 -0
  36. package/dist/esm/src/wechaty-mixins/plugin-mixin.d.ts.map +1 -1
  37. package/dist/esm/src/wechaty-mixins/puppet-mixin.d.ts +12 -12
  38. package/dist/esm/src/wechaty-mixins/puppet-mixin.d.ts.map +1 -1
  39. package/dist/esm/src/wechaty-mixins/puppet-mixin.js +50 -4
  40. package/dist/esm/src/wechaty-mixins/puppet-mixin.js.map +1 -1
  41. package/package.json +2 -1
  42. package/src/package-json.ts +3 -2
  43. package/src/user-modules/room.ts +1 -0
  44. package/src/wechaty/wechaty-base.spec.ts +96 -3
  45. package/src/wechaty-mixins/puppet-mixin.ts +60 -6
@@ -50,6 +50,7 @@ import type {
50
50
  WechatyInterface,
51
51
  } from '../wechaty/wechaty-impl.js'
52
52
  import { WechatySkeleton } from './wechaty-skeleton.js'
53
+ import { WechatyBuilder } from '../mods/mod.js'
53
54
 
54
55
  class WechatyTest extends WechatyBase {
55
56
  }
@@ -246,21 +247,30 @@ test('@event ready', async t => {
246
247
  const sandbox = sinon.createSandbox()
247
248
  const spy = sandbox.spy()
248
249
 
250
+ const mockContact = puppet.mocker.createContact({ name: 'any' })
251
+
249
252
  wechaty.on('ready', spy)
250
253
  t.ok(spy.notCalled, 'should no ready event with new wechaty instance')
251
254
 
252
255
  await wechaty.start()
253
256
  t.ok(spy.notCalled, 'should no ready event right start wechaty started')
254
257
 
258
+ await puppet.mocker.login(mockContact)
255
259
  puppet.emit('ready', { data: 'test' })
260
+ await new Promise(resolve => {
261
+ setTimeout(resolve, 16 * 1000)
262
+ })
256
263
  t.equal(spy.callCount, 1, 'should fire ready event after puppet ready')
257
264
 
258
265
  await wechaty.stop()
259
266
  await wechaty.start()
260
267
  t.equal(spy.callCount, 1, 'should fire ready event second time after stop/start wechaty')
261
268
 
269
+ await puppet.mocker.login(mockContact)
262
270
  puppet.emit('ready', { data: 'test' })
263
-
271
+ await new Promise(resolve => {
272
+ setTimeout(resolve, 16 * 1000)
273
+ })
264
274
  t.equal(spy.callCount, 2, 'should fire ready event third time after stop/start wechaty')
265
275
 
266
276
  await wechaty.stop()
@@ -274,6 +284,8 @@ test('ready()', async t => {
274
284
 
275
285
  const spy = sandbox.spy()
276
286
 
287
+ const mockContact = puppet.mocker.createContact({ name: 'any' })
288
+
277
289
  wechaty.ready()
278
290
  .then(spy)
279
291
  .catch(e => t.fail('rejection: ' + e))
@@ -284,8 +296,11 @@ test('ready()', async t => {
284
296
 
285
297
  t.ok(spy.notCalled, 'should not ready after right start wechaty')
286
298
 
299
+ await puppet.mocker.login(mockContact)
287
300
  puppet.emit('ready', { data: 'test' })
288
- await new Promise(resolve => setImmediate(resolve))
301
+ await new Promise(resolve => {
302
+ setTimeout(resolve, 16 * 1000)
303
+ })
289
304
  t.ok(spy.calledOnce, 'should ready after puppet ready')
290
305
 
291
306
  await wechaty.stop()
@@ -294,8 +309,11 @@ test('ready()', async t => {
294
309
  .then(spy)
295
310
  .catch(e => t.fail('rejection: ' + e))
296
311
 
312
+ await puppet.mocker.login(mockContact)
297
313
  puppet.emit('ready', { data: 'test' })
298
- await new Promise(resolve => setImmediate(resolve))
314
+ await new Promise(resolve => {
315
+ setTimeout(resolve, 16 * 1000)
316
+ })
299
317
  t.ok(spy.calledTwice, 'should ready again after stop/start wechaty')
300
318
 
301
319
  await wechaty.stop()
@@ -390,3 +408,78 @@ test('WechatySkeleton: super.{start,stop}()', async t => {
390
408
  t.ok(startStub.calledOnce, 'should only call start once')
391
409
  t.ok(stopStub.calledOnce, 'should call the skeleton stop(), which means all mixin stops()s are chained correctly')
392
410
  })
411
+
412
+ test('ReadyDelay', async t => {
413
+
414
+ const puppet = new PuppetMock() as any
415
+ const wechaty = WechatyBuilder.build({ puppet })
416
+
417
+ const mockContact = puppet.mocker.createContact({ name: 'any' })
418
+
419
+ await wechaty.start()
420
+
421
+ let loginCalled = false
422
+ wechaty.on('login', () => {
423
+ loginCalled = true
424
+ })
425
+
426
+ const future = new Promise<void>(resolve => {
427
+ wechaty.on('ready', () => {
428
+ if (loginCalled) {
429
+ t.pass('ready emitted after login')
430
+ } else {
431
+ t.fail('ready emitted before login')
432
+ }
433
+ resolve()
434
+ })
435
+ })
436
+
437
+ puppet.emit('ready')
438
+ await puppet.mocker.login(mockContact)
439
+
440
+ await future
441
+ await wechaty.stop()
442
+ })
443
+
444
+ test('ReadyMeetsLogout', async t => {
445
+ const puppet = new PuppetMock() as any
446
+ const wechaty = WechatyBuilder.build({ puppet })
447
+
448
+ const mockContact = puppet.mocker.createContact({ name: 'any' })
449
+
450
+ await wechaty.start()
451
+ await puppet.mocker.login(mockContact)
452
+
453
+ let readyEmitted = false
454
+ wechaty.on('ready', () => {
455
+ readyEmitted = true
456
+ })
457
+
458
+ puppet.emit('ready')
459
+ await new Promise(resolve => {
460
+ setTimeout(resolve, 5 * 1000)
461
+ })
462
+
463
+ puppet.emit('logout', { contactId: mockContact.id })
464
+ await new Promise(resolve => {
465
+ setTimeout(resolve, 15 * 1000)
466
+ })
467
+
468
+ t.ok(!readyEmitted, 'ready should not be emitted because puppet logout')
469
+
470
+ puppet.emit('login', { contactId: mockContact.id })
471
+
472
+ await new Promise(resolve => {
473
+ setTimeout(resolve, 5 * 1000)
474
+ })
475
+
476
+ t.ok(!readyEmitted, 'ready should not be emitted because it should wait for a new ready')
477
+
478
+ puppet.emit('ready')
479
+ await new Promise(resolve => {
480
+ setTimeout(resolve, 16 * 1000)
481
+ })
482
+ t.ok(readyEmitted, 'ready should be emitted')
483
+
484
+ await wechaty.stop()
485
+ })
@@ -6,10 +6,11 @@ import {
6
6
  TimeoutPromiseGError,
7
7
  } from 'gerror'
8
8
 
9
- import { StateSwitch } from 'state-switch'
10
- import type {
9
+ import {
10
+ StateSwitch,
11
+ BooleanIndicator,
11
12
  StateSwitchInterface,
12
- } from 'state-switch'
13
+ } from 'state-switch'
13
14
 
14
15
  import { config, PUPPET_PAYLOAD_SYNC_GAP, PUPPET_PAYLOAD_SYNC_MAX_RETRY } from '../config.js'
15
16
  import { timestampToDate } from '../pure-functions/timestamp-to-date.js'
@@ -57,13 +58,18 @@ const puppetMixin = <MixinBase extends WechatifyUserModuleMixin & GErrorMixin &
57
58
 
58
59
  readonly __readyState : StateSwitchInterface
59
60
 
61
+ __loginIndicator: BooleanIndicator
62
+
60
63
  __puppetMixinInited = false
61
64
 
65
+ __offCallbackList: (() => void)[] = []
66
+
62
67
  constructor (...args: any[]) {
63
68
  log.verbose('WechatyPuppetMixin', 'construct()')
64
69
  super(...args)
65
70
 
66
71
  this.__readyState = new StateSwitch('WechatyReady', { log })
72
+ this.__loginIndicator = new BooleanIndicator()
67
73
  }
68
74
 
69
75
  override async start (): Promise<void> {
@@ -111,6 +117,20 @@ const puppetMixin = <MixinBase extends WechatifyUserModuleMixin & GErrorMixin &
111
117
  } catch (e) {
112
118
  this.emitError(e)
113
119
  }
120
+
121
+ const loginListener = () => {
122
+ this.__loginIndicator.value(true)
123
+ }
124
+ this.on('login', loginListener)
125
+ const offLoginListener = () => this.off('login', loginListener)
126
+ this.__offCallbackList.push(offLoginListener)
127
+
128
+ const logoutListener = () => {
129
+ this.__loginIndicator.value(false)
130
+ }
131
+ this.on('logout', logoutListener)
132
+ const offLogoutListener = () => this.off('logout', logoutListener)
133
+ this.__offCallbackList.push(offLogoutListener)
114
134
  }
115
135
 
116
136
  override async stop (): Promise<void> {
@@ -134,6 +154,11 @@ const puppetMixin = <MixinBase extends WechatifyUserModuleMixin & GErrorMixin &
134
154
  log.verbose('WechatyPuppetMixin', 'stop() super.stop() ...')
135
155
  await super.stop()
136
156
  log.verbose('WechatyPuppetMixin', 'stop() super.stop() ... done')
157
+
158
+ while (this.__offCallbackList.length > 0) {
159
+ const func = this.__offCallbackList.pop()
160
+ func && func()
161
+ }
137
162
  }
138
163
 
139
164
  async ready (): Promise<void> {
@@ -359,11 +384,38 @@ const puppetMixin = <MixinBase extends WechatifyUserModuleMixin & GErrorMixin &
359
384
  break
360
385
 
361
386
  case 'ready':
362
- puppet.on('ready', () => {
387
+ puppet.on('ready', async () => {
363
388
  log.silly('WechatyPuppetMixin', '__setupPuppetEvents() puppet.on(ready)')
364
389
 
365
- this.emit('ready')
366
- this.__readyState.active(true)
390
+ // ready event should be emitted 15s after login
391
+ let onceLogout: () => void
392
+ let timeout: ReturnType<typeof setTimeout> // 'NodeJS' is not defined.
393
+ const future = new Promise((resolve, reject) => {
394
+ onceLogout = () => {
395
+ reject(new Error('puppet logout!'))
396
+ }
397
+ puppet.once('logout', onceLogout)
398
+ timeout = setTimeout(() => {
399
+ reject(new Error('waiting for login timeout'))
400
+ }, 60 * 1000)
401
+ void this.__loginIndicator.ready(true).then(resolve)
402
+ }).finally(() => {
403
+ puppet.off('logout', onceLogout)
404
+ clearTimeout(timeout)
405
+ })
406
+
407
+ try {
408
+ await future
409
+ await new Promise(resolve => {
410
+ setTimeout(resolve, 15 * 1000)
411
+ })
412
+ if (this.__loginIndicator.value()) {
413
+ this.emit('ready')
414
+ this.__readyState.active(true)
415
+ }
416
+ } catch (e) {
417
+ log.error(`ready ignored: ${(e as Error).message}`)
418
+ }
367
419
  })
368
420
  break
369
421
 
@@ -747,6 +799,8 @@ type ProtectedPropertyPuppetMixin =
747
799
  | '__puppet'
748
800
  | '__readyState'
749
801
  | '__setupPuppetEvents'
802
+ | '__loginIndicator'
803
+ | '__offCallbackList'
750
804
 
751
805
  export type {
752
806
  PuppetMixin,