Skip to content

Commit 8746f50

Browse files
Merge remote-tracking branch 'origin/main' into metadata-logs
2 parents 06847c6 + 57f7660 commit 8746f50

File tree

12 files changed

+831
-17
lines changed

12 files changed

+831
-17
lines changed

.changeset/khaki-toys-cheat.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
---
2+
'@powersync/service-module-postgres-storage': patch
3+
'@powersync/service-module-mongodb-storage': patch
4+
'@powersync/service-core-tests': patch
5+
'@powersync/service-core': patch
6+
'@powersync/service-types': patch
7+
---
8+
9+
General client connections analytics added
10+

.github/workflows/packages_release.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@ jobs:
2222
steps:
2323
- name: Checkout Repo
2424
uses: actions/checkout@v5
25+
with:
26+
# check out full history. development packages need this for changesets
27+
fetch-depth: 0
2528
- name: Enable Corepack
2629
run: corepack enable
2730
- name: Setup Node.js

modules/module-mongodb-storage/src/storage/MongoReportStorage.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { storage } from '@powersync/service-core';
22
import { event_types } from '@powersync/service-types';
33
import { PowerSyncMongo } from './implementation/db.js';
44
import { logger } from '@powersync/lib-services-framework';
5+
import { createPaginatedConnectionQuery } from '../utils/util.js';
56

