amplifyquery 1.0.20 → 1.0.21

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/dist/singleton.js CHANGED
@@ -11,11 +11,11 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
11
11
  Object.defineProperty(exports, "__esModule", { value: true });
12
12
  exports.getModelIds = void 0;
13
13
  exports.createSingletonService = createSingletonService;
14
- const client_1 = require("./client");
15
14
  const auth_1 = require("aws-amplify/auth");
16
15
  const react_query_1 = require("@tanstack/react-query");
17
16
  const config_1 = require("./config");
18
17
  const react_1 = require("react");
18
+ const config_2 = require("./config");
19
19
  /**
20
20
  * Function to create an extension service for singleton models
21
21
  * @param baseService Base service
@@ -29,93 +29,68 @@ function createSingletonService(baseService, getModelId) {
29
29
  const singletonService = Object.assign(Object.assign({}, baseService), {
30
30
  // Add singleton instance management methods
31
31
  getCurrent: (options) => __awaiter(this, void 0, void 0, function* () {
32
- var _a, _b, _c;
33
32
  try {
34
33
  const modelId = yield getModelId();
34
+ (0, config_2.debugLog)(`🍬 ${modelName} singleton.getCurrent`, {
35
+ modelId,
36
+ forceRefresh: (options === null || options === void 0 ? void 0 : options.forceRefresh) === true,
37
+ });
35
38
  return baseService.get(modelId, options);
36
39
  }
37
40
  catch (error) {
41
+ // Keep singleton reads soft-failing (null) like base get().
42
+ // (Do not call getStore here: TanStack Query service doesn't support it.)
38
43
  // console.error(`${modelName} singleton instance lookup error:`, error);
39
- // Safely call getStore
40
- try {
41
- (_c = (_b = (_a = baseService
42
- .getStore) === null || _a === void 0 ? void 0 : _a.call(baseService)) === null || _b === void 0 ? void 0 : _b.setError) === null || _c === void 0 ? void 0 : _c.call(_b, error instanceof Error ? error : new Error(String(error)));
43
- }
44
- catch (storeError) {
45
- // Ignore if getStore doesn't exist or call fails
46
- }
47
44
  return null;
48
45
  }
49
46
  }), updateCurrent: (data) => __awaiter(this, void 0, void 0, function* () {
50
- var _a, _b, _c;
51
47
  try {
52
48
  const modelId = yield getModelId();
53
49
  return baseService.update(Object.assign(Object.assign({}, data), { id: modelId }));
54
50
  }
55
51
  catch (error) {
56
52
  console.error(`${modelName} singleton instance update error:`, error);
57
- // Safely call getStore
58
- try {
59
- (_c = (_b = (_a = baseService
60
- .getStore) === null || _a === void 0 ? void 0 : _a.call(baseService)) === null || _b === void 0 ? void 0 : _b.setError) === null || _c === void 0 ? void 0 : _c.call(_b, error instanceof Error ? error : new Error(String(error)));
61
- }
62
- catch (storeError) {
63
- // Ignore if getStore doesn't exist or call fails
64
- }
65
53
  return null;
66
54
  }
67
55
  }), upsertCurrent: (data) => __awaiter(this, void 0, void 0, function* () {
68
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q;
69
56
  try {
70
57
  const modelId = yield getModelId();
71
58
  // Check the latest status by forced refresh
59
+ (0, config_2.debugLog)(`🍬 ${modelName} singleton.upsertCurrent check existing`, {
60
+ modelId,
61
+ });
72
62
  const existingItem = yield baseService.get(modelId, {
73
63
  forceRefresh: true,
74
64
  });
75
65
  if (existingItem) {
76
66
  // Update
67
+ (0, config_2.debugLog)(`🍬 ${modelName} singleton.upsertCurrent -> update`, {
68
+ modelId,
69
+ });
77
70
  return baseService.update(Object.assign(Object.assign({}, data), { id: modelId }));
78
71
  }
79
72
  else {
80
- // Create (Direct call to Amplify Client - prevents random ID generation of generic create)
73
+ // Create using baseService so authMode/owner handling stays consistent.
74
+ // (We still pass a fixed id to guarantee singleton identity.)
75
+ (0, config_2.debugWarn)(`🍬 ${modelName} singleton.upsertCurrent missing -> create`, {
76
+ modelId,
77
+ });
81
78
  const modelData = Object.assign(Object.assign({}, data), { id: modelId });
82
- // Safely call getStore
83
79
  try {
84
- (_c = (_b = (_a = baseService.getStore) === null || _a === void 0 ? void 0 : _a.call(baseService)) === null || _b === void 0 ? void 0 : _b.setLoading) === null || _c === void 0 ? void 0 : _c.call(_b, true);
85
- }
86
- catch (storeError) {
87
- // Ignore if getStore doesn't exist or call fails
88
- }
89
- try {
90
- // Call appropriate model from Amplify Models
91
- const { data: createdItem } = yield (0, client_1.getClient)().models[modelName].create(modelData);
92
- if (createdItem) {
93
- try {
94
- (_f = (_e = (_d = baseService.getStore) === null || _d === void 0 ? void 0 : _d.call(baseService)) === null || _e === void 0 ? void 0 : _e.setItem) === null || _f === void 0 ? void 0 : _f.call(_e, createdItem);
95
- }
96
- catch (storeError) {
97
- // Ignore if getStore doesn't exist or call fails
98
- }
99
- }
80
+ // Use service.create to keep cache + auth mode consistent
81
+ const createdItem = yield baseService.create(modelData, {
82
+ authMode: baseService.getAuthMode(),
83
+ });
84
+ // Ensure cache is synced to latest server state
100
85
  try {
101
- (_j = (_h = (_g = baseService.getStore) === null || _g === void 0 ? void 0 : _g.call(baseService)) === null || _h === void 0 ? void 0 : _h.setLoading) === null || _j === void 0 ? void 0 : _j.call(_h, false);
86
+ yield baseService.get(modelId, { forceRefresh: true });
102
87
  }
103
- catch (storeError) {
104
- // Ignore if getStore doesn't exist or call fails
88
+ catch (_a) {
89
+ // ignore cache sync failures
105
90
  }
106
91
  return createdItem !== null && createdItem !== void 0 ? createdItem : null;
107
92
  }
108
93
  catch (apiError) {
109
- try {
110
- (_m = (_l = (_k = baseService.getStore) === null || _k === void 0 ? void 0 : _k.call(baseService)) === null || _l === void 0 ? void 0 : _l.setLoading) === null || _m === void 0 ? void 0 : _m.call(_l, false);
111
- (_q = (_p = (_o = baseService
112
- .getStore) === null || _o === void 0 ? void 0 : _o.call(baseService)) === null || _p === void 0 ? void 0 : _p.setError) === null || _q === void 0 ? void 0 : _q.call(_p, apiError instanceof Error
113
- ? apiError
114
- : new Error(String(apiError)));
115
- }
116
- catch (storeError) {
117
- // Ignore if getStore doesn't exist or call fails
118
- }
119
94
  console.error(`${modelName} singleton instance Upsert error:`, apiError);
120
95
  throw apiError; // Propagate error upwards
121
96
  }
@@ -127,21 +102,15 @@ function createSingletonService(baseService, getModelId) {
127
102
  }
128
103
  }),
129
104
  // React hook to manage the current singleton item
130
- useCurrentHook: (options) => {
105
+ useSigletoneHook: (options) => {
131
106
  const { data: currentId, isLoading: isIdLoading, error: idError, refetch: refetchId, } = (0, react_query_1.useQuery)({
132
107
  queryKey: [modelName, "currentId"],
133
108
  queryFn: () => __awaiter(this, void 0, void 0, function* () {
134
- var _a, _b, _c;
135
109
  try {
136
110
  const id = yield getModelId();
137
111
  return id || null;
138
112
  }
139
113
  catch (error) {
140
- try {
141
- (_c = (_b = (_a = baseService
142
- .getStore) === null || _a === void 0 ? void 0 : _a.call(baseService)) === null || _b === void 0 ? void 0 : _b.setError) === null || _c === void 0 ? void 0 : _c.call(_b, error instanceof Error ? error : new Error(String(error)));
143
- }
144
- catch (_storeError) { }
145
114
  return null;
146
115
  }
147
116
  }),
@@ -149,70 +118,91 @@ function createSingletonService(baseService, getModelId) {
149
118
  refetchOnWindowFocus: false,
150
119
  });
151
120
  const idForItemHook = currentId !== null && currentId !== void 0 ? currentId : "";
152
- const core = baseService.useItemHook(idForItemHook, options);
153
- const didAutoCreateRef = (0, react_1.useRef)(false);
154
- const item = (() => {
155
- var _a;
156
- if (!currentId)
157
- return null;
158
- const raw = core.item;
159
- if (Array.isArray(raw)) {
160
- const match = raw.find((i) => (i === null || i === void 0 ? void 0 : i.id) === currentId);
161
- return match || null;
162
- }
163
- return (_a = raw) !== null && _a !== void 0 ? _a : null;
164
- })();
121
+ (0, config_2.debugLog)(`🍬 ${modelName} useSigletoneHook currentId`, {
122
+ currentId,
123
+ idForItemHook,
124
+ });
125
+ const core = baseService.useItemHook(idForItemHook, (options === null || options === void 0 ? void 0 : options.realtime) ? { realtime: options.realtime } : undefined);
126
+ const attemptedAutoCreateForIdRef = (0, react_1.useRef)(null);
127
+ const cfg = (0, config_1.getSingletonAutoCreate)();
128
+ const autoCreateEnabled = typeof (options === null || options === void 0 ? void 0 : options.autoCreate) === "boolean"
129
+ ? options.autoCreate
130
+ : cfg
131
+ ? (0, config_1.isSingletonAutoCreateEnabledForModel)(modelName)
132
+ : true;
133
+ const item = currentId ? core.item : null;
165
134
  const isLoading = isIdLoading || core.isLoading;
166
135
  const error = idError || core.error || null;
167
136
  (0, react_1.useEffect)(() => {
137
+ (0, config_2.debugLog)(`🍬 ${modelName} useSigletoneHook effect check`, {
138
+ currentId,
139
+ isLoading,
140
+ autoCreateEnabled,
141
+ attemptedFor: attemptedAutoCreateForIdRef.current,
142
+ hasError: Boolean(error),
143
+ hasItem: Boolean(item),
144
+ });
168
145
  if (!currentId)
169
146
  return;
170
147
  if (isLoading)
171
148
  return;
172
- if (!(0, config_1.isSingletonAutoCreateEnabledForModel)(modelName))
149
+ if (!autoCreateEnabled)
173
150
  return;
174
- if (didAutoCreateRef.current)
151
+ if (attemptedAutoCreateForIdRef.current === currentId)
152
+ return;
153
+ if (error)
175
154
  return;
176
155
  if (item)
177
156
  return;
178
- didAutoCreateRef.current = true;
157
+ attemptedAutoCreateForIdRef.current = currentId;
179
158
  // Best-effort: create { id } if missing.
180
159
  void (() => __awaiter(this, void 0, void 0, function* () {
181
160
  try {
161
+ (0, config_2.debugWarn)(`🍬 ${modelName} useSigletoneHook auto-create starting`, {
162
+ currentId,
163
+ });
182
164
  yield singletonService.upsertCurrent({});
183
- yield core.refresh();
165
+ yield singletonService.getCurrent({ forceRefresh: true });
166
+ (0, config_2.debugLog)(`🍬 ${modelName} useSigletoneHook auto-create done`, {
167
+ currentId,
168
+ });
184
169
  }
185
170
  catch (e) {
186
- console.warn(`🍬 ${modelName} useCurrentHook auto-create failed:`, e);
171
+ attemptedAutoCreateForIdRef.current = null; // allow retry later
172
+ (0, config_2.debugWarn)(`🍬 ${modelName} useSigletoneHook auto-create failed:`, e);
187
173
  }
188
174
  }))();
189
- }, [currentId, isLoading, item, modelName]);
175
+ }, [currentId, isLoading, item, modelName, autoCreateEnabled, error]);
190
176
  const refresh = () => __awaiter(this, void 0, void 0, function* () {
191
- if (!currentId) {
192
- const { data } = yield refetchId({ throwOnError: false });
193
- if (!data)
194
- return null;
195
- }
196
- return core.refresh();
177
+ var _a;
178
+ const latest = yield singletonService.getCurrent({ forceRefresh: true });
179
+ if (latest)
180
+ return latest;
181
+ if (!autoCreateEnabled)
182
+ return null;
183
+ // If missing, create then re-fetch to sync cache.
184
+ yield singletonService.upsertCurrent({});
185
+ return (_a = (yield singletonService.getCurrent({ forceRefresh: true }))) !== null && _a !== void 0 ? _a : null;
197
186
  });
198
187
  const update = (data) => __awaiter(this, void 0, void 0, function* () {
199
- if (!currentId) {
200
- const { data } = yield refetchId({ throwOnError: false });
201
- if (!data)
202
- return null;
203
- }
204
- return core.update(data);
188
+ var _a;
189
+ // Upsert to satisfy "create if missing" behavior.
190
+ yield singletonService.upsertCurrent(data);
191
+ return (_a = (yield singletonService.getCurrent({ forceRefresh: true }))) !== null && _a !== void 0 ? _a : null;
205
192
  });
206
193
  const remove = () => __awaiter(this, void 0, void 0, function* () {
207
- if (!currentId) {
208
- const { data } = yield refetchId({ throwOnError: false });
209
- if (!data)
210
- return false;
194
+ try {
195
+ const modelId = yield getModelId();
196
+ return baseService.delete(modelId);
197
+ }
198
+ catch (e) {
199
+ return false;
211
200
  }
212
- return core.delete();
213
201
  });
214
202
  return { item, isLoading, error, refresh, update, delete: remove };
215
- } });
203
+ },
204
+ // Backward-compatible alias
205
+ useCurrentHook: (options) => singletonService.useSigletoneHook(options) });
216
206
  return singletonService;
217
207
  }
218
208
  /**
package/dist/types.d.ts CHANGED
@@ -33,6 +33,7 @@ export type ModelHook<T> = {
33
33
  delete: (id: string) => Promise<boolean>;
34
34
  customList: (queryName: string, args: Record<string, any>, options?: {
35
35
  forceRefresh?: boolean;
36
+ throwOnError?: boolean;
36
37
  }) => Promise<T[]>;
37
38
  };
38
39
  /**
@@ -65,10 +66,12 @@ export interface AmplifyDataService<T> {
65
66
  filter?: Record<string, any>;
66
67
  forceRefresh?: boolean;
67
68
  authMode?: AuthMode;
69
+ throwOnError?: boolean;
68
70
  }) => Promise<T[]>;
69
71
  customList: (queryName: string, args: Record<string, any>, options?: {
70
72
  forceRefresh?: boolean;
71
73
  authMode?: AuthMode;
74
+ throwOnError?: boolean;
72
75
  }) => Promise<T[]>;
73
76
  update: (data: Partial<T> & {
74
77
  id: string;
@@ -118,7 +121,22 @@ export interface SingletonAmplifyService<T> extends AmplifyDataService<T> {
118
121
  }) => Promise<T | null>;
119
122
  updateCurrent: (data: Partial<T>) => Promise<T | null>;
120
123
  upsertCurrent: (data: Partial<T>) => Promise<T | null>;
124
+ useSigletoneHook: (options?: {
125
+ /**
126
+ * When true (default), if the singleton item does not exist it will be created.
127
+ * You can set false to disable auto-create for this hook call.
128
+ */
129
+ autoCreate?: boolean;
130
+ realtime?: {
131
+ enabled?: boolean;
132
+ observeOptions?: Record<string, any>;
133
+ };
134
+ }) => ItemHook<T>;
135
+ /**
136
+ * @deprecated Use useSigletoneHook() instead.
137
+ */
121
138
  useCurrentHook: (options?: {
139
+ autoCreate?: boolean;
122
140
  realtime?: {
123
141
  enabled?: boolean;
124
142
  observeOptions?: Record<string, any>;
@@ -146,6 +164,11 @@ import { QueryClientConfig } from "@tanstack/react-query";
146
164
  export interface AmplifyQueryConfig {
147
165
  client: GraphQLClient;
148
166
  defaultAuthMode?: AuthMode;
167
+ /**
168
+ * Enable AmplifyQuery internal debug logs.
169
+ * Default: false.
170
+ */
171
+ debug?: boolean;
149
172
  modelOwnerQueryMap?: Record<string, string>;
150
173
  singletonAutoCreate?: {
151
174
  enabled?: boolean;
package/dist/utils.d.ts CHANGED
@@ -33,78 +33,6 @@ export declare const Utils: {
33
33
  */
34
34
  removeOwnerField: <T extends Record<string, any>>(data: T, operation: "create" | "update" | "upsert") => Omit<T, "owner">;
35
35
  };
36
- /**
37
- * Storage related utilities
38
- */
39
- export declare const StorageService: {
40
- _types: {
41
- Item: {
42
- url: string;
43
- expiresAt: number;
44
- };
45
- CacheData: {
46
- [key: string]: {
47
- url: string;
48
- expiresAt: number;
49
- };
50
- };
51
- };
52
- _urlCache: Map<string, {
53
- url: string;
54
- expiresAt: number;
55
- }>;
56
- _CACHE_KEY: string;
57
- _initialized: boolean;
58
- /**
59
- * Initialize the memory cache.
60
- * Loads URL cache from MMKV storage.
61
- */
62
- _initCache: () => void;
63
- /**
64
- * Save cache to MMKV storage.
65
- */
66
- _saveCache: () => void;
67
- /**
68
- * Upload an image file to Storage.
69
- * @param file File to upload (Blob or File object)
70
- * @param key Path and filename to save as (auto-generated if not specified)
71
- * @returns Key of the uploaded file
72
- */
73
- uploadImage: (file: Blob | File, key?: string) => Promise<string>;
74
- /**
75
- * Get the URL of a stored file. (Auto-caching)
76
- * @param key File key
77
- * @param options Caching options (forceRefresh: ignore cache and fetch new URL)
78
- * @returns File URL
79
- */
80
- getFileUrl: (key: string, options?: {
81
- forceRefresh?: boolean;
82
- }) => Promise<string>;
83
- /**
84
- * Delete a stored file.
85
- * @param key Key of the file to delete
86
- */
87
- deleteFile: (key: string) => Promise<void>;
88
- /**
89
- * Clear the URL cache.
90
- */
91
- clearUrlCache: () => void;
92
- /**
93
- * Remove a specific key's URL cache.
94
- * @param key Key of the URL to remove
95
- */
96
- clearUrlCacheForKey: (key: string) => void;
97
- /**
98
- * Remove only expired URL caches.
99
- */
100
- clearExpiredUrlCache: () => void;
101
- /**
102
- * Download an audio file.
103
- * @param audioKey Key of the audio file to download
104
- * @returns Local file system path of the downloaded file
105
- */
106
- downloadAudioFile: (audioKey: string) => Promise<string>;
107
- };
108
36
  /**
109
37
  * Authentication related utilities
110
38
  */