@aws-amplify/datastore 3.10.1-unstable.7 → 3.11.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/CHANGELOG.md +18 -0
- package/dist/aws-amplify-datastore.js +350 -109
- package/dist/aws-amplify-datastore.js.map +1 -1
- package/dist/aws-amplify-datastore.min.js +6 -6
- package/dist/aws-amplify-datastore.min.js.map +1 -1
- package/lib/datastore/datastore.js.map +1 -1
- package/lib/sync/index.js +3 -3
- package/lib/sync/index.js.map +1 -1
- package/lib/sync/processors/mutation.d.ts +2 -2
- package/lib/sync/processors/mutation.js +12 -5
- package/lib/sync/processors/mutation.js.map +1 -1
- package/lib/sync/processors/subscription.d.ts +3 -2
- package/lib/sync/processors/subscription.js +73 -32
- package/lib/sync/processors/subscription.js.map +1 -1
- package/lib/sync/processors/sync.d.ts +5 -2
- package/lib/sync/processors/sync.js +61 -26
- package/lib/sync/processors/sync.js.map +1 -1
- package/lib/sync/utils.d.ts +11 -1
- package/lib/sync/utils.js +59 -0
- package/lib/sync/utils.js.map +1 -1
- package/lib/types.d.ts +18 -8
- package/lib/types.js +6 -0
- package/lib/types.js.map +1 -1
- package/lib-esm/datastore/datastore.js.map +1 -1
- package/lib-esm/sync/index.js +3 -3
- package/lib-esm/sync/index.js.map +1 -1
- package/lib-esm/sync/processors/mutation.d.ts +2 -2
- package/lib-esm/sync/processors/mutation.js +14 -7
- package/lib-esm/sync/processors/mutation.js.map +1 -1
- package/lib-esm/sync/processors/subscription.d.ts +3 -2
- package/lib-esm/sync/processors/subscription.js +74 -33
- package/lib-esm/sync/processors/subscription.js.map +1 -1
- package/lib-esm/sync/processors/sync.d.ts +5 -2
- package/lib-esm/sync/processors/sync.js +62 -27
- package/lib-esm/sync/processors/sync.js.map +1 -1
- package/lib-esm/sync/utils.d.ts +11 -1
- package/lib-esm/sync/utils.js +58 -0
- package/lib-esm/sync/utils.js.map +1 -1
- package/lib-esm/types.d.ts +18 -8
- package/lib-esm/types.js +6 -0
- package/lib-esm/types.js.map +1 -1
- package/package.json +7 -7
- package/src/datastore/datastore.ts +2 -2
- package/src/sync/index.ts +6 -4
- package/src/sync/processors/mutation.ts +17 -8
- package/src/sync/processors/subscription.ts +39 -4
- package/src/sync/processors/sync.ts +33 -4
- package/src/sync/utils.ts +22 -0
- package/src/types.ts +25 -8
|
@@ -12,6 +12,8 @@ import {
|
|
|
12
12
|
PredicatesGroup,
|
|
13
13
|
ModelPredicate,
|
|
14
14
|
AuthModeStrategy,
|
|
15
|
+
ErrorHandler,
|
|
16
|
+
ProcessName,
|
|
15
17
|
} from '../../types';
|
|
16
18
|
import {
|
|
17
19
|
buildSubscriptionGraphQLOperation,
|
|
@@ -20,12 +22,27 @@ import {
|
|
|
20
22
|
getUserGroupsFromToken,
|
|
21
23
|
TransformerMutationType,
|
|
22
24
|
getTokenForCustomAuth,
|
|
25
|
+
mapErrorToType,
|
|
26
|
+
ErrorMap,
|
|
23
27
|
} from '../utils';
|
|
24
28
|
import { ModelPredicateCreator } from '../../predicates';
|
|
25
29
|
import { validatePredicate } from '../../util';
|
|
26
30
|
|
|
27
31
|
const logger = new Logger('DataStore');
|
|
28
32
|
|
|
33
|
+
// TODO: add additional error maps
|
|
34
|
+
const errorMap = {
|
|
35
|
+
Unauthorized: (givenError: any) => {
|
|
36
|
+
const {
|
|
37
|
+
error: { errors: [{ message = '' } = {}] } = {
|
|
38
|
+
errors: [],
|
|
39
|
+
},
|
|
40
|
+
} = givenError;
|
|
41
|
+
const regex = /Connection failed.+Unauthorized/;
|
|
42
|
+
return regex.test(message);
|
|
43
|
+
},
|
|
44
|
+
} as ErrorMap;
|
|
45
|
+
|
|
29
46
|
export enum CONTROL_MSG {
|
|
30
47
|
CONNECTED = 'CONNECTED',
|
|
31
48
|
}
|
|
@@ -56,7 +73,8 @@ class SubscriptionProcessor {
|
|
|
56
73
|
private readonly schema: InternalSchema,
|
|
57
74
|
private readonly syncPredicates: WeakMap<SchemaModel, ModelPredicate<any>>,
|
|
58
75
|
private readonly amplifyConfig: Record<string, any> = {},
|
|
59
|
-
private readonly authModeStrategy: AuthModeStrategy
|
|
76
|
+
private readonly authModeStrategy: AuthModeStrategy,
|
|
77
|
+
private readonly errorHandler: ErrorHandler
|
|
60
78
|
) {}
|
|
61
79
|
|
|
62
80
|
private buildSubscription(
|
|
@@ -436,12 +454,31 @@ class SubscriptionProcessor {
|
|
|
436
454
|
}
|
|
437
455
|
this.drainBuffer();
|
|
438
456
|
},
|
|
439
|
-
error: subscriptionError => {
|
|
457
|
+
error: async subscriptionError => {
|
|
440
458
|
const {
|
|
441
459
|
error: { errors: [{ message = '' } = {}] } = {
|
|
442
460
|
errors: [],
|
|
443
461
|
},
|
|
444
462
|
} = subscriptionError;
|
|
463
|
+
try {
|
|
464
|
+
await this.errorHandler({
|
|
465
|
+
recoverySuggestion:
|
|
466
|
+
'Ensure app code is up to date, auth directives exist and are correct on each model, and that server-side data has not been invalidated by a schema change. If the problem persists, search for or create an issue: https://github.com/aws-amplify/amplify-js/issues',
|
|
467
|
+
localModel: null,
|
|
468
|
+
message,
|
|
469
|
+
model: modelDefinition.name,
|
|
470
|
+
operation,
|
|
471
|
+
errorType: mapErrorToType(
|
|
472
|
+
errorMap,
|
|
473
|
+
subscriptionError
|
|
474
|
+
),
|
|
475
|
+
process: ProcessName.subscribe,
|
|
476
|
+
remoteModel: null,
|
|
477
|
+
cause: subscriptionError,
|
|
478
|
+
});
|
|
479
|
+
} catch (e) {
|
|
480
|
+
logger.error('Sync error handler failed with:', e);
|
|
481
|
+
}
|
|
445
482
|
|
|
446
483
|
if (
|
|
447
484
|
message.includes(
|
|
@@ -487,7 +524,6 @@ class SubscriptionProcessor {
|
|
|
487
524
|
return;
|
|
488
525
|
}
|
|
489
526
|
}
|
|
490
|
-
|
|
491
527
|
logger.warn('subscriptionError', message);
|
|
492
528
|
|
|
493
529
|
if (typeof subscriptionReadyCallback === 'function') {
|
|
@@ -500,7 +536,6 @@ class SubscriptionProcessor {
|
|
|
500
536
|
) {
|
|
501
537
|
return;
|
|
502
538
|
}
|
|
503
|
-
|
|
504
539
|
observer.error(message);
|
|
505
540
|
},
|
|
506
541
|
})
|
|
@@ -8,6 +8,8 @@ import {
|
|
|
8
8
|
PredicatesGroup,
|
|
9
9
|
GraphQLFilter,
|
|
10
10
|
AuthModeStrategy,
|
|
11
|
+
ErrorHandler,
|
|
12
|
+
ProcessName,
|
|
11
13
|
} from '../../types';
|
|
12
14
|
import {
|
|
13
15
|
buildGraphQLOperation,
|
|
@@ -16,6 +18,8 @@ import {
|
|
|
16
18
|
getForbiddenError,
|
|
17
19
|
predicateToGraphQLFilter,
|
|
18
20
|
getTokenForCustomAuth,
|
|
21
|
+
mapErrorToType,
|
|
22
|
+
ErrorMap,
|
|
19
23
|
} from '../utils';
|
|
20
24
|
import {
|
|
21
25
|
jitteredExponentialRetry,
|
|
@@ -24,7 +28,7 @@ import {
|
|
|
24
28
|
NonRetryableError,
|
|
25
29
|
} from '@aws-amplify/core';
|
|
26
30
|
import { ModelPredicateCreator } from '../../predicates';
|
|
27
|
-
|
|
31
|
+
import { ModelInstanceCreator } from '../../datastore/datastore';
|
|
28
32
|
const opResultDefaults = {
|
|
29
33
|
items: [],
|
|
30
34
|
nextToken: null,
|
|
@@ -33,6 +37,11 @@ const opResultDefaults = {
|
|
|
33
37
|
|
|
34
38
|
const logger = new Logger('DataStore');
|
|
35
39
|
|
|
40
|
+
// TODO: add additional error maps
|
|
41
|
+
const errorMap = {
|
|
42
|
+
BadRecord: error => /^Cannot return \w+ for [\w-_]+ type/.test(error.message),
|
|
43
|
+
} as ErrorMap;
|
|
44
|
+
|
|
36
45
|
class SyncProcessor {
|
|
37
46
|
private readonly typeQuery = new WeakMap<SchemaModel, [string, string]>();
|
|
38
47
|
|
|
@@ -40,7 +49,9 @@ class SyncProcessor {
|
|
|
40
49
|
private readonly schema: InternalSchema,
|
|
41
50
|
private readonly syncPredicates: WeakMap<SchemaModel, ModelPredicate<any>>,
|
|
42
51
|
private readonly amplifyConfig: Record<string, any> = {},
|
|
43
|
-
private readonly authModeStrategy: AuthModeStrategy
|
|
52
|
+
private readonly authModeStrategy: AuthModeStrategy,
|
|
53
|
+
private readonly errorHandler: ErrorHandler,
|
|
54
|
+
private readonly modelInstanceCreator?: ModelInstanceCreator
|
|
44
55
|
) {
|
|
45
56
|
this.generateQueries();
|
|
46
57
|
}
|
|
@@ -223,15 +234,33 @@ class SyncProcessor {
|
|
|
223
234
|
error.data[opName] &&
|
|
224
235
|
error.data[opName].items
|
|
225
236
|
);
|
|
226
|
-
|
|
227
237
|
if (this.partialDataFeatureFlagEnabled()) {
|
|
228
238
|
if (hasItems) {
|
|
229
239
|
const result = error;
|
|
230
240
|
result.data[opName].items = result.data[opName].items.filter(
|
|
231
241
|
item => item !== null
|
|
232
242
|
);
|
|
233
|
-
|
|
234
243
|
if (error.errors) {
|
|
244
|
+
await Promise.all(
|
|
245
|
+
error.errors.map(async err => {
|
|
246
|
+
try {
|
|
247
|
+
await this.errorHandler({
|
|
248
|
+
recoverySuggestion:
|
|
249
|
+
'Ensure app code is up to date, auth directives exist and are correct on each model, and that server-side data has not been invalidated by a schema change. If the problem persists, search for or create an issue: https://github.com/aws-amplify/amplify-js/issues',
|
|
250
|
+
localModel: null,
|
|
251
|
+
message: err.message,
|
|
252
|
+
model: modelDefinition.name,
|
|
253
|
+
operation: opName,
|
|
254
|
+
errorType: mapErrorToType(errorMap, err),
|
|
255
|
+
process: ProcessName.sync,
|
|
256
|
+
remoteModel: null,
|
|
257
|
+
cause: err,
|
|
258
|
+
});
|
|
259
|
+
} catch (e) {
|
|
260
|
+
logger.error('Sync error handler failed with:', e);
|
|
261
|
+
}
|
|
262
|
+
})
|
|
263
|
+
);
|
|
235
264
|
Hub.dispatch('datastore', {
|
|
236
265
|
event: 'syncQueriesPartialSyncError',
|
|
237
266
|
data: {
|
package/src/sync/utils.ts
CHANGED
|
@@ -26,6 +26,7 @@ import {
|
|
|
26
26
|
ModelOperation,
|
|
27
27
|
InternalSchema,
|
|
28
28
|
AuthModeStrategy,
|
|
29
|
+
ErrorType,
|
|
29
30
|
} from '../types';
|
|
30
31
|
import { exhaustiveCheck } from '../util';
|
|
31
32
|
import { MutationEvent } from './';
|
|
@@ -40,6 +41,27 @@ enum GraphQLOperationType {
|
|
|
40
41
|
GET = 'query',
|
|
41
42
|
}
|
|
42
43
|
|
|
44
|
+
export type ErrorMap = {
|
|
45
|
+
[key in ErrorType]: (error: Error) => boolean;
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Categorizes an error with a broad error type, intended to make
|
|
50
|
+
* customer error handling code simpler.
|
|
51
|
+
* @param errorMap Error names and a list of patterns that indicate them (each pattern as a regex or function)
|
|
52
|
+
* @param error The underying error to categorize.
|
|
53
|
+
*/
|
|
54
|
+
export function mapErrorToType(errorMap: ErrorMap, error: Error): ErrorType {
|
|
55
|
+
const errorTypes = [...Object.keys(errorMap)] as ErrorType[];
|
|
56
|
+
for (const errorType of errorTypes) {
|
|
57
|
+
const matcher = errorMap[errorType];
|
|
58
|
+
if (matcher(error)) {
|
|
59
|
+
return errorType;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
return 'Unknown';
|
|
63
|
+
}
|
|
64
|
+
|
|
43
65
|
export enum TransformerMutationType {
|
|
44
66
|
CREATE = 'Create',
|
|
45
67
|
UPDATE = 'Update',
|
package/src/types.ts
CHANGED
|
@@ -658,7 +658,7 @@ export type DataStoreConfig = {
|
|
|
658
658
|
DataStore?: {
|
|
659
659
|
authModeStrategyType?: AuthModeStrategyType;
|
|
660
660
|
conflictHandler?: ConflictHandler; // default : retry until client wins up to x times
|
|
661
|
-
errorHandler?: (error: SyncError) => void; // default : logger.warn
|
|
661
|
+
errorHandler?: (error: SyncError<PersistentModel>) => void; // default : logger.warn
|
|
662
662
|
maxRecordsToSync?: number; // merge
|
|
663
663
|
syncPageSize?: number;
|
|
664
664
|
fullSyncInterval?: number;
|
|
@@ -668,7 +668,7 @@ export type DataStoreConfig = {
|
|
|
668
668
|
};
|
|
669
669
|
authModeStrategyType?: AuthModeStrategyType;
|
|
670
670
|
conflictHandler?: ConflictHandler; // default : retry until client wins up to x times
|
|
671
|
-
errorHandler?: (error: SyncError) => void; // default : logger.warn
|
|
671
|
+
errorHandler?: (error: SyncError<PersistentModel>) => void; // default : logger.warn
|
|
672
672
|
maxRecordsToSync?: number; // merge
|
|
673
673
|
syncPageSize?: number;
|
|
674
674
|
fullSyncInterval?: number;
|
|
@@ -775,15 +775,32 @@ export type SyncConflict = {
|
|
|
775
775
|
attempts: number;
|
|
776
776
|
};
|
|
777
777
|
|
|
778
|
-
export type SyncError = {
|
|
778
|
+
export type SyncError<T extends PersistentModel> = {
|
|
779
779
|
message: string;
|
|
780
|
-
errorType:
|
|
781
|
-
errorInfo
|
|
782
|
-
|
|
783
|
-
|
|
780
|
+
errorType: ErrorType;
|
|
781
|
+
errorInfo?: string;
|
|
782
|
+
recoverySuggestion?: string;
|
|
783
|
+
model?: string;
|
|
784
|
+
localModel: T;
|
|
785
|
+
remoteModel: T;
|
|
786
|
+
process: ProcessName;
|
|
784
787
|
operation: string;
|
|
788
|
+
cause?: Error;
|
|
785
789
|
};
|
|
786
790
|
|
|
791
|
+
export type ErrorType =
|
|
792
|
+
| 'ConfigError'
|
|
793
|
+
| 'BadRecord'
|
|
794
|
+
| 'Unauthorized'
|
|
795
|
+
| 'Transient'
|
|
796
|
+
| 'Unknown';
|
|
797
|
+
|
|
798
|
+
export enum ProcessName {
|
|
799
|
+
'sync' = 'sync',
|
|
800
|
+
'mutate' = 'mutate',
|
|
801
|
+
'subscribe' = 'subscribe',
|
|
802
|
+
}
|
|
803
|
+
|
|
787
804
|
export const DISCARD = Symbol('DISCARD');
|
|
788
805
|
|
|
789
806
|
export type ConflictHandler = (
|
|
@@ -792,7 +809,7 @@ export type ConflictHandler = (
|
|
|
792
809
|
| Promise<PersistentModel | typeof DISCARD>
|
|
793
810
|
| PersistentModel
|
|
794
811
|
| typeof DISCARD;
|
|
795
|
-
export type ErrorHandler = (error: SyncError) => void;
|
|
812
|
+
export type ErrorHandler = (error: SyncError<PersistentModel>) => void;
|
|
796
813
|
|
|
797
814
|
export type DeferredCallbackResolverOptions = {
|
|
798
815
|
callback: () => void;
|