@genesislcap/foundation-state-machine 14.70.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 (173) hide show
  1. package/README.md +26 -0
  2. package/dist/dts/core/actions.d.ts +61 -0
  3. package/dist/dts/core/actions.d.ts.map +1 -0
  4. package/dist/dts/core/binding.d.ts +37 -0
  5. package/dist/dts/core/binding.d.ts.map +1 -0
  6. package/dist/dts/core/errors.d.ts +41 -0
  7. package/dist/dts/core/errors.d.ts.map +1 -0
  8. package/dist/dts/core/guards.d.ts +67 -0
  9. package/dist/dts/core/guards.d.ts.map +1 -0
  10. package/dist/dts/core/index.d.ts +8 -0
  11. package/dist/dts/core/index.d.ts.map +1 -0
  12. package/dist/dts/core/inputs.d.ts +19 -0
  13. package/dist/dts/core/inputs.d.ts.map +1 -0
  14. package/dist/dts/core/machine.d.ts +338 -0
  15. package/dist/dts/core/machine.d.ts.map +1 -0
  16. package/dist/dts/core/state.d.ts +11 -0
  17. package/dist/dts/core/state.d.ts.map +1 -0
  18. package/dist/dts/index.d.ts +4 -0
  19. package/dist/dts/index.d.ts.map +1 -0
  20. package/dist/dts/index.federated.d.ts +1 -0
  21. package/dist/dts/index.federated.d.ts.map +1 -0
  22. package/dist/dts/machines/fetch/errors.d.ts +39 -0
  23. package/dist/dts/machines/fetch/errors.d.ts.map +1 -0
  24. package/dist/dts/machines/fetch/index.d.ts +5 -0
  25. package/dist/dts/machines/fetch/index.d.ts.map +1 -0
  26. package/dist/dts/machines/fetch/machine.d.ts +57 -0
  27. package/dist/dts/machines/fetch/machine.d.ts.map +1 -0
  28. package/dist/dts/machines/fetch/policies.d.ts +25 -0
  29. package/dist/dts/machines/fetch/policies.d.ts.map +1 -0
  30. package/dist/dts/machines/fetch/types.d.ts +118 -0
  31. package/dist/dts/machines/fetch/types.d.ts.map +1 -0
  32. package/dist/dts/machines/index.d.ts +2 -0
  33. package/dist/dts/machines/index.d.ts.map +1 -0
  34. package/dist/dts/tsdoc-metadata.json +11 -0
  35. package/dist/dts/utils/index.d.ts +2 -0
  36. package/dist/dts/utils/index.d.ts.map +1 -0
  37. package/dist/dts/utils/logger.d.ts +5 -0
  38. package/dist/dts/utils/logger.d.ts.map +1 -0
  39. package/dist/esm/core/actions.js +46 -0
  40. package/dist/esm/core/binding.js +16 -0
  41. package/dist/esm/core/errors.js +70 -0
  42. package/dist/esm/core/guards.js +73 -0
  43. package/dist/esm/core/index.js +7 -0
  44. package/dist/esm/core/inputs.js +10 -0
  45. package/dist/esm/core/machine.js +180 -0
  46. package/dist/esm/core/state.js +26 -0
  47. package/dist/esm/index.federated.js +1 -0
  48. package/dist/esm/index.js +3 -0
  49. package/dist/esm/machines/fetch/errors.js +46 -0
  50. package/dist/esm/machines/fetch/index.js +4 -0
  51. package/dist/esm/machines/fetch/machine.js +216 -0
  52. package/dist/esm/machines/fetch/policies.js +48 -0
  53. package/dist/esm/machines/fetch/types.js +48 -0
  54. package/dist/esm/machines/index.js +1 -0
  55. package/dist/esm/utils/index.js +1 -0
  56. package/dist/esm/utils/logger.js +5 -0
  57. package/dist/foundation-state-machine.api.json +5594 -0
  58. package/dist/foundation-state-machine.d.ts +884 -0
  59. package/docs/.gitattributes +2 -0
  60. package/docs/api/foundation-state-machine.abstractmachine.actor.md +18 -0
  61. package/docs/api/foundation-state-machine.abstractmachine.binding.md +27 -0
  62. package/docs/api/foundation-state-machine.abstractmachine.complete.md +13 -0
  63. package/docs/api/foundation-state-machine.abstractmachine.context.md +13 -0
  64. package/docs/api/foundation-state-machine.abstractmachine.error.md +13 -0
  65. package/docs/api/foundation-state-machine.abstractmachine.errors.md +13 -0
  66. package/docs/api/foundation-state-machine.abstractmachine.getfromcontainer.md +23 -0
  67. package/docs/api/foundation-state-machine.abstractmachine.hastag.md +28 -0
  68. package/docs/api/foundation-state-machine.abstractmachine.machine.md +18 -0
  69. package/docs/api/foundation-state-machine.abstractmachine.matches.md +28 -0
  70. package/docs/api/foundation-state-machine.abstractmachine.md +44 -0
  71. package/docs/api/foundation-state-machine.abstractmachine.onsendevent.md +13 -0
  72. package/docs/api/foundation-state-machine.abstractmachine.output.md +13 -0
  73. package/docs/api/foundation-state-machine.abstractmachine.provide.md +24 -0
  74. package/docs/api/foundation-state-machine.abstractmachine.send.md +24 -0
  75. package/docs/api/foundation-state-machine.abstractmachine.start.md +28 -0
  76. package/docs/api/foundation-state-machine.abstractmachine.startingcontext.md +13 -0
  77. package/docs/api/foundation-state-machine.abstractmachine.startingstate.md +13 -0
  78. package/docs/api/foundation-state-machine.abstractmachine.state.md +13 -0
  79. package/docs/api/foundation-state-machine.abstractmachine.stop.md +17 -0
  80. package/docs/api/foundation-state-machine.apierror._constructor_.md +22 -0
  81. package/docs/api/foundation-state-machine.apierror.data.md +11 -0
  82. package/docs/api/foundation-state-machine.apierror.md +32 -0
  83. package/docs/api/foundation-state-machine.apierror.status.md +11 -0
  84. package/docs/api/foundation-state-machine.assertevent.md +27 -0
  85. package/docs/api/foundation-state-machine.createerrorstatenode.md +13 -0
  86. package/docs/api/foundation-state-machine.createfetchpolicy.md +18 -0
  87. package/docs/api/foundation-state-machine.createresponsedataextractorwithdeserializer.md +13 -0
  88. package/docs/api/foundation-state-machine.defaultfetchconfig.md +13 -0
  89. package/docs/api/foundation-state-machine.defaultfetchmachine._constructor_.md +20 -0
  90. package/docs/api/foundation-state-machine.defaultfetchmachine.getfromcontainer.md +23 -0
  91. package/docs/api/foundation-state-machine.defaultfetchmachine.md +30 -0
  92. package/docs/api/foundation-state-machine.defaultfetchmachine.start.md +28 -0
  93. package/docs/api/foundation-state-machine.defaultfetchmachinecontext.md +13 -0
  94. package/docs/api/foundation-state-machine.defaultfetchpolicy.md +13 -0
  95. package/docs/api/foundation-state-machine.defaultresponsedataextractor.md +18 -0
  96. package/docs/api/foundation-state-machine.defaultresponseokchecker.md +13 -0
  97. package/docs/api/foundation-state-machine.defaultretrystatscodes.md +13 -0
  98. package/docs/api/foundation-state-machine.errorworkflowinput.md +15 -0
  99. package/docs/api/foundation-state-machine.escalateerror.md +42 -0
  100. package/docs/api/foundation-state-machine.fetchconfig.fetcher.md +13 -0
  101. package/docs/api/foundation-state-machine.fetchconfig.fetchpolicy.md +13 -0
  102. package/docs/api/foundation-state-machine.fetchconfig.md +23 -0
  103. package/docs/api/foundation-state-machine.fetchconfig.responsedataextractor.md +13 -0
  104. package/docs/api/foundation-state-machine.fetchconfig.responseokchecker.md +13 -0
  105. package/docs/api/foundation-state-machine.fetchmachine.md +15 -0
  106. package/docs/api/foundation-state-machine.fetchmachinecontext.controller.md +13 -0
  107. package/docs/api/foundation-state-machine.fetchmachinecontext.data.md +13 -0
  108. package/docs/api/foundation-state-machine.fetchmachinecontext.md +28 -0
  109. package/docs/api/foundation-state-machine.fetchmachinecontext.params.md +17 -0
  110. package/docs/api/foundation-state-machine.fetchmachinecontext.response.md +13 -0
  111. package/docs/api/foundation-state-machine.fetchmachineevent.md +24 -0
  112. package/docs/api/foundation-state-machine.fetchmachineeventmap.md +21 -0
  113. package/docs/api/foundation-state-machine.fetchmachineoutput.md +21 -0
  114. package/docs/api/foundation-state-machine.genesisservererror._constructor_.md +22 -0
  115. package/docs/api/foundation-state-machine.genesisservererror.getdetailserror.md +15 -0
  116. package/docs/api/foundation-state-machine.genesisservererror.getmessageerror.md +15 -0
  117. package/docs/api/foundation-state-machine.genesisservererror.haserrorcode.md +22 -0
  118. package/docs/api/foundation-state-machine.genesisservererror.isignorableerror.md +17 -0
  119. package/docs/api/foundation-state-machine.genesisservererror.md +41 -0
  120. package/docs/api/foundation-state-machine.genesisservererror.received.md +11 -0
  121. package/docs/api/foundation-state-machine.genesisservererror.sent.md +11 -0
  122. package/docs/api/foundation-state-machine.isaborterror.md +15 -0
  123. package/docs/api/foundation-state-machine.isactorerrorevent.md +13 -0
  124. package/docs/api/foundation-state-machine.isapierror.md +11 -0
  125. package/docs/api/foundation-state-machine.isdoneinvokeevent.md +13 -0
  126. package/docs/api/foundation-state-machine.iserrorcustomevent.md +18 -0
  127. package/docs/api/foundation-state-machine.iserrorevent.md +13 -0
  128. package/docs/api/foundation-state-machine.iserrortype.md +13 -0
  129. package/docs/api/foundation-state-machine.isgenesisservererror.md +11 -0
  130. package/docs/api/foundation-state-machine.ismappingerror.md +11 -0
  131. package/docs/api/foundation-state-machine.isnetworkerror.md +11 -0
  132. package/docs/api/foundation-state-machine.isnotfounderror.md +13 -0
  133. package/docs/api/foundation-state-machine.issyntaxerror.md +15 -0
  134. package/docs/api/foundation-state-machine.istypeerror.md +15 -0
  135. package/docs/api/foundation-state-machine.logger.md +12 -0
  136. package/docs/api/foundation-state-machine.machine.actor.md +18 -0
  137. package/docs/api/foundation-state-machine.machine.binding.md +47 -0
  138. package/docs/api/foundation-state-machine.machine.complete.md +13 -0
  139. package/docs/api/foundation-state-machine.machine.context.md +13 -0
  140. package/docs/api/foundation-state-machine.machine.error.md +13 -0
  141. package/docs/api/foundation-state-machine.machine.errors.md +13 -0
  142. package/docs/api/foundation-state-machine.machine.getfromcontainer.md +35 -0
  143. package/docs/api/foundation-state-machine.machine.hastag.md +35 -0
  144. package/docs/api/foundation-state-machine.machine.machine.md +18 -0
  145. package/docs/api/foundation-state-machine.machine.matches.md +35 -0
  146. package/docs/api/foundation-state-machine.machine.md +101 -0
  147. package/docs/api/foundation-state-machine.machine.onsendevent.md +24 -0
  148. package/docs/api/foundation-state-machine.machine.output.md +13 -0
  149. package/docs/api/foundation-state-machine.machine.provide.md +44 -0
  150. package/docs/api/foundation-state-machine.machine.send.md +24 -0
  151. package/docs/api/foundation-state-machine.machine.start.md +28 -0
  152. package/docs/api/foundation-state-machine.machine.startingcontext.md +13 -0
  153. package/docs/api/foundation-state-machine.machine.startingstate.md +13 -0
  154. package/docs/api/foundation-state-machine.machine.state.md +13 -0
  155. package/docs/api/foundation-state-machine.machine.stop.md +17 -0
  156. package/docs/api/foundation-state-machine.machinecontext.error.md +13 -0
  157. package/docs/api/foundation-state-machine.machinecontext.errors.md +13 -0
  158. package/docs/api/foundation-state-machine.machinecontext.md +36 -0
  159. package/docs/api/foundation-state-machine.mappingerror._constructor_.md +21 -0
  160. package/docs/api/foundation-state-machine.mappingerror.dto.md +11 -0
  161. package/docs/api/foundation-state-machine.mappingerror.md +27 -0
  162. package/docs/api/foundation-state-machine.md +81 -0
  163. package/docs/api/foundation-state-machine.networkerror._constructor_.md +21 -0
  164. package/docs/api/foundation-state-machine.networkerror.md +31 -0
  165. package/docs/api/foundation-state-machine.networkerror.url.md +11 -0
  166. package/docs/api/foundation-state-machine.responsedataextractor.md +18 -0
  167. package/docs/api/foundation-state-machine.responseokchecker.md +13 -0
  168. package/docs/api/foundation-state-machine.seterror.md +25 -0
  169. package/docs/api/foundation-state-machine.seterrorbykey.md +25 -0
  170. package/docs/api/index.md +12 -0
  171. package/docs/api-report.md +393 -0
  172. package/license.txt +46 -0
  173. package/package.json +60 -0
