@pihanga2/core 0.2.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.
Files changed (76) hide show
  1. package/dist/card.d.ts +22 -0
  2. package/dist/card.d.ts.map +1 -0
  3. package/dist/card.js +493 -0
  4. package/dist/card.js.map +1 -0
  5. package/dist/index.d.ts +50 -0
  6. package/dist/index.d.ts.map +1 -0
  7. package/dist/index.js +88 -0
  8. package/dist/index.js.map +1 -0
  9. package/dist/logger.d.ts +5 -0
  10. package/dist/logger.d.ts.map +1 -0
  11. package/dist/logger.js +12 -0
  12. package/dist/logger.js.map +1 -0
  13. package/dist/reducer.d.ts +5 -0
  14. package/dist/reducer.d.ts.map +1 -0
  15. package/dist/reducer.js +77 -0
  16. package/dist/reducer.js.map +1 -0
  17. package/dist/redux.d.ts +31 -0
  18. package/dist/redux.d.ts.map +1 -0
  19. package/dist/redux.js +50 -0
  20. package/dist/redux.js.map +1 -0
  21. package/dist/rest/delete.d.ts +4 -0
  22. package/dist/rest/delete.d.ts.map +1 -0
  23. package/dist/rest/delete.js +23 -0
  24. package/dist/rest/delete.js.map +1 -0
  25. package/dist/rest/enums.d.ts +6 -0
  26. package/dist/rest/enums.d.ts.map +1 -0
  27. package/dist/rest/enums.js +9 -0
  28. package/dist/rest/enums.js.map +1 -0
  29. package/dist/rest/get.d.ts +10 -0
  30. package/dist/rest/get.d.ts.map +1 -0
  31. package/dist/rest/get.js +31 -0
  32. package/dist/rest/get.js.map +1 -0
  33. package/dist/rest/index.d.ts +6 -0
  34. package/dist/rest/index.d.ts.map +1 -0
  35. package/dist/rest/index.js +6 -0
  36. package/dist/rest/index.js.map +1 -0
  37. package/dist/rest/postPutPatch.d.ts +6 -0
  38. package/dist/rest/postPutPatch.d.ts.map +1 -0
  39. package/dist/rest/postPutPatch.js +72 -0
  40. package/dist/rest/postPutPatch.js.map +1 -0
  41. package/dist/rest/types.d.ts +93 -0
  42. package/dist/rest/types.d.ts.map +1 -0
  43. package/dist/rest/types.js +38 -0
  44. package/dist/rest/types.js.map +1 -0
  45. package/dist/rest/utils.d.ts +8 -0
  46. package/dist/rest/utils.d.ts.map +1 -0
  47. package/dist/rest/utils.js +212 -0
  48. package/dist/rest/utils.js.map +1 -0
  49. package/dist/router.d.ts +25 -0
  50. package/dist/router.d.ts.map +1 -0
  51. package/dist/router.js +136 -0
  52. package/dist/router.js.map +1 -0
  53. package/dist/store.d.ts +1 -0
  54. package/dist/store.d.ts.map +1 -0
  55. package/dist/store.js +18 -0
  56. package/dist/store.js.map +1 -0
  57. package/dist/types.d.ts +94 -0
  58. package/dist/types.d.ts.map +1 -0
  59. package/dist/types.js +2 -0
  60. package/dist/types.js.map +1 -0
  61. package/package.json +71 -0
  62. package/src/card.tsx +628 -0
  63. package/src/index.tsx +193 -0
  64. package/src/logger.ts +13 -0
  65. package/src/reducer.ts +127 -0
  66. package/src/redux.ts +64 -0
  67. package/src/rest/delete.ts +41 -0
  68. package/src/rest/enums.ts +8 -0
  69. package/src/rest/get.ts +50 -0
  70. package/src/rest/index.ts +7 -0
  71. package/src/rest/postPutPatch.ts +118 -0
  72. package/src/rest/types.ts +135 -0
  73. package/src/rest/utils.ts +265 -0
  74. package/src/router.ts +171 -0
  75. package/src/store.ts +19 -0
  76. package/src/types.ts +146 -0
package/src/index.tsx ADDED
@@ -0,0 +1,193 @@
1
+ import React from "react"
2
+ import ReactDOM from "react-dom/client"
3
+ import { Provider } from "react-redux"
4
+ import { Dispatch } from "react"
5
+
6
+ import {
7
+ PiCardDef,
8
+ PiCardRef,
9
+ PiRegisterComponent,
10
+ ReduxAction,
11
+ ReduxState,
12
+ PiReducer,
13
+ RegisterCardF,
14
+ MetaCardMapperF,
15
+ PiRegisterMetaCard,
16
+ } from "./types"
17
+ import { Card, registerCard, registerCardComponent, registerMetacard } from "./card"
18
+ import { createReducer } from "./reducer"
19
+ import { ON_INIT_ACTION, currentRoute, init as routerInit } from "./router"
20
+
21
+ import { configureStore } from "@reduxjs/toolkit"
22
+
23
+ //import monitorReducerEnhancer from "./monitor_enhancer"
24
+ import { getLogger } from "./logger"
25
+ import {
26
+ PiRegisterDeleteProps,
27
+ PiRegisterGetProps,
28
+ PiRegisterPoPuPaProps,
29
+ registerDELETE,
30
+ registerGET,
31
+ registerPATCH,
32
+ registerPOST,
33
+ registerPUT,
34
+ } from "./rest"
35
+ const logger = getLogger("root")
36
+
37
+ export type {
38
+ PiMapProps,
39
+ PiCardDef,
40
+ RegisterCardF,
41
+ ReduxState,
42
+ ReduxAction,
43
+ DispatchF,
44
+ ReduceF,
45
+ PiDefCtxtProps,
46
+ StateMapperContext,
47
+ StateMapper,
48
+ PiReducer,
49
+ PiRegisterMetaCard,
50
+ } from "./types"
51
+ export { registerActions, actionTypesToEvents, createOnAction } from "./redux"
52
+ export { Card, memo, createCardDeclaration, isCardRef } from "./card"
53
+ export { getLogger } from "./logger"
54
+ export type { PiCardProps, PiCardRef } from "./types"
55
+ export type { ErrorAction as RestErrorAction } from "./rest"
56
+ export { RestContentType } from "./rest"
57
+
58
+ export { showPage, onInit, onShowPage, createShowPageAction, onNavigateToPage } from "./router"
59
+ export type { ShowPageEvent, NavigateToPageEvent } from "./router"
60
+
61
+ export interface PiRegister {
62
+ card(name: string, parameters: PiCardDef): PiCardRef
63
+
64
+ cardComponent(declaration: PiRegisterComponent): void
65
+
66
+ /**
67
+ * Register a meta card which expands a single card definition of type `name`
68
+ * into a new set of cards which can be registered in turn through `registerCards`.
69
+ *
70
+ * The `transformF` function takes the property declaration and uses the
71
+ * the common `PiRegister` to define the inner content of this meta card
72
+ *
73
+ * @param {string} type
74
+ * @param {function} mapper
75
+ */
76
+ metaCard<C>(declaration: PiRegisterMetaCard): void
77
+
78
+ GET<S extends ReduxState, A extends ReduxAction, R, C = any>(
79
+ props: PiRegisterGetProps<S, A, R, C>,
80
+ ): void
81
+ PUT<S extends ReduxState, A extends ReduxAction, R, C = any>(
82
+ props: PiRegisterPoPuPaProps<S, A, R, C>,
83
+ ): void
84
+ POST<S extends ReduxState, A extends ReduxAction, R, C = any>(
85
+ props: PiRegisterPoPuPaProps<S, A, R, C>,
86
+ ): void
87
+ PATCH<S extends ReduxState, A extends ReduxAction, R, C = any>(
88
+ props: PiRegisterPoPuPaProps<S, A, R, C>,
89
+ ): void
90
+ DELETE<S extends ReduxState, A extends ReduxAction, R, C = any>(
91
+ props: PiRegisterDeleteProps<S, A, R, C>,
92
+ ): void
93
+ //registerPeriodicGET<S extends ReduxState, A extends ReduxAction, R>(props: PiRegisterPeridicGetProps<S, A, R>): void;
94
+
95
+ reducer: PiReducer
96
+ }
97
+
98
+ export const DEFAULT_REDUX_STATE = {
99
+ route: { path: [], query: {}, url: "", fromBrowser: false },
100
+ pihanga: {},
101
+ }
102
+
103
+ export type StartProps = {
104
+ // redux settins
105
+ disableSerializableStateCheck?: boolean
106
+ disableSerializableActionCheck?: boolean
107
+ ignoredActions?: string[]
108
+ ignoredActionPaths?: string[]
109
+ ignoredStatePaths?: string[]
110
+ }
111
+
112
+ export function start<S extends Partial<ReduxState>>(
113
+ initialState: S,
114
+ inits: ((register: PiRegister) => void)[] = [],
115
+ props: StartProps = {}
116
+ ): PiRegister {
117
+ const state = {
118
+ ...DEFAULT_REDUX_STATE,
119
+ ...initialState,
120
+ ...{ route: currentRoute() }, // override route with current one
121
+ }
122
+ let dispatchF: Dispatch<any> | null = null
123
+ const dispatcherW: Dispatch<any> = (a: any): void => {
124
+ if (dispatchF) {
125
+ dispatchF(a)
126
+ } else {
127
+ logger.error("dispatch function is not properly set")
128
+ }
129
+ }
130
+ const [reducer, piReducer] = createReducer(state, dispatcherW)
131
+ const route = routerInit(piReducer)
132
+
133
+ const ignoredActions = ([] as string[]).concat(props.ignoredActions || [])
134
+ const ignoredActionPaths = [
135
+ "apiURL", // from IVCAP
136
+ "mapper",
137
+ "content", // from REST
138
+ "request",
139
+ "headers",
140
+ "cause",
141
+ "data",
142
+ ].concat(props.ignoredActionPaths || [])
143
+ const ignoredPaths = ["cause.content"].concat(props.ignoredStatePaths || [])
144
+
145
+ const store = configureStore({
146
+ reducer,
147
+ preloadedState: state as any, // keep type checking happy
148
+ // enhancers: [monitorReducerEnhancer as unknown as StoreEnhancer],
149
+ middleware: (getDefaultMiddleware) =>
150
+ getDefaultMiddleware({
151
+ serializableCheck: {
152
+ ignoredActions,
153
+ ignoredActionPaths,
154
+ ignoredPaths,
155
+ ignoreState: props.disableSerializableStateCheck,
156
+ ignoreAction: props.disableSerializableActionCheck,
157
+ }
158
+ })
159
+ })
160
+ dispatchF = store.dispatch
161
+
162
+ const card = registerCard(piReducer.register, dispatchF)
163
+ const register: PiRegister = {
164
+ card,
165
+ cardComponent: registerCardComponent,
166
+ metaCard: registerMetacard(card),
167
+ reducer: piReducer,
168
+ GET: registerGET(piReducer),
169
+ PUT: registerPUT(piReducer),
170
+ POST: registerPOST(piReducer),
171
+ PATCH: registerPATCH(piReducer),
172
+ DELETE: registerDELETE(piReducer),
173
+ }
174
+ inits.forEach((f) => f(register))
175
+
176
+ piReducer.dispatch({ type: ON_INIT_ACTION })
177
+
178
+ const rootComp = RootComponent(store)
179
+ const root = ReactDOM.createRoot(document.getElementById("root")!)
180
+ root.render(rootComp)
181
+
182
+ return register
183
+ }
184
+
185
+ function RootComponent(store: any) {
186
+ return (
187
+ <React.StrictMode>
188
+ <Provider store={store}>
189
+ <Card cardName="page" parentCard="" />
190
+ </Provider>
191
+ </React.StrictMode>
192
+ )
193
+ }
package/src/logger.ts ADDED
@@ -0,0 +1,13 @@
1
+ /* eslint-disable prettier/prettier */
2
+ import { Logger } from "tslog";
3
+
4
+ export const core = new Logger({
5
+ type: "pretty",
6
+ name: "",
7
+ prettyLogTemplate: "{{hh}}:{{MM}}:{{ss}}:{{ms}} {{logLevelName}} {{name}} "
8
+ });
9
+ export const pihanga = core.getSubLogger({ name: "pihanga" });
10
+
11
+ export function getLogger(name: string): Logger<unknown> {
12
+ return core.getSubLogger({ name });
13
+ }
package/src/reducer.ts ADDED
@@ -0,0 +1,127 @@
1
+ import { Action, Reducer } from "@reduxjs/toolkit"
2
+ import {
3
+ DispatchF,
4
+ PiReducer,
5
+ PiRegisterOneShotReducerF,
6
+ PiRegisterReducerF,
7
+ ReduceF,
8
+ ReduceOnceF,
9
+ ReduxAction,
10
+ ReduxState,
11
+ } from "./types"
12
+ import { produce } from "immer"
13
+ import { RegisterCardState, UPDATE_STATE_ACTION } from "./card"
14
+ import StackTrace from "stacktrace-js"
15
+ import { getLogger } from "./logger"
16
+ import { Dispatch } from "react"
17
+
18
+ const logger = getLogger("reducer")
19
+
20
+ type ReducerDef<S extends ReduxState, A extends ReduxAction> = {
21
+ mapperMany?: ReduceF<S, A>
22
+ mapperOnce?: ReduceOnceF<S, A>
23
+ priority?: number
24
+ definedIn?: StackTrace.StackFrame
25
+ }
26
+
27
+ export function createReducer(
28
+ initialState: ReduxState,
29
+ dispatcher: Dispatch<any>,
30
+ ): [Reducer<ReduxState, Action>, PiReducer] {
31
+ const mappings: { [k: string]: ReducerDef<ReduxState, Action>[] } = {}
32
+ mappings[UPDATE_STATE_ACTION] = [{ mapperMany: RegisterCardState.reducer }]
33
+
34
+ const delayedDispatcher = (a: any): void => {
35
+ setTimeout(() => dispatcher(a), 0)
36
+ }
37
+ const reducer = (
38
+ state: ReduxState | undefined,
39
+ action: Action,
40
+ ): ReduxState => {
41
+ const s = state || initialState
42
+ const ra = mappings[action.type]
43
+ if (!ra || ra.length === 0) {
44
+ return s
45
+ }
46
+
47
+ const nextState = produce<ReduxState, ReduxState>(s, (draft) => {
48
+ const rout: ReducerDef<ReduxState, Action<any>>[] = []
49
+ const outDraft = ra.reduce((d, m) => {
50
+ try {
51
+ if (m.mapperMany) {
52
+ const s = m.mapperMany(d, action, delayedDispatcher)
53
+ rout.push(m)
54
+ return s
55
+ } else if (m.mapperOnce) {
56
+ const [s, flag] = m.mapperOnce(d, action, delayedDispatcher)
57
+ if (!flag) {
58
+ rout.push(m)
59
+ }
60
+ return s
61
+ } else {
62
+ return d
63
+ }
64
+ } catch (err: any) {
65
+ logger.error(err.message, m.definedIn)
66
+ return d
67
+ }
68
+ }, draft)
69
+ mappings[action.type] = rout
70
+ return outDraft
71
+ })
72
+ return nextState
73
+ }
74
+
75
+ const registerReducer: PiRegisterReducerF = <
76
+ S extends ReduxState,
77
+ A extends ReduxAction,
78
+ >(
79
+ eventType: string,
80
+ mapper: ReduceF<S, A>,
81
+ priority: number = 0,
82
+ ): void => {
83
+ addReducer(eventType, { mapperMany: mapper, priority })
84
+ }
85
+
86
+ const registerOneShot: PiRegisterOneShotReducerF = <
87
+ S extends ReduxState,
88
+ A extends ReduxAction,
89
+ >(
90
+ eventType: string,
91
+ mapper: (state: S, action: A, dispatch: DispatchF) => [S, boolean],
92
+ priority: number = 0,
93
+ ): void => {
94
+ addReducer(eventType, { mapperOnce: mapper, priority })
95
+ }
96
+
97
+ function addReducer<S extends ReduxState, A extends ReduxAction>(
98
+ eventType: string,
99
+ reducerDef: ReducerDef<S, A>,
100
+ // mappings: { [k: string]: ReducerDef<ReduxState, Action>[] }
101
+ ) {
102
+ const m = mappings[eventType] || []
103
+ m.push(reducerDef as any as ReducerDef<ReduxState, Action<any>>) // keep typing happy
104
+ m.sort((a, b) => (b.priority || 0) - (a.priority || 0))
105
+ mappings[eventType] = m
106
+
107
+ const callback = (frames: StackTrace.StackFrame[]) => {
108
+ // const stack = frames.map((sf) => `${sf.fileName}:${sf.lineNumber}`)
109
+ // console.log(stack)
110
+ reducerDef.definedIn = frames[2]
111
+ }
112
+
113
+ const errback = (err: any) => {
114
+ logger.warn(err.message)
115
+ }
116
+ StackTrace.get().then(callback).catch(errback)
117
+ }
118
+
119
+ const piReducer: PiReducer = {
120
+ register: registerReducer,
121
+ registerOneShot,
122
+ dispatch: dispatcher,
123
+ dispatchFromReducer: delayedDispatcher,
124
+ }
125
+
126
+ return [reducer, piReducer]
127
+ }
package/src/redux.ts ADDED
@@ -0,0 +1,64 @@
1
+ import { PiRegister } from "."
2
+ import { pihanga as logger } from "./logger"
3
+ import { CardAction, ReduceF, ReduxState } from "./types"
4
+
5
+ const ns2Actions: { [k: string]: boolean } = {}
6
+
7
+ /**
8
+ * Register a set of actions for a particular namespace.
9
+ *
10
+ * The 'actions' parameter is an array of local action
11
+ * names which will be converted into a hash where the local name
12
+ * is the key and the value is of the pattern 'namespace:name'.
13
+ *
14
+ * The function returns the hash registered under this namespace.
15
+ *
16
+ * @param {string} namespace
17
+ * @param {hash||array} actions
18
+ */
19
+ export function registerActions<T extends string>(
20
+ namespace: string,
21
+ actions: readonly T[],
22
+ ): { [S in Uppercase<T>]: string } {
23
+ if (ns2Actions[namespace]) {
24
+ logger.warn(`Overwriting action namespace "${namespace}"`)
25
+ }
26
+ const ah: any = {}
27
+ actions.forEach((a) => {
28
+ ah[a.toUpperCase()] = `${namespace}/${a}`
29
+ })
30
+ logger.info(`Register action ns "${namespace}"`)
31
+ ns2Actions[namespace] = true
32
+ return ah as { [S in Uppercase<T>]: string }
33
+ }
34
+
35
+ export function actionTypesToEvents(actionTypes: { [k: string]: string }): {
36
+ [k: string]: string
37
+ } {
38
+ return Object.entries(actionTypes).reduce((p, el) => {
39
+ const [k, v] = el
40
+ const n = k
41
+ .split("_")
42
+ .map((s) => s.charAt(0).toUpperCase() + s.slice(1).toLowerCase())
43
+ .join("")
44
+ p[`on${n}`] = v
45
+ return p
46
+ }, {} as { [k: string]: string })
47
+ }
48
+
49
+ /**
50
+ * Return a function to more conventiently register a
51
+ * reducer function for 'actionType'.
52
+ *
53
+ * @param {string} actionType
54
+ * @returns a function to register a reducer for 'actionType'
55
+ */
56
+ export function createOnAction<E>(actionType: string): <S extends ReduxState>(
57
+ register: PiRegister,
58
+ //f: (state: S, ev: CardAction & E) => S,
59
+ f: ReduceF<S, CardAction & E>,
60
+ ) => void {
61
+ return (register, f) => {
62
+ register.reducer.register(actionType, f)
63
+ }
64
+ }
@@ -0,0 +1,41 @@
1
+ import { PiReducer, ReduxAction, ReduxState } from "../types"
2
+ import { registerCommon } from "./utils"
3
+ import { Bindings, ACTION_TYPES, PiRegisterDeleteProps } from "./types"
4
+
5
+ export function registerDELETE<S extends ReduxState, A extends ReduxAction, R, C = any>(
6
+ reducer: PiReducer,
7
+ ): (props: PiRegisterDeleteProps<S, A, R, C>) => void {
8
+ return function (props: PiRegisterDeleteProps<S, A, R>) {
9
+ _registerDELETE(props, reducer)
10
+ }
11
+ }
12
+
13
+ function _registerDELETE<S extends ReduxState, A extends ReduxAction, R, C = any>(
14
+ props: PiRegisterDeleteProps<S, A, R, C>,
15
+ reducer: PiReducer,
16
+ ) {
17
+ const { name, request } = props
18
+
19
+ const submitType = `${ACTION_TYPES.DELETE_SUBMITTED}:${name}`
20
+ const resultType = `${ACTION_TYPES.DELETE_RESULT}:${name}`
21
+ const errorType = `${ACTION_TYPES.DELETE_ERROR}:${name}`
22
+ const intErrorType = `${ACTION_TYPES.DELETE_INTERNAL_ERROR}:${name}`
23
+
24
+ function requestF(state: S, action: A): [RequestInit, Bindings] {
25
+ const bindings = request ? request(action, state) : {}
26
+ const reqInit = {
27
+ method: "DELETE",
28
+ }
29
+ return [reqInit, bindings]
30
+ }
31
+
32
+ registerCommon(
33
+ reducer,
34
+ props,
35
+ requestF,
36
+ submitType,
37
+ resultType,
38
+ errorType,
39
+ intErrorType,
40
+ )
41
+ }
@@ -0,0 +1,8 @@
1
+ // Enums are not types, but we kind of use them like types, so we have
2
+ // to work around imports and type checking
3
+
4
+ export enum RestContentType {
5
+ Blob = "blob",
6
+ Text = "text",
7
+ Object = "object",
8
+ }
@@ -0,0 +1,50 @@
1
+ import { PiReducer, ReduxAction, ReduxState } from "../types"
2
+ import { registerCommon } from "./utils"
3
+ import { Bindings, Domain, PiRegisterGetProps } from "./types"
4
+ import { registerActions } from "../redux"
5
+
6
+ export const ACTION_TYPES = registerActions(`${Domain}/get`, [
7
+ "submitted",
8
+ "result",
9
+ "error",
10
+ "internal_error",
11
+ // "PERIODIC_TICK",
12
+ ])
13
+
14
+ export function registerGET<S extends ReduxState, A extends ReduxAction, R, C = any>(
15
+ reducer: PiReducer,
16
+ ): (props: PiRegisterGetProps<S, A, R, C>) => void {
17
+ return function (props: PiRegisterGetProps<S, A, R, C>) {
18
+ _registerGET(props, reducer)
19
+ }
20
+ }
21
+
22
+ function _registerGET<S extends ReduxState, A extends ReduxAction, R, C = any>(
23
+ props: PiRegisterGetProps<S, A, R, C>,
24
+ reducer: PiReducer,
25
+ ) {
26
+ const { name, request } = props
27
+
28
+ const submitType = `${ACTION_TYPES.SUBMITTED}/${name}`
29
+ const resultType = `${ACTION_TYPES.RESULT}/${name}`
30
+ const errorType = `${ACTION_TYPES.ERROR}/${name}`
31
+ const intErrorType = `${ACTION_TYPES.INTERNAL_ERROR}/${name}`
32
+
33
+ function requestF(state: S, action: A): [RequestInit, Bindings] {
34
+ const bindings = request ? request(action, state) : {}
35
+ const reqInit = {
36
+ method: "GET",
37
+ }
38
+ return [reqInit, bindings]
39
+ }
40
+
41
+ registerCommon(
42
+ reducer,
43
+ props,
44
+ requestF,
45
+ submitType,
46
+ resultType,
47
+ errorType,
48
+ intErrorType,
49
+ )
50
+ }
@@ -0,0 +1,7 @@
1
+ export { registerGET } from "./get"
2
+ //export { registerPeriodicGET } from './get-periodic';
3
+ export { registerPOST, registerPUT, registerPATCH } from "./postPutPatch"
4
+ export { registerDELETE } from "./delete"
5
+
6
+ export type * from "./types"
7
+ export * from "./enums"
@@ -0,0 +1,118 @@
1
+ import { PiReducer, ReduxAction, ReduxState } from "../types"
2
+ import {
3
+ ACTION_TYPES,
4
+ Bindings,
5
+ PiRegisterPoPuPaProps,
6
+ PoPuPaRequest,
7
+ } from "./types"
8
+ import { RequestF, registerCommon } from "./utils"
9
+
10
+ export function registerPOST<S extends ReduxState, A extends ReduxAction, R, C = any>(
11
+ reducer: PiReducer,
12
+ ): (props: PiRegisterPoPuPaProps<S, A, R>) => void {
13
+ return function (props: PiRegisterPoPuPaProps<S, A, R>) {
14
+ const { name, request } = props
15
+
16
+ const submitType = `${ACTION_TYPES.POST_SUBMITTED}:${name}`
17
+ const resultType = `${ACTION_TYPES.POST_RESULT}:${name}`
18
+ const errorType = `${ACTION_TYPES.POST_ERROR}:${name}`
19
+ const intErrorType = `${ACTION_TYPES.POST_INTERNAL_ERROR}:${name}`
20
+
21
+ registerCommon(
22
+ reducer,
23
+ props,
24
+ requestF("POST", request),
25
+ submitType,
26
+ resultType,
27
+ errorType,
28
+ intErrorType,
29
+ )
30
+ }
31
+ }
32
+
33
+ export function registerPUT<S extends ReduxState, A extends ReduxAction, R, C = any>(
34
+ reducer: PiReducer,
35
+ ): (props: PiRegisterPoPuPaProps<S, A, R>) => void {
36
+ return function (props: PiRegisterPoPuPaProps<S, A, R>) {
37
+ const { name, request } = props
38
+
39
+ const submitType = `${ACTION_TYPES.PUT_SUBMITTED}:${name}`
40
+ const resultType = `${ACTION_TYPES.PUT_RESULT}:${name}`
41
+ const errorType = `${ACTION_TYPES.PUT_ERROR}:${name}`
42
+ const intErrorType = `${ACTION_TYPES.PUT_INTERNAL_ERROR}:${name}`
43
+
44
+ registerCommon(
45
+ reducer,
46
+ props,
47
+ requestF("PUT", request),
48
+ submitType,
49
+ resultType,
50
+ errorType,
51
+ intErrorType,
52
+ )
53
+ }
54
+ }
55
+
56
+ export function registerPATCH<S extends ReduxState, A extends ReduxAction, R, C = any>(
57
+ reducer: PiReducer,
58
+ ): (props: PiRegisterPoPuPaProps<S, A, R, C>) => void {
59
+ return function (props: PiRegisterPoPuPaProps<S, A, R>) {
60
+ const { name, request } = props
61
+
62
+ const submitType = `${ACTION_TYPES.PATCH_SUBMITTED}:${name}`
63
+ const resultType = `${ACTION_TYPES.PATCH_RESULT}:${name}`
64
+ const errorType = `${ACTION_TYPES.PATCH_ERROR}:${name}`
65
+ const intErrorType = `${ACTION_TYPES.PATCH_INTERNAL_ERROR}:${name}`
66
+
67
+ registerCommon(
68
+ reducer,
69
+ props,
70
+ requestF("PATCH", request),
71
+ submitType,
72
+ resultType,
73
+ errorType,
74
+ intErrorType,
75
+ )
76
+ }
77
+ }
78
+
79
+ function requestF<S extends ReduxState, A extends ReduxAction>(
80
+ method: string,
81
+ request: (action: A, state: S) => PoPuPaRequest,
82
+ ): RequestF<S, A> {
83
+ return (state: S, action: A): [RequestInit, Bindings] => {
84
+ const r = request(action, state)
85
+ let ct = r.contentType
86
+ const headers = {} as { [k: string]: any }
87
+ let body = r.body
88
+ if (body) {
89
+ if (!ct) {
90
+ if (typeof body === "object") {
91
+ ct = "application/json"
92
+ } else if (typeof body === "string") {
93
+ ct = "text"
94
+ } else {
95
+ throw Error("Cannot determin 'contentType'")
96
+ }
97
+ }
98
+ headers["Content-Type"] = ct
99
+ if (ct === "application/json") {
100
+ body = JSON.stringify(body)
101
+ }
102
+ }
103
+ if (!ct) {
104
+ if (typeof body === "string") {
105
+ ct = "text"
106
+ } else {
107
+ throw Error("Cannot determin 'contentType'")
108
+ }
109
+ }
110
+
111
+ const reqInit = {
112
+ method,
113
+ body,
114
+ headers,
115
+ }
116
+ return [reqInit, r.bindings || {}]
117
+ }
118
+ }