Thanks to visit codestin.com
Credit goes to github.com

Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
68 commits
Select commit Hold shift + click to select a range
5fd87b6
classify
huan Mar 17, 2022
4471c23
init snake to camelCase helper
huan Mar 18, 2022
085ad06
use a simple version of typing for convert SNAKE_CASE to CamelCase
huan Mar 18, 2022
ac0a44e
fix & clean SnakeToCameCase typing converter
huan Mar 18, 2022
1246a2c
finish classify helper functgions
huan Mar 18, 2022
1f6fc68
add docs
huan Mar 18, 2022
97c00f6
add classify utilities
huan Mar 19, 2022
e3fef67
0.11.1
huan Mar 19, 2022
77839f9
add classifyMap utils
huan Mar 20, 2022
f24bcf3
add export classifyMap
huan Mar 20, 2022
6b27fd5
0.11.2
huan Mar 20, 2022
b8438a1
fix classify typings
huan Mar 20, 2022
9b2d800
fix MetaActionCreator typing
huan Mar 20, 2022
d0f156a
export Class instead of payload creator
huan Mar 20, 2022
2df0a44
clean exports with classifirized action creators
huan Mar 20, 2022
3d04bf3
add plainToClass converter
huan Mar 20, 2022
e1cbc17
restruct folders
huan Mar 20, 2022
0897906
refactor classes
huan Mar 20, 2022
a9b0196
fix classify with string type
huan Mar 20, 2022
6f2e602
clean response code & add unit tests
huan Mar 21, 2022
b037a35
clean response pair code
huan Mar 21, 2022
e715d52
code clean
huan Mar 21, 2022
391cc96
code clean
huan Mar 21, 2022
b5ae707
wip, before refactory responseTypeMap
huan Mar 23, 2022
7d38a37
finish responseOf type with typings
huan Mar 25, 2022
7c5b412
finish responsee type converter with typing
huan Mar 25, 2022
1b84dee
deprecate responsePair helper
huan Mar 25, 2022
a5ec603
rename & code clean
huan Mar 25, 2022
947bd5f
code clean
huan Mar 25, 2022
5e9e638
refactoring commands without pair
huan Mar 25, 2022
0f389ea
code clean
huan Mar 25, 2022
e38bc03
use types-responses converter
huan Mar 25, 2022
5faaf86
map actions with the type key
huan Mar 25, 2022
619b7b9
use navie query action creator instead of the pair helper
huan Mar 25, 2022
bdac5ff
depracated pair response
huan Mar 25, 2022
67f994f
code clean up
huan Mar 25, 2022
737bce0
code clean up
huan Mar 25, 2022
9d751c4
fix unit tests for get object creator by class
huan Mar 25, 2022
7ad19ce
enhance get class utils & restructure folders
huan Mar 25, 2022
4b82a7e
wip execute$
huan Mar 25, 2022
85e0bd9
code clean
huan Mar 25, 2022
16c3dc1
refactoring typing system & wip
huan Mar 26, 2022
a6099d9
code clean
huan Mar 26, 2022
c56fbc7
rename to DTO Factory/Class (Data Transfer Object)
huan Mar 26, 2022
2e9a95a
rename to DTO Factory/Class (Data Transfer Object)
huan Mar 26, 2022
36af788
enhance recv typings
huan Mar 26, 2022
15719bf
make typing correct & clearer
huan Mar 26, 2022
fdcf27e
return undefined when convert plain object to class object failed
huan Mar 26, 2022
7a82e7e
fix query payload lost bug
huan Mar 26, 2022
45b252f
return undefined when convert plain object to class object failed
huan Mar 26, 2022
b41cf77
code clean
huan Mar 26, 2022
6777ced
fix cqrs unit tests
huan Mar 27, 2022
b4e89e7
rename to PayloadMetaCreator for creating PayloadMetaAction
huan Mar 27, 2022
f07fa45
rename to instance
huan Mar 27, 2022
d61947e
fix classify typing system
huan Mar 27, 2022
3fb8f93
code clean
huan Mar 27, 2022
5be3c85
rename & fix typing
huan Mar 27, 2022
daac6d3
use Object.setPrototype to convert the object to instance
huan Mar 27, 2022
a23caca
fix cqrs unit tests
huan Mar 27, 2022
cecd2ec
fix all unit tests
huan Mar 27, 2022
81631c7
0.11.3
huan Mar 27, 2022
254d3b3
code clean
huan Mar 27, 2022
c227188
clean
huan Mar 27, 2022
af32c79
0.11.4
huan Mar 27, 2022
2f5aaee
fix smoke testing
huan Mar 27, 2022
eeed234
v1.12
huan Mar 27, 2022
ab6f279
fix linting
huan Mar 27, 2022
85578e1
0.12.1
huan Mar 27, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .eslintrc.cjs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@

