supastash 0.1.4 → 0.1.6
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/README.md +78 -119
- package/dist/hooks/supastashData/addPayloadToUI.d.ts.map +1 -1
- package/dist/hooks/supastashData/addPayloadToUI.js +1 -0
- package/dist/hooks/supastashData/dataState.d.ts +3 -4
- package/dist/hooks/supastashData/dataState.d.ts.map +1 -1
- package/dist/hooks/supastashData/dataState.js +5 -4
- package/dist/hooks/supastashData/eventQueues.d.ts +1 -1
- package/dist/hooks/supastashData/eventQueues.d.ts.map +1 -1
- package/dist/hooks/supastashData/eventQueues.js +4 -6
- package/dist/hooks/supastashData/fetchCalls.d.ts +1 -2
- package/dist/hooks/supastashData/fetchCalls.d.ts.map +1 -1
- package/dist/hooks/supastashData/fetchCalls.js +3 -8
- package/dist/hooks/supastashData/index.d.ts +38 -35
- package/dist/hooks/supastashData/index.d.ts.map +1 -1
- package/dist/hooks/supastashData/index.js +51 -45
- package/dist/hooks/syncEngine/index.d.ts.map +1 -1
- package/dist/hooks/syncEngine/index.js +56 -51
- package/dist/hooks/syncEngine/pushLocal/index.js +1 -1
- package/dist/store/localCache.d.ts +7 -0
- package/dist/store/localCache.d.ts.map +1 -0
- package/dist/store/localCache.js +1 -0
- package/dist/types/query.types.d.ts +6 -1
- package/dist/types/realtimeData.types.d.ts +38 -5
- package/dist/utils/fetchData/deleteData.d.ts +1 -1
- package/dist/utils/fetchData/deleteData.d.ts.map +1 -1
- package/dist/utils/fetchData/deleteData.js +3 -4
- package/dist/utils/fetchData/fetchLocalData.d.ts +10 -3
- package/dist/utils/fetchData/fetchLocalData.d.ts.map +1 -1
- package/dist/utils/fetchData/fetchLocalData.js +79 -27
- package/dist/utils/fetchData/realTimeCall.d.ts.map +1 -1
- package/dist/utils/fetchData/realTimeCall.js +6 -10
- package/dist/utils/fetchData/receiveData.d.ts +1 -1
- package/dist/utils/fetchData/receiveData.d.ts.map +1 -1
- package/dist/utils/fetchData/receiveData.js +9 -9
- package/dist/utils/fetchData/snapShot.d.ts +4 -0
- package/dist/utils/fetchData/snapShot.d.ts.map +1 -0
- package/dist/utils/fetchData/snapShot.js +34 -0
- package/dist/utils/query/builder/crud.d.ts +17 -3
- package/dist/utils/query/builder/crud.d.ts.map +1 -1
- package/dist/utils/query/builder/crud.js +16 -3
- package/dist/utils/query/builder/index.d.ts.map +1 -1
- package/dist/utils/query/builder/index.js +1 -0
- package/dist/utils/query/builder/mainQuery.js +1 -1
- package/dist/utils/query/helpers/localDb/getLocalMethod.d.ts +1 -1
- package/dist/utils/query/helpers/localDb/getLocalMethod.d.ts.map +1 -1
- package/dist/utils/query/helpers/localDb/getLocalMethod.js +2 -2
- package/dist/utils/query/helpers/localDb/localQueryBuilder.d.ts +1 -1
- package/dist/utils/query/helpers/localDb/localQueryBuilder.d.ts.map +1 -1
- package/dist/utils/query/helpers/localDb/localQueryBuilder.js +2 -2
- package/dist/utils/query/helpers/mainQueryHelpers.d.ts.map +1 -1
- package/dist/utils/query/helpers/mainQueryHelpers.js +8 -1
- package/dist/utils/query/localDbQuery/index.d.ts.map +1 -1
- package/dist/utils/query/localDbQuery/index.js +2 -2
- package/dist/utils/query/localDbQuery/upsert.d.ts +1 -1
- package/dist/utils/query/localDbQuery/upsert.d.ts.map +1 -1
- package/dist/utils/query/localDbQuery/upsert.js +37 -18
- package/dist/utils/query/remoteQuery/supabaseQuery.d.ts +1 -0
- package/dist/utils/query/remoteQuery/supabaseQuery.d.ts.map +1 -1
- package/dist/utils/query/remoteQuery/supabaseQuery.js +52 -6
- package/dist/utils/schema/wipeTables.js +1 -1
- package/dist/utils/sync/pullFromRemote/pullData.js +8 -8
- package/dist/utils/sync/pullFromRemote/pullDeletedData.js +8 -8
- package/dist/utils/sync/pullFromRemote/updateLocalDb.d.ts.map +1 -1
- package/dist/utils/sync/pullFromRemote/updateLocalDb.js +5 -2
- package/dist/utils/sync/pushLocal/sendUnsyncedToSupabase.js +1 -1
- package/dist/utils/sync/refreshTables.d.ts +1 -0
- package/dist/utils/sync/refreshTables.d.ts.map +1 -1
- package/dist/utils/sync/refreshTables.js +2 -1
- package/package.json +5 -2
package/README.md
CHANGED
|
@@ -1,27 +1,25 @@
|
|
|
1
1
|
# Supastash
|
|
2
2
|
|
|
3
|
-
**Offline-First Sync Engine for Supabase + React Native
|
|
3
|
+
**Offline-First Sync Engine for Supabase + React Native**
|
|
4
4
|
|
|
5
|
-
>
|
|
5
|
+
> Sync local SQLite data with Supabase in real-time — even when your app is offline. Built for React Native, no boilerplate required.
|
|
6
6
|
|
|
7
|
-
Supastash
|
|
7
|
+
Supastash gives your app **instant offline access**, **two-way syncing**, and **real-time updates** — all while letting you work with local data as the source of truth.
|
|
8
8
|
|
|
9
9
|
---
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
Read the [Docs](https://0xzekea.github.io/supastash/)
|
|
11
|
+
## 📚 **[Read the Full Docs »](https://0xzekea.github.io/supastash/)**
|
|
14
12
|
|
|
15
13
|
---
|
|
16
14
|
|
|
17
|
-
##
|
|
15
|
+
## ✨ Features
|
|
18
16
|
|
|
19
|
-
- 🔁
|
|
20
|
-
- 💾
|
|
21
|
-
- ⚡
|
|
22
|
-
- 🔌
|
|
23
|
-
-
|
|
24
|
-
-
|
|
17
|
+
- 🔁 Two-way sync with Supabase
|
|
18
|
+
- 💾 Local-first querying via SQLite
|
|
19
|
+
- ⚡ Realtime updates (INSERT, UPDATE, DELETE)
|
|
20
|
+
- 🔌 Works with any SQLite adapter (`expo-sqlite`, `rn-nitro`, `sqlite-storage`)
|
|
21
|
+
- 🧠 Handles conflict resolution, batching, retries
|
|
22
|
+
- 🧩 Supports filtering, job staging, and advanced sync control
|
|
25
23
|
|
|
26
24
|
---
|
|
27
25
|
|
|
@@ -29,31 +27,34 @@ Read the [Docs](https://0xzekea.github.io/supastash/)
|
|
|
29
27
|
|
|
30
28
|
```bash
|
|
31
29
|
npm install supastash
|
|
32
|
-
# or
|
|
33
|
-
yarn add supastash
|
|
34
30
|
```
|
|
35
31
|
|
|
36
|
-
###
|
|
32
|
+
### Required Peer Dependencies
|
|
37
33
|
|
|
38
34
|
```bash
|
|
39
|
-
npm install @supabase/supabase-js
|
|
40
|
-
@react-native-community/netinfo
|
|
41
|
-
react
|
|
42
|
-
|
|
35
|
+
npm install @supabase/supabase-js \
|
|
36
|
+
@react-native-community/netinfo \
|
|
37
|
+
react react-native
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
### Choose one SQLite adapter:
|
|
43
41
|
|
|
44
|
-
|
|
42
|
+
```bash
|
|
43
|
+
# Expo
|
|
45
44
|
npm install expo-sqlite
|
|
46
|
-
|
|
45
|
+
|
|
46
|
+
# React Native Nitro (faster)
|
|
47
47
|
npm install react-native-nitro-sqlite
|
|
48
|
-
|
|
48
|
+
|
|
49
|
+
# Or classic storage
|
|
49
50
|
npm install react-native-sqlite-storage
|
|
50
51
|
```
|
|
51
52
|
|
|
52
|
-
> `sqliteClientType
|
|
53
|
+
> Match with: `"sqliteClientType": "expo"`, `"rn-nitro"`, or `"rn-storage"`
|
|
53
54
|
|
|
54
55
|
---
|
|
55
56
|
|
|
56
|
-
## ⚙️ Setup
|
|
57
|
+
## ⚙️ Quick Setup
|
|
57
58
|
|
|
58
59
|
```ts
|
|
59
60
|
// lib/supastash.ts
|
|
@@ -66,6 +67,7 @@ configureSupastash({
|
|
|
66
67
|
dbName: "supastash_db",
|
|
67
68
|
sqliteClient: { openDatabaseAsync },
|
|
68
69
|
sqliteClientType: "expo",
|
|
70
|
+
|
|
69
71
|
onSchemaInit: () => {
|
|
70
72
|
defineLocalSchema(
|
|
71
73
|
"users",
|
|
@@ -73,60 +75,48 @@ configureSupastash({
|
|
|
73
75
|
id: "TEXT PRIMARY KEY",
|
|
74
76
|
name: "TEXT",
|
|
75
77
|
email: "TEXT",
|
|
76
|
-
created_at: "TIMESTAMP
|
|
77
|
-
updated_at: "TIMESTAMP
|
|
78
|
+
created_at: "TIMESTAMP",
|
|
79
|
+
updated_at: "TIMESTAMP",
|
|
78
80
|
},
|
|
79
81
|
true
|
|
80
82
|
);
|
|
81
83
|
},
|
|
84
|
+
|
|
82
85
|
debugMode: true,
|
|
83
86
|
syncEngine: {
|
|
84
87
|
push: true,
|
|
85
|
-
pull: false, //
|
|
88
|
+
pull: false, // enable if using RLS
|
|
86
89
|
},
|
|
87
90
|
});
|
|
88
91
|
```
|
|
89
92
|
|
|
90
|
-
Then
|
|
93
|
+
Then in your root layout:
|
|
91
94
|
|
|
92
95
|
```ts
|
|
93
|
-
//
|
|
96
|
+
// App.tsx or _layout.tsx
|
|
94
97
|
import "@/lib/supastash";
|
|
95
98
|
|
|
96
|
-
export default function
|
|
99
|
+
export default function App() {
|
|
97
100
|
return <Stack />;
|
|
98
101
|
}
|
|
99
102
|
```
|
|
100
103
|
|
|
101
104
|
---
|
|
102
105
|
|
|
103
|
-
## 🚨
|
|
104
|
-
|
|
105
|
-
> ⚠️ **Important:** All timestamp fields (`created_at`, `updated_at`) used for syncing **must be `timestamptz`** in Supabase. This avoids timezone mismatch issues and ensures reliable sync.
|
|
106
|
+
## 🚨 Important Notes
|
|
106
107
|
|
|
107
|
-
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
- Avoid null primary keys
|
|
111
|
-
|
|
112
|
-
- To enable schema reflection, create this Supabase RPC:
|
|
108
|
+
- Timestamp fields (`created_at`, `updated_at`, `deleted_at`) **must be `timestamptz`** in Supabase
|
|
109
|
+
- Every synced table must have a valid `id`
|
|
110
|
+
- Create this SQL function in Supabase to allow schema reflection:
|
|
113
111
|
|
|
114
112
|
```sql
|
|
115
113
|
create or replace function get_table_schema(table_name text)
|
|
116
|
-
returns table(
|
|
117
|
-
column_name text,
|
|
118
|
-
data_type text,
|
|
119
|
-
is_nullable text
|
|
120
|
-
)
|
|
114
|
+
returns table(column_name text, data_type text, is_nullable text)
|
|
121
115
|
security definer
|
|
122
116
|
as $$
|
|
123
|
-
select
|
|
124
|
-
column_name,
|
|
125
|
-
data_type,
|
|
126
|
-
is_nullable
|
|
117
|
+
select column_name, data_type, is_nullable
|
|
127
118
|
from information_schema.columns
|
|
128
|
-
where table_schema = 'public'
|
|
129
|
-
and table_name = $1;
|
|
119
|
+
where table_schema = 'public' and table_name = $1;
|
|
130
120
|
$$ language sql;
|
|
131
121
|
|
|
132
122
|
grant execute on function get_table_schema(text) to anon, authenticated;
|
|
@@ -134,130 +124,99 @@ grant execute on function get_table_schema(text) to anon, authenticated;
|
|
|
134
124
|
|
|
135
125
|
---
|
|
136
126
|
|
|
137
|
-
## 🧪
|
|
138
|
-
|
|
139
|
-
### `useSupatashData` hook
|
|
127
|
+
## 🧪 Example: `useSupatashData`
|
|
140
128
|
|
|
141
|
-
```
|
|
129
|
+
```tsx
|
|
142
130
|
import { useSupatashData } from "supastash";
|
|
143
131
|
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
user_id: string;
|
|
147
|
-
deleted_at: string | null;
|
|
148
|
-
updated_at: string;
|
|
149
|
-
created_at: string;
|
|
150
|
-
};
|
|
132
|
+
const { data, dataMap } = useSupatashData("orders");
|
|
133
|
+
```
|
|
151
134
|
|
|
152
|
-
|
|
135
|
+
Filtered by user:
|
|
153
136
|
|
|
154
|
-
|
|
137
|
+
```tsx
|
|
155
138
|
const { userId } = useAuth();
|
|
156
|
-
const { data: userOrders } = useSupatashData
|
|
139
|
+
const { data: userOrders } = useSupatashData("orders", {
|
|
157
140
|
filter: { column: "user_id", operator: "eq", value: userId },
|
|
158
141
|
shouldFetch: !!userId,
|
|
159
142
|
});
|
|
160
143
|
```
|
|
161
144
|
|
|
162
|
-
|
|
145
|
+
Ensure sync engine is ready:
|
|
163
146
|
|
|
164
|
-
```
|
|
147
|
+
```tsx
|
|
165
148
|
import { useSupatash } from "supastash";
|
|
166
149
|
|
|
167
150
|
const { dbReady } = useSupatash();
|
|
168
151
|
if (!dbReady) return null;
|
|
169
|
-
return <Stack />;
|
|
170
152
|
```
|
|
171
153
|
|
|
172
154
|
---
|
|
173
155
|
|
|
174
|
-
##
|
|
175
|
-
|
|
176
|
-
### `configureSupastash(config)`
|
|
177
|
-
|
|
178
|
-
Initialize sync system.
|
|
179
|
-
|
|
180
|
-
### `useSupatashData(table, options)`
|
|
156
|
+
## 🔧 API Overview
|
|
181
157
|
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
Returns:
|
|
185
|
-
|
|
186
|
-
```ts
|
|
187
|
-
{
|
|
188
|
-
data: R[];
|
|
189
|
-
dataMap: Map<string, R>;
|
|
190
|
-
trigger: () => void;
|
|
191
|
-
cancel: () => void;
|
|
192
|
-
}
|
|
193
|
-
```
|
|
194
|
-
|
|
195
|
-
### `refreshTable(table: string)` / `refreshAllTables()`
|
|
196
|
-
|
|
197
|
-
Force-refresh any or all table data.
|
|
158
|
+
- [`configureSupastash()`](https://0xzekea.github.io/supastash/docs/configuration)) – setup + schema
|
|
159
|
+
- [`useSupatashData()`](https://0xzekea.github.io/supastash/docs/data-access)) – read/write synced local data
|
|
198
160
|
|
|
199
161
|
---
|
|
200
162
|
|
|
201
|
-
## 🔄 Sync
|
|
163
|
+
## 🔄 How Sync Works
|
|
202
164
|
|
|
203
|
-
-
|
|
204
|
-
- Retries with
|
|
205
|
-
-
|
|
206
|
-
-
|
|
165
|
+
- Tracks changes with `created_at`, `updated_at`, `deleted_at`
|
|
166
|
+
- Retries failed syncs with exponential backoff
|
|
167
|
+
- Batches realtime + manual changes efficiently
|
|
168
|
+
- Keeps local cache as the main source of truth
|
|
207
169
|
|
|
208
170
|
---
|
|
209
171
|
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
You can control how each query syncs:
|
|
213
|
-
|
|
214
|
-
- `localOnly`: Use only local data
|
|
215
|
-
- `remoteOnly`: Fetch directly from Supabase
|
|
216
|
-
- `localFirst` _(default)_: Read/write locally, then sync to Supabase
|
|
217
|
-
- `remoteFirst`: Write to Supabase first, then update local
|
|
172
|
+
## 🧩 Sync Modes (via query builder)
|
|
218
173
|
|
|
219
|
-
|
|
174
|
+
```ts
|
|
175
|
+
supastash
|
|
176
|
+
.from("orders")
|
|
177
|
+
.select("*")
|
|
178
|
+
.syncMode("remoteOnly") // or localOnly, localFirst, remoteFirst
|
|
179
|
+
.run();
|
|
180
|
+
```
|
|
220
181
|
|
|
221
182
|
---
|
|
222
183
|
|
|
223
|
-
##
|
|
184
|
+
## 🗂 Example Project Structure
|
|
224
185
|
|
|
225
186
|
```
|
|
226
187
|
src/
|
|
227
|
-
├─ core/ #
|
|
228
|
-
├─ hooks/ #
|
|
188
|
+
├─ core/ # Config
|
|
189
|
+
├─ hooks/ # Custom hooks
|
|
229
190
|
├─ types/ # Type definitions
|
|
230
|
-
├─ utils/ #
|
|
191
|
+
├─ utils/ # Helpers
|
|
231
192
|
```
|
|
232
193
|
|
|
233
194
|
---
|
|
234
195
|
|
|
235
|
-
##
|
|
196
|
+
## 🧪 Testing & Dev
|
|
236
197
|
|
|
237
198
|
```bash
|
|
199
|
+
# Run tests
|
|
238
200
|
yarn test
|
|
239
|
-
```
|
|
240
201
|
|
|
241
|
-
|
|
202
|
+
# Start local dev build
|
|
203
|
+
yarn dev
|
|
204
|
+
```
|
|
242
205
|
|
|
243
206
|
---
|
|
244
207
|
|
|
245
208
|
## 🤝 Contributing
|
|
246
209
|
|
|
247
|
-
|
|
248
|
-
yarn dev
|
|
249
|
-
```
|
|
250
|
-
|
|
251
|
-
Open a PR with tests and typed signatures. PRs welcome.
|
|
210
|
+
PRs welcome! Please include tests and type signatures.
|
|
252
211
|
|
|
253
212
|
---
|
|
254
213
|
|
|
255
214
|
## 📜 License
|
|
256
215
|
|
|
257
|
-
MIT
|
|
216
|
+
MIT © Ezekiel Akpan
|
|
258
217
|
|
|
259
218
|
---
|
|
260
219
|
|
|
261
220
|
## 💬 Questions?
|
|
262
221
|
|
|
263
|
-
Open an issue or reach out on [X @0xZekeA](https://x.com/0xZekeA)
|
|
222
|
+
Open an issue or reach out on [X (Twitter) @0xZekeA](https://x.com/0xZekeA)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"addPayloadToUI.d.ts","sourceRoot":"","sources":["../../../src/hooks/supastashData/addPayloadToUI.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"addPayloadToUI.d.ts","sourceRoot":"","sources":["../../../src/hooks/supastashData/addPayloadToUI.ts"],"names":[],"mappings":"AAsBA,wBAAgB,cAAc,CAC5B,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,GAAG,GAAG,GAAG,EAAE,EACpB,MAAM,EAAE,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,cAAc,CAAC,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,CAAC,EAC9D,UAAU,EAAE,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC,EACxD,SAAS,EAAE,QAAQ,GAAG,QAAQ,GAAG,QAAQ,GAAG,QAAQ,QAoBrD"}
|
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
declare function useDataState<R
|
|
1
|
+
declare function useDataState<R, T>(table: string): {
|
|
2
2
|
dataMap: Map<string, R>;
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
setVersion: import("react").Dispatch<import("react").SetStateAction<string>>;
|
|
3
|
+
data: Array<R>;
|
|
4
|
+
groupedBy?: { [K in keyof T]: Map<T[K], Array<R>>; };
|
|
6
5
|
};
|
|
7
6
|
export default useDataState;
|
|
8
7
|
//# sourceMappingURL=dataState.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dataState.d.ts","sourceRoot":"","sources":["../../../src/hooks/supastashData/dataState.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"dataState.d.ts","sourceRoot":"","sources":["../../../src/hooks/supastashData/dataState.ts"],"names":[],"mappings":"AAGA,iBAAS,YAAY,CAAC,CAAC,EAAE,CAAC,EAAE,KAAK,EAAE,MAAM,GAQ4B;IACjE,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;IACxB,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC;IACf,SAAS,CAAC,EAAE,GACT,CAAC,IAAI,MAAM,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,GACpC,CAAC;CACH,CACF;AAED,eAAe,YAAY,CAAC"}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { useCallback, useSyncExternalStore } from "react";
|
|
2
|
+
import { getSnapshot, subscribe } from "../../utils/fetchData/snapShot";
|
|
2
3
|
function useDataState(table) {
|
|
3
|
-
const
|
|
4
|
-
const
|
|
5
|
-
return
|
|
4
|
+
const stableSubscribe = useCallback((cb) => subscribe(table, cb), [table]);
|
|
5
|
+
const getStableSnapshot = useCallback(() => getSnapshot(table), [table]);
|
|
6
|
+
return useSyncExternalStore(stableSubscribe, getStableSnapshot);
|
|
6
7
|
}
|
|
7
8
|
export default useDataState;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { PayloadData } from "../../types/query.types";
|
|
2
2
|
import { RealtimeOptions } from "../../types/realtimeData.types";
|
|
3
|
-
declare function useEventQueues(table: string,
|
|
3
|
+
declare function useEventQueues<R>(table: string, options: RealtimeOptions<R>, flushIntervalMs: number): (eventType: string, data: PayloadData) => void;
|
|
4
4
|
export default useEventQueues;
|
|
5
5
|
//# sourceMappingURL=eventQueues.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"eventQueues.d.ts","sourceRoot":"","sources":["../../../src/hooks/supastashData/eventQueues.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AACtD,OAAO,EAAE,eAAe,EAAE,MAAM,gCAAgC,CAAC;AAKjE,iBAAS,cAAc,
|
|
1
|
+
{"version":3,"file":"eventQueues.d.ts","sourceRoot":"","sources":["../../../src/hooks/supastashData/eventQueues.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AACtD,OAAO,EAAE,eAAe,EAAE,MAAM,gCAAgC,CAAC;AAKjE,iBAAS,cAAc,CAAC,CAAC,EACvB,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,eAAe,CAAC,CAAC,CAAC,EAC3B,eAAe,EAAE,MAAM,eA8CU,MAAM,QAAQ,WAAW,UAgB3D;AAED,eAAe,cAAc,CAAC"}
|
|
@@ -2,7 +2,7 @@ import { useRef } from "react";
|
|
|
2
2
|
import { deleteData } from "../../utils/fetchData/deleteData";
|
|
3
3
|
import { receiveData } from "../../utils/fetchData/receiveData";
|
|
4
4
|
import useDataState from "./dataState";
|
|
5
|
-
function useEventQueues(table,
|
|
5
|
+
function useEventQueues(table, options, flushIntervalMs) {
|
|
6
6
|
const { dataMap } = useDataState(table);
|
|
7
7
|
const insertQueue = useRef([]);
|
|
8
8
|
const updateQueue = useRef([]);
|
|
@@ -11,15 +11,13 @@ function useEventQueues(table, setDataMap, setVersion, options, flushIntervalMs)
|
|
|
11
11
|
const flush = () => {
|
|
12
12
|
if (options.shouldFetch) {
|
|
13
13
|
insertQueue.current.forEach((item) => {
|
|
14
|
-
receiveData(item, table,
|
|
15
|
-
options.onInsertAndUpdate?.(item) || options.onInsert?.(item);
|
|
14
|
+
receiveData(item, table, options.shouldFetch, options.onInsertAndUpdate || options.onInsert);
|
|
16
15
|
});
|
|
17
16
|
updateQueue.current.forEach((item) => {
|
|
18
|
-
receiveData(item, table,
|
|
19
|
-
options.onInsertAndUpdate?.(item) || options.onUpdate?.(item);
|
|
17
|
+
receiveData(item, table, options.shouldFetch, options.onInsertAndUpdate || options.onInsert);
|
|
20
18
|
});
|
|
21
19
|
deleteQueue.current.forEach((item) => {
|
|
22
|
-
deleteData(item, table,
|
|
20
|
+
deleteData(item, table, options.shouldFetch);
|
|
23
21
|
options.onDelete?.(item);
|
|
24
22
|
});
|
|
25
23
|
insertQueue.current = [];
|
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
import { RealtimeOptions } from "../../types/realtimeData.types";
|
|
2
|
-
export declare function fetchCalls(table: string,
|
|
2
|
+
export declare function fetchCalls<R>(table: string, options: RealtimeOptions<R>, initialized: React.RefObject<boolean>): {
|
|
3
3
|
triggerRefresh: () => Promise<void>;
|
|
4
4
|
trigger: () => void;
|
|
5
5
|
cancel: () => void;
|
|
6
6
|
initialFetchAndSync: () => Promise<void>;
|
|
7
|
-
pushToUI: (payload: any | any[], operation: "insert" | "update" | "delete" | "upsert") => Promise<void>;
|
|
8
7
|
};
|
|
9
8
|
//# sourceMappingURL=fetchCalls.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fetchCalls.d.ts","sourceRoot":"","sources":["../../../src/hooks/supastashData/fetchCalls.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,eAAe,EAAE,MAAM,gCAAgC,CAAC;
|
|
1
|
+
{"version":3,"file":"fetchCalls.d.ts","sourceRoot":"","sources":["../../../src/hooks/supastashData/fetchCalls.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,eAAe,EAAE,MAAM,gCAAgC,CAAC;AAQjE,wBAAgB,UAAU,CAAC,CAAC,EAC1B,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,eAAe,CAAC,CAAC,CAAC,EAC3B,WAAW,EAAE,KAAK,CAAC,SAAS,CAAC,OAAO,CAAC;;;;;EAkFtC"}
|
|
@@ -4,11 +4,10 @@ import { tableFilters } from "../../store/tableFilters";
|
|
|
4
4
|
import { fetchLocalData } from "../../utils/fetchData/fetchLocalData";
|
|
5
5
|
import { initialFetch } from "../../utils/fetchData/initialFetch";
|
|
6
6
|
import log from "../../utils/logs";
|
|
7
|
-
import { addPayloadToUI } from "./addPayloadToUI";
|
|
8
7
|
const timesFetched = new Map();
|
|
9
8
|
let lastFetched = new Map();
|
|
10
|
-
export function fetchCalls(table,
|
|
11
|
-
const { shouldFetch = true, limit, filter, onPushToRemote, onInsertAndUpdate, useFilterWhileSyncing = true, } = options;
|
|
9
|
+
export function fetchCalls(table, options, initialized) {
|
|
10
|
+
const { shouldFetch = true, limit, filter, onPushToRemote, onInsertAndUpdate, useFilterWhileSyncing = true, extraMapKeys, daylength, } = options;
|
|
12
11
|
const cancelled = useRef(false);
|
|
13
12
|
useEffect(() => {
|
|
14
13
|
if (filter && useFilterWhileSyncing && !tableFilters.get(table)) {
|
|
@@ -29,7 +28,7 @@ export function fetchCalls(table, setDataMap, setVersion, options, initialized)
|
|
|
29
28
|
}, []);
|
|
30
29
|
const fetch = async () => {
|
|
31
30
|
if (!cancelled.current) {
|
|
32
|
-
await fetchLocalData(table,
|
|
31
|
+
await fetchLocalData(table, shouldFetch, limit, extraMapKeys, daylength);
|
|
33
32
|
}
|
|
34
33
|
};
|
|
35
34
|
const trigger = () => {
|
|
@@ -63,14 +62,10 @@ export function fetchCalls(table, setDataMap, setVersion, options, initialized)
|
|
|
63
62
|
console.error(`[Supastash] Error on initial fetch for ${table}`, error);
|
|
64
63
|
}
|
|
65
64
|
};
|
|
66
|
-
const pushToUI = async (payload, operation) => {
|
|
67
|
-
addPayloadToUI(table, payload, setDataMap, setVersion, operation);
|
|
68
|
-
};
|
|
69
65
|
return {
|
|
70
66
|
triggerRefresh,
|
|
71
67
|
trigger,
|
|
72
68
|
cancel,
|
|
73
69
|
initialFetchAndSync,
|
|
74
|
-
pushToUI,
|
|
75
70
|
};
|
|
76
71
|
}
|
|
@@ -1,53 +1,56 @@
|
|
|
1
1
|
import { RealtimeOptions, SupastashDataResult } from "../../types/realtimeData.types";
|
|
2
2
|
/**
|
|
3
3
|
* @description
|
|
4
|
-
* React hook to sync and subscribe to local-first data from a Supabase table.
|
|
4
|
+
* React hook to sync and subscribe to local-first data from a Supabase table using Supastash.
|
|
5
5
|
*
|
|
6
|
-
*
|
|
7
|
-
* -
|
|
8
|
-
* -
|
|
9
|
-
* -
|
|
10
|
-
* -
|
|
6
|
+
* This hook:
|
|
7
|
+
* - Fetches initial data from local SQLite (offline-first).
|
|
8
|
+
* - Optionally subscribes to Supabase `postgres_changes` for realtime updates.
|
|
9
|
+
* - Batches and flushes changes into state at a controlled interval.
|
|
10
|
+
* - Supports lazy loading, manual triggers, and event callbacks.
|
|
11
11
|
*
|
|
12
12
|
* @example
|
|
13
13
|
* const authenticated = !!session?.user;
|
|
14
|
-
*
|
|
15
14
|
* const { data, dataMap, trigger, cancel } = useSupastashData("users", {
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
* operator: "eq",
|
|
19
|
-
* value: 1,
|
|
20
|
-
* },
|
|
21
|
-
* shouldFetch: authenticated, // Only fetch if allowed
|
|
15
|
+
* shouldFetch: authenticated,
|
|
16
|
+
* filter: { column: "user_id", operator: "eq", value: 1 },
|
|
22
17
|
* flushIntervalMs: 200,
|
|
23
18
|
* onInsert: (user) => console.log("User added:", user),
|
|
24
|
-
* lazy: true,
|
|
19
|
+
* lazy: true,
|
|
25
20
|
* });
|
|
26
21
|
*
|
|
27
22
|
* useEffect(() => {
|
|
28
|
-
* trigger(); //
|
|
23
|
+
* trigger(); // manually start sync
|
|
29
24
|
* }, []);
|
|
30
25
|
*
|
|
31
|
-
* @param table - The
|
|
32
|
-
* @param options
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
* @param options.
|
|
36
|
-
* @param options.
|
|
37
|
-
* @param options.
|
|
38
|
-
* @param options.
|
|
39
|
-
* @param options.
|
|
40
|
-
*
|
|
41
|
-
*
|
|
42
|
-
* @param options.
|
|
43
|
-
* @param options.
|
|
44
|
-
* @param options.
|
|
45
|
-
*
|
|
46
|
-
*
|
|
47
|
-
*
|
|
48
|
-
*
|
|
49
|
-
*
|
|
50
|
-
*
|
|
26
|
+
* @param table - The table name (must match local SQLite table).
|
|
27
|
+
* @param options - Configuration object:
|
|
28
|
+
*
|
|
29
|
+
* ### Fetch Options:
|
|
30
|
+
* @param options.shouldFetch - If `false`, prevents initial fetch. Defaults to `true`.
|
|
31
|
+
* @param options.lazy - If `true`, disables auto-fetch. Call `trigger()` manually.
|
|
32
|
+
* @param options.limit - Max number of records to load from local DB. Defaults to `200`.
|
|
33
|
+
* @param options.useFilterWhileSyncing - If `true`, applies filter while syncing. Defaults to `true`.
|
|
34
|
+
* @param options.extraMapKey - Field to additionally group data by (`groupedBy`).
|
|
35
|
+
*
|
|
36
|
+
* ### Realtime Options:
|
|
37
|
+
* @param options.realtime - If `true`, subscribes to Supabase realtime. Defaults to `true`.
|
|
38
|
+
* @param options.filter - Structured filter (column, operator, value) for realtime subscription.
|
|
39
|
+
* @param options.flushIntervalMs - How often (ms) to apply batched changes to UI. Defaults to `100`.
|
|
40
|
+
*
|
|
41
|
+
* ### Event Callbacks:
|
|
42
|
+
* @param options.onInsert - Triggered on INSERT event.
|
|
43
|
+
* @param options.onUpdate - Triggered on UPDATE event.
|
|
44
|
+
* @param options.onDelete - Triggered on DELETE event.
|
|
45
|
+
* @param options.onInsertAndUpdate - Triggered on both INSERT and UPDATE.
|
|
46
|
+
* @param options.onPushToRemote - Called when a record is pushed to Supabase.
|
|
47
|
+
*
|
|
48
|
+
* @returns Object with:
|
|
49
|
+
* - `data`: Array of records.
|
|
50
|
+
* - `dataMap`: Map of records keyed by ID.
|
|
51
|
+
* - `groupedBy`: Optional maps grouped by fields (like `chat_id`).
|
|
52
|
+
* - `trigger()`: Manually start sync (used with lazy).
|
|
53
|
+
* - `cancel()`: Cancel a pending or lazy fetch.
|
|
51
54
|
*/
|
|
52
55
|
export declare function useSupastashData<R = any>(table: string, options?: RealtimeOptions): SupastashDataResult<R>;
|
|
53
56
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/hooks/supastashData/index.ts"],"names":[],"mappings":"AAEA,OAAO,EACL,eAAe,EACf,mBAAmB,EACpB,MAAM,gCAAgC,CAAC;AAWxC
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/hooks/supastashData/index.ts"],"names":[],"mappings":"AAEA,OAAO,EACL,eAAe,EACf,mBAAmB,EACpB,MAAM,gCAAgC,CAAC;AAWxC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoDG;AACH,wBAAgB,gBAAgB,CAAC,CAAC,GAAG,GAAG,EACtC,KAAK,EAAE,MAAM,EACb,OAAO,GAAE,eAAoB,GAC5B,mBAAmB,CAAC,CAAC,CAAC,CA2ExB"}
|