supastash 0.1.22 → 0.1.24
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.
|
@@ -5,7 +5,7 @@ export declare function assignInsertIds<R>(payload: R | R[] | null): R | R[] | n
|
|
|
5
5
|
export declare function getCommonError<U extends boolean, T extends CrudMethods, R, Z>(table: string, method: CrudMethods, localResult: MethodReturnTypeMap<U, Z>[T] | null, remoteResult: SupabaseQueryReturn<U, Z> | null): (Error & {
|
|
6
6
|
supabaseError?: PostgrestError;
|
|
7
7
|
}) | null;
|
|
8
|
-
export declare function
|
|
8
|
+
export declare function queueRemoteCall<T extends CrudMethods, U extends boolean, R>(state: SupastashQuery<T, U, R>): Promise<boolean>;
|
|
9
9
|
export declare function runSyncStrategy<T extends CrudMethods, U extends boolean, R, Z>(state: SupastashQuery<T, U, R>): Promise<{
|
|
10
10
|
localResult: MethodReturnTypeMap<U, Z>[T] | null;
|
|
11
11
|
remoteResult: SupabaseQueryReturn<U, Z> | null;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mainQueryHelpers.d.ts","sourceRoot":"","sources":["../../../../src/utils/query/helpers/mainQueryHelpers.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,
|
|
1
|
+
{"version":3,"file":"mainQueryHelpers.d.ts","sourceRoot":"","sources":["../../../../src/utils/query/helpers/mainQueryHelpers.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAEL,WAAW,EACX,mBAAmB,EACnB,mBAAmB,EACnB,cAAc,EACf,MAAM,4BAA4B,CAAC;AAOpC,wBAAgB,8BAA8B,CAC5C,MAAM,EAAE,WAAW,EACnB,QAAQ,EAAE,OAAO,EACjB,OAAO,EAAE,OAAO,EAChB,KAAK,EAAE,MAAM,GACZ,IAAI,CAUN;AAED,wBAAgB,eAAe,CAAC,CAAC,EAC/B,OAAO,EAAE,CAAC,GAAG,CAAC,EAAE,GAAG,IAAI,GACtB,CAAC,GAAG,CAAC,EAAE,GAAG,IAAI,GAAG,SAAS,CAc5B;AAED,wBAAgB,cAAc,CAAC,CAAC,SAAS,OAAO,EAAE,CAAC,SAAS,WAAW,EAAE,CAAC,EAAE,CAAC,EAC3E,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,WAAW,EACnB,WAAW,EAAE,mBAAmB,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI,EAChD,YAAY,EAAE,mBAAmB,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,IAAI,GAC7C,CAAC,KAAK,GAAG;IAAE,aAAa,CAAC,EAAE,cAAc,CAAA;CAAE,CAAC,GAAG,IAAI,CAwBrD;AAyBD,wBAAgB,eAAe,CAAC,CAAC,SAAS,WAAW,EAAE,CAAC,SAAS,OAAO,EAAE,CAAC,EACzE,KAAK,EAAE,cAAc,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,GAC7B,OAAO,CAAC,OAAO,CAAC,CAYlB;AA+ED,wBAAsB,eAAe,CACnC,CAAC,SAAS,WAAW,EACrB,CAAC,SAAS,OAAO,EACjB,CAAC,EACD,CAAC,EAED,KAAK,EAAE,cAAc,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,GAC7B,OAAO,CAAC;IACT,WAAW,EAAE,mBAAmB,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC;IACjD,YAAY,EAAE,mBAAmB,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,IAAI,CAAC;CAChD,CAAC,CA2CD"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { isOnline } from "../../../utils/connection";
|
|
2
|
-
import { log,
|
|
2
|
+
import { log, logWarn } from "../../../utils/logs";
|
|
3
3
|
import { generateUUIDv4 } from "../../genUUID";
|
|
4
4
|
import { queryLocalDb } from "../localDbQuery";
|
|
5
5
|
import { querySupabase } from "../remoteQuery/supabaseQuery";
|
|
@@ -46,42 +46,60 @@ export function getCommonError(table, method, localResult, remoteResult) {
|
|
|
46
46
|
}
|
|
47
47
|
return null;
|
|
48
48
|
}
|
|
49
|
-
|
|
49
|
+
let batchQueue = [];
|
|
50
|
+
let isProcessing = false;
|
|
51
|
+
let batchTimer = null;
|
|
52
|
+
const BATCH_DELAY = 10;
|
|
50
53
|
const retryCount = new Map();
|
|
51
54
|
const calledOfflineRetries = new Map();
|
|
52
|
-
const
|
|
53
|
-
|
|
54
|
-
const
|
|
55
|
-
const MAX_OFFLINE_RETRIES = 10;
|
|
56
|
-
const getOpKey = (state) => `${state.method}:${state.table}:${state.id}`;
|
|
55
|
+
const successfulCalls = new Set();
|
|
56
|
+
const MAX_RETRIES = 3;
|
|
57
|
+
const MAX_OFFLINE_RETRIES = 5;
|
|
57
58
|
function delay(ms) {
|
|
58
|
-
return new Promise((
|
|
59
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
60
|
+
}
|
|
61
|
+
function generateOpKey(state) {
|
|
62
|
+
return `${state.table}_${state.method}_${state.id}_${JSON.stringify(state.payload)}`;
|
|
63
|
+
}
|
|
64
|
+
export function queueRemoteCall(state) {
|
|
65
|
+
return new Promise((resolve, reject) => {
|
|
66
|
+
const opKey = generateOpKey(state);
|
|
67
|
+
if (successfulCalls.has(opKey)) {
|
|
68
|
+
resolve(true);
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
batchQueue.push({ state, opKey, resolve, reject });
|
|
72
|
+
scheduleBatch();
|
|
73
|
+
});
|
|
59
74
|
}
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
if (stateCache.has(opKey))
|
|
75
|
+
function scheduleBatch() {
|
|
76
|
+
if (batchTimer)
|
|
63
77
|
return;
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
78
|
+
batchTimer = setTimeout(() => {
|
|
79
|
+
processBatch();
|
|
80
|
+
batchTimer = null;
|
|
81
|
+
}, BATCH_DELAY);
|
|
67
82
|
}
|
|
68
|
-
async function
|
|
69
|
-
if (isProcessing)
|
|
83
|
+
async function processBatch() {
|
|
84
|
+
if (isProcessing || batchQueue.length === 0)
|
|
70
85
|
return;
|
|
71
86
|
isProcessing = true;
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
87
|
+
const batch = [...batchQueue];
|
|
88
|
+
batchQueue = [];
|
|
89
|
+
for (const call of batch) {
|
|
90
|
+
const { state, opKey, resolve, reject } = call;
|
|
91
|
+
if (successfulCalls.has(opKey)) {
|
|
92
|
+
resolve(true);
|
|
76
93
|
continue;
|
|
77
|
-
|
|
94
|
+
}
|
|
78
95
|
try {
|
|
79
96
|
while ((retryCount.get(opKey) ?? 0) <= MAX_RETRIES) {
|
|
80
97
|
const isConnected = await isOnline();
|
|
81
98
|
if (!isConnected) {
|
|
82
99
|
const offlineRetries = (calledOfflineRetries.get(opKey) || 0) + 1;
|
|
83
100
|
if (offlineRetries > MAX_OFFLINE_RETRIES) {
|
|
84
|
-
|
|
101
|
+
logWarn(`[Supastash] Gave up on ${opKey} after ${MAX_OFFLINE_RETRIES} offline retries`);
|
|
102
|
+
reject(new Error(`Offline retry limit exceeded for ${opKey}`));
|
|
85
103
|
break;
|
|
86
104
|
}
|
|
87
105
|
calledOfflineRetries.set(opKey, offlineRetries);
|
|
@@ -91,21 +109,26 @@ async function processQueue() {
|
|
|
91
109
|
calledOfflineRetries.delete(opKey);
|
|
92
110
|
const { error } = await querySupabase({ ...state }, true);
|
|
93
111
|
if (!error) {
|
|
112
|
+
successfulCalls.add(opKey);
|
|
113
|
+
retryCount.delete(opKey);
|
|
94
114
|
log(`[Supastash] Synced item on ${state.table} with ${state.method} to supabase`);
|
|
115
|
+
resolve(true);
|
|
95
116
|
break;
|
|
96
117
|
}
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
118
|
+
else {
|
|
119
|
+
const currentRetries = retryCount.get(opKey) ?? 0;
|
|
120
|
+
retryCount.set(opKey, currentRetries + 1);
|
|
121
|
+
if (currentRetries >= MAX_RETRIES) {
|
|
122
|
+
logWarn(`[Supastash] Gave up on ${opKey} after ${MAX_RETRIES} retries`);
|
|
123
|
+
reject(new Error(`Max retries exceeded for ${opKey}`));
|
|
124
|
+
break;
|
|
125
|
+
}
|
|
126
|
+
await delay(1000 * (currentRetries + 1));
|
|
127
|
+
}
|
|
101
128
|
}
|
|
102
129
|
}
|
|
103
130
|
catch (error) {
|
|
104
|
-
|
|
105
|
-
}
|
|
106
|
-
finally {
|
|
107
|
-
retryCount.delete(opKey);
|
|
108
|
-
stateCache.delete(opKey);
|
|
131
|
+
reject(error);
|
|
109
132
|
}
|
|
110
133
|
}
|
|
111
134
|
isProcessing = false;
|
|
@@ -138,7 +161,7 @@ export async function runSyncStrategy(state) {
|
|
|
138
161
|
remoteResult = await querySupabase(state);
|
|
139
162
|
}
|
|
140
163
|
else {
|
|
141
|
-
|
|
164
|
+
queueRemoteCall(state);
|
|
142
165
|
}
|
|
143
166
|
break;
|
|
144
167
|
case "remoteFirst":
|