amplifyquery 2.0.1 → 2.0.3

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 +85 -21
  2. package/package.json +2 -1
package/dist/service.js CHANGED
@@ -73,17 +73,35 @@ function getOwnerByAuthMode(authMode) {
73
73
  if (authMode === "userPool") {
74
74
  try {
75
75
  const { username, userId } = yield (0, auth_1.getCurrentUser)();
76
- // Canonical "owner" in Amplify is typically the Cognito user sub / userId.
77
- // Some legacy codepaths used `${userId}::${username}`. We keep it as a fallback
78
- // candidate so list-by-owner can still find older records.
79
- const canonicalOwner = userId;
80
- // Avoid useless legacy candidates like `${userId}::${userId}` (can happen depending on username config).
81
- const legacyOwner = username && userId && username !== userId ? `${userId}::${username}` : "";
82
- owner = canonicalOwner;
83
- ownerCandidates = [canonicalOwner].filter(Boolean);
84
- if (legacyOwner && legacyOwner !== canonicalOwner) {
85
- ownerCandidates.push(legacyOwner);
86
- }
76
+ // IMPORTANT:
77
+ // In this workspace we standardize on the default Amplify owner claim:
78
+ // `cognito:username` (i.e. `username` from getCurrentUser()).
79
+ //
80
+ // This prevents a common bug where some records are written with `sub` (userId)
81
+ // while the owner secondary index is queried with `username`, or vice versa,
82
+ // causing refetch to "lose" most items and overwrite cache with a partial list.
83
+ const canonicalUsername = typeof username === "string" ? username : "";
84
+ const canonicalSub = typeof userId === "string" ? userId : "";
85
+ const legacyOwner = canonicalSub && canonicalUsername && canonicalUsername !== canonicalSub
86
+ ? `${canonicalSub}::${canonicalUsername}`
87
+ : "";
88
+ // Preferred owner value for create/update payloads.
89
+ owner = canonicalUsername || canonicalSub;
90
+ // Preferred owner candidates for list-by-owner queries.
91
+ // If username is available, ONLY use username-based owner to keep list results consistent.
92
+ // If username is missing for some reason, fall back to sub to avoid total failure.
93
+ const candidates = canonicalUsername
94
+ ? [canonicalUsername, legacyOwner]
95
+ : [canonicalSub];
96
+ ownerCandidates = Array.from(new Set(candidates.filter((v) => typeof v === "string" && v.length > 0)));
97
+ // Debug: surface the actual Cognito identifiers in dev logs
98
+ (0, config_1.debugLog)(`🍬 Auth identity resolved`, {
99
+ authMode,
100
+ username,
101
+ userId,
102
+ owner,
103
+ ownerCandidates,
104
+ });
87
105
  }
88
106
  catch (error) {
89
107
  console.error("Error getting user authentication info:", error);
@@ -667,7 +685,7 @@ function createAmplifyService(modelName, defaultAuthMode) {
667
685
  }
668
686
  const client = (0, client_1.getClient)();
669
687
  const model = (_b = client.models) === null || _b === void 0 ? void 0 : _b[modelName];
670
- // Execute owner query (try canonical owner first, then legacy owner formats)
688
+ // Execute owner query (try multiple owner candidates)
671
689
  const ownersToTry = Array.isArray(ownerCandidates) && ownerCandidates.length > 0
672
690
  ? ownerCandidates
673
691
  : owner
@@ -690,6 +708,21 @@ function createAmplifyService(modelName, defaultAuthMode) {
690
708
  }
691
709
  // If empty, try next candidate (legacy owner format)
692
710
  }
711
+ // If owner-query returns empty for all candidates, fall back to default list().
712
+ // This prevents "data disappears on refetch" when the project stores owner using
713
+ // a different identity claim than expected (e.g., username vs sub) OR when the
714
+ // owner secondary index exists but doesn't match stored owner values.
715
+ if (!result) {
716
+ (0, config_1.debugWarn)(`🍬 ${modelName} list: owner-query returned 0 items for all candidates, falling back to model.list()`, { ownersToTry, authMode });
717
+ const { data: fallback } = yield model.list({}, authModeParams);
718
+ const fallbackItems = ((fallback === null || fallback === void 0 ? void 0 : fallback.items) ||
719
+ (fallback === null || fallback === void 0 ? void 0 : fallback.data) ||
720
+ fallback ||
721
+ []).filter((item) => item !== null);
722
+ // Use the same shape below by setting `result` to array-ish
723
+ result = fallbackItems;
724
+ usedOwner = null;
725
+ }
693
726
  if (usedOwner && usedOwner !== ownersToTry[0]) {
694
727
  (0, config_1.debugWarn)(`🍬 ${modelName} list: owner-query returned results only for legacy owner format`, { tried: ownersToTry, usedOwner });
695
728
  }
@@ -1122,14 +1155,13 @@ function createAmplifyService(modelName, defaultAuthMode) {
1122
1155
  // Determine auth mode (use provided options if available)
1123
1156
  const authMode = (options === null || options === void 0 ? void 0 : options.authMode) || currentAuthMode;
1124
1157
  // Get owner and parameters based on auth mode
1125
- const { owner, authModeParams } = yield getOwnerByAuthMode(authMode);
1126
- // Add owner value to queries requiring owner field when userPool auth
1158
+ const { owner, ownerCandidates, authModeParams } = yield getOwnerByAuthMode(authMode);
1159
+ // Add owner value to queries requiring owner field when userPool auth.
1160
+ // IMPORTANT: many projects store owner as `cognito:username`, not `sub`.
1161
+ // If this is an owner-based index query, try multiple owner candidates to
1162
+ // avoid returning empty results and accidentally clearing UI state on refetch.
1163
+ const isOwnerQuery = authMode === "userPool" && queryName.toLowerCase().includes("owner");
1127
1164
  const enhancedArgs = Object.assign({}, args);
1128
- if (owner &&
1129
- authMode === "userPool" &&
1130
- queryName.toLowerCase().includes("owner")) {
1131
- enhancedArgs.owner = owner;
1132
- }
1133
1165
  // Detect relational query (if fields like dailyId, userId exist)
1134
1166
  const relationField = Object.keys(enhancedArgs).find((key) => key.endsWith("Id"));
1135
1167
  const isRelationalQuery = !!relationField;
@@ -1165,8 +1197,40 @@ function createAmplifyService(modelName, defaultAuthMode) {
1165
1197
  if (!((_a = (0, client_1.getClient)().models[modelName]) === null || _a === void 0 ? void 0 : _a[queryName])) {
1166
1198
  throw new Error(`🍬 Query ${queryName} does not exist.`);
1167
1199
  }
1168
- // Execute index query - apply auth mode
1169
- const { data: result } = yield (0, client_1.getClient)().models[modelName][queryName](enhancedArgs, authModeParams);
1200
+ const model = (0, client_1.getClient)().models[modelName];
1201
+ // Execute index query - apply auth mode (with owner-candidate fallback)
1202
+ let result = null;
1203
+ if (isOwnerQuery) {
1204
+ const candidates = [
1205
+ // If caller explicitly passed owner, try that first
1206
+ typeof (args === null || args === void 0 ? void 0 : args.owner) === "string" ? args.owner : "",
1207
+ ...(Array.isArray(ownerCandidates) ? ownerCandidates : []),
1208
+ typeof owner === "string" ? owner : "",
1209
+ ].filter((v) => typeof v === "string" && v.length > 0);
1210
+ const ownersToTry = Array.from(new Set(candidates));
1211
+ if (ownersToTry.length === 0) {
1212
+ throw new Error(`🍬 owner is missing for ${modelName}.${queryName}`);
1213
+ }
1214
+ for (const candidateOwner of ownersToTry) {
1215
+ const nextArgs = Object.assign(Object.assign({}, enhancedArgs), { owner: candidateOwner });
1216
+ const { data } = yield model[queryName](nextArgs, authModeParams);
1217
+ 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);
1218
+ if (items.length > 0) {
1219
+ result = data;
1220
+ if (candidateOwner !== ownersToTry[0]) {
1221
+ (0, config_1.debugWarn)(`🍬 ${modelName} ${queryName}: returned results only for non-primary owner candidate`, { tried: ownersToTry, usedOwner: candidateOwner });
1222
+ }
1223
+ break;
1224
+ }
1225
+ }
1226
+ // If still empty, return empty list (do not throw unless requested)
1227
+ if (!result) {
1228
+ result = [];
1229
+ }
1230
+ }
1231
+ else {
1232
+ ({ data: result } = yield model[queryName](enhancedArgs, authModeParams));
1233
+ }
1170
1234
  // Extract result data
1171
1235
  const items = (result === null || result === void 0 ? void 0 : result.items) || (result === null || result === void 0 ? void 0 : result.data) || result || [];
1172
1236
  (0, config_1.debugLog)(`🍬 ${modelName} ${queryName} result:`, items.length, "items");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "amplifyquery",
3
- "version": "2.0.1",
3
+ "version": "2.0.3",
4
4
  "description": "Amplify+Query",
5
5
  "keywords": [
6
6
  "Amplify",
@@ -29,6 +29,7 @@
29
29
  "dev": "expo-module build --watch",
30
30
  "lint": "expo-module lint",
31
31
  "typecheck": "expo-module typecheck",
32
+ "codegen:service": "node ./codegen/generateAmplifyService.js",
32
33
  "prepare": "expo-module prepare",
33
34
  "prepublishOnly": "expo-module prepublishOnly",
34
35
  "test": "expo-module test"