const rules = {
'no-redeclare': 'off',
}

module.exports = {
Expand Down
8 changes: 7 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,13 @@ Read CQRS Wechaty API Reference at: <https://paka.dev/npm/wechaty-cqrs>

## History

### main
### main v1.12

1. Classify action builders so that they will be compatible with Class events
with NestJS [#1](https://github.com/wechaty/cqrs/issues/1)
1. `execute$()` helper function for sending the events to the bus
and get back the response, with automatically type inferring.
1. lots of typing enhancements.

## v0.10 (Mar 17) Beta release

Expand Down
27 changes: 12 additions & 15 deletions examples/ding-dong-bot.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,12 +64,12 @@ const onMessage$ = (bus$: CQRS.Bus) => CQRS.events$.messageReceivedEvent$(bus$).
/**
* message -> sayable
*/
map(messageId => CQRS.queries.getSayablePayloadQuery(
map(messageId => CQRS.queries.GetSayablePayloadQuery(
messageReceivedEvent.meta.puppetId,
messageId,
)),
mergeMap(CQRS.execute$(bus$)(CQRS.queries.getSayablePayloadQuery)),
map(sayablePayloadGotMessage => sayablePayloadGotMessage.payload),
mergeMap(CQRS.execute$(bus$)),
map(sayablePayloadGotMessage => sayablePayloadGotMessage.payload.sayable),
filter(Boolean),
tap(sayable => console.info('sayable:', sayable)),

Expand All @@ -85,19 +85,19 @@ const onMessage$ = (bus$: CQRS.Bus) => CQRS.events$.messageReceivedEvent$(bus$).
/**
* ding -> talkerId
*/
map(messageReceivedEvent => CQRS.queries.getMessagePayloadQuery(messageReceivedEvent.meta.puppetId, messageReceivedEvent.payload.messageId)),
mergeMap(CQRS.execute$(bus$)(CQRS.queries.getMessagePayloadQuery)),
map(messageReceivedEvent => CQRS.queries.GetMessagePayloadQuery(messageReceivedEvent.meta.puppetId, messageReceivedEvent.payload.messageId)),
mergeMap(CQRS.execute$(bus$)),
/**
* Huan(202203): `.fromId` deprecated, will be removed after v2.0
*/
map(messagePayloadGotMmessage => messagePayloadGotMmessage.payload?.talkerId || messagePayloadGotMmessage.payload?.fromId),
map(messagePayloadGotMmessage => messagePayloadGotMmessage.payload.message?.talkerId || messagePayloadGotMmessage.payload.message?.fromId),
filter(Boolean),
tap(talkerId => console.info('talkerId:', talkerId)),

/**
* talkerId -> command
*/
map(talkerId => CQRS.commands.sendMessageCommand(
map(talkerId => CQRS.commands.SendMessageCommand(
messageReceivedEvent.meta.puppetId,
talkerId,
CQRS.sayables.text('dong'),
Expand All @@ -107,7 +107,7 @@ const onMessage$ = (bus$: CQRS.Bus) => CQRS.events$.messageReceivedEvent$(bus$).
/**
* execute command (return MessageSentMessage)
*/
mergeMap(CQRS.execute$(bus$)(CQRS.commands.sendMessageCommand)),
mergeMap(CQRS.execute$(bus$)),
)),
)),
)
Expand All @@ -127,10 +127,7 @@ async function cqrsWechaty () {
}

async function main () {
const {
bus$,
puppetId,
} = await cqrsWechaty()
const { bus$, puppetId } = await cqrsWechaty()

const onStartedEvent$ = (bus$: CQRS.Bus) => CQRS.events$.startedEvent$(bus$).pipe(
switchMap(() => merge(
Expand All @@ -141,13 +138,13 @@ async function main () {
)),
)

const main$ = defer(() => of(CQRS.commands.startCommand(puppetId))).pipe(
const main$ = defer(() => of(CQRS.commands.StartCommand(puppetId))).pipe(
mergeMap(startCommand => merge(
onStartedEvent$(bus$),
CQRS.execute$(bus$)(CQRS.commands.startCommand)(startCommand),
CQRS.execute$(bus$)(startCommand),
)),
ignoreElements(),
finalize(() => bus$.next(CQRS.commands.stopCommand(puppetId))),
finalize(() => bus$.next(CQRS.commands.StopCommand(puppetId))),
)

/**
Expand Down
8 changes: 4 additions & 4 deletions examples/template.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,11 +42,11 @@ const onScan$ = (source$: CQRS.BusObs) => CQRS.events$.scanReceivedEvent$(source
)

const onMessage$ = (bus$: CQRS.Bus) => CQRS.events$.messageReceivedEvent$(bus$).pipe(
map(messageReceivedEvent => CQRS.queries.getSayablePayloadQuery(
map(messageReceivedEvent => CQRS.queries.GetSayablePayloadQuery(
messageReceivedEvent.meta.puppetId,
messageReceivedEvent.payload.messageId,
)),
mergeMap(CQRS.execute$(bus$)(CQRS.queries.getSayablePayloadQuery)),
mergeMap(CQRS.execute$(bus$)),
map(sayablePayloadGotMessage => sayablePayloadGotMessage.payload),
tap(sayable => console.info('onMessage$:', sayable)),
)
Expand All @@ -59,8 +59,8 @@ async function main () {
/**
* Start/stop Wechaty when subscribing/unsubscribing
*/
const onSubscribe$ = () => defer(() => CQRS.execute$(bus$)(CQRS.commands.startCommand)(CQRS.commands.startCommand(wechaty.puppet.id)))
const onUnsubscribe = () => finalize(() => bus$.next(CQRS.commands.stopCommand(wechaty.puppet.id)))
const onSubscribe$ = () => defer(() => CQRS.execute$(bus$)(CQRS.commands.StartCommand(wechaty.puppet.id)))
const onUnsubscribe = () => finalize(() => bus$.next(CQRS.commands.StopCommand(wechaty.puppet.id)))

const handlers$ = (bus$: CQRS.Bus) => merge(
onScan$(bus$),
Expand Down
7 changes: 5 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "wechaty-cqrs",
"version": "0.10.4",
"version": "0.12.1",
"description": "An event-driven architecture wrapper for Wechaty that applies the CQS principle by using separate Query and Command messages to retrieve and modify the bot state, respectively.",
"type": "module",
"exports": {
Expand Down Expand Up @@ -107,7 +107,9 @@
},
"dependencies": {
"ducks": "^1.3.2",
"lodash": "^4.17.21",
"redux": "^4.1.2",
"reflect-metadata": "^0.1.13",
"rxjs": "^7.5.5",
"time-constants": "^1.0.3",
"typesafe-actions": "^5.1.0",
Expand All @@ -123,10 +125,11 @@
"@chatie/semver": "^0.4.7",
"@chatie/tsconfig": "^4.6.3",
"@types/glob": "^7.2.0",
"@types/lodash": "^4.14.180",
"@types/time-constants": "^1.0.0",
"@types/uuid": "^8.3.4",
"glob": "^7.2.0",
"tstest": "^1.2.6",
"tstest": "^1.2.8",
"wechaty-puppet-mock": "^1.18.2",
"wechaty-puppet-wechat": "^1.12.2"
},
Expand Down
4 changes: 2 additions & 2 deletions src/bus.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ import type {
ActionType,
} from 'typesafe-actions'

import type * as CqrsDuck from './duck/mod.js'
import type * as classified from './classified/mod.js'

// type BusSubject<T> = Subject<
// ActionType<T>
Expand All @@ -34,7 +34,7 @@ import type * as CqrsDuck from './duck/mod.js'
/**
* Huan(202203): Use a simplified interface for Bus
*/
export interface Bus<T = ActionType<typeof CqrsDuck.actions>> {
export interface Bus<T = ActionType<typeof classified.actions>> {
asObservable : Subject<T>['asObservable']
next : Subject<T>['next']
// complete : Subject<T>['complete']
Expand Down
14 changes: 14 additions & 0 deletions src/classified/actions/commands.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { classifyMap } from '../../classify/classify-map.js'
import * as commands from '../../duck/actions/commands.js'

/**
* Selective export `Command` only
*/
export const {
DingCommand,
ResetCommand,
NopCommand,
SendMessageCommand,
StartCommand,
StopCommand,
} = classifyMap(commands)
26 changes: 26 additions & 0 deletions src/classified/actions/events.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { classifyMap } from '../../classify/classify-map.js'
import * as events from '../../duck/actions/events.js'

/**
* Selective export for `Event` only
*/
export const {
DongReceivedEvent,
ErrorReceivedEvent,
FriendshipReceivedEvent,
HeartbeatReceivedEvent,
LoginReceivedEvent,
LogoutReceivedEvent,
MessageReceivedEvent,
ReadyReceivedEvent,
ResetReceivedEvent,
RoomInviteReceivedEvent,
RoomJoinReceivedEvent,
RoomLeaveReceivedEvent,
RoomTopicReceivedEvent,
ScanReceivedEvent,
StartedEvent,
StateActivatedEvent,
StateInactivatedEvent,
StoppedEvent,
} = classifyMap(events)
4 changes: 4 additions & 0 deletions src/classified/actions/mod.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export * from './commands.js'
export * from './events.js'
export * from './queries.js'
export * from './responses.js'
13 changes: 13 additions & 0 deletions src/classified/actions/queries.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { classifyMap } from '../../classify/classify-map.js'
import * as queries from '../../duck/actions/queries.js'

/**
* Selective export `Query` only
*/
export const {
GetAuthQrCodeQuery,
GetCurrentUserIdQuery,
GetIsLoggedInQuery,
GetMessagePayloadQuery,
GetSayablePayloadQuery,
} = classifyMap(queries)
23 changes: 23 additions & 0 deletions src/classified/actions/responses.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { classifyMap } from '../../classify/classify-map.js'
import * as commands from '../../duck/actions/commands.js'
import * as queries from '../../duck/actions/queries.js'

/**
* Selective export for `Response` only
*/
export const {
DingCommandResponse,
GetAuthQrCodeQueryResponse,
GetCurrentUserIdQueryResponse,
GetIsLoggedInQueryResponse,
GetMessagePayloadQueryResponse,
GetSayablePayloadQueryResponse,
NopCommandResponse,
ResetCommandResponse,
SendMessageCommandResponse,
StartCommandResponse,
StopCommandResponse,
} = classifyMap({
...commands,
...queries,
})
17 changes: 17 additions & 0 deletions src/classified/mod.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import type * as commandTypes from './types/commands.js'
import type * as queryTypes from './types/queries.js'

import type * as commandActions from './actions/commands.js'
import type * as queryActions from './actions/queries.js'

export type CQType =
| typeof commandTypes [keyof typeof commandTypes]
| typeof queryTypes [keyof typeof queryTypes]

export type CQAction =
| InstanceType<typeof commandActions[keyof typeof commandActions]>
| InstanceType<typeof queryActions [keyof typeof queryActions]>

export type { Type } from './types/types.js'
export * as types from './types/mod.js'
export * as actions from './actions/mod.js'
9 changes: 9 additions & 0 deletions src/classified/types/commands.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { types } from './types.js'

export const {
DING_COMMAND,
RESET_COMMAND,
SEND_MESSAGE_COMMAND,
START_COMMAND,
STOP_COMMAND,
} = types
22 changes: 22 additions & 0 deletions src/classified/types/events.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { types } from './types.js'

export const {
DONG_RECEIVED_EVENT,
ERROR_RECEIVED_EVENT,
FRIENDSHIP_RECEIVED_EVENT,
HEARTBEAT_RECEIVED_EVENT,
LOGIN_RECEIVED_EVENT,
LOGOUT_RECEIVED_EVENT,
MESSAGE_RECEIVED_EVENT,
READY_RECEIVED_EVENT,
RESET_RECEIVED_EVENT,
ROOM_INVITE_RECEIVED_EVENT,
ROOM_JOIN_RECEIVED_EVENT,
ROOM_LEAVE_RECEIVED_EVENT,
ROOM_TOPIC_RECEIVED_EVENT,
SCAN_RECEIVED_EVENT,
STARTED_EVENT,
STATE_ACTIVATED_EVENT,
STATE_INACTIVATED_EVENT,
STOPPED_EVENT,
} = types
4 changes: 4 additions & 0 deletions src/classified/types/mod.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export * from './commands.js'
export * from './events.js'
export * from './queries.js'
export * from './responses.js'
9 changes: 9 additions & 0 deletions src/classified/types/queries.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { types } from './types.js'

export const {
GET_AUTH_QR_CODE_QUERY,
GET_CURRENT_USER_ID_QUERY,
GET_IS_LOGGED_IN_QUERY,
GET_MESSAGE_PAYLOAD_QUERY,
GET_SAYABLE_PAYLOAD_QUERY,
} = types
14 changes: 14 additions & 0 deletions src/classified/types/responses.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { types } from './types.js'

export const {
DING_COMMAND_RESPONSE,
GET_AUTH_QR_CODE_QUERY_RESPONSE,
GET_CURRENT_USER_ID_QUERY_RESPONSE,
GET_IS_LOGGED_IN_QUERY_RESPONSE,
GET_MESSAGE_PAYLOAD_QUERY_RESPONSE,
GET_SAYABLE_PAYLOAD_QUERY_RESPONSE,
RESET_COMMAND_RESPONSE,
SEND_MESSAGE_COMMAND_RESPONSE,
START_COMMAND_RESPONSE,
STOP_COMMAND_RESPONSE,
} = types
17 changes: 17 additions & 0 deletions src/classified/types/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { ActionCreatorTypeMetadata, getType } from 'typesafe-actions'

import { PureTypeName, pureTypeName } from '../../classify/pure-type-name.js'

import * as actions from '../actions/mod.js'

export type Type = typeof actions[keyof typeof actions] extends ActionCreatorTypeMetadata<infer TType> ? TType : never

type TypeMap = {
[T in Type as PureTypeName<T>]: T
}

export const types = Object.values(actions).reduce((acc, action) => {
const type = getType(action)
acc[pureTypeName(type)] = type
return acc
}, {} as any) as TypeMap
31 changes: 31 additions & 0 deletions src/classify/classify-map.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
#!/usr/bin/env -S node --no-warnings --loader ts-node/esm

import {
test,
AssertEqual,
} from 'tstest'

import * as duck from '../duck/mod.js'

import { classify } from './classify.js'
import { classifyMap } from './classify-map.js'

test('classify smoke testing', async t => {
const actionMap = {
dongReceivedEvent: duck.actions.dongReceivedEvent,
sendMessageCommand: duck.actions.sendMessageCommand,
sendMessageCommandResponse: duck.actions.sendMessageCommandResponse,
}

const EXPECTED = {
DongReceivedEvent: classify(duck.actions.dongReceivedEvent),
SendMessageCommand: classify(duck.actions.sendMessageCommand),
SendMessageCommandResponse: classify(duck.actions.sendMessageCommandResponse),
}

const classMap = classifyMap(actionMap)
t.same(classMap, EXPECTED, 'should be the same of classMap & EXPECTED')

const test: AssertEqual<typeof classMap, typeof EXPECTED> = true
t.ok(test, 'should be the same typing of classMap & EXPECTED')
})
Loading