saga-toolkit 2.0.5 → 2.1.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/README.md CHANGED
@@ -40,7 +40,7 @@ const slice = createSlice({
40
40
  result: payload,
41
41
  loading: false,
42
42
  }),
43
- [fetchThings.rejected]: (state, { payload }) => ({
43
+ [fetchThings.rejected]: (state, { error }) => ({
44
44
  ...state,
45
45
  error,
46
46
  loading: false,
@@ -1,11 +1,11 @@
1
1
  {
2
2
  "name": "example",
3
- "version": "0.1.0",
3
+ "version": "0.0.1",
4
4
  "lockfileVersion": 2,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
- "version": "0.1.0",
8
+ "version": "0.0.1",
9
9
  "dependencies": {
10
10
  "@reduxjs/toolkit": "^1.6.1",
11
11
  "@testing-library/jest-dom": "^5.11.4",
@@ -17,26 +17,10 @@
17
17
  "react-scripts": "4.0.3",
18
18
  "redux": "^4.1.1",
19
19
  "redux-saga": "^1.1.3",
20
- "saga-toolkit": "file:..",
20
+ "saga-toolkit": "^2.0.6",
21
21
  "web-vitals": "^1.0.1"
22
22
  }
23
23
  },
24
- "..": {
25
- "version": "2.0.4",
26
- "license": "ISC",
27
- "devDependencies": {
28
- "@babel/cli": "^7.16.8",
29
- "@babel/core": "^7.16.12",
30
- "@babel/node": "^7.16.8",
31
- "@babel/preset-env": "^7.16.11",
32
- "@reduxjs/toolkit": "^1.7.2",
33
- "babel-jest": "^27.4.6",
34
- "jest": "^27.4.7",
35
- "redux": "^4.1.2",
36
- "redux-saga": "^1.1.3",
37
- "redux-saga-test-plan": "^4.0.4"
38
- }
39
- },
40
24
  "node_modules/@babel/code-frame": {
41
25
  "version": "7.12.13",
42
26
  "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.13.tgz",
@@ -15302,8 +15286,9 @@
15302
15286
  "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
15303
15287
  },
15304
15288
  "node_modules/saga-toolkit": {
15305
- "resolved": "..",
15306
- "link": true
15289
+ "version": "2.0.6",
15290
+ "resolved": "https://registry.npmjs.org/saga-toolkit/-/saga-toolkit-2.0.6.tgz",
15291
+ "integrity": "sha512-KBWuzC0PSmGFGm8/t7dhjvnyoudBqWK2VENKx0Ka+sroPZq6/inAXWSCpukHxaOYAH4afO2czZb1fgve3dyB8g=="
15307
15292
  },
15308
15293
  "node_modules/sane": {
15309
15294
  "version": "4.1.0",
@@ -30691,19 +30676,9 @@
30691
30676
  "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
30692
30677
  },
30693
30678
  "saga-toolkit": {
30694
- "version": "file:..",
30695
- "requires": {
30696
- "@babel/cli": "^7.16.8",
30697
- "@babel/core": "^7.16.12",
30698
- "@babel/node": "^7.16.8",
30699
- "@babel/preset-env": "^7.16.11",
30700
- "@reduxjs/toolkit": "^1.7.2",
30701
- "babel-jest": "^27.4.6",
30702
- "jest": "^27.4.7",
30703
- "redux": "^4.1.2",
30704
- "redux-saga": "^1.1.3",
30705
- "redux-saga-test-plan": "^4.0.4"
30706
- }
30679
+ "version": "2.0.6",
30680
+ "resolved": "https://registry.npmjs.org/saga-toolkit/-/saga-toolkit-2.0.6.tgz",
30681
+ "integrity": "sha512-KBWuzC0PSmGFGm8/t7dhjvnyoudBqWK2VENKx0Ka+sroPZq6/inAXWSCpukHxaOYAH4afO2czZb1fgve3dyB8g=="
30707
30682
  },
30708
30683
  "sane": {
30709
30684
  "version": "4.1.0",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "example",
3
- "version": "0.1.0",
3
+ "version": "0.0.1",
4
4
  "private": true,
5
5
  "dependencies": {
6
6
  "@reduxjs/toolkit": "^1.6.1",
@@ -13,7 +13,7 @@
13
13
  "react-scripts": "4.0.3",
14
14
  "redux": "^4.1.1",
15
15
  "redux-saga": "^1.1.3",
16
- "saga-toolkit": "file:..",
16
+ "saga-toolkit": "^2.0.6",
17
17
  "web-vitals": "^1.0.1"
18
18
  },
19
19
  "scripts": {
@@ -1,40 +1,44 @@
1
1
  import { call, cancelled, delay, put, select, takeEvery } from 'redux-saga/effects'
2
- import { LOCATION_CHANGE } from 'connected-react-router'
3
2
  import {
4
3
  takeEveryAsync,
5
4
  takeLatestAsync,
6
5
  takeAggregateAsync,
7
6
  putAsync,
8
- } from './sagaToolkit'
7
+ } from 'saga-toolkit'
9
8
  import * as actions from './slice'
10
9
 
11
10
  const hyperSuperApi = (success = true) => {
12
11
  console.log('hyperSuperApi')
13
12
 
14
- let timeoutId
15
- const deferred = {}
13
+ // let timeoutId
14
+ // const deferred = {}
16
15
 
17
16
  const promise = new Promise((resolve, reject) => {
18
- deferred.resolve = resolve
19
- deferred.reject = reject
20
- timeoutId = setTimeout(() => (success ? resolve : reject)('result'), 1000)
17
+ // deferred.resolve = resolve
18
+ // deferred.reject = reject
19
+ // timeoutId = setTimeout(() => (success ? resolve : reject)('result'), 1000)
20
+ setTimeout(() => (success ? resolve : reject)('result'), 1000)
21
21
  })
22
22
 
23
- deferred.promise = promise
23
+ // deferred.promise = promise
24
24
 
25
- promise.abort = () => {
26
- clearTimeout(timeoutId)
27
- deferred.reject('Aborted')
28
- }
25
+ // promise.abort = () => {
26
+ // clearTimeout(timeoutId)
27
+ // deferred.reject('Aborted')
28
+ // }
29
29
 
30
30
  return promise
31
31
  }
32
32
 
33
33
  function* appStart() {
34
34
  try {
35
+ // fetch things at app start
36
+
37
+ // non blocking way
35
38
  // yield put(actions.fetchThings())
36
- // yield put(actions.fetchThings(false))
37
- // yield put(actions.fetchThings())
39
+
40
+ // OR wait for it to finish - a blocking way
41
+ // yield putAsync(actions.fetchThings())
38
42
  } catch (error) {
39
43
  console.log('appStart 1', error)
40
44
  }
@@ -50,9 +54,6 @@ function* appStart() {
50
54
  console.log('Started')
51
55
  }
52
56
 
53
- function* locationChange() {
54
- }
55
-
56
57
  function* fetchThings({ meta }) {
57
58
  const result = yield call(() => hyperSuperApi(meta.arg))
58
59
 
@@ -62,7 +63,7 @@ function* fetchThings({ meta }) {
62
63
  function* fetchThingsDebounce({ meta }) {
63
64
  try {
64
65
  yield delay(1000)
65
-
66
+
66
67
  console.log('STILL RUNNING', meta.requestId)
67
68
  } finally {
68
69
  if (yield cancelled()) {
@@ -70,25 +71,21 @@ function* fetchThingsDebounce({ meta }) {
70
71
  }
71
72
  }
72
73
 
73
- // const result = yield call(() => hyperSuperApi(true))
74
-
75
- // return result
76
74
  return 'shite'
77
75
  }
78
76
 
79
77
  function* click() {
80
78
  try {
81
- yield putAsync(actions.fetchThings(false))
79
+ yield putAsync(actions.fetchThings(false)) // wait
82
80
  } catch (error) {
83
81
  console.log('click', { error })
84
82
  }
85
83
  }
86
84
 
87
85
  export default [
88
- takeEveryAsync(actions.start.pending.toString(), appStart),
89
- // takeAggregateAsync(actions.fetchThings.pending.toString(), fetchThings),
90
- takeEveryAsync(actions.fetchThings.pending.toString(), fetchThings),
91
- takeLatestAsync(actions.fetchThingsDebounce.pending.toString(), fetchThingsDebounce),
92
- takeEvery(actions.click.type.toString(), click),
93
- takeEvery(LOCATION_CHANGE, locationChange),
86
+ takeEveryAsync(actions.start.pending, appStart),
87
+ // takeAggregateAsync(actions.fetchThings.pending, fetchThings),
88
+ takeEveryAsync(actions.fetchThings.pending, fetchThings),
89
+ takeLatestAsync(actions.fetchThingsDebounce.pending, fetchThingsDebounce),
90
+ takeEvery(actions.click.type, click),
94
91
  ]
@@ -1,5 +1,5 @@
1
1
  import { createAction, createSlice } from '@reduxjs/toolkit'
2
- import { createSagaAction } from './sagaToolkit'
2
+ import { createSagaAction } from 'saga-toolkit'
3
3
 
4
4
  const name = 'root'
5
5
 
package/index.d.ts ADDED
@@ -0,0 +1,50 @@
1
+ // generated with chatGTP
2
+
3
+ declare module 'saga-toolkit' {
4
+ import { createAsyncThunk, ThunkAction } from '@reduxjs/toolkit'
5
+ import { Dispatch } from 'redux'
6
+ import { SagaIterator } from 'redux-saga'
7
+ import { ActionCreatorWithPayload } from '@reduxjs/toolkit/src/createAction'
8
+ import { AsyncThunkFulfilledActionCreator, AsyncThunkConfig } from '@reduxjs/toolkit/src/createAsyncThunk'
9
+
10
+ type AsyncSagaPayloadCreator<Returned, ThunkArg = void> = (
11
+ arg: ThunkArg,
12
+ requestId: string
13
+ ) => Promise<Returned>
14
+
15
+ type AsyncSagaActionCreator<
16
+ Returned,
17
+ ThunkArg,
18
+ ThunkApiConfig extends AsyncThunkConfig = {}
19
+ > = (
20
+ arg: ThunkArg
21
+ ) => ActionCreatorWithPayload<
22
+ Promise<Returned>,
23
+ ReturnType<Dispatch>,
24
+ unknown,
25
+ ReturnType<
26
+ AsyncThunkFulfilledActionCreator<Returned, ThunkArg, ThunkApiConfig>
27
+ >
28
+ >
29
+
30
+ export interface AsyncSagaThunkConfig {
31
+ requestId: string
32
+ signal: AbortSignal
33
+ abort: (reason?: string) => void
34
+ }
35
+
36
+ export function createSagaAction<Returned, ThunkArg = void>(
37
+ type: string
38
+ ): AsyncSagaActionCreator<Returned, ThunkArg> & {
39
+ pending: string;
40
+ fulfilled: string;
41
+ rejected: string;
42
+ typePrefix: string;
43
+ type: string;
44
+ }
45
+
46
+ export function takeEveryAsync(pattern: any, saga: any, ...args: any[]): any
47
+ export function takeLatestAsync(pattern: any, saga: any, ...args: any[]): any
48
+ export function takeAggregateAsync(pattern: any, saga: any, ...args: any[]): any
49
+ export function putAsync(action: any): any
50
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "saga-toolkit",
3
- "version": "2.0.5",
3
+ "version": "2.1.0",
4
4
  "description": "An extension for redux-toolkit that allows sagas to resolve async thunk actions.",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -29,6 +29,8 @@
29
29
  "@babel/cli": "^7.16.8",
30
30
  "@babel/core": "^7.16.12",
31
31
  "@babel/node": "^7.16.8",
32
- "@babel/preset-env": "^7.16.11"
32
+ "@babel/preset-env": "^7.16.11",
33
+ "@reduxjs/toolkit": "^1.7.2",
34
+ "redux": "^4.1.2"
33
35
  }
34
36
  }
package/sagaToolkit.js CHANGED
@@ -50,7 +50,6 @@ const cleanup = requestId => {
50
50
  }
51
51
 
52
52
  function* getRequest(requestId) {
53
- // const { requestId } = action.meta
54
53
  const request = requests[requestId]
55
54
 
56
55
  if (!request) {
@@ -70,7 +69,6 @@ const wrap = saga => function* (action, ...rest) {
70
69
  try {
71
70
  deferred.resolve(yield saga(action, ...rest))
72
71
  } catch (error) {
73
- console.log(error)
74
72
  deferred.reject(error)
75
73
  } finally {
76
74
  cleanup(requestId)
package/.babelrc DELETED
@@ -1,12 +0,0 @@
1
- {
2
- "presets": [
3
- [
4
- "@babel/preset-env",
5
- {
6
- "targets": {
7
- "node": "current"
8
- }
9
- }
10
- ]
11
- ]
12
- }
@@ -1,154 +0,0 @@
1
- import { createAsyncThunk, unwrapResult } from '@reduxjs/toolkit'
2
- import { put, take, fork, takeEvery, cancel } from '@redux-saga/core/effects'
3
- import createDeferred from '@redux-saga/deferred'
4
-
5
- const requests = {}
6
-
7
- const addRequest = requestId => {
8
- const deferred = createDeferred()
9
- const request = {
10
- ...requests[requestId],
11
- requestId,
12
- deferred,
13
- }
14
-
15
- if (requests[requestId]) {
16
- requests[requestId].deferred = deferred
17
- requests[requestId].onAdd(request)
18
- } else {
19
- requests[requestId] = request
20
- }
21
-
22
- return deferred.promise
23
- }
24
-
25
- export const createSagaAction = type => {
26
- const thunk = createAsyncThunk(type, (_, { requestId }) => addRequest(requestId))
27
-
28
- function actionCreator(...args) {
29
- const originalActionCreator = thunk(...args)
30
-
31
- return (...args) => {
32
- const promise = originalActionCreator(...args)
33
- requests[promise.requestId].abort = promise.abort
34
-
35
- return promise
36
- }
37
- }
38
-
39
- actionCreator.pending = thunk.pending
40
- actionCreator.rejected = thunk.rejected
41
- actionCreator.fulfilled = thunk.fulfilled
42
- actionCreator.typePrefix = thunk.typePrefix
43
- actionCreator.type = thunk.pending
44
-
45
- return actionCreator
46
- }
47
-
48
- const cleanup = requestId => {
49
- delete requests[requestId]
50
- }
51
-
52
- function* getRequest(requestId) {
53
- // const { requestId } = action.meta
54
- const request = requests[requestId]
55
-
56
- if (!request) {
57
- return yield (new Promise(onAdd => {
58
- requests[requestId] = { onAdd }
59
- }))
60
- }
61
-
62
- return request
63
- }
64
-
65
- const wrap = saga => function* (action, ...rest) {
66
- const { requestId } = action.meta
67
- const request = yield getRequest(requestId)
68
- const deferred = request.deferred
69
-
70
- try {
71
- deferred.resolve(yield saga(action, ...rest))
72
- } catch (error) {
73
- console.log(error)
74
- deferred.reject(error)
75
- } finally {
76
- cleanup(requestId)
77
- }
78
- }
79
-
80
- export function takeEveryAsync(pattern, saga, ...args) {
81
- return takeEvery(pattern, wrap(saga), ...args)
82
- }
83
-
84
- export function takeLatestAsync(pattern, saga, ...args) {
85
- let deferred
86
- const tasks = {}
87
-
88
- function* wrapper(action, ...rest) {
89
- if (deferred) {
90
- const lastRequestId = yield deferred.promise
91
- const request = yield getRequest(lastRequestId)
92
-
93
- request.abort()
94
-
95
- const task = yield tasks[lastRequestId].promise
96
-
97
- yield cancel(task)
98
- }
99
-
100
- deferred = createDeferred()
101
- const { requestId } = yield getRequest(action.meta.requestId)
102
-
103
- deferred.resolve(requestId)
104
-
105
- yield wrap(saga)(action, ...rest)
106
-
107
- deferred = null
108
- }
109
-
110
- const takeEvery = (patternOrChannel, saga, ...args) => fork(function* () {
111
- while (true) {
112
- const action = yield take(patternOrChannel)
113
- const { requestId } = action.meta
114
- tasks[requestId] = createDeferred()
115
- tasks[requestId].resolve(yield fork(saga, ...args.concat(action)))
116
- }
117
- })
118
-
119
- return takeEvery(pattern, wrapper, ...args)
120
- }
121
-
122
- export function takeAggregateAsync(pattern, saga, ...args) {
123
- let deferred
124
-
125
- function* wrapper(action, ...rest) {
126
- const { requestId } = action.meta
127
-
128
- if (deferred) {
129
- const request = yield getRequest(requestId)
130
- const { resolve, reject } = request.deferred
131
- const { promise } = yield deferred.promise
132
-
133
- promise
134
- .then(resolve, reject)
135
- .finally(() => cleanup(requestId))
136
- .catch(() => { })
137
- } else {
138
- deferred = createDeferred()
139
- const request = yield getRequest(requestId)
140
- const { promise } = request.deferred
141
-
142
- yield wrap(saga)(action, ...rest)
143
-
144
- deferred.resolve({ promise })
145
- deferred = null
146
- }
147
- }
148
-
149
- return takeEvery(pattern, wrapper, ...args)
150
- }
151
-
152
- export function* putAsync(action) {
153
- return unwrapResult(yield (yield put(action)))
154
- }
@@ -1,24 +0,0 @@
1
- import { combineReducers } from 'redux'
2
- import { configureStore, getDefaultMiddleware } from '@reduxjs/toolkit'
3
- import createSagaMiddleware from 'redux-saga'
4
- import { all } from 'redux-saga/effects'
5
-
6
- export default ({ initialState, reducers, sagas }) => {
7
- const sagaMiddleware = createSagaMiddleware()
8
- const store = configureStore({
9
- reducer: combineReducers(reducers),
10
- middleware: [...getDefaultMiddleware(), sagaMiddleware],
11
- devTools: false,
12
- })
13
- // const store = createStore(
14
- // combineReducers(reducers),
15
- // initialState,
16
- // applyMiddleware(sagaMiddleware)
17
- // )
18
-
19
- sagaMiddleware.run(function* () {
20
- yield all(sagas)
21
- })
22
-
23
- return store
24
- }
@@ -1,95 +0,0 @@
1
- import { put } from 'redux-saga/effects'
2
- import { createSlice } from '@reduxjs/toolkit'
3
- import { expectSaga, testSaga } from 'redux-saga-test-plan'
4
- import createStore from './createStore'
5
- import { createSagaAction, takeEveryAsync } from '../sagaToolkit'
6
-
7
- const initialState = {
8
- test: null,
9
- testAsync: null,
10
- error: null,
11
- }
12
-
13
- const testAsyncAction = createSagaAction('testSlice/testAsyncAction')
14
-
15
- const slice = createSlice({
16
- name: 'testSlice',
17
- initialState,
18
- reducers: {
19
- testAction: (state, action) => ({ test: action.payload }),
20
- },
21
- extraReducers: {
22
- [testAsyncAction.pending]: (state, action) => ({
23
- ...state,
24
- test: action.payload,
25
- }),
26
- [testAsyncAction.resolved]: (state, action) => ({
27
- ...state,
28
- testAsync: 'action.meta.args',
29
- }),
30
- [testAsyncAction.rejected]: (state, action) => ({
31
- ...state,
32
- test: action.payload,
33
- }),
34
- },
35
- })
36
-
37
- const { testAction } = slice.actions
38
-
39
- function* saga() {
40
- yield put(testAction('testing'))
41
-
42
- return 'resolved value'
43
- }
44
-
45
- test('testing sync', () => {
46
- const reducers = { slice: slice.reducer }
47
- const sagas = [takeEveryAsync(testAsyncAction.pending, saga)]
48
- const store = createStore({ initialState, reducers, sagas })
49
-
50
- store.dispatch(testAction('testing'))
51
-
52
- const state = store.getState()
53
-
54
- expect(state).toEqual({
55
- slice: { test: 'testing' },
56
- })
57
- })
58
-
59
- test('testing async', () => {
60
- return expectSaga(saga)
61
- .withReducer(slice.reducer)
62
- .hasFinalState({
63
- test: 'testing',
64
- testAsync: 'testing async',
65
- })
66
- .run()
67
- })
68
-
69
- test('testing async 2', () => {
70
- testSaga(function *() {
71
- yield takeEveryAsync(testAsyncAction.pending, saga)
72
- }, 40, 2)
73
- // advance saga with `next()`
74
- .next()
75
-
76
- // assert that the saga yields `take` with `'HELLO'` as type
77
- // .take('HELLO')
78
-
79
- // pass back in a value to a saga after it yields
80
- // .next(action)
81
-
82
- // assert that the saga yields `put` with the expected action
83
- .put(testAction('testing'))
84
-
85
- .next()
86
-
87
- // assert that the saga yields a `call` to `identity` with
88
- // the `action` argument
89
- // .call(identity, action)
90
-
91
- .next()
92
-
93
- // assert that the saga is finished
94
- .isDone();
95
- })