amplifyquery 2.0.2 → 2.0.4

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 (2) hide show
  1. package/dist/service.js +40 -200
  2. package/package.json +1 -1
package/dist/service.js CHANGED
@@ -68,30 +68,14 @@ function areItemArraysEquivalentById(a, b) {
68
68
  function getOwnerByAuthMode(authMode) {
69
69
  return __awaiter(this, void 0, void 0, function* () {
70
70
  let owner = "";
71
- let ownerCandidates = [];
72
71
  // Set owner value only in userPool auth mode
73
72
  if (authMode === "userPool") {
74
73
  try {
75
74
  const { username, userId } = yield (0, auth_1.getCurrentUser)();
76
- // IMPORTANT:
77
- // Amplify "owner" authorization commonly uses `cognito:username` by default,
78
- // but some projects store `sub` (userId) instead. To avoid "refetch clears list"
79
- // issues when using list-by-owner secondary indexes, we try multiple candidates.
80
- //
81
- // Candidates priority (unique, non-empty):
82
- // - userId (sub)
83
- // - username (cognito:username)
84
- // - legacy `${userId}::${username}` (older patterns)
85
- const canonicalSub = typeof userId === "string" ? userId : "";
86
- const canonicalUsername = typeof username === "string" ? username : "";
87
- const legacyOwner = canonicalSub && canonicalUsername && canonicalUsername !== canonicalSub
88
- ? `${canonicalSub}::${canonicalUsername}`
89
- : "";
90
- // Keep `owner` for compatibility (used in some create/update paths), prefer sub.
91
- owner = canonicalSub || canonicalUsername;
92
- const candidates = [canonicalSub, canonicalUsername, legacyOwner].filter((v) => typeof v === "string" && v.length > 0);
93
- // De-dupe while preserving order
94
- ownerCandidates = Array.from(new Set(candidates));
75
+ // Keep behavior consistent with old-AmplifyQuery:
76
+ // owner = `${userId}::${username}`
77
+ owner = `${userId}::${username}`;
78
+ (0, config_1.debugLog)(`🍬 Auth identity resolved`, { authMode, username, userId, owner });
95
79
  }
96
80
  catch (error) {
97
81
  console.error("Error getting user authentication info:", error);
@@ -101,7 +85,6 @@ function getOwnerByAuthMode(authMode) {
101
85
  // Return with auth mode parameters
102
86
  return {
103
87
  owner,
104
- ownerCandidates,
105
88
  authModeParams: { authMode },
106
89
  };
107
90
  });
@@ -296,8 +279,8 @@ function createAmplifyService(modelName, defaultAuthMode) {
296
279
  }
297
280
  // Determine auth mode (use provided option if available)
298
281
  const authMode = (options === null || options === void 0 ? void 0 : options.authMode) || currentAuthMode;
299
- // Get owner and parameters based on auth mode
300
- const { owner, authModeParams } = yield getOwnerByAuthMode(authMode);
282
+ // Get parameters based on auth mode
283
+ const { authModeParams } = yield getOwnerByAuthMode(authMode);
301
284
  const dataWithoutOwner = utils_1.Utils.removeOwnerField(data, "create");
302
285
  const cleanedData = {};
303
286
  Object.entries(dataWithoutOwner).forEach(([key, value]) => {
@@ -348,8 +331,11 @@ function createAmplifyService(modelName, defaultAuthMode) {
348
331
  });
349
332
  }
350
333
  }
351
- else if (queryKey.length === 1) {
352
- // Regular list query (e.g. ["User"]). Avoid internal keys like ["User","currentId"].
334
+ else if (queryKey.length < 3 && queryKey[1] !== "currentId") {
335
+ // Regular list query (old-AmplifyQuery behavior: update all short list keys)
336
+ // - [Model]
337
+ // - [Model, ...] (length 2)
338
+ // But avoid internal singleton keys like ["User","currentId"].
353
339
  const data = query_1.queryClient.getQueryData(queryKey);
354
340
  if (data) {
355
341
  previousDataMap.set(queryKey, data);
@@ -363,21 +349,7 @@ function createAmplifyService(modelName, defaultAuthMode) {
363
349
  try {
364
350
  // Attempt API call - apply auth mode
365
351
  (0, config_1.debugLog)(`🍬 ${modelName} creation attempt [Auth: ${authMode}]:`, newItem.id);
366
- // Many schemas use an owner field for auth. Prefer adding owner when available,
367
- // but retry without it if the model doesn't define it.
368
- const createPayload = owner ? Object.assign(Object.assign({}, newItem), { owner }) : newItem;
369
- let createdItem = null;
370
- try {
371
- ({ data: createdItem } = yield (0, client_1.getClient)().models[modelName].create(createPayload, authModeParams));
372
- }
373
- catch (e) {
374
- if (owner && isOwnerNotInSchemaError(e)) {
375
- ({ data: createdItem } = yield (0, client_1.getClient)().models[modelName].create(newItem, authModeParams));
376
- }
377
- else {
378
- throw e;
379
- }
380
- }
352
+ const { data: createdItem } = yield (0, client_1.getClient)().models[modelName].create(newItem, authModeParams);
381
353
  if (createdItem) {
382
354
  // Update cache on API success
383
355
  query_1.queryClient.setQueryData(singleItemQueryKey, createdItem);
@@ -426,8 +398,8 @@ function createAmplifyService(modelName, defaultAuthMode) {
426
398
  }
427
399
  // Determine auth mode (use provided option if available)
428
400
  const authMode = (options === null || options === void 0 ? void 0 : options.authMode) || currentAuthMode;
429
- // Get owner and parameters based on auth mode
430
- const { owner, authModeParams } = yield getOwnerByAuthMode(authMode);
401
+ // Get parameters based on auth mode
402
+ const { authModeParams } = yield getOwnerByAuthMode(authMode);
431
403
  const preparedItems = dataList
432
404
  .map((data) => {
433
405
  if (!data)
@@ -479,8 +451,9 @@ function createAmplifyService(modelName, defaultAuthMode) {
479
451
  return oldItems; // No change if no items match relation ID
480
452
  });
481
453
  }
482
- else if (queryKey.length === 1) {
483
- // Regular list query - add all items (e.g. ["User"]). Avoid internal keys like ["User","currentId"].
454
+ else if (queryKey.length < 3 && queryKey[1] !== "currentId") {
455
+ // Regular list query - add all items (old-AmplifyQuery behavior)
456
+ // Avoid internal singleton keys like ["User","currentId"].
484
457
  query_1.queryClient.setQueryData(queryKey, (oldData) => {
485
458
  const oldItems = Array.isArray(oldData) ? oldData : [];
486
459
  return [...oldItems, ...preparedItems];
@@ -498,20 +471,7 @@ function createAmplifyService(modelName, defaultAuthMode) {
498
471
  // Parallel API calls - apply auth mode
499
472
  const createPromises = preparedItems.map((newItem) => __awaiter(this, void 0, void 0, function* () {
500
473
  try {
501
- const createPayload = owner
502
- ? Object.assign(Object.assign({}, newItem), { owner }) : newItem;
503
- let createdItem = null;
504
- try {
505
- ({ data: createdItem } = yield (0, client_1.getClient)().models[modelName].create(createPayload, authModeParams));
506
- }
507
- catch (e) {
508
- if (owner && isOwnerNotInSchemaError(e)) {
509
- ({ data: createdItem } = yield (0, client_1.getClient)().models[modelName].create(newItem, authModeParams));
510
- }
511
- else {
512
- throw e;
513
- }
514
- }
474
+ const { data: createdItem } = yield (0, client_1.getClient)().models[modelName].create(newItem, authModeParams);
515
475
  // Update individual item cache on API success
516
476
  if (createdItem) {
517
477
  const itemId = createdItem === null || createdItem === void 0 ? void 0 : createdItem.id;
@@ -639,7 +599,7 @@ function createAmplifyService(modelName, defaultAuthMode) {
639
599
  }),
640
600
  // Batch get items
641
601
  list: (...args_1) => __awaiter(this, [...args_1], void 0, function* (options = { filter: undefined, forceRefresh: false, throwOnError: false }) {
642
- var _a, _b, _c, _d, _e, _f, _g;
602
+ var _a, _b, _c, _d;
643
603
  try {
644
604
  // Determine query key
645
605
  const queryKey = options.filter
@@ -659,63 +619,21 @@ function createAmplifyService(modelName, defaultAuthMode) {
659
619
  // Determine auth mode (use provided option if available)
660
620
  const authMode = (options === null || options === void 0 ? void 0 : options.authMode) || currentAuthMode;
661
621
  // Get owner and parameters based on auth mode
662
- const { owner, ownerCandidates, authModeParams } = yield getOwnerByAuthMode(authMode);
622
+ const { owner, authModeParams } = yield getOwnerByAuthMode(authMode);
663
623
  // Get owner-based query name from global config
664
624
  const ownerQueryName = (0, config_1.getOwnerQueryName)(modelName);
665
625
  // Try query call
666
626
  try {
667
627
  (0, config_1.debugLog)(`🍬 ${modelName} list API call`, queryKey, `by ${ownerQueryName}`, `[Auth: ${authMode}]`);
668
628
  if ((0, config_1.isDebugEnabled)()) {
669
- // Debug: Check if model and query exist
670
629
  const client = (0, client_1.getClient)();
671
630
  (0, config_1.debugLog)(`🍬 Debug - client.models exists:`, !!client.models);
672
631
  (0, config_1.debugLog)(`🍬 Debug - client.models[${modelName}] exists:`, !!client.models[modelName]);
673
632
  (0, config_1.debugLog)(`🍬 Debug - client.models[${modelName}][${ownerQueryName}] exists:`, !!((_a = client.models[modelName]) === null || _a === void 0 ? void 0 : _a[ownerQueryName]));
674
633
  (0, config_1.debugLog)(`🍬 Debug - Available methods for ${modelName}:`, Object.keys(client.models[modelName] || {}));
675
634
  }
676
- const client = (0, client_1.getClient)();
677
- const model = (_b = client.models) === null || _b === void 0 ? void 0 : _b[modelName];
678
- // Execute owner query (try multiple owner candidates)
679
- const ownersToTry = Array.isArray(ownerCandidates) && ownerCandidates.length > 0
680
- ? ownerCandidates
681
- : owner
682
- ? [owner]
683
- : [];
684
- if (!(model === null || model === void 0 ? void 0 : model[ownerQueryName]) || ownersToTry.length === 0) {
685
- throw new Error(`owner query not available or owner missing: ${modelName}.${ownerQueryName}`);
686
- }
687
- let result = null;
688
- let usedOwner = null;
689
- for (const candidateOwner of ownersToTry) {
690
- (0, config_1.debugLog)(`🍬 ${modelName} list owner-query attempt`, `[${ownerQueryName}]`, { owner: candidateOwner, authMode });
691
- // Generated secondary index query typically expects { owner } only.
692
- const { data } = yield model[ownerQueryName]({ owner: candidateOwner }, authModeParams);
693
- const items = ((data === null || data === void 0 ? void 0 : data.items) || (data === null || data === void 0 ? void 0 : data.data) || data || []).filter((item) => item !== null);
694
- if (items.length > 0) {
695
- result = data;
696
- usedOwner = candidateOwner;
697
- break;
698
- }
699
- // If empty, try next candidate (legacy owner format)
700
- }
701
- // If owner-query returns empty for all candidates, fall back to default list().
702
- // This prevents "data disappears on refetch" when the project stores owner using
703
- // a different identity claim than expected (e.g., username vs sub) OR when the
704
- // owner secondary index exists but doesn't match stored owner values.
705
- if (!result) {
706
- (0, config_1.debugWarn)(`🍬 ${modelName} list: owner-query returned 0 items for all candidates, falling back to model.list()`, { ownersToTry, authMode });
707
- const { data: fallback } = yield model.list({}, authModeParams);
708
- const fallbackItems = ((fallback === null || fallback === void 0 ? void 0 : fallback.items) ||
709
- (fallback === null || fallback === void 0 ? void 0 : fallback.data) ||
710
- fallback ||
711
- []).filter((item) => item !== null);
712
- // Use the same shape below by setting `result` to array-ish
713
- result = fallbackItems;
714
- usedOwner = null;
715
- }
716
- if (usedOwner && usedOwner !== ownersToTry[0]) {
717
- (0, config_1.debugWarn)(`🍬 ${modelName} list: owner-query returned results only for legacy owner format`, { tried: ownersToTry, usedOwner });
718
- }
635
+ // Execute owner query (old-AmplifyQuery behavior)
636
+ const { data: result } = yield (0, client_1.getClient)().models[modelName][ownerQueryName]({ owner, authMode }, authModeParams);
719
637
  // Extract result data + filter null values
720
638
  const items = ((result === null || result === void 0 ? void 0 : result.items) || (result === null || result === void 0 ? void 0 : result.data) || result || []).filter((item) => item !== null);
721
639
  // Apply filter (if client-side filtering needed)
@@ -763,11 +681,9 @@ function createAmplifyService(modelName, defaultAuthMode) {
763
681
  }
764
682
  catch (error) {
765
683
  // Check if the error is because the owner query doesn't exist
766
- if (((_c = error === null || error === void 0 ? void 0 : error.message) === null || _c === void 0 ? void 0 : _c.includes("not found")) ||
767
- ((_d = error === null || error === void 0 ? void 0 : error.message) === null || _d === void 0 ? void 0 : _d.includes("is not a function")) ||
768
- ((_e = error === null || error === void 0 ? void 0 : error.message) === null || _e === void 0 ? void 0 : _e.includes("is undefined")) ||
769
- ((_f = error === null || error === void 0 ? void 0 : error.message) === null || _f === void 0 ? void 0 : _f.includes("owner query not available")) ||
770
- ((_g = error === null || error === void 0 ? void 0 : error.message) === null || _g === void 0 ? void 0 : _g.includes("owner missing"))) {
684
+ if (((_b = error === null || error === void 0 ? void 0 : error.message) === null || _b === void 0 ? void 0 : _b.includes("not found")) ||
685
+ ((_c = error === null || error === void 0 ? void 0 : error.message) === null || _c === void 0 ? void 0 : _c.includes("is not a function")) ||
686
+ ((_d = error === null || error === void 0 ? void 0 : error.message) === null || _d === void 0 ? void 0 : _d.includes("is undefined"))) {
771
687
  console.warn(`🍬 ${ownerQueryName} query not found. Trying default list query...`);
772
688
  // Try default list query if owner query not found
773
689
  const { data: result } = yield (0, client_1.getClient)().models[modelName].list({}, authModeParams);
@@ -1145,13 +1061,14 @@ function createAmplifyService(modelName, defaultAuthMode) {
1145
1061
  // Determine auth mode (use provided options if available)
1146
1062
  const authMode = (options === null || options === void 0 ? void 0 : options.authMode) || currentAuthMode;
1147
1063
  // Get owner and parameters based on auth mode
1148
- const { owner, ownerCandidates, authModeParams } = yield getOwnerByAuthMode(authMode);
1149
- // Add owner value to queries requiring owner field when userPool auth.
1150
- // IMPORTANT: many projects store owner as `cognito:username`, not `sub`.
1151
- // If this is an owner-based index query, try multiple owner candidates to
1152
- // avoid returning empty results and accidentally clearing UI state on refetch.
1153
- const isOwnerQuery = authMode === "userPool" && queryName.toLowerCase().includes("owner");
1064
+ const { owner, authModeParams } = yield getOwnerByAuthMode(authMode);
1065
+ // Add owner value to queries requiring owner field when userPool auth
1154
1066
  const enhancedArgs = Object.assign({}, args);
1067
+ if (owner &&
1068
+ authMode === "userPool" &&
1069
+ queryName.toLowerCase().includes("owner")) {
1070
+ enhancedArgs.owner = owner;
1071
+ }
1155
1072
  // Detect relational query (if fields like dailyId, userId exist)
1156
1073
  const relationField = Object.keys(enhancedArgs).find((key) => key.endsWith("Id"));
1157
1074
  const isRelationalQuery = !!relationField;
@@ -1187,40 +1104,8 @@ function createAmplifyService(modelName, defaultAuthMode) {
1187
1104
  if (!((_a = (0, client_1.getClient)().models[modelName]) === null || _a === void 0 ? void 0 : _a[queryName])) {
1188
1105
  throw new Error(`🍬 Query ${queryName} does not exist.`);
1189
1106
  }
1190
- const model = (0, client_1.getClient)().models[modelName];
1191
- // Execute index query - apply auth mode (with owner-candidate fallback)
1192
- let result = null;
1193
- if (isOwnerQuery) {
1194
- const candidates = [
1195
- // If caller explicitly passed owner, try that first
1196
- typeof (args === null || args === void 0 ? void 0 : args.owner) === "string" ? args.owner : "",
1197
- ...(Array.isArray(ownerCandidates) ? ownerCandidates : []),
1198
- typeof owner === "string" ? owner : "",
1199
- ].filter((v) => typeof v === "string" && v.length > 0);
1200
- const ownersToTry = Array.from(new Set(candidates));
1201
- if (ownersToTry.length === 0) {
1202
- throw new Error(`🍬 owner is missing for ${modelName}.${queryName}`);
1203
- }
1204
- for (const candidateOwner of ownersToTry) {
1205
- const nextArgs = Object.assign(Object.assign({}, enhancedArgs), { owner: candidateOwner });
1206
- const { data } = yield model[queryName](nextArgs, authModeParams);
1207
- const items = ((data === null || data === void 0 ? void 0 : data.items) || (data === null || data === void 0 ? void 0 : data.data) || data || []).filter((item) => item !== null);
1208
- if (items.length > 0) {
1209
- result = data;
1210
- if (candidateOwner !== ownersToTry[0]) {
1211
- (0, config_1.debugWarn)(`🍬 ${modelName} ${queryName}: returned results only for non-primary owner candidate`, { tried: ownersToTry, usedOwner: candidateOwner });
1212
- }
1213
- break;
1214
- }
1215
- }
1216
- // If still empty, return empty list (do not throw unless requested)
1217
- if (!result) {
1218
- result = [];
1219
- }
1220
- }
1221
- else {
1222
- ({ data: result } = yield model[queryName](enhancedArgs, authModeParams));
1223
- }
1107
+ // Execute index query - apply auth mode
1108
+ const { data: result } = yield (0, client_1.getClient)().models[modelName][queryName](enhancedArgs, authModeParams);
1224
1109
  // Extract result data
1225
1110
  const items = (result === null || result === void 0 ? void 0 : result.items) || (result === null || result === void 0 ? void 0 : result.data) || result || [];
1226
1111
  (0, config_1.debugLog)(`🍬 ${modelName} ${queryName} result:`, items.length, "items");
@@ -1291,7 +1176,7 @@ function createAmplifyService(modelName, defaultAuthMode) {
1291
1176
  },
1292
1177
  // React Hook returning method - Reimplemented based on TanStack Query
1293
1178
  useHook: (options) => {
1294
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p;
1179
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o;
1295
1180
  const hookQueryClient = (0, react_query_1.useQueryClient)();
1296
1181
  // Determine query key
1297
1182
  const queryKey = (0, react_1.useMemo)(() => {
@@ -1580,57 +1465,12 @@ function createAmplifyService(modelName, defaultAuthMode) {
1580
1465
  }), [service, refetch] // refetch dependency added
1581
1466
  );
1582
1467
  const refresh = (0, react_1.useCallback)((refreshOptions) => __awaiter(this, void 0, void 0, function* () {
1583
- var _a;
1584
1468
  (0, config_1.debugLog)(`🍬 ${modelName} useHook refresh called`, queryKey);
1585
- // IMPORTANT: refresh must always fetch from server (no cache).
1586
- // We do this by calling service.list/customList with forceRefresh: true.
1587
- const currentData = hookQueryClient.getQueryData(queryKey);
1588
- (0, config_1.debugLog)(`🍬 ${modelName} useHook refresh - current data before server refresh:`, (currentData === null || currentData === void 0 ? void 0 : currentData.length) || 0, "items");
1589
- try {
1590
- // If filter is provided and different from current filter, we'd need a new query key.
1591
- // For now, we ignore refreshOptions.filter and refresh the current hook query only.
1592
- if (refreshOptions === null || refreshOptions === void 0 ? void 0 : refreshOptions.filter) {
1593
- console.warn(`🍬 ${modelName} useHook refresh: refreshOptions.filter is currently ignored (queryKey is fixed per hook instance).`);
1594
- }
1595
- let newData = [];
1596
- if (options === null || options === void 0 ? void 0 : options.customList) {
1597
- newData = yield service.customList(options.customList.queryName, options.customList.args, { forceRefresh: true, throwOnError: true });
1598
- }
1599
- else if ((_a = options === null || options === void 0 ? void 0 : options.initialFetchOptions) === null || _a === void 0 ? void 0 : _a.filter) {
1600
- newData = yield service.list({
1601
- filter: options.initialFetchOptions.filter,
1602
- forceRefresh: true,
1603
- throwOnError: true,
1604
- });
1605
- }
1606
- else {
1607
- newData = yield service.list({
1608
- forceRefresh: true,
1609
- throwOnError: true,
1610
- });
1611
- }
1612
- (0, config_1.debugLog)(`🍬 ${modelName} useHook refresh - server refresh result:`, (newData === null || newData === void 0 ? void 0 : newData.length) || 0, "items");
1613
- // Keep hook cache in sync with hook's queryKey.
1614
- hookQueryClient.setQueryData(queryKey, newData);
1615
- return newData || [];
1616
- }
1617
- catch (e) {
1618
- console.error(`🍬 ${modelName} useHook refresh error:`, e);
1619
- // On error, restore previous data if available (prevents list flashing empty)
1620
- if (currentData && currentData.length > 0) {
1621
- hookQueryClient.setQueryData(queryKey, currentData);
1622
- return currentData;
1623
- }
1624
- return [];
1625
- }
1626
- }), [
1627
- modelName,
1628
- queryKey,
1629
- hookQueryClient,
1630
- service,
1631
- options === null || options === void 0 ? void 0 : options.customList,
1632
- (_p = options === null || options === void 0 ? void 0 : options.initialFetchOptions) === null || _p === void 0 ? void 0 : _p.filter,
1633
- ]);
1469
+ // Keep behavior consistent with old-AmplifyQuery:
1470
+ // refresh == refetch() (same queryFn as initial load)
1471
+ const { data } = yield refetch({ throwOnError: true });
1472
+ return data || [];
1473
+ }), [refetch, queryKey, modelName]);
1634
1474
  const customListFn = (0, react_1.useCallback)((queryName, args, options) => __awaiter(this, void 0, void 0, function* () {
1635
1475
  try {
1636
1476
  const result = yield service.customList(queryName, args, options);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "amplifyquery",
3
- "version": "2.0.2",
3
+ "version": "2.0.4",
4
4
  "description": "Amplify+Query",
5
5
  "keywords": [
6
6
  "Amplify",