67
export class MongoReportStorage implements storage.ReportStorage {
78
public readonly db: PowerSyncMongo;
@@ -43,6 +44,27 @@ export class MongoReportStorage implements storage.ReportStorage {
4344
return result[0];
4445
}
4546

47+
async getGeneralClientConnectionAnalytics(
48+
data: event_types.ClientConnectionAnalyticsRequest
49+
): Promise<event_types.PaginatedResponse<event_types.ClientConnection>> {
50+
const { cursor, date_range } = data;
51+
const limit = data?.limit || 100;
52+
53+
const connected_at = date_range ? { connected_at: { $lte: date_range.end, $gte: date_range.start } } : undefined;
54+
const user_id = data.user_id != null ? { user_id: data.user_id } : undefined;
55+
const client_id = data.client_id != null ? { client_id: data.client_id } : undefined;
56+
return (await createPaginatedConnectionQuery(
57+
{
58+
...client_id,
59+
...user_id,
60+
...connected_at
61+
},
62+
this.db.connection_report_events,
63+
limit,
64+
cursor
65+
)) as event_types.PaginatedResponse<event_types.ClientConnection>;
66+
}
67+
4668
async reportClientConnection(data: event_types.ClientConnectionBucketData): Promise<void> {
4769
const updateFilter = this.updateDocFilter(data.user_id, data.client_id!);
4870
await this.db.connection_report_events.findOneAndUpdate(

modules/module-mongodb-storage/src/utils/util.ts

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,3 +114,43 @@ export function setSessionSnapshotTime(session: mongo.ClientSession, time: bson.
114114
throw new ServiceAssertionError(`Session snapshotTime is already set`);
115115
}
116116
}
117+
118+
export const createPaginatedConnectionQuery = async <T extends mongo.Document>(
119+
query: mongo.Filter<T>,
120+
collection: mongo.Collection<T>,
121+
limit: number,
122+
cursor?: string
123+
) => {
124+
const createQuery = (cursor?: string) => {
125+
if (!cursor) {
126+
return query;
127+
}
128+
const connected_at = query.connected_at
129+
? { $lt: new Date(cursor), $gte: query.connected_at.$gte }
130+
: { $lt: new Date(cursor) };
131+
return {
132+
...query,
133+
connected_at
134+
} as mongo.Filter<T>;
135+
};
136+
137+
const findCursor = collection.find(createQuery(cursor), {
138+
sort: {
139+
/** We are sorting by connected at date descending to match cursor Postgres implementation */
140+
connected_at: -1
141+
}
142+
});
143+
144+
const items = await findCursor.limit(limit).toArray();
145+
const count = items.length;
146+
/** The returned total has been defaulted to 0 due to the overhead using documentCount from the mogo driver.
147+
* cursor.count has been deprecated.
148+
* */
149+
return {
150+
items,
151+
count,
152+
/** Setting the cursor to the connected at date of the last item in the list */
153+
cursor: count === limit ? items[items.length - 1].connected_at.toISOString() : undefined,
154+
more: !(count !== limit)
155+
};
156+
};

modules/module-mongodb-storage/test/src/__snapshots__/connection-report-storage.test.ts.snap

Lines changed: 238 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,13 @@
33
exports[`Connection reporting storage > Should create a connection report if its after a day 1`] = `
44
[
55
{
6-
"client_id": "client_week",
6+
"client_id": "client_one",
77
"sdk": "powersync-js/1.24.5",
88
"user_agent": "powersync-js/1.21.0 powersync-web Firefox/141 linux",
99
"user_id": "user_week",
1010
},
1111
{
12-
"client_id": "client_week",
12+
"client_id": "client_one",
1313
"sdk": "powersync-js/1.24.5",
1414
"user_agent": "powersync-js/1.21.0 powersync-web Firefox/141 linux",
1515
"user_id": "user_week",
@@ -213,3 +213,239 @@ exports[`Report storage tests > Should show currently connected users 1`] = `
213213
"users": 2,
214214
}
215215
`;
216+
217+
exports[`Report storage tests > Should show paginated response of all connections of specified client_id 1`] = `
218+
{
219+
"count": 1,
220+
"cursor": undefined,
221+
"items": [
222+
{
223+
"client_id": "client_two",
224+
"sdk": "powersync-js/1.21.1",
225+
"user_agent": "powersync-js/1.21.0 powersync-web Chromium/138 linux",
226+
"user_id": "user_two",
227+
},
228+
],
229+
"more": false,
230+
}
231+
`;
232+
233+
exports[`Report storage tests > Should show paginated response of all connections with a limit 1`] = `
234+
{
235+
"count": 4,
236+
"cursor": "<removed-for-snapshot>",
237+
"items": [
238+
{
239+
"client_id": "client_one",
240+
"sdk": "powersync-dart/1.6.4",
241+
"user_agent": "powersync-dart/1.6.4 Dart (flutter-web) Chrome/128 android",
242+
"user_id": "user_one",
243+
},
244+
{
245+
"client_id": "client_four",
246+
"sdk": "powersync-js/1.21.4",
247+
"user_agent": "powersync-js/1.21.0 powersync-web Firefox/141 linux",
248+
"user_id": "user_four",
249+
},
250+
{
251+
"client_id": "",
252+
"sdk": "unknown",
253+
"user_agent": "Dart (flutter-web) Chrome/128 android",
254+
"user_id": "user_one",
255+
},
256+
{
257+
"client_id": "client_two",
258+
"sdk": "powersync-js/1.21.1",
259+
"user_agent": "powersync-js/1.21.0 powersync-web Chromium/138 linux",
260+
"user_id": "user_two",
261+
},
262+
],
263+
"more": true,
264+
}
265+
`;
266+
267+
exports[`Report storage tests > Should show paginated response of all connections with a limit 2`] = `
268+
{
269+
"count": 4,
270+
"cursor": undefined,
271+
"items": [
272+
{
273+
"client_id": "client_three",
274+
"sdk": "powersync-js/1.21.2",
275+
"user_agent": "powersync-js/1.21.0 powersync-web Firefox/141 linux",
276+
"user_id": "user_three",
277+
},
278+
{
279+
"client_id": "client_one",
280+
"sdk": "powersync-js/1.24.5",
281+
"user_agent": "powersync-js/1.21.0 powersync-web Firefox/141 linux",
282+
"user_id": "user_week",
283+
},
284+
{
285+
"client_id": "client_month",
286+
"sdk": "powersync-js/1.23.6",
287+
"user_agent": "powersync-js/1.23.0 powersync-web Firefox/141 linux",
288+
"user_id": "user_month",
289+
},
290+
{
291+
"client_id": "client_expired",
292+
"sdk": "powersync-js/1.23.7",
293+
"user_agent": "powersync-js/1.23.0 powersync-web Firefox/141 linux",
294+
"user_id": "user_expired",
295+
},
296+
],
297+
"more": false,
298+
}
299+
`;
300+
301+
exports[`Report storage tests > Should show paginated response of all connections with a limit with date range 1`] = `
302+
{
303+
"count": 4,
304+
"cursor": "<removed-for-snapshot>",
305+
"items": [
306+
{
307+
"client_id": "",
308+
"sdk": "unknown",
309+
"user_agent": "Dart (flutter-web) Chrome/128 android",
310+
"user_id": "user_one",
311+
},
312+
{
313+
"client_id": "client_two",
314+
"sdk": "powersync-js/1.21.1",
315+
"user_agent": "powersync-js/1.21.0 powersync-web Chromium/138 linux",
316+
"user_id": "user_two",
317+
},
318+
{
319+
"client_id": "client_three",
320+
"sdk": "powersync-js/1.21.2",
321+
"user_agent": "powersync-js/1.21.0 powersync-web Firefox/141 linux",
322+
"user_id": "user_three",
323+
},
324+
{
325+
"client_id": "client_one",
326+
"sdk": "powersync-js/1.24.5",
327+
"user_agent": "powersync-js/1.21.0 powersync-web Firefox/141 linux",
328+
"user_id": "user_week",
329+
},
330+
],
331+
"more": true,
332+
}
333+
`;
334+
335+
exports[`Report storage tests > Should show paginated response of all connections with a limit with date range 2`] = `
336+
{
337+
"count": 2,
338+
"cursor": undefined,
339+
"items": [
340+
{
341+
"client_id": "",
342+
"sdk": "unknown",
343+
"user_agent": "Dart (flutter-web) Chrome/128 android",
344+
"user_id": "user_one",
345+
},
346+
{
347+
"client_id": "client_two",
348+
"sdk": "powersync-js/1.21.1",
349+
"user_agent": "powersync-js/1.21.0 powersync-web Chromium/138 linux",
350+
"user_id": "user_two",
351+
},
352+
{
353+
"client_id": "client_three",
354+
"sdk": "powersync-js/1.21.2",
355+
"user_agent": "powersync-js/1.21.0 powersync-web Firefox/141 linux",
356+
"user_id": "user_three",
357+
},
358+
{
359+
"client_id": "client_one",
360+
"sdk": "powersync-js/1.24.5",
361+
"user_agent": "powersync-js/1.21.0 powersync-web Firefox/141 linux",
362+
"user_id": "user_week",
363+
},
364+
],
365+
"more": false,
366+
}
367+
`;
368+
369+
exports[`Report storage tests > Should show paginated response of connections of specified user_id 1`] = `
370+
{
371+
"count": 2,
372+
"cursor": undefined,
373+
"items": [
374+
{
375+
"client_id": "client_one",
376+
"sdk": "powersync-dart/1.6.4",
377+
"user_agent": "powersync-dart/1.6.4 Dart (flutter-web) Chrome/128 android",
378+
"user_id": "user_one",
379+
},
380+
{
381+
"client_id": "",
382+
"sdk": "unknown",
383+
"user_agent": "Dart (flutter-web) Chrome/128 android",
384+
"user_id": "user_one",
385+
},
386+
],
387+
"more": false,
388+
}
389+
`;
390+
391+
exports[`Report storage tests > Should show paginated response of connections over a date range 1`] = `
392+
{
393+
"count": 6,
394+
"cursor": undefined,
395+
"items": [
396+
{
397+
"client_id": "client_one",
398+
"sdk": "powersync-dart/1.6.4",
399+
"user_agent": "powersync-dart/1.6.4 Dart (flutter-web) Chrome/128 android",
400+
"user_id": "user_one",
401+
},
402+
{
403+
"client_id": "client_four",
404+
"sdk": "powersync-js/1.21.4",
405+
"user_agent": "powersync-js/1.21.0 powersync-web Firefox/141 linux",
406+
"user_id": "user_four",
407+
},
408+
{
409+
"client_id": "client_two",
410+
"sdk": "powersync-js/1.21.1",
411+
"user_agent": "powersync-js/1.21.0 powersync-web Chromium/138 linux",
412+
"user_id": "user_two",
413+
},
414+
{
415+
"client_id": "",
416+
"sdk": "unknown",
417+
"user_agent": "Dart (flutter-web) Chrome/128 android",
418+
"user_id": "user_one",
419+
},
420+
{
421+
"client_id": "client_three",
422+
"sdk": "powersync-js/1.21.2",
423+
"user_agent": "powersync-js/1.21.0 powersync-web Firefox/141 linux",
424+
"user_id": "user_three",
425+
},
426+
{
427+
"client_id": "client_one",
428+
"sdk": "powersync-js/1.24.5",
429+
"user_agent": "powersync-js/1.21.0 powersync-web Firefox/141 linux",
430+
"user_id": "user_week",
431+
},
432+
],
433+
"more": false,
434+
}
435+
`;
436+
437+
exports[`Report storage tests > Should show paginated response of connections over a date range of specified client_id and user_id 1`] = `
438+
{
439+
"count": 1,
440+
"cursor": undefined,
441+
"items": [
442+
{
443+
"client_id": "client_one",
444+
"sdk": "powersync-dart/1.6.4",
445+
"user_agent": "powersync-dart/1.6.4 Dart (flutter-web) Chrome/128 android",
446+
"user_id": "user_one",
447+
},
448+
],
449+
"more": false,
450+
}
451+
`;

modules/module-postgres-storage/package.json

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,16 +17,16 @@
1717
},
1818
"exports": {
1919
".": {
20+
"types": "./dist/@types/index.d.ts",
2021
"import": "./dist/index.js",
2122
"require": "./dist/index.js",
22-
"default": "./dist/index.js",
23-
"types": "./dist/@types/index.d.ts"
23+
"default": "./dist/index.js"
2424
},
2525
"./types": {
26+
"types": "./dist/@types/index.d.ts",
2627
"import": "./dist/types/types.js",
2728
"require": "./dist/types/types.js",
28-
"default": "./dist/types/types.js",
29-
"types": "./dist/@types/index.d.ts"
29+
"default": "./dist/types/types.js"
3030
}
3131
},
3232
"dependencies": {

0 commit comments

Comments
 (0)