supastash 0.1.62 → 0.2.0
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 +17 -5
- package/dist/core/config/index.d.ts.map +1 -1
- package/dist/core/config/index.js +5 -1
- package/dist/db/adapters/expo_sqlite.d.ts.map +1 -1
- package/dist/db/adapters/expo_sqlite.js +11 -0
- package/dist/db/adapters/rn_nitro.d.ts.map +1 -1
- package/dist/db/adapters/rn_nitro.js +20 -0
- package/dist/db/adapters/rn_sqlite_storage.d.ts.map +1 -1
- package/dist/db/adapters/rn_sqlite_storage.js +27 -0
- package/dist/hooks/supastashData/fetchCalls.d.ts.map +1 -1
- package/dist/hooks/supastashData/index.d.ts.map +1 -1
- package/dist/hooks/supastashData/index.js +12 -4
- package/dist/hooks/supastashData/realtimeSubscription.js +4 -4
- package/dist/hooks/supastashData/registerSub.d.ts +3 -3
- package/dist/hooks/supastashData/registerSub.d.ts.map +1 -1
- package/dist/hooks/supastashData/registerSub.js +3 -3
- package/dist/hooks/supastashFilters/index.d.ts +2 -2
- package/dist/hooks/supastashFilters/index.d.ts.map +1 -1
- package/dist/hooks/supastashFilters/index.js +6 -4
- package/dist/hooks/supastashLiteQuery/index.d.ts.map +1 -1
- package/dist/hooks/supastashLiteQuery/index.js +12 -2
- package/dist/hooks/syncEngine/pushLocal/index.js +1 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/store/tableFilters.d.ts +3 -3
- package/dist/store/tableFilters.d.ts.map +1 -1
- package/dist/store/tx.d.ts +3 -0
- package/dist/store/tx.d.ts.map +1 -0
- package/dist/store/tx.js +1 -0
- package/dist/types/expoSqlite.types.d.ts +3 -13
- package/dist/types/index.d.ts +1 -1
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/liteQuery.types.d.ts +2 -2
- package/dist/types/query.types.d.ts +24 -1
- package/dist/types/realtimeData.types.d.ts +8 -4
- package/dist/types/supastashConfig.types.d.ts +83 -6
- package/dist/types/syncEngine.types.d.ts +49 -7
- package/dist/utils/errorHandler.d.ts +6 -0
- package/dist/utils/errorHandler.d.ts.map +1 -0
- package/dist/utils/errorHandler.js +8 -0
- package/dist/utils/fetchData/buildFilter.d.ts +8 -4
- package/dist/utils/fetchData/buildFilter.d.ts.map +1 -1
- package/dist/utils/fetchData/createTable.d.ts.map +1 -1
- package/dist/utils/fetchData/createTable.js +3 -46
- package/dist/utils/fetchData/deleteData.d.ts.map +1 -1
- package/dist/utils/fetchData/deleteData.js +6 -3
- package/dist/utils/fetchData/fetchLocalData.d.ts +2 -2
- package/dist/utils/fetchData/fetchLocalData.d.ts.map +1 -1
- package/dist/utils/fetchData/initialFetch.d.ts +2 -2
- package/dist/utils/fetchData/initialFetch.d.ts.map +1 -1
- package/dist/utils/fetchData/liteHelpers.d.ts +2 -2
- package/dist/utils/fetchData/liteHelpers.d.ts.map +1 -1
- package/dist/utils/fetchData/liteHelpers.js +14 -119
- package/dist/utils/fetchData/realTimeCall.js +2 -2
- package/dist/utils/fetchData/receiveData.js +1 -1
- package/dist/utils/query/builder/crud.d.ts +5 -5
- package/dist/utils/query/builder/crud.d.ts.map +1 -1
- package/dist/utils/query/builder/filters.d.ts +36 -12
- package/dist/utils/query/builder/filters.d.ts.map +1 -1
- package/dist/utils/query/builder/filters.js +32 -0
- package/dist/utils/query/builder/index.d.ts +29 -1
- package/dist/utils/query/builder/index.d.ts.map +1 -1
- package/dist/utils/query/builder/index.js +77 -1
- package/dist/utils/query/builder/mainQuery.d.ts.map +1 -1
- package/dist/utils/query/builder/mainQuery.js +17 -2
- package/dist/utils/query/helpers/localDb/getLocalMethod.d.ts +2 -2
- package/dist/utils/query/helpers/localDb/getLocalMethod.d.ts.map +1 -1
- package/dist/utils/query/helpers/localDb/getLocalMethod.js +7 -6
- package/dist/utils/query/helpers/localDb/insertMany.d.ts +3 -0
- package/dist/utils/query/helpers/localDb/insertMany.d.ts.map +1 -1
- package/dist/utils/query/helpers/localDb/insertMany.js +10 -3
- package/dist/utils/query/helpers/localDb/localQueryBuilder.d.ts +6 -6
- package/dist/utils/query/helpers/localDb/localQueryBuilder.d.ts.map +1 -1
- package/dist/utils/query/helpers/localDb/localQueryBuilder.js +17 -10
- package/dist/utils/query/helpers/localDb/upsertMany.d.ts +3 -0
- package/dist/utils/query/helpers/localDb/upsertMany.d.ts.map +1 -1
- package/dist/utils/query/helpers/localDb/upsertMany.js +9 -2
- package/dist/utils/query/helpers/mainQueryHelpers.d.ts.map +1 -1
- package/dist/utils/query/helpers/mainQueryHelpers.js +38 -8
- package/dist/utils/query/helpers/queueRemote.d.ts.map +1 -1
- package/dist/utils/query/helpers/queueRemote.js +33 -24
- package/dist/utils/query/localDbQuery/delete.d.ts +9 -3
- package/dist/utils/query/localDbQuery/delete.d.ts.map +1 -1
- package/dist/utils/query/localDbQuery/delete.js +16 -5
- package/dist/utils/query/localDbQuery/index.d.ts.map +1 -1
- package/dist/utils/query/localDbQuery/index.js +3 -3
- package/dist/utils/query/localDbQuery/insert.d.ts +2 -2
- package/dist/utils/query/localDbQuery/insert.d.ts.map +1 -1
- package/dist/utils/query/localDbQuery/insert.js +8 -5
- package/dist/utils/query/localDbQuery/select.d.ts +2 -2
- package/dist/utils/query/localDbQuery/select.d.ts.map +1 -1
- package/dist/utils/query/localDbQuery/select.js +5 -2
- package/dist/utils/query/localDbQuery/update.d.ts +2 -2
- package/dist/utils/query/localDbQuery/update.d.ts.map +1 -1
- package/dist/utils/query/localDbQuery/update.js +5 -2
- package/dist/utils/query/localDbQuery/upsert.d.ts +2 -2
- package/dist/utils/query/localDbQuery/upsert.d.ts.map +1 -1
- package/dist/utils/query/localDbQuery/upsert.js +8 -3
- package/dist/utils/query/remoteQuery/supabaseQuery.d.ts.map +1 -1
- package/dist/utils/query/remoteQuery/supabaseQuery.js +4 -1
- package/dist/utils/reusedHelpers.d.ts +8 -0
- package/dist/utils/reusedHelpers.d.ts.map +1 -0
- package/dist/utils/reusedHelpers.js +162 -0
- package/dist/utils/schema/createSyncStatus.d.ts +3 -1
- package/dist/utils/schema/createSyncStatus.d.ts.map +1 -1
- package/dist/utils/schema/createSyncStatus.js +30 -3
- package/dist/utils/sync/pullFromRemote/fetchOlder.d.ts +44 -0
- package/dist/utils/sync/pullFromRemote/fetchOlder.d.ts.map +1 -0
- package/dist/utils/sync/pullFromRemote/fetchOlder.js +55 -0
- package/dist/utils/sync/pullFromRemote/fetchOlderHelpers.d.ts +33 -0
- package/dist/utils/sync/pullFromRemote/fetchOlderHelpers.d.ts.map +1 -0
- package/dist/utils/sync/pullFromRemote/fetchOlderHelpers.js +110 -0
- package/dist/utils/sync/pullFromRemote/helpers.d.ts +10 -7
- package/dist/utils/sync/pullFromRemote/helpers.d.ts.map +1 -1
- package/dist/utils/sync/pullFromRemote/helpers.js +20 -14
- package/dist/utils/sync/pullFromRemote/pullData.d.ts +2 -3
- package/dist/utils/sync/pullFromRemote/pullData.d.ts.map +1 -1
- package/dist/utils/sync/pullFromRemote/pullData.js +4 -9
- package/dist/utils/sync/pullFromRemote/pullDeletedData.d.ts +8 -5
- package/dist/utils/sync/pullFromRemote/updateFilter.d.ts +1 -1
- package/dist/utils/sync/pullFromRemote/updateFilter.d.ts.map +1 -1
- package/dist/utils/sync/pullFromRemote/updateFilter.js +5 -3
- package/dist/utils/sync/pullFromRemote/updateLocalDb.d.ts +4 -3
- package/dist/utils/sync/pullFromRemote/updateLocalDb.d.ts.map +1 -1
- package/dist/utils/sync/pullFromRemote/updateLocalDb.js +51 -46
- package/dist/utils/sync/pullFromRemote/validateFilters.d.ts +2 -4
- package/dist/utils/sync/pullFromRemote/validateFilters.d.ts.map +1 -1
- package/dist/utils/sync/pullFromRemote/validateFilters.js +9 -63
- package/dist/utils/sync/pushLocal/deleteChunks.d.ts.map +1 -1
- package/dist/utils/sync/pushLocal/deleteChunks.js +7 -5
- package/dist/utils/sync/pushLocal/getAllUnsyncedData.d.ts.map +1 -1
- package/dist/utils/sync/pushLocal/getAllUnsyncedData.js +12 -44
- package/dist/utils/sync/pushLocal/uploadHelpers.js +1 -1
- package/dist/utils/sync/status/filterKey.d.ts +3 -3
- package/dist/utils/sync/status/filterKey.d.ts.map +1 -1
- package/dist/utils/sync/status/filterKey.js +5 -2
- package/dist/utils/sync/status/remoteSchema.d.ts +4 -0
- package/dist/utils/sync/status/remoteSchema.d.ts.map +1 -0
- package/dist/utils/sync/status/remoteSchema.js +140 -0
- package/dist/utils/sync/status/repo.d.ts +5 -5
- package/dist/utils/sync/status/repo.d.ts.map +1 -1
- package/dist/utils/sync/status/repo.js +29 -23
- package/dist/utils/sync/status/services.d.ts +5 -6
- package/dist/utils/sync/status/services.d.ts.map +1 -1
- package/dist/utils/sync/status/services.js +1 -6
- package/dist/utils/sync/status/syncStatus.d.ts +5 -7
- package/dist/utils/sync/status/syncStatus.d.ts.map +1 -1
- package/dist/utils/sync/status/syncStatus.js +11 -3
- package/package.json +2 -2
- package/dist/types/supastashFilters.types.d.ts +0 -3
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import { getSupastashConfig } from "../../../core/config";
|
|
2
|
+
import { getSupastashDb } from "../../../db/dbInitializer";
|
|
3
|
+
import { tableSchemaData } from "../../../store/tableSchemaData";
|
|
4
|
+
import { isNetworkError, isOnline } from "../../connection";
|
|
5
|
+
import log, { logWarn } from "../../logs";
|
|
6
|
+
const SERVER_SIDE_DOCS_URL = `https://0xzekea.github.io/supastash/docs/getting-started/#%EF%B8%8F-server-side-setup-for-filtered-pulls`;
|
|
7
|
+
async function ensureRemoteSchemaTableExists() {
|
|
8
|
+
const db = await getSupastashDb();
|
|
9
|
+
await db.execAsync(`CREATE TABLE IF NOT EXISTS supastash_remote_table_schema (
|
|
10
|
+
table_name TEXT PRIMARY KEY,
|
|
11
|
+
schema_json TEXT NOT NULL,
|
|
12
|
+
updated_at TEXT NOT NULL
|
|
13
|
+
);`);
|
|
14
|
+
}
|
|
15
|
+
function validatePayloadForTable(payload, tableName) {
|
|
16
|
+
const columnsMap = new Map();
|
|
17
|
+
payload.forEach((col) => {
|
|
18
|
+
columnsMap.set(col.column_name, col);
|
|
19
|
+
});
|
|
20
|
+
const id = columnsMap.get("id");
|
|
21
|
+
if (!id ||
|
|
22
|
+
!["uuid", "text"].includes(id.data_type) ||
|
|
23
|
+
id.is_nullable === "YES") {
|
|
24
|
+
throw new Error(`Column 'id' must be uuid/text and NOT NULL for table ${tableName}`);
|
|
25
|
+
}
|
|
26
|
+
const timestampType = ["timestamp with time zone", "timestamptz"];
|
|
27
|
+
const updatedAt = columnsMap.get("updated_at");
|
|
28
|
+
if (!updatedAt) {
|
|
29
|
+
throw new Error(`'updated_at' must be present on table ${tableName}
|
|
30
|
+
See docs ${SERVER_SIDE_DOCS_URL}
|
|
31
|
+
`);
|
|
32
|
+
}
|
|
33
|
+
if (!timestampType.includes(updatedAt.data_type)) {
|
|
34
|
+
logWarn(`'updated_at' must be of type "timestamptz" on table ${tableName}. Current type: ${updatedAt.data_type}. This can cause inconsistencies in the sync logic.`);
|
|
35
|
+
}
|
|
36
|
+
const createdAt = columnsMap.get("created_at");
|
|
37
|
+
if (!createdAt) {
|
|
38
|
+
throw new Error(`'created_at' must be present on table ${tableName}
|
|
39
|
+
See docs ${SERVER_SIDE_DOCS_URL}
|
|
40
|
+
`);
|
|
41
|
+
}
|
|
42
|
+
if (!timestampType.includes(createdAt.data_type)) {
|
|
43
|
+
logWarn(`'created_at' must be of type "timestamptz" on table ${tableName}. Current type: ${createdAt.data_type}. This can cause inconsistencies in the sync logic.`);
|
|
44
|
+
}
|
|
45
|
+
const deletedAt = columnsMap.get("deleted_at");
|
|
46
|
+
if (!deletedAt) {
|
|
47
|
+
throw new Error(`'deleted_at' must be present on table ${tableName}
|
|
48
|
+
See docs ${SERVER_SIDE_DOCS_URL}
|
|
49
|
+
`);
|
|
50
|
+
}
|
|
51
|
+
if (!timestampType.includes(deletedAt.data_type)) {
|
|
52
|
+
logWarn(`'deleted_at' must be of type "timestamptz" on table ${tableName}. Current type: ${deletedAt.data_type}. This can cause inconsistencies in the sync logic.`);
|
|
53
|
+
}
|
|
54
|
+
const cfg = getSupastashConfig();
|
|
55
|
+
if (cfg.replicationMode === "server-side") {
|
|
56
|
+
const arrivedAt = columnsMap.get("arrived_at");
|
|
57
|
+
if (!arrivedAt) {
|
|
58
|
+
throw new Error(`'arrived_at' must be present on table ${tableName}
|
|
59
|
+
See docs ${SERVER_SIDE_DOCS_URL}
|
|
60
|
+
`);
|
|
61
|
+
}
|
|
62
|
+
if (!timestampType.includes(arrivedAt.data_type)) {
|
|
63
|
+
logWarn(`'arrived_at' must be of type "timestamptz" on table ${tableName}. Current type: ${arrivedAt.data_type}. This can cause inconsistencies in the sync logic.`);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
async function upsertRemoteSchema(table, schema) {
|
|
68
|
+
const payload = JSON.stringify(schema);
|
|
69
|
+
const db = await getSupastashDb();
|
|
70
|
+
await db.runAsync(`
|
|
71
|
+
INSERT INTO supastash_remote_table_schema (table_name, schema_json, updated_at)
|
|
72
|
+
VALUES (?, ?, datetime('now'))
|
|
73
|
+
ON CONFLICT(table_name)
|
|
74
|
+
DO UPDATE SET
|
|
75
|
+
schema_json = excluded.schema_json,
|
|
76
|
+
updated_at = excluded.updated_at;
|
|
77
|
+
`, [table, payload]);
|
|
78
|
+
}
|
|
79
|
+
async function getLocalSchema(table) {
|
|
80
|
+
const db = await getSupastashDb();
|
|
81
|
+
const row = await db.getFirstAsync(`
|
|
82
|
+
SELECT schema_json
|
|
83
|
+
FROM supastash_remote_table_schema
|
|
84
|
+
WHERE table_name = ?
|
|
85
|
+
`, [table]);
|
|
86
|
+
if (!row)
|
|
87
|
+
return null;
|
|
88
|
+
return JSON.parse(row.schema_json);
|
|
89
|
+
}
|
|
90
|
+
export function appendSyncedAt(schema) {
|
|
91
|
+
return [
|
|
92
|
+
...schema,
|
|
93
|
+
{
|
|
94
|
+
column_name: "synced_at",
|
|
95
|
+
data_type: "text",
|
|
96
|
+
is_nullable: "YES",
|
|
97
|
+
},
|
|
98
|
+
];
|
|
99
|
+
}
|
|
100
|
+
const localSchemaCache = new Map();
|
|
101
|
+
export async function getRemoteTableSchema(table) {
|
|
102
|
+
const config = getSupastashConfig();
|
|
103
|
+
const supabase = config?.supabaseClient;
|
|
104
|
+
if (!supabase) {
|
|
105
|
+
throw new Error(`Supabase client not found`);
|
|
106
|
+
}
|
|
107
|
+
// 1. Memory cache
|
|
108
|
+
if (tableSchemaData.has(table)) {
|
|
109
|
+
return appendSyncedAt(tableSchemaData.get(table));
|
|
110
|
+
}
|
|
111
|
+
await ensureRemoteSchemaTableExists();
|
|
112
|
+
const online = await isOnline();
|
|
113
|
+
// 2. If offline → SQLite fallback
|
|
114
|
+
if (!online) {
|
|
115
|
+
if (localSchemaCache.has(table)) {
|
|
116
|
+
return appendSyncedAt(localSchemaCache.get(table));
|
|
117
|
+
}
|
|
118
|
+
const local = await getLocalSchema(table);
|
|
119
|
+
if (!local)
|
|
120
|
+
return null;
|
|
121
|
+
localSchemaCache.set(table, local);
|
|
122
|
+
return appendSyncedAt(local);
|
|
123
|
+
}
|
|
124
|
+
// 3. Remote fetch
|
|
125
|
+
const { data, error } = await supabase.rpc("get_table_schema", {
|
|
126
|
+
table_name: table,
|
|
127
|
+
});
|
|
128
|
+
if (error || !Array.isArray(data)) {
|
|
129
|
+
if (error && !isNetworkError(error)) {
|
|
130
|
+
log(`[Supastash] Error getting remote keys for table ${table} on public schema: ${error.message}
|
|
131
|
+
You can find more information in the Supastash docs: ${SERVER_SIDE_DOCS_URL}`);
|
|
132
|
+
}
|
|
133
|
+
return null;
|
|
134
|
+
}
|
|
135
|
+
validatePayloadForTable(data, table);
|
|
136
|
+
// 4. Persist
|
|
137
|
+
await upsertRemoteSchema(table, data);
|
|
138
|
+
tableSchemaData.set(table, data);
|
|
139
|
+
return appendSyncedAt(data);
|
|
140
|
+
}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { SupastashFilter } from "../../../types/realtimeData.types";
|
|
2
2
|
import { SupastashSQLiteDatabase } from "../../../types/supastashConfig.types";
|
|
3
3
|
import { SupastashSyncStatus } from "../../../types/syncEngine.types";
|
|
4
4
|
export declare function ensureSyncMarksTable(): Promise<void>;
|
|
5
5
|
export declare function selectMarks(db: SupastashSQLiteDatabase, table: string, filterKey: string): Promise<SupastashSyncStatus | null>;
|
|
6
|
-
export declare function selectSyncStatus(db: SupastashSQLiteDatabase, table: string, tableFilters?:
|
|
7
|
-
export declare function upsertMarks(db: SupastashSQLiteDatabase, row: Partial<SupastashSyncStatus>): Promise<
|
|
8
|
-
export declare function resetColumn(db: SupastashSQLiteDatabase, table: string, filterKey: string, col: "last_synced_at" | "
|
|
9
|
-
export declare function deleteMarks(db: SupastashSQLiteDatabase, table: string, filterKey?: string): Promise<
|
|
6
|
+
export declare function selectSyncStatus(db: SupastashSQLiteDatabase, table: string, tableFilters?: SupastashFilter[]): Promise<SupastashSyncStatus>;
|
|
7
|
+
export declare function upsertMarks(db: SupastashSQLiteDatabase, row: Partial<SupastashSyncStatus>): Promise<any>;
|
|
8
|
+
export declare function resetColumn(db: SupastashSQLiteDatabase, table: string, filterKey: string, col: "last_synced_at" | "last_deleted_at", value: string, filterJson: string): Promise<any>;
|
|
9
|
+
export declare function deleteMarks(db: SupastashSQLiteDatabase, table: string, filterKey?: string): Promise<any>;
|
|
10
10
|
//# sourceMappingURL=repo.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"repo.d.ts","sourceRoot":"","sources":["../../../../src/utils/sync/status/repo.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"repo.d.ts","sourceRoot":"","sources":["../../../../src/utils/sync/status/repo.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAE,MAAM,mCAAmC,CAAC;AACpE,OAAO,EAAE,uBAAuB,EAAE,MAAM,sCAAsC,CAAC;AAC/E,OAAO,EAAE,mBAAmB,EAAE,MAAM,iCAAiC,CAAC;AAuDtE,wBAAsB,oBAAoB,kBAEzC;AAED,wBAAsB,WAAW,CAC/B,EAAE,EAAE,uBAAuB,EAC3B,KAAK,EAAE,MAAM,EACb,SAAS,EAAE,MAAM,uCAOlB;AAED,wBAAsB,gBAAgB,CACpC,EAAE,EAAE,uBAAuB,EAC3B,KAAK,EAAE,MAAM,EACb,YAAY,CAAC,EAAE,eAAe,EAAE,GAC/B,OAAO,CAAC,mBAAmB,CAAC,CAoB9B;AAED,wBAAsB,WAAW,CAC/B,EAAE,EAAE,uBAAuB,EAC3B,GAAG,EAAE,OAAO,CAAC,mBAAmB,CAAC,gBA8BlC;AAED,wBAAsB,WAAW,CAC/B,EAAE,EAAE,uBAAuB,EAC3B,KAAK,EAAE,MAAM,EACb,SAAS,EAAE,MAAM,EACjB,GAAG,EAAE,gBAAgB,GAAG,iBAAiB,EACzC,KAAK,EAAE,MAAM,EACb,UAAU,EAAE,MAAM,gBAYnB;AAED,wBAAsB,WAAW,CAC/B,EAAE,EAAE,uBAAuB,EAC3B,KAAK,EAAE,MAAM,EACb,SAAS,CAAC,EAAE,MAAM,gBASnB"}
|
|
@@ -1,7 +1,16 @@
|
|
|
1
|
+
import { getSupastashConfig } from "../../../core/config";
|
|
1
2
|
import { logWarn } from "../../logs";
|
|
2
3
|
import { createSyncStatusTable } from "../../schema/createSyncStatus";
|
|
3
4
|
import { computeFilterKey } from "./filterKey";
|
|
4
5
|
const OLD_DATE = "2000-01-01T00:00:00Z";
|
|
6
|
+
const SYNC_STATUS_TABLE = "supastash_sync_marks";
|
|
7
|
+
const SERVER_SYNC_STATUS_TABLE = "supastash_server_sync_marks";
|
|
8
|
+
const getSyncStatusTable = () => {
|
|
9
|
+
const cfg = getSupastashConfig();
|
|
10
|
+
return cfg.replicationMode === "server-side"
|
|
11
|
+
? SERVER_SYNC_STATUS_TABLE
|
|
12
|
+
: SYNC_STATUS_TABLE;
|
|
13
|
+
};
|
|
5
14
|
const cleanDate = ({ date, table, column, }) => {
|
|
6
15
|
const original = date || OLD_DATE;
|
|
7
16
|
const d = new Date(original);
|
|
@@ -12,17 +21,14 @@ const cleanDate = ({ date, table, column, }) => {
|
|
|
12
21
|
return original;
|
|
13
22
|
};
|
|
14
23
|
const cleanSyncStatus = (syncStatus) => {
|
|
24
|
+
const cfg = getSupastashConfig();
|
|
25
|
+
const lastSyncedAtColumn = cfg.replicationMode === "server-side" ? "arrived_at" : "updated_at";
|
|
15
26
|
return {
|
|
16
27
|
...syncStatus,
|
|
17
|
-
last_created_at: cleanDate({
|
|
18
|
-
date: syncStatus.last_created_at,
|
|
19
|
-
table: syncStatus.table_name,
|
|
20
|
-
column: "created_at",
|
|
21
|
-
}),
|
|
22
28
|
last_synced_at: cleanDate({
|
|
23
29
|
date: syncStatus.last_synced_at,
|
|
24
30
|
table: syncStatus.table_name,
|
|
25
|
-
column:
|
|
31
|
+
column: lastSyncedAtColumn,
|
|
26
32
|
}),
|
|
27
33
|
last_deleted_at: cleanDate({
|
|
28
34
|
date: syncStatus.last_deleted_at || OLD_DATE,
|
|
@@ -35,11 +41,13 @@ export async function ensureSyncMarksTable() {
|
|
|
35
41
|
await createSyncStatusTable();
|
|
36
42
|
}
|
|
37
43
|
export async function selectMarks(db, table, filterKey) {
|
|
38
|
-
|
|
44
|
+
const syncStatusTable = getSyncStatusTable();
|
|
45
|
+
return db.getFirstAsync(`SELECT * FROM ${syncStatusTable} WHERE table_name=? AND filter_key=?`, [table, filterKey]);
|
|
39
46
|
}
|
|
40
47
|
export async function selectSyncStatus(db, table, tableFilters) {
|
|
41
48
|
const filterKey = await computeFilterKey(tableFilters ?? []);
|
|
42
|
-
const
|
|
49
|
+
const syncStatusTable = getSyncStatusTable();
|
|
50
|
+
const result = await db.getFirstAsync(`SELECT * FROM ${syncStatusTable} WHERE table_name=? AND filter_key=?`, [table, filterKey]);
|
|
43
51
|
if (result) {
|
|
44
52
|
return cleanSyncStatus(result);
|
|
45
53
|
}
|
|
@@ -47,35 +55,34 @@ export async function selectSyncStatus(db, table, tableFilters) {
|
|
|
47
55
|
table_name: table,
|
|
48
56
|
filter_key: filterKey,
|
|
49
57
|
filter_json: "{}",
|
|
50
|
-
last_created_at: OLD_DATE,
|
|
51
58
|
last_synced_at: OLD_DATE,
|
|
52
59
|
last_synced_at_pk: null,
|
|
53
60
|
last_deleted_at: OLD_DATE,
|
|
54
61
|
};
|
|
55
62
|
}
|
|
56
63
|
export async function upsertMarks(db, row) {
|
|
57
|
-
const { table_name, filter_key, filter_json = null,
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
64
|
+
const { table_name, filter_key, filter_json = null, last_synced_at = null, last_deleted_at = null, last_synced_at_pk = null, } = row;
|
|
65
|
+
const syncStatusTable = getSyncStatusTable();
|
|
66
|
+
return db.runAsync(`INSERT INTO ${syncStatusTable}
|
|
67
|
+
(table_name, filter_key, filter_json, last_synced_at, last_deleted_at, updated_at, last_synced_at_pk)
|
|
68
|
+
VALUES (?,?,?,?,?,datetime('now'),?)
|
|
61
69
|
ON CONFLICT(table_name, filter_key) DO UPDATE SET
|
|
62
70
|
filter_json = excluded.filter_json,
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
last_deleted_at = COALESCE(excluded.last_deleted_at, supastash_sync_marks.last_deleted_at),
|
|
71
|
+
last_synced_at = COALESCE(excluded.last_synced_at, ${syncStatusTable}.last_synced_at),
|
|
72
|
+
last_deleted_at = COALESCE(excluded.last_deleted_at, ${syncStatusTable}.last_deleted_at),
|
|
66
73
|
updated_at = datetime('now'),
|
|
67
|
-
last_synced_at_pk = COALESCE(excluded.last_synced_at_pk,
|
|
74
|
+
last_synced_at_pk = COALESCE(excluded.last_synced_at_pk, ${syncStatusTable}.last_synced_at_pk)`, [
|
|
68
75
|
table_name,
|
|
69
76
|
filter_key,
|
|
70
77
|
filter_json,
|
|
71
|
-
last_created_at,
|
|
72
78
|
last_synced_at,
|
|
73
79
|
last_deleted_at,
|
|
74
80
|
last_synced_at_pk,
|
|
75
81
|
]);
|
|
76
82
|
}
|
|
77
83
|
export async function resetColumn(db, table, filterKey, col, value, filterJson) {
|
|
78
|
-
|
|
84
|
+
const syncStatusTable = getSyncStatusTable();
|
|
85
|
+
return db.runAsync(`INSERT INTO ${syncStatusTable} (table_name, filter_key, filter_json, ${col}, updated_at)
|
|
79
86
|
VALUES (?,?,?,?,datetime('now'))
|
|
80
87
|
ON CONFLICT(table_name, filter_key) DO UPDATE SET
|
|
81
88
|
filter_json = excluded.filter_json,
|
|
@@ -83,9 +90,8 @@ export async function resetColumn(db, table, filterKey, col, value, filterJson)
|
|
|
83
90
|
updated_at = datetime('now')`, [table, filterKey, filterJson, value]);
|
|
84
91
|
}
|
|
85
92
|
export async function deleteMarks(db, table, filterKey) {
|
|
93
|
+
const syncStatusTable = getSyncStatusTable();
|
|
86
94
|
return filterKey
|
|
87
|
-
? db.runAsync(`DELETE FROM
|
|
88
|
-
: db.runAsync(`DELETE FROM
|
|
89
|
-
table,
|
|
90
|
-
]);
|
|
95
|
+
? db.runAsync(`DELETE FROM ${syncStatusTable} WHERE table_name=? AND filter_key=?`, [table, filterKey])
|
|
96
|
+
: db.runAsync(`DELETE FROM ${syncStatusTable} WHERE table_name=?`, [table]);
|
|
91
97
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { SupastashFilter } from "../../../types/realtimeData.types";
|
|
2
2
|
import { PublicScope, SupastashSyncStatus } from "../../../types/syncEngine.types";
|
|
3
3
|
/**
|
|
4
4
|
* Gets the supastash sync status for a given table and filters
|
|
@@ -6,9 +6,8 @@ import { PublicScope, SupastashSyncStatus } from "../../../types/syncEngine.type
|
|
|
6
6
|
* @param filters - The filters to apply to the sync status
|
|
7
7
|
* @returns The supastash sync status
|
|
8
8
|
*/
|
|
9
|
-
export declare function getSupastashSyncStatus(table: string, filters?:
|
|
10
|
-
export declare function setSupastashSyncStatus(table: string, filters:
|
|
11
|
-
lastCreatedAt?: string | null;
|
|
9
|
+
export declare function getSupastashSyncStatus(table: string, filters?: SupastashFilter[]): Promise<SupastashSyncStatus | null>;
|
|
10
|
+
export declare function setSupastashSyncStatus(table: string, filters: SupastashFilter[] | undefined, opts: {
|
|
12
11
|
lastSyncedAt?: string | null;
|
|
13
12
|
lastDeletedAt?: string | null;
|
|
14
13
|
lastSyncedAtPk?: string | null;
|
|
@@ -21,12 +20,12 @@ export declare function setSupastashSyncStatus(table: string, filters: RealtimeF
|
|
|
21
20
|
* @param scope - The scope to reset the sync status for
|
|
22
21
|
* @returns The supastash sync status
|
|
23
22
|
*/
|
|
24
|
-
export declare function resetSupastashSyncStatus(table: string, filters:
|
|
23
|
+
export declare function resetSupastashSyncStatus(table: string, filters: SupastashFilter[] | undefined, scope?: PublicScope): Promise<void>;
|
|
25
24
|
/**
|
|
26
25
|
* Clears the supastash sync status for a given table and filters
|
|
27
26
|
* @param table - The name of the table to clear the sync status for
|
|
28
27
|
* @param filters - The filters to apply to the sync status
|
|
29
28
|
* @returns The supastash sync status
|
|
30
29
|
*/
|
|
31
|
-
export declare function clearSupastashSyncStatus(table: string, filters?:
|
|
30
|
+
export declare function clearSupastashSyncStatus(table: string, filters?: SupastashFilter[]): Promise<void>;
|
|
32
31
|
//# sourceMappingURL=services.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"services.d.ts","sourceRoot":"","sources":["../../../../src/utils/sync/status/services.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"services.d.ts","sourceRoot":"","sources":["../../../../src/utils/sync/status/services.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,eAAe,EAAE,MAAM,mCAAmC,CAAC;AACpE,OAAO,EACL,WAAW,EACX,mBAAmB,EACpB,MAAM,iCAAiC,CAAC;AAmBzC;;;;;GAKG;AACH,wBAAsB,sBAAsB,CAC1C,KAAK,EAAE,MAAM,EACb,OAAO,CAAC,EAAE,eAAe,EAAE,GAC1B,OAAO,CAAC,mBAAmB,GAAG,IAAI,CAAC,CAWrC;AAED,wBAAsB,sBAAsB,CAC1C,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,eAAe,EAAE,GAAG,SAAS,EACtC,IAAI,EAAE;IACJ,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,cAAc,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B,iBAyCF;AAED;;;;;;GAMG;AACH,wBAAsB,wBAAwB,CAC5C,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,eAAe,EAAE,GAAG,SAAS,EACtC,KAAK,GAAE,WAAmB,iBAmB3B;AAED;;;;;GAKG;AACH,wBAAsB,wBAAwB,CAC5C,KAAK,EAAE,MAAM,EACb,OAAO,CAAC,EAAE,eAAe,EAAE,iBAY5B"}
|
|
@@ -39,9 +39,6 @@ export async function setSupastashSyncStatus(table, filters, opts) {
|
|
|
39
39
|
const fk = await computeFilterKey(filterToUse, ns);
|
|
40
40
|
const filterJson = canonicalizeFilters(filterToUse);
|
|
41
41
|
const existing = await selectMarks(db, table, fk);
|
|
42
|
-
const nextLastCreated = opts.lastCreatedAt !== undefined
|
|
43
|
-
? maxIso(opts.lastCreatedAt, existing?.last_created_at ?? null)
|
|
44
|
-
: existing?.last_created_at ?? null;
|
|
45
42
|
const nextLastSynced = opts.lastSyncedAt !== undefined
|
|
46
43
|
? maxIso(opts.lastSyncedAt, existing?.last_synced_at ?? null)
|
|
47
44
|
: existing?.last_synced_at ?? null;
|
|
@@ -53,11 +50,10 @@ export async function setSupastashSyncStatus(table, filters, opts) {
|
|
|
53
50
|
filter_key: fk,
|
|
54
51
|
filter_json: filterJson,
|
|
55
52
|
last_synced_at_pk: opts.lastSyncedAtPk ?? undefined,
|
|
56
|
-
last_created_at: nextLastCreated ?? undefined,
|
|
57
53
|
last_synced_at: nextLastSynced ?? undefined,
|
|
58
54
|
last_deleted_at: nextLastDeleted ?? undefined,
|
|
59
55
|
});
|
|
60
|
-
if (!opts.
|
|
56
|
+
if (!opts.lastSyncedAt && !opts.lastDeletedAt) {
|
|
61
57
|
logWarn(`[Supastash] setSupastashSyncStatus(${table}): no fields provided`);
|
|
62
58
|
}
|
|
63
59
|
}
|
|
@@ -81,7 +77,6 @@ export async function resetSupastashSyncStatus(table, filters, scope = "all") {
|
|
|
81
77
|
const filterJson = canonicalizeFilters(filterToUse);
|
|
82
78
|
if (scope === "all") {
|
|
83
79
|
await resetColumn(db, table, fk, "last_synced_at", OLD_DATE, filterJson);
|
|
84
|
-
await resetColumn(db, table, fk, "last_created_at", OLD_DATE, filterJson);
|
|
85
80
|
await resetColumn(db, table, fk, "last_deleted_at", OLD_DATE, filterJson);
|
|
86
81
|
}
|
|
87
82
|
else {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { SupastashFilter } from "../../../types/realtimeData.types";
|
|
2
2
|
import { PublicScope, SupastashSyncStatus } from "../../../types/syncEngine.types";
|
|
3
3
|
/**
|
|
4
4
|
* Clears the sync log for a specific table.
|
|
@@ -32,7 +32,6 @@ export declare function clearAllLocalSyncLog(): Promise<void>;
|
|
|
32
32
|
* return {
|
|
33
33
|
* table_name: "users",
|
|
34
34
|
* last_synced_at: "2021-01-01T00:00:00.000Z",
|
|
35
|
-
* last_created_at: "2021-01-01T00:00:00.000Z",
|
|
36
35
|
* last_deleted_at: "2021-01-01T00:00:00.000Z",
|
|
37
36
|
* filter_key: "1234567890",
|
|
38
37
|
* filter_json: "[...]",
|
|
@@ -55,8 +54,7 @@ export declare function getSyncLog(tableName: string): Promise<SupastashSyncStat
|
|
|
55
54
|
* lastSyncedAtPk: "00000000-0000-0000-0000-000000000000",
|
|
56
55
|
* });
|
|
57
56
|
*/
|
|
58
|
-
export declare function setSyncLog(table: string, filters:
|
|
59
|
-
lastCreatedAt?: string | null;
|
|
57
|
+
export declare function setSyncLog(table: string, filters: SupastashFilter[] | undefined, opts: {
|
|
60
58
|
lastSyncedAt?: string | null;
|
|
61
59
|
lastDeletedAt?: string | null;
|
|
62
60
|
lastSyncedAtPk?: string | null;
|
|
@@ -68,11 +66,11 @@ export declare function setSyncLog(table: string, filters: RealtimeFilter[] | un
|
|
|
68
66
|
* @param table - Table to reset.
|
|
69
67
|
* @param filters - Optional filters for a scoped reset.
|
|
70
68
|
* @param scope - Field(s) to reset: "all" (default),
|
|
71
|
-
* "last_synced_at",
|
|
69
|
+
* "last_synced_at", or "last_deleted_at".
|
|
72
70
|
* @example
|
|
73
71
|
* await resetSyncLog("users", undefined, "all");
|
|
74
72
|
*/
|
|
75
|
-
export declare function resetSyncLog(table: string, filters:
|
|
73
|
+
export declare function resetSyncLog(table: string, filters: SupastashFilter[] | undefined, scope?: PublicScope): Promise<void>;
|
|
76
74
|
/**
|
|
77
75
|
* Deletes the sync log entry for a table (and optional filter key).
|
|
78
76
|
*
|
|
@@ -81,7 +79,7 @@ export declare function resetSyncLog(table: string, filters: RealtimeFilter[] |
|
|
|
81
79
|
* @example
|
|
82
80
|
* await clearSyncLog("users");
|
|
83
81
|
*/
|
|
84
|
-
export declare function clearSyncLog(table: string, filters?:
|
|
82
|
+
export declare function clearSyncLog(table: string, filters?: SupastashFilter[]): Promise<void>;
|
|
85
83
|
/** ------------------- DEPRECATED 🗑 Local Sync & Delete Log ------------------- */
|
|
86
84
|
/**
|
|
87
85
|
* @deprecated Use `setSyncLog` instead.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"syncStatus.d.ts","sourceRoot":"","sources":["../../../../src/utils/sync/status/syncStatus.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"syncStatus.d.ts","sourceRoot":"","sources":["../../../../src/utils/sync/status/syncStatus.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,eAAe,EAAE,MAAM,mCAAmC,CAAC;AACpE,OAAO,EACL,WAAW,EACX,mBAAmB,EACpB,MAAM,iCAAiC,CAAC;AAkBzC;;;;;;;;;GASG;AACH,wBAAsB,iBAAiB,CAAC,SAAS,EAAE,MAAM,iBAExD;AAED;;;;;;;;GAQG;AACH,wBAAsB,oBAAoB,kBAKzC;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAsB,UAAU,CAC9B,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,mBAAmB,GAAG,IAAI,CAAC,CASrC;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAsB,UAAU,CAC9B,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,eAAe,EAAE,GAAG,SAAS,EACtC,IAAI,EAAE;IACJ,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,cAAc,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B,iBAOF;AAED;;;;;;;;;GASG;AACH,wBAAsB,YAAY,CAChC,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,eAAe,EAAE,GAAG,SAAS,EACtC,KAAK,GAAE,WAAmB,iBAO3B;AAED;;;;;;;GAOG;AACH,wBAAsB,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,eAAe,EAAE,iBAM5E;AAED,oFAAoF;AAEpF;;;GAGG;AACH,wBAAsB,eAAe,CACnC,SAAS,EAAE,MAAM,EACjB,YAAY,EAAE,MAAM,EACpB,aAAa,CAAC,EAAE,MAAM,iBAGvB;AAED;;;GAGG;AACH,wBAAsB,mBAAmB,CAAC,SAAS,EAAE,MAAM,iBAE1D;AAED;;;GAGG;AACH,wBAAsB,sBAAsB,kBAE3C;AAED;;;GAGG;AACH,wBAAsB,iBAAiB,CAAC,SAAS,EAAE,MAAM,iBAExD;AAED;;;GAGG;AACH,wBAAsB,iBAAiB,CACrC,SAAS,EAAE,MAAM,EACjB,aAAa,EAAE,MAAM,iBAGtB"}
|
|
@@ -1,8 +1,16 @@
|
|
|
1
|
+
import { getSupastashConfig } from "../../../core/config";
|
|
1
2
|
import { getSupastashDb } from "../../../db/dbInitializer";
|
|
2
3
|
import { logError } from "../../logs";
|
|
3
4
|
import { createSyncStatusTable } from "../../schema/createSyncStatus";
|
|
4
5
|
import { clearSupastashSyncStatus, getSupastashSyncStatus, resetSupastashSyncStatus, setSupastashSyncStatus, } from "./services";
|
|
5
6
|
const SYNC_STATUS_TABLE = "supastash_sync_marks";
|
|
7
|
+
const SERVER_SYNC_STATUS_TABLE = "supastash_server_sync_marks";
|
|
8
|
+
const getSyncStatusTable = () => {
|
|
9
|
+
const cfg = getSupastashConfig();
|
|
10
|
+
return cfg.replicationMode === "server-side"
|
|
11
|
+
? SERVER_SYNC_STATUS_TABLE
|
|
12
|
+
: SYNC_STATUS_TABLE;
|
|
13
|
+
};
|
|
6
14
|
/**
|
|
7
15
|
* Clears the sync log for a specific table.
|
|
8
16
|
*
|
|
@@ -27,7 +35,8 @@ export async function clearLocalSyncLog(tableName) {
|
|
|
27
35
|
*/
|
|
28
36
|
export async function clearAllLocalSyncLog() {
|
|
29
37
|
const db = await getSupastashDb();
|
|
30
|
-
|
|
38
|
+
const syncStatusTable = getSyncStatusTable();
|
|
39
|
+
await db.runAsync(`DROP TABLE IF EXISTS ${syncStatusTable}`);
|
|
31
40
|
await createSyncStatusTable();
|
|
32
41
|
}
|
|
33
42
|
/**
|
|
@@ -41,7 +50,6 @@ export async function clearAllLocalSyncLog() {
|
|
|
41
50
|
* return {
|
|
42
51
|
* table_name: "users",
|
|
43
52
|
* last_synced_at: "2021-01-01T00:00:00.000Z",
|
|
44
|
-
* last_created_at: "2021-01-01T00:00:00.000Z",
|
|
45
53
|
* last_deleted_at: "2021-01-01T00:00:00.000Z",
|
|
46
54
|
* filter_key: "1234567890",
|
|
47
55
|
* filter_json: "[...]",
|
|
@@ -87,7 +95,7 @@ export async function setSyncLog(table, filters, opts) {
|
|
|
87
95
|
* @param table - Table to reset.
|
|
88
96
|
* @param filters - Optional filters for a scoped reset.
|
|
89
97
|
* @param scope - Field(s) to reset: "all" (default),
|
|
90
|
-
* "last_synced_at",
|
|
98
|
+
* "last_synced_at", or "last_deleted_at".
|
|
91
99
|
* @example
|
|
92
100
|
* await resetSyncLog("users", undefined, "all");
|
|
93
101
|
*/
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "supastash",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"main": "dist/index.js",
|
|
5
5
|
"types": "dist/index.d.ts",
|
|
6
6
|
"type": "module",
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
"@types/better-sqlite3": "^7.6.13",
|
|
27
27
|
"@types/jest": "^29.5.14",
|
|
28
28
|
"@types/node": "^22.15.21",
|
|
29
|
-
"@types/react-native-sqlite-storage": "
|
|
29
|
+
"@types/react-native-sqlite-storage": "^6.0.5",
|
|
30
30
|
"better-sqlite3": "^11.10.0",
|
|
31
31
|
"jest": "^29.7.0",
|
|
32
32
|
"ts-jest": "^29.4.1",
|