mnfst 0.5.246 → 0.5.248
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/lib/manifest.appwrite.data.js +230 -147
- package/lib/manifest.data.js +157 -31
- package/lib/manifest.integrity.json +4 -4
- package/lib/manifest.js +2 -2
- package/lib/manifest.schema.json +417 -97
- package/lib/manifest.sw.js +1 -1
- package/package.json +1 -1
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
(function () {
|
|
4
4
|
|
|
5
|
-
const MANIFEST_BUILD_VERSION = '0.5.
|
|
5
|
+
const MANIFEST_BUILD_VERSION = '0.5.248';
|
|
6
6
|
|
|
7
7
|
/* Manifest Data Sources - Appwrite Integration */
|
|
8
8
|
|
|
@@ -91,6 +91,20 @@ async function initializeAppwriteClient() {
|
|
|
91
91
|
return appwriteClientPromise;
|
|
92
92
|
}
|
|
93
93
|
|
|
94
|
+
// Shared Realtime: ONE instance (one socket) per tab, keyed to the client it
|
|
95
|
+
// wraps. Auth identity events drop it (below) so the next use rebuilds against
|
|
96
|
+
// the current session; manifest.data.realtime.js re-binds live channels.
|
|
97
|
+
let realtimeCache = null;
|
|
98
|
+
let realtimeClient = null;
|
|
99
|
+
function getSharedRealtime(client) {
|
|
100
|
+
if (!client || !window.Appwrite?.Realtime) return null;
|
|
101
|
+
if (!realtimeCache || realtimeClient !== client) {
|
|
102
|
+
realtimeCache = new window.Appwrite.Realtime(client);
|
|
103
|
+
realtimeClient = client;
|
|
104
|
+
}
|
|
105
|
+
return realtimeCache;
|
|
106
|
+
}
|
|
107
|
+
|
|
94
108
|
// Get Appwrite data services (TablesDB, Storage, Realtime)
|
|
95
109
|
// Works with or without auth plugin
|
|
96
110
|
async function getAppwriteDataServices() {
|
|
@@ -102,7 +116,7 @@ async function getAppwriteDataServices() {
|
|
|
102
116
|
return {
|
|
103
117
|
tablesDB: window.Appwrite.TablesDB ? new window.Appwrite.TablesDB(client) : null,
|
|
104
118
|
storage: window.Appwrite.Storage ? new window.Appwrite.Storage(client) : null,
|
|
105
|
-
realtime:
|
|
119
|
+
realtime: getSharedRealtime(client)
|
|
106
120
|
};
|
|
107
121
|
}
|
|
108
122
|
|
|
@@ -110,7 +124,10 @@ async function getAppwriteDataServices() {
|
|
|
110
124
|
let authCheck = null;
|
|
111
125
|
let authVerified = false;
|
|
112
126
|
['manifest:auth:login', 'manifest:auth:logout', 'manifest:auth:anonymous', 'manifest:auth:session-cleared', 'manifest:auth:initialized']
|
|
113
|
-
.forEach(type => window.addEventListener(type, () => {
|
|
127
|
+
.forEach(type => window.addEventListener(type, () => {
|
|
128
|
+
authCheck = null; authVerified = false;
|
|
129
|
+
realtimeCache = null; realtimeClient = null; // socket re-authenticates as the new identity
|
|
130
|
+
}));
|
|
114
131
|
|
|
115
132
|
async function verifyAuthenticated() {
|
|
116
133
|
if (!window.ManifestAppwriteAuthConfig || authVerified) return;
|
|
@@ -665,103 +682,89 @@ window.ManifestDataAppwrite = {
|
|
|
665
682
|
};
|
|
666
683
|
|
|
667
684
|
|
|
668
|
-
/* Manifest Data Sources - Real-time Subscriptions
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
685
|
+
/* Manifest Data Sources - Real-time Subscriptions
|
|
686
|
+
One shared Realtime client per tab; channels ref-counted across sources. */
|
|
687
|
+
|
|
688
|
+
// Map<channel, { refs, unsubscribe, handlers: Map<sourceName, handler> }>
|
|
689
|
+
const channels = new Map();
|
|
690
|
+
// Map<sourceName, { channel, token }> — token guards a stale unsubscribe closure
|
|
691
|
+
const sources = new Map();
|
|
692
|
+
// Map<sourceName, fn(eventType, row)> — pre-filters, run per event per source
|
|
693
|
+
const filters = new Map();
|
|
694
|
+
// Back-compat/debug surface: Map<sourceName, unsubscribeFunction>
|
|
695
|
+
const subscriptions = new Map();
|
|
696
|
+
// Instance the current channel subscriptions live on
|
|
697
|
+
let activeRealtime = null;
|
|
698
|
+
|
|
699
|
+
function classify(event) {
|
|
700
|
+
if (typeof event !== 'string') return null;
|
|
701
|
+
if (event.includes('create')) return 'create';
|
|
702
|
+
if (event.includes('update')) return 'update';
|
|
703
|
+
if (event.includes('delete')) return 'delete';
|
|
704
|
+
return null;
|
|
705
|
+
}
|
|
672
706
|
|
|
673
|
-
//
|
|
674
|
-
//
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
if (
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
707
|
+
// Fan one SDK message out: each registered source handler gets each event once,
|
|
708
|
+
// after that source's pre-filter (setFilter) — before any merge/dedup work
|
|
709
|
+
function dispatch(channel, response) {
|
|
710
|
+
const entry = channels.get(channel);
|
|
711
|
+
if (!entry || !response || !response.events) return;
|
|
712
|
+
const events = Array.isArray(response.events) ? response.events : [response.events];
|
|
713
|
+
let payload = response.payload;
|
|
714
|
+
if (!payload || (!payload.$id && !payload.row)) payload = response;
|
|
715
|
+
for (const event of events) {
|
|
716
|
+
const type = classify(event);
|
|
717
|
+
if (!type) continue;
|
|
718
|
+
for (const [name, handler] of entry.handlers) {
|
|
719
|
+
const filter = filters.get(name);
|
|
720
|
+
if (filter && filter(type, payload) === false) continue;
|
|
721
|
+
handler(type, payload);
|
|
681
722
|
}
|
|
682
|
-
subscriptions.delete(dataSourceName);
|
|
683
723
|
}
|
|
724
|
+
}
|
|
684
725
|
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
if (!services?.realtime) {
|
|
688
|
-
console.warn('[Manifest Data] Realtime service not available for', dataSourceName);
|
|
689
|
-
return null;
|
|
690
|
-
}
|
|
691
|
-
|
|
692
|
-
// Channel format: buckets.[BUCKET_ID].files
|
|
693
|
-
const channel = `buckets.${bucketId}.files`;
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
try {
|
|
697
|
-
const unsubscribe = services.realtime.subscribe(channel, (response) => {
|
|
698
|
-
if (!response || !response.events) {
|
|
699
|
-
return;
|
|
700
|
-
}
|
|
701
|
-
|
|
702
|
-
// Handle both array and single event formats
|
|
703
|
-
const events = Array.isArray(response.events) ? response.events : [response.events];
|
|
704
|
-
|
|
705
|
-
events.forEach(event => {
|
|
706
|
-
if (typeof event !== 'string') return;
|
|
707
|
-
|
|
708
|
-
// Payload might be in response.payload or response directly
|
|
709
|
-
const payload = response.payload || response;
|
|
710
|
-
|
|
711
|
-
// Handle different event types
|
|
712
|
-
if (event.includes('create') || event.includes('storage.files.create')) {
|
|
713
|
-
// New file created
|
|
714
|
-
onEvent('create', payload);
|
|
715
|
-
} else if (event.includes('update') || event.includes('storage.files.update')) {
|
|
716
|
-
// File updated
|
|
717
|
-
onEvent('update', payload);
|
|
718
|
-
} else if (event.includes('delete') || event.includes('storage.files.delete')) {
|
|
719
|
-
// File deleted
|
|
720
|
-
onEvent('delete', payload);
|
|
721
|
-
}
|
|
722
|
-
});
|
|
723
|
-
});
|
|
724
|
-
|
|
725
|
-
subscriptions.set(dataSourceName, unsubscribe);
|
|
726
|
-
|
|
727
|
-
return unsubscribe;
|
|
728
|
-
} catch (error) {
|
|
729
|
-
console.error('[Manifest Data] Failed to subscribe to storage bucket:', error);
|
|
730
|
-
return null;
|
|
731
|
-
}
|
|
726
|
+
function sdkSubscribe(realtime, channel) {
|
|
727
|
+
return realtime.subscribe(channel, response => dispatch(channel, response));
|
|
732
728
|
}
|
|
733
729
|
|
|
734
|
-
//
|
|
735
|
-
function
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
730
|
+
// Drop a source's registration; tear the channel down when the last source leaves
|
|
731
|
+
function detach(name, token) {
|
|
732
|
+
const cur = sources.get(name);
|
|
733
|
+
if (!cur || (token && cur.token !== token)) return;
|
|
734
|
+
sources.delete(name);
|
|
735
|
+
const entry = channels.get(cur.channel);
|
|
736
|
+
if (!entry) return;
|
|
737
|
+
entry.handlers.delete(name);
|
|
738
|
+
entry.refs = entry.handlers.size;
|
|
739
|
+
if (entry.refs === 0) {
|
|
740
|
+
channels.delete(cur.channel);
|
|
741
|
+
if (typeof entry.unsubscribe === 'function') {
|
|
742
|
+
try { entry.unsubscribe(); } catch (e) { /* socket already gone */ }
|
|
740
743
|
}
|
|
741
|
-
subscriptions.delete(dataSourceName);
|
|
742
744
|
}
|
|
743
745
|
}
|
|
744
746
|
|
|
745
|
-
//
|
|
746
|
-
function
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
747
|
+
// Instance changed (client rebuilt on identity change): re-bind live channels
|
|
748
|
+
function syncInstance(realtime) {
|
|
749
|
+
if (activeRealtime === realtime) return;
|
|
750
|
+
activeRealtime = realtime;
|
|
751
|
+
for (const [channel, entry] of channels) {
|
|
752
|
+
if (typeof entry.unsubscribe === 'function') {
|
|
753
|
+
try { entry.unsubscribe(); } catch (e) { /* old instance */ }
|
|
750
754
|
}
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
}
|
|
754
|
-
|
|
755
|
-
// Subscribe to database table row changes
|
|
756
|
-
async function subscribeToTable(dataSourceName, databaseId, tableId, scope, onEvent, isCurrent) {
|
|
757
|
-
// Unsubscribe from existing subscription if any
|
|
758
|
-
if (subscriptions.has(dataSourceName)) {
|
|
759
|
-
const unsubscribe = subscriptions.get(dataSourceName);
|
|
760
|
-
if (unsubscribe && typeof unsubscribe === 'function') {
|
|
761
|
-
unsubscribe();
|
|
755
|
+
try {
|
|
756
|
+
entry.unsubscribe = sdkSubscribe(realtime, channel);
|
|
757
|
+
} catch (error) {
|
|
758
|
+
console.error('[Manifest Data] Failed to re-subscribe channel:', channel, error);
|
|
762
759
|
}
|
|
763
|
-
subscriptions.delete(dataSourceName);
|
|
764
760
|
}
|
|
761
|
+
}
|
|
762
|
+
|
|
763
|
+
// One SDK subscribe per distinct channel, however many sources share it.
|
|
764
|
+
// isCurrent: false once the requesting load is superseded (logout) — skip, never touch a newer entry
|
|
765
|
+
async function subscribeChannel(dataSourceName, channel, onEvent, isCurrent) {
|
|
766
|
+
detach(dataSourceName);
|
|
767
|
+
subscriptions.delete(dataSourceName);
|
|
765
768
|
|
|
766
769
|
const services = await window.ManifestDataAppwrite.getAppwriteDataServices();
|
|
767
770
|
if (isCurrent && !isCurrent()) return null;
|
|
@@ -769,55 +772,67 @@ async function subscribeToTable(dataSourceName, databaseId, tableId, scope, onEv
|
|
|
769
772
|
console.warn('[Manifest Data] Realtime service not available for', dataSourceName);
|
|
770
773
|
return null;
|
|
771
774
|
}
|
|
775
|
+
syncInstance(services.realtime);
|
|
772
776
|
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
777
|
+
let entry = channels.get(channel);
|
|
778
|
+
if (!entry) {
|
|
779
|
+
entry = { refs: 0, unsubscribe: null, handlers: new Map() };
|
|
780
|
+
try {
|
|
781
|
+
entry.unsubscribe = sdkSubscribe(services.realtime, channel);
|
|
782
|
+
} catch (error) {
|
|
783
|
+
console.error('[Manifest Data] Failed to subscribe:', channel, error);
|
|
784
|
+
return null;
|
|
785
|
+
}
|
|
786
|
+
channels.set(channel, entry);
|
|
787
|
+
}
|
|
788
|
+
const token = Symbol(dataSourceName);
|
|
789
|
+
entry.handlers.set(dataSourceName, onEvent);
|
|
790
|
+
entry.refs = entry.handlers.size;
|
|
791
|
+
sources.set(dataSourceName, { channel, token });
|
|
781
792
|
|
|
782
|
-
|
|
783
|
-
|
|
793
|
+
const unsubscribe = () => detach(dataSourceName, token);
|
|
794
|
+
subscriptions.set(dataSourceName, unsubscribe);
|
|
795
|
+
return unsubscribe;
|
|
796
|
+
}
|
|
784
797
|
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
798
|
+
// Subscribe to storage bucket file changes
|
|
799
|
+
function subscribeToStorageBucket(dataSourceName, bucketId, scope, onEvent, isCurrent) {
|
|
800
|
+
return subscribeChannel(dataSourceName, `buckets.${bucketId}.files`, onEvent, isCurrent);
|
|
801
|
+
}
|
|
789
802
|
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
803
|
+
// Subscribe to database table row changes
|
|
804
|
+
function subscribeToTable(dataSourceName, databaseId, tableId, scope, onEvent, isCurrent) {
|
|
805
|
+
return subscribeChannel(dataSourceName, `databases.${databaseId}.tables.${tableId}.rows`, onEvent, isCurrent);
|
|
806
|
+
}
|
|
793
807
|
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
808
|
+
// Unsubscribe from a data source
|
|
809
|
+
function unsubscribeFromDataSource(dataSourceName) {
|
|
810
|
+
detach(dataSourceName);
|
|
811
|
+
subscriptions.delete(dataSourceName);
|
|
812
|
+
}
|
|
798
813
|
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
// Row updated
|
|
805
|
-
onEvent('update', payload);
|
|
806
|
-
} else if (event.includes('delete') || event.includes('rows.delete') || event.includes('documents.delete')) {
|
|
807
|
-
// Row deleted
|
|
808
|
-
onEvent('delete', payload);
|
|
809
|
-
} else {
|
|
810
|
-
}
|
|
811
|
-
});
|
|
812
|
-
});
|
|
814
|
+
// Unsubscribe from all data sources
|
|
815
|
+
function unsubscribeAll() {
|
|
816
|
+
for (const name of [...sources.keys()]) detach(name);
|
|
817
|
+
subscriptions.clear();
|
|
818
|
+
}
|
|
813
819
|
|
|
814
|
-
|
|
820
|
+
// Programmatic pre-filter: fn(eventType, row) runs per event per source BEFORE
|
|
821
|
+
// any merge/dedup work; returning false drops the event. null clears it.
|
|
822
|
+
function setFilter(sourceName, fn) {
|
|
823
|
+
if (fn == null) filters.delete(sourceName);
|
|
824
|
+
else if (typeof fn === 'function') filters.set(sourceName, fn);
|
|
825
|
+
}
|
|
815
826
|
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
827
|
+
// Identity events rebuild the shared Realtime (manifest.data.appwrite.js drops
|
|
828
|
+
// its memo on the same events); re-bind any live channels to the new instance
|
|
829
|
+
if (typeof window !== 'undefined') {
|
|
830
|
+
['manifest:auth:login', 'manifest:auth:logout', 'manifest:auth:anonymous', 'manifest:auth:session-cleared', 'manifest:auth:initialized']
|
|
831
|
+
.forEach(type => window.addEventListener(type, async () => {
|
|
832
|
+
if (!channels.size) return;
|
|
833
|
+
const services = await window.ManifestDataAppwrite?.getAppwriteDataServices?.();
|
|
834
|
+
if (services?.realtime) syncInstance(services.realtime);
|
|
835
|
+
}));
|
|
821
836
|
}
|
|
822
837
|
|
|
823
838
|
// Export functions
|
|
@@ -826,7 +841,9 @@ window.ManifestDataRealtime = {
|
|
|
826
841
|
subscribeToTable,
|
|
827
842
|
unsubscribeFromDataSource,
|
|
828
843
|
unsubscribeAll,
|
|
829
|
-
|
|
844
|
+
setFilter,
|
|
845
|
+
subscriptions, // Expose for debugging
|
|
846
|
+
_channels: channels // Expose for debugging
|
|
830
847
|
};
|
|
831
848
|
|
|
832
849
|
|
|
@@ -1186,6 +1203,86 @@ async function buildQueries(queriesConfig, scope, scopeColumns) {
|
|
|
1186
1203
|
return [...scopeQueries, ...userQueries];
|
|
1187
1204
|
}
|
|
1188
1205
|
|
|
1206
|
+
// Query methods buildAppwriteQueries serializes (anything else is dropped at
|
|
1207
|
+
// load and must therefore never drop rows in the realtime matcher below)
|
|
1208
|
+
const QUERY_MAP = {
|
|
1209
|
+
'equal': 'equal',
|
|
1210
|
+
'notEqual': 'notEqual',
|
|
1211
|
+
'lessThan': 'lessThan',
|
|
1212
|
+
'lessThanEqual': 'lessThanEqual',
|
|
1213
|
+
'greaterThan': 'greaterThan',
|
|
1214
|
+
'greaterThanEqual': 'greaterThanEqual',
|
|
1215
|
+
'contains': 'contains',
|
|
1216
|
+
'search': 'search',
|
|
1217
|
+
'or': 'or', // Support for multi-team queries (Query.or([Query.equal(...), ...]))
|
|
1218
|
+
'orderAsc': 'orderAsc',
|
|
1219
|
+
'orderDesc': 'orderDesc',
|
|
1220
|
+
'limit': 'limit',
|
|
1221
|
+
'offset': 'offset',
|
|
1222
|
+
'cursorAfter': 'cursorAfter',
|
|
1223
|
+
'cursorBefore': 'cursorBefore'
|
|
1224
|
+
};
|
|
1225
|
+
|
|
1226
|
+
// Client-side row matcher for realtime events: evaluates a source's configured
|
|
1227
|
+
// filter queries against one row. Only operators the load actually serializes
|
|
1228
|
+
// (QUERY_MAP) are evaluable. Liveness over precision: anything unevaluable —
|
|
1229
|
+
// search, an operator the load drops, or a $auth. arg that can't resolve
|
|
1230
|
+
// synchronously — counts as a MATCH so live events are never silently dropped.
|
|
1231
|
+
const NON_FILTER_METHODS = new Set(['limit', 'offset', 'orderAsc', 'orderDesc', 'select', 'cursorAfter', 'cursorBefore']);
|
|
1232
|
+
|
|
1233
|
+
function rowMatchesQueries(row, queriesConfig) {
|
|
1234
|
+
if (!row || !Array.isArray(queriesConfig) || queriesConfig.length === 0) return true;
|
|
1235
|
+
return queriesConfig.every(query => matchQuery(row, query));
|
|
1236
|
+
}
|
|
1237
|
+
|
|
1238
|
+
function matchQuery(row, query) {
|
|
1239
|
+
if (!Array.isArray(query) || query.length === 0) return true;
|
|
1240
|
+
let interpolated;
|
|
1241
|
+
try {
|
|
1242
|
+
interpolated = interpolateQuery(query);
|
|
1243
|
+
} catch (e) {
|
|
1244
|
+
if (e === NOT_READY) return true; // unresolved $auth. arg
|
|
1245
|
+
throw e;
|
|
1246
|
+
}
|
|
1247
|
+
const [method, ...args] = interpolated;
|
|
1248
|
+
if (NON_FILTER_METHODS.has(method)) return true;
|
|
1249
|
+
if (!(method in QUERY_MAP)) return true; // load drops it: unevaluable
|
|
1250
|
+
if (method === 'and') return Array.isArray(args[0]) ? args[0].every(sub => matchQuery(row, sub)) : true;
|
|
1251
|
+
if (method === 'or') return Array.isArray(args[0]) ? args[0].some(sub => matchQuery(row, sub)) : true;
|
|
1252
|
+
|
|
1253
|
+
const attr = args[0];
|
|
1254
|
+
const val = row ? row[attr] : undefined;
|
|
1255
|
+
const values = Array.isArray(args[1]) ? args[1] : [args[1]];
|
|
1256
|
+
// Strings compare case-insensitively (Appwrite's ci collation); other types strictly
|
|
1257
|
+
const eq = (a, b) => (typeof a === 'string' && typeof b === 'string')
|
|
1258
|
+
? a.toLowerCase() === b.toLowerCase()
|
|
1259
|
+
: a === b;
|
|
1260
|
+
const anyEqual = () => Array.isArray(val)
|
|
1261
|
+
? values.some(v => val.some(el => eq(el, v)))
|
|
1262
|
+
: values.some(v => eq(val, v));
|
|
1263
|
+
const cmp = (bound, op) => val !== null && val !== undefined && bound !== null && bound !== undefined && op(val, bound);
|
|
1264
|
+
const lower = s => String(s).toLowerCase();
|
|
1265
|
+
|
|
1266
|
+
switch (method) {
|
|
1267
|
+
case 'equal': return anyEqual();
|
|
1268
|
+
case 'notEqual': return !anyEqual();
|
|
1269
|
+
case 'lessThan': return cmp(args[1], (a, b) => a < b);
|
|
1270
|
+
case 'lessThanEqual': return cmp(args[1], (a, b) => a <= b);
|
|
1271
|
+
case 'greaterThan': return cmp(args[1], (a, b) => a > b);
|
|
1272
|
+
case 'greaterThanEqual': return cmp(args[1], (a, b) => a >= b);
|
|
1273
|
+
case 'between': return cmp(args[1], (a, b) => a >= b) && cmp(args[2], (a, b) => a <= b);
|
|
1274
|
+
case 'isNull': return val === null || val === undefined;
|
|
1275
|
+
case 'isNotNull': return val !== null && val !== undefined;
|
|
1276
|
+
case 'startsWith': return typeof val === 'string' && values.some(v => lower(val).startsWith(lower(v)));
|
|
1277
|
+
case 'endsWith': return typeof val === 'string' && values.some(v => lower(val).endsWith(lower(v)));
|
|
1278
|
+
case 'contains':
|
|
1279
|
+
if (Array.isArray(val)) return values.some(v => val.some(el => eq(el, v)));
|
|
1280
|
+
if (typeof val === 'string') return values.some(v => lower(val).includes(lower(v)));
|
|
1281
|
+
return false;
|
|
1282
|
+
default: return true; // search: unevaluable
|
|
1283
|
+
}
|
|
1284
|
+
}
|
|
1285
|
+
|
|
1189
1286
|
// Convert query array to Appwrite Query object
|
|
1190
1287
|
function toAppwriteQuery(queryArray) {
|
|
1191
1288
|
if (!Array.isArray(queryArray) || queryArray.length === 0) {
|
|
@@ -1194,24 +1291,9 @@ function toAppwriteQuery(queryArray) {
|
|
|
1194
1291
|
|
|
1195
1292
|
const [method, ...args] = queryArray;
|
|
1196
1293
|
|
|
1197
|
-
// Map common query methods to Appwrite Query methods
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
'notEqual': 'notEqual',
|
|
1201
|
-
'lessThan': 'lessThan',
|
|
1202
|
-
'lessThanEqual': 'lessThanEqual',
|
|
1203
|
-
'greaterThan': 'greaterThan',
|
|
1204
|
-
'greaterThanEqual': 'greaterThanEqual',
|
|
1205
|
-
'contains': 'contains',
|
|
1206
|
-
'search': 'search',
|
|
1207
|
-
'or': 'or', // Support for multi-team queries (Query.or([Query.equal(...), ...]))
|
|
1208
|
-
'orderAsc': 'orderAsc',
|
|
1209
|
-
'orderDesc': 'orderDesc',
|
|
1210
|
-
'limit': 'limit',
|
|
1211
|
-
'offset': 'offset',
|
|
1212
|
-
'cursorAfter': 'cursorAfter',
|
|
1213
|
-
'cursorBefore': 'cursorBefore'
|
|
1214
|
-
};
|
|
1294
|
+
// Map common query methods to Appwrite Query methods (QUERY_MAP above —
|
|
1295
|
+
// also the realtime matcher's evaluable set)
|
|
1296
|
+
const queryMap = QUERY_MAP;
|
|
1215
1297
|
|
|
1216
1298
|
if (!window.Appwrite || !window.Appwrite.Query) {
|
|
1217
1299
|
console.error('[Manifest Data] Appwrite Query not available');
|
|
@@ -1271,6 +1353,7 @@ window.ManifestDataQueries = {
|
|
|
1271
1353
|
getAuthValue,
|
|
1272
1354
|
buildQueries,
|
|
1273
1355
|
buildAppwriteQueries,
|
|
1356
|
+
rowMatchesQueries,
|
|
1274
1357
|
toAppwriteQuery,
|
|
1275
1358
|
ALLOWED_VARIABLES,
|
|
1276
1359
|
DEFAULT_SCOPE_COLUMNS
|