@@ -0,0 +1,180 @@
1
+ import { __decorate } from "tslib";
2
+ import { createErrorMap } from '@genesislcap/foundation-utils';
3
+ import { defaultExecutionContext, observable, Observable, } from '@microsoft/fast-element';
4
+ import { Container } from '@microsoft/fast-foundation';
5
+ import { interpret, InterpreterStatus } from 'xstate';
6
+ import { logger } from '../utils';
7
+ import { getBindArgs } from './binding';
8
+ /**
9
+ * AbstractMachine base class.
10
+ * @public
11
+ */
12
+ export class AbstractMachine {
13
+ constructor() {
14
+ /** {@inheritDoc Machine.onSendEvent} */
15
+ this.onSendEvent = (event) => {
16
+ this.send(event.detail);
17
+ };
18
+ }
19
+ /** {@inheritDoc Machine.start} */
20
+ start(options) {
21
+ this.interpret(options);
22
+ this.subscribe();
23
+ this.startActor();
24
+ }
25
+ /** {@inheritDoc Machine.stop} */
26
+ stop() {
27
+ this.stopActor();
28
+ this.unsubscribe();
29
+ }
30
+ /**
31
+ * @internal
32
+ */
33
+ interpret(options = {}) {
34
+ if (!this.machine) {
35
+ throw new Error('Create this.machine before calling interpret()');
36
+ }
37
+ const contextWithErrors = {
38
+ errors: createErrorMap(logger.error),
39
+ error: undefined,
40
+ };
41
+ this.startingState = options === null || options === void 0 ? void 0 : options.state;
42
+ this.startingContext = (options.input
43
+ ? Object.assign(Object.assign({}, contextWithErrors), options.input) : contextWithErrors);
44
+ this.actor = interpret(this.machine, Object.assign(Object.assign({}, options), { input: this.startingContext, state: this.startingState }));
45
+ const { value: currentValue, context: currentContext } = this.actor.getSnapshot();
46
+ this.state = currentValue;
47
+ this.context = currentContext;
48
+ this.complete = false;
49
+ this.output = undefined;
50
+ this.errors = currentContext.errors;
51
+ this.error = undefined;
52
+ }
53
+ /**
54
+ * @internal
55
+ */
56
+ subscribe() {
57
+ if (!this.actor) {
58
+ throw new Error('Call interpret() before calling subscribe()');
59
+ }
60
+ this.subscription = this.actor.subscribe({
61
+ next: (snapshot) => {
62
+ var _a;
63
+ this.state = snapshot.value;
64
+ this.context = snapshot.context;
65
+ this.errors = this.context.errors;
66
+ this.error = (_a = this.context.error) !== null && _a !== void 0 ? _a : this.errors.lastError;
67
+ logger.debug(`${this.machine.id} changed, state:`, this.state, `context:`, this.context);
68
+ },
69
+ error: (err) => {
70
+ this.error = err;
71
+ logger.error(`${this.machine.id} error:`, err);
72
+ },
73
+ complete: () => {
74
+ this.complete = true;
75
+ this.output = this.actor.getSnapshot().output;
76
+ logger.debug(`${this.machine.id} complete:`, this.output);
77
+ },
78
+ });
79
+ }
80
+ /**
81
+ * @internal
82
+ */
83
+ unsubscribe() {
84
+ this.subscription && this.subscription.unsubscribe();
85
+ }
86
+ /**
87
+ * @internal
88
+ */
89
+ startActor() {
90
+ var _a;
91
+ if (((_a = this.actor) === null || _a === void 0 ? void 0 : _a.status) !== InterpreterStatus.Running) {
92
+ this.actor.start();
93
+ }
94
+ }
95
+ /**
96
+ * @internal
97
+ */
98
+ stopActor() {
99
+ var _a;
100
+ if (((_a = this.actor) === null || _a === void 0 ? void 0 : _a.status) === InterpreterStatus.Running) {
101
+ this.actor.stop();
102
+ }
103
+ }
104
+ /** {@inheritDoc Machine.provide} */
105
+ provide(implementations) {
106
+ if (!this.machine) {
107
+ throw new Error('Create this.machine before calling provide()');
108
+ }
109
+ this.machine = this.machine.provide(implementations);
110
+ if (this.actor) {
111
+ this.stop();
112
+ logger.debug('You will need to recall start() after calling provide() on a running machine.');
113
+ }
114
+ }
115
+ /** {@inheritDoc Machine.matches} */
116
+ matches(value) {
117
+ if (!this.actor) {
118
+ throw new Error('Call interpret() before calling matches()');
119
+ }
120
+ return this.actor.getSnapshot().matches(value);
121
+ }
122
+ /** {@inheritDoc Machine.hasTag} */
123
+ hasTag(tag) {
124
+ if (!this.actor) {
125
+ throw new Error('Call interpret() before calling hasTag()');
126
+ }
127
+ return this.actor.getSnapshot().hasTag(tag);
128
+ }
129
+ /** {@inheritDoc Machine.send} */
130
+ send(event) {
131
+ this.actor.send(event);
132
+ }
133
+ /** {@inheritDoc Machine.binding} */
134
+ binding(token, subscriberChangeCallback, isVolatileBinding = false, context = defaultExecutionContext) {
135
+ const valueGetter = getBindArgs(token);
136
+ const initialSubscriber = {
137
+ handleChange: (binding, args) => {
138
+ if (subscriberChangeCallback) {
139
+ subscriberChangeCallback(binding(this, context), args);
140
+ }
141
+ },
142
+ };
143
+ const bindingObserver = Observable.binding(valueGetter, initialSubscriber, isVolatileBinding);
144
+ bindingObserver.observe(this, context);
145
+ return bindingObserver;
146
+ }
147
+ }
148
+ __decorate([
149
+ Container
150
+ ], AbstractMachine.prototype, "container", void 0);
151
+ __decorate([
152
+ observable
153
+ ], AbstractMachine.prototype, "machine", void 0);
154
+ __decorate([
155
+ observable
156
+ ], AbstractMachine.prototype, "actor", void 0);
157
+ __decorate([
158
+ observable
159
+ ], AbstractMachine.prototype, "state", void 0);
160
+ __decorate([
161
+ observable
162
+ ], AbstractMachine.prototype, "startingState", void 0);
163
+ __decorate([
164
+ observable
165
+ ], AbstractMachine.prototype, "context", void 0);
166
+ __decorate([
167
+ observable
168
+ ], AbstractMachine.prototype, "startingContext", void 0);
169
+ __decorate([
170
+ observable
171
+ ], AbstractMachine.prototype, "complete", void 0);
172
+ __decorate([
173
+ observable
174
+ ], AbstractMachine.prototype, "output", void 0);
175
+ __decorate([
176
+ observable
177
+ ], AbstractMachine.prototype, "errors", void 0);
178
+ __decorate([
179
+ observable
180
+ ], AbstractMachine.prototype, "error", void 0);
@@ -0,0 +1,26 @@
1
+ import { setErrorByKey } from './actions';
2
+ /**
3
+ * Creates an error state node.
4
+ *
5
+ * @param key - An error state key.
6
+ * @param metaContent - An optional meta content value.
7
+ * @param final - An optional flag which adds final with output functionality.
8
+ * @public
9
+ */
10
+ export const createErrorStateNode = (key, metaContent, final = true) => {
11
+ return {
12
+ tags: ['error', key],
13
+ meta: {
14
+ content: metaContent ? metaContent : `${key} error.`,
15
+ },
16
+ entry: [setErrorByKey(`${key}-error`)],
17
+ /**
18
+ * Provide final output to parent machines.
19
+ */
20
+ type: final ? 'final' : 'atomic',
21
+ output: ({ context }) => ({
22
+ error: context.error,
23
+ data: context.error,
24
+ }),
25
+ };
26
+ };
@@ -0,0 +1 @@
1
+ import('./index');
@@ -0,0 +1,3 @@
1
+ export * from './core';
2
+ export * from './machines';
3
+ export * from './utils';
@@ -0,0 +1,46 @@
1
+ import { StatusCodes } from 'http-status-codes';
2
+ /**
3
+ * NetworkError.
4
+ * @remarks
5
+ * Failed to reach server.
6
+ * @public
7
+ */
8
+ export class NetworkError extends Error {
9
+ constructor(url, message = 'Network Error Occurred') {
10
+ super(message);
11
+ this.url = url;
12
+ this.name = 'NetworkError';
13
+ Object.setPrototypeOf(this, NetworkError.prototype);
14
+ }
15
+ }
16
+ /**
17
+ * APIError.
18
+ * @remarks
19
+ * Bad server `Response`.
20
+ * @public
21
+ */
22
+ export class APIError extends Error {
23
+ constructor(status, data, message = 'API Error Occurred') {
24
+ super(message);
25
+ this.status = status;
26
+ this.data = data;
27
+ this.name = 'APIError';
28
+ Object.setPrototypeOf(this, APIError.prototype);
29
+ }
30
+ }
31
+ /**
32
+ * @param error - An error.
33
+ * @public
34
+ */
35
+ export const isAPIError = (error) => error instanceof APIError;
36
+ /**
37
+ * @param error - An error.
38
+ * @public
39
+ */
40
+ export const isNetworkError = (error) => error instanceof NetworkError ||
41
+ (error instanceof TypeError && error.message === 'Failed to fetch');
42
+ /**
43
+ * @param error - An error.
44
+ * @public
45
+ */
46
+ export const isNotFoundError = (error) => isAPIError(error) && error.status === StatusCodes.NOT_FOUND;
@@ -0,0 +1,4 @@
1
+ export * from './errors';
2
+ export * from './policies';
3
+ export * from './types';
4
+ export * from './machine';
@@ -0,0 +1,216 @@
1
+ import { __awaiter, __decorate, __param } from "tslib";
2
+ import { DI, optional } from '@microsoft/fast-foundation';
3
+ import { assign, createMachine, fromPromise } from 'xstate';
4
+ import { AbstractMachine, createErrorStateNode, isAbortError, isDoneInvokeEvent, isErrorEvent, isSyntaxError, isTypeError, setError, } from '../../core';
5
+ import { logger } from '../../utils';
6
+ import { APIError, isAPIError, isNetworkError, isNotFoundError, NetworkError } from './errors';
7
+ import { defaultFetchConfig, defaultFetchMachineContext } from './types';
8
+ /**
9
+ * FetchConfig DI key.
10
+ * @internal
11
+ */
12
+ export const FetchConfig = DI.createInterface();
13
+ /**
14
+ * Default FetchMachine.
15
+ * @public
16
+ */
17
+ let DefaultFetchMachine = class DefaultFetchMachine extends AbstractMachine {
18
+ constructor(config = defaultFetchConfig) {
19
+ super();
20
+ this.config = config;
21
+ this.machine = createMachine({
22
+ id: 'fetchMachine',
23
+ context: ({ input }) => (Object.assign({}, input)),
24
+ initial: 'idle',
25
+ states: {
26
+ idle: {
27
+ tags: ['idle'],
28
+ meta: {
29
+ content: 'Idle.',
30
+ },
31
+ },
32
+ pending: {
33
+ tags: ['pending'],
34
+ meta: {
35
+ content: 'Fetching, please wait.',
36
+ },
37
+ invoke: {
38
+ src: 'fetch',
39
+ input: ({ context }) => (Object.assign(Object.assign({}, context.params), { controller: context.controller })),
40
+ onDone: 'success',
41
+ onError: [
42
+ {
43
+ guard: 'isNetworkError',
44
+ target: 'error.network',
45
+ },
46
+ {
47
+ guard: 'isNotFoundError',
48
+ target: 'error.notFound',
49
+ },
50
+ {
51
+ guard: 'isAPIError',
52
+ target: 'error.api',
53
+ },
54
+ {
55
+ guard: 'isAbortError',
56
+ target: 'error.abort',
57
+ },
58
+ {
59
+ guard: 'isSyntaxError',
60
+ target: 'error.syntax',
61
+ },
62
+ {
63
+ target: 'error.unknown',
64
+ },
65
+ ],
66
+ },
67
+ },
68
+ success: {
69
+ tags: ['success'],
70
+ meta: {
71
+ content: 'Success.',
72
+ },
73
+ entry: ['setResponse', 'setData', 'successCallback'],
74
+ /**
75
+ * Provide final output to parent machines.
76
+ */
77
+ type: 'final',
78
+ output: ({ context }) => ({
79
+ response: context.response,
80
+ data: context.data,
81
+ }),
82
+ },
83
+ error: {
84
+ tags: ['error'],
85
+ initial: 'unknown',
86
+ entry: ['setError', 'errorCallback'],
87
+ states: {
88
+ unknown: createErrorStateNode('unknown', 'Unknown error.'),
89
+ network: createErrorStateNode('network', 'Network error.'),
90
+ notFound: createErrorStateNode('notFound', 'Not found error.'),
91
+ api: createErrorStateNode('api', 'API error.'),
92
+ abort: createErrorStateNode('abort', 'Abort error.'),
93
+ syntax: createErrorStateNode('syntax', 'Syntax error.'),
94
+ },
95
+ },
96
+ },
97
+ on: {
98
+ fetch: {
99
+ actions: ['abortInFlight', 'resetContext', 'setParams'],
100
+ target: '#fetchMachine.pending',
101
+ },
102
+ cancel: {
103
+ actions: ['abortInFlight', 'resetContext'],
104
+ target: '#fetchMachine.idle',
105
+ },
106
+ },
107
+ }, {
108
+ actors: {
109
+ fetch: fromPromise(({ input }) => __awaiter(this, void 0, void 0, function* () {
110
+ var _a, _b, _c, _d, _e;
111
+ const { controller, fetchConfig, requestInit, url } = input;
112
+ const fetcher = (_b = (_a = fetchConfig === null || fetchConfig === void 0 ? void 0 : fetchConfig.fetcher) !== null && _a !== void 0 ? _a : this.config.fetcher) !== null && _b !== void 0 ? _b : fetch;
113
+ const fetchPolicy = (_c = fetchConfig === null || fetchConfig === void 0 ? void 0 : fetchConfig.fetchPolicy) !== null && _c !== void 0 ? _c : this.config.fetchPolicy;
114
+ const init = requestInit !== null && requestInit !== void 0 ? requestInit : { method: 'GET' };
115
+ const okChecker = (_d = fetchConfig === null || fetchConfig === void 0 ? void 0 : fetchConfig.responseOkChecker) !== null && _d !== void 0 ? _d : this.config.responseOkChecker;
116
+ const dataExtractor = (_e = fetchConfig === null || fetchConfig === void 0 ? void 0 : fetchConfig.responseDataExtractor) !== null && _e !== void 0 ? _e : this.config.responseDataExtractor;
117
+ return fetchPolicy.execute(() => __awaiter(this, void 0, void 0, function* () {
118
+ try {
119
+ const response = yield fetcher(url, Object.assign(Object.assign({}, init), { signal: controller.signal }));
120
+ const data = yield dataExtractor(response);
121
+ if (!okChecker(response)) {
122
+ throw new APIError(response.status, data);
123
+ }
124
+ return [data, response];
125
+ }
126
+ catch (error) {
127
+ if (isNetworkError(error)) {
128
+ throw new NetworkError(url);
129
+ }
130
+ throw error; // < API, Syntax / JS Error
131
+ }
132
+ }));
133
+ })),
134
+ },
135
+ actions: {
136
+ setParams: assign(({ event }) => {
137
+ if (event.type === 'fetch') {
138
+ return {
139
+ params: event.params,
140
+ controller: new AbortController(),
141
+ };
142
+ }
143
+ }),
144
+ setResponse: assign(({ event }) => {
145
+ if (isDoneInvokeEvent(event)) {
146
+ const [_, response] = event.output;
147
+ return {
148
+ response,
149
+ };
150
+ }
151
+ }),
152
+ setData: assign(({ event }) => {
153
+ if (isDoneInvokeEvent(event)) {
154
+ const [data] = event.output;
155
+ return {
156
+ data,
157
+ };
158
+ }
159
+ }),
160
+ setError,
161
+ abortInFlight: ({ context }) => {
162
+ if (context.controller) {
163
+ context.controller.abort();
164
+ }
165
+ },
166
+ resetContext: assign(() => this.startingContext),
167
+ /**
168
+ * successCallback.
169
+ * @remarks
170
+ * Can be overridden by the caller. Alternatively callers can observe context or successful output.
171
+ * @public
172
+ */
173
+ successCallback: () => {
174
+ logger.debug('FetchMachine.successCallback invoked.');
175
+ },
176
+ /**
177
+ * errorCallback.
178
+ * @remarks
179
+ * Can be overridden by the caller. Alternatively callers can observe context or successful output.
180
+ * @public
181
+ */
182
+ errorCallback: () => {
183
+ logger.debug('FetchMachine.errorCallback invoked.');
184
+ },
185
+ },
186
+ guards: {
187
+ isNetworkError: ({ event }) => (isErrorEvent(event) ? isNetworkError(event.data) : false),
188
+ isAPIError: ({ event }) => (isErrorEvent(event) ? isAPIError(event.data) : false),
189
+ isNotFoundError: ({ event }) => isErrorEvent(event) ? isNotFoundError(event.data) : false,
190
+ isAbortError,
191
+ isSyntaxError,
192
+ isTypeError,
193
+ },
194
+ });
195
+ this.start();
196
+ }
197
+ /** {@inheritDoc Machine.start} */
198
+ start(options = {
199
+ input: defaultFetchMachineContext,
200
+ }) {
201
+ super.start(options);
202
+ }
203
+ /** {@inheritDoc Machine.getFromContainer} */
204
+ getFromContainer() {
205
+ return this.container.get(FetchMachine);
206
+ }
207
+ };
208
+ DefaultFetchMachine = __decorate([
209
+ __param(0, optional(FetchConfig))
210
+ ], DefaultFetchMachine);
211
+ export { DefaultFetchMachine };
212
+ /**
213
+ * FetchMachine DI key.
214
+ * @internal
215
+ */
216
+ export const FetchMachine = DI.createInterface((x) => x.transient(DefaultFetchMachine));
@@ -0,0 +1,48 @@
1
+ import { ExponentialBackoff, TimeoutStrategy, handleType, retry, timeout, wrap } from 'cockatiel';
2
+ import { StatusCodes } from 'http-status-codes';
3
+ import { logger } from '../../utils';
4
+ import { APIError, NetworkError } from './errors';
5
+ /**
6
+ * Default retry stats codes.
7
+ * @public
8
+ */
9
+ export const defaultRetryStatsCodes = [
10
+ StatusCodes.REQUEST_TIMEOUT,
11
+ StatusCodes.TOO_MANY_REQUESTS,
12
+ StatusCodes.INTERNAL_SERVER_ERROR,
13
+ StatusCodes.BAD_GATEWAY,
14
+ StatusCodes.SERVICE_UNAVAILABLE,
15
+ StatusCodes.GATEWAY_TIMEOUT,
16
+ ];
17
+ /**
18
+ * A fetch policy factory.
19
+ * @remarks
20
+ * Will retry network errors and responses with certain status codes up to the specified max attempts.
21
+ * @param maxAttempts - Max attempts. Defaults to `2`.
22
+ * @param retryCodes - Status code array to retry. Defaults to {@link defaultRetryStatsCodes}.
23
+ * @param backoff - Backoff algo. Defaults to {@link cockatiel#ExponentialBackoff}.
24
+ * @param timeoutDuration - Timeout duration. Defaults to 3 seconds.
25
+ * @param logEvents - Log events to the console. Defaults to `true`.
26
+ * @public
27
+ */
28
+ export const createFetchPolicy = (maxAttempts = 2, retryCodes = defaultRetryStatsCodes, backoff = new ExponentialBackoff(), timeoutDuration = 3000, logEvents = true) => {
29
+ const retryPolicy = retry(handleType(NetworkError).orType(APIError, (error) => retryCodes.includes(error.status)), {
30
+ maxAttempts,
31
+ backoff,
32
+ });
33
+ const timeoutPolicy = timeout(timeoutDuration, TimeoutStrategy.Aggressive);
34
+ const policy = wrap(retryPolicy, timeoutPolicy);
35
+ if (logEvents) {
36
+ retryPolicy.onRetry((data) => logger.info('Fetch retrying...', data));
37
+ retryPolicy.onFailure((data) => logger.info('Fetch failed:', data));
38
+ retryPolicy.onSuccess((data) => logger.info('Fetch success:', data));
39
+ retryPolicy.onGiveUp((data) => logger.info('Fetch gave up:', data));
40
+ timeoutPolicy.onTimeout(() => logger.info('Fetch timed out'));
41
+ }
42
+ return policy;
43
+ };
44
+ /**
45
+ * The default fetch policy.
46
+ * @public
47
+ */
48
+ export const defaultFetchPolicy = createFetchPolicy();
@@ -0,0 +1,48 @@
1
+ import { __awaiter } from "tslib";
2
+ import { JSONReviver } from '@genesislcap/foundation-utils';
3
+ import { defaultFetchPolicy } from './policies';
4
+ /**
5
+ * {@inheritDoc ResponseOkChecker}
6
+ * @public
7
+ */
8
+ export const defaultResponseOkChecker = (response) => response.ok;
9
+ /**
10
+ * {@inheritDoc ResponseDataExtractor}
11
+ * @public
12
+ */
13
+ export const defaultResponseDataExtractor = (response) => __awaiter(void 0, void 0, void 0, function* () {
14
+ const text = yield response.text();
15
+ const contentType = response.headers.get('content-type');
16
+ const expectingJson = contentType === null || contentType === void 0 ? void 0 : contentType.includes('application/json');
17
+ return expectingJson ? JSON.parse(text, JSONReviver) : text;
18
+ });
19
+ /**
20
+ * Creates an extractor that applies a deserializer to the extracted response data.
21
+ * @param deserializer - The deserializer to apply.
22
+ * @param extractor - An optional data extractor. Defaults to {@link defaultResponseDataExtractor}.
23
+ * @public
24
+ */
25
+ export const createResponseDataExtractorWithDeserializer = (deserializer, extractor = defaultResponseDataExtractor) => (response) => __awaiter(void 0, void 0, void 0, function* () {
26
+ const json = yield extractor(response);
27
+ return deserializer(json);
28
+ });
29
+ /**
30
+ * The default fetch config.
31
+ * @public
32
+ */
33
+ export const defaultFetchConfig = {
34
+ fetcher: fetch,
35
+ fetchPolicy: defaultFetchPolicy,
36
+ responseOkChecker: defaultResponseOkChecker,
37
+ responseDataExtractor: defaultResponseDataExtractor,
38
+ };
39
+ /**
40
+ * Default FetchMachineContext.
41
+ * @public
42
+ */
43
+ export const defaultFetchMachineContext = {
44
+ params: undefined,
45
+ controller: undefined,
46
+ response: undefined,
47
+ data: undefined,
48
+ };
@@ -0,0 +1 @@
1
+ export * from './fetch';
@@ -0,0 +1 @@
1
+ export * from './logger';
@@ -0,0 +1,5 @@
1
+ import { createLogger } from '@genesislcap/foundation-utils';
2
+ /**
3
+ * @public
4
+ */
5
+ export const logger = createLogger('foundation-state-machine');