@flowerforce/flowerbase 1.7.5-beta.5 → 1.7.5-beta.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.
@@ -1 +1 @@
1
- {"version":3,"file":"collections.d.ts","sourceRoot":"","sources":["../../../src/monitoring/routes/collections.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAA;AAK9C,OAAO,EAGL,qBAAqB,EAMtB,MAAM,UAAU,CAAA;AAEjB,MAAM,MAAM,oBAAoB,GAAG;IACjC,MAAM,EAAE,MAAM,CAAA;IACd,iBAAiB,EAAE,qBAAqB,EAAE,CAAA;IAC1C,oBAAoB,EAAE,MAAM,CAAA;IAC5B,oBAAoB,EAAE,CAAC,KAAK,EAAE,qBAAqB,KAAK,IAAI,CAAA;CAC7D,CAAA;AAED,eAAO,MAAM,wBAAwB,GAAI,KAAK,eAAe,EAAE,MAAM,oBAAoB,SAkMxF,CAAA"}
1
+ {"version":3,"file":"collections.d.ts","sourceRoot":"","sources":["../../../src/monitoring/routes/collections.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAA;AAK9C,OAAO,EAGL,qBAAqB,EAMtB,MAAM,UAAU,CAAA;AAEjB,MAAM,MAAM,oBAAoB,GAAG;IACjC,MAAM,EAAE,MAAM,CAAA;IACd,iBAAiB,EAAE,qBAAqB,EAAE,CAAA;IAC1C,oBAAoB,EAAE,MAAM,CAAA;IAC5B,oBAAoB,EAAE,CAAC,KAAK,EAAE,qBAAqB,KAAK,IAAI,CAAA;CAC7D,CAAA;AAED,eAAO,MAAM,wBAAwB,GAAI,KAAK,eAAe,EAAE,MAAM,oBAAoB,SAqSxF,CAAA"}
@@ -193,5 +193,94 @@ const registerCollectionRoutes = (app, deps) => {
193
193
  return { error: details.message, stack: details.stack };
194
194
  }
195
195
  }));
196
+ app.post(`${prefix}/api/collections/insert`, (req, reply) => __awaiter(void 0, void 0, void 0, function* () {
197
+ const body = req.body;
198
+ const collection = body === null || body === void 0 ? void 0 : body.collection;
199
+ if (!collection) {
200
+ reply.code(400);
201
+ return { error: 'Missing collection name' };
202
+ }
203
+ const mode = (body === null || body === void 0 ? void 0 : body.mode) === 'insertMany' ? 'insertMany' : 'insertOne';
204
+ if (mode === 'insertOne') {
205
+ if (!(0, utils_1.isPlainObject)(body === null || body === void 0 ? void 0 : body.document)) {
206
+ reply.code(400);
207
+ return { error: 'Document must be an object' };
208
+ }
209
+ }
210
+ else {
211
+ if (!Array.isArray(body === null || body === void 0 ? void 0 : body.documents) || !body.documents.length) {
212
+ reply.code(400);
213
+ return { error: 'Documents must be a non-empty array' };
214
+ }
215
+ const invalid = body.documents.some((entry) => !(0, utils_1.isPlainObject)(entry));
216
+ if (invalid) {
217
+ reply.code(400);
218
+ return { error: 'Every document must be an object' };
219
+ }
220
+ }
221
+ const rules = state_1.StateManager.select('rules');
222
+ const services = state_1.StateManager.select('services');
223
+ const resolvedUser = yield (0, utils_1.resolveUserContext)(app, body === null || body === void 0 ? void 0 : body.userId);
224
+ const runAsSystem = (body === null || body === void 0 ? void 0 : body.runAsSystem) !== false;
225
+ const recordHistory = (body === null || body === void 0 ? void 0 : body.recordHistory) !== false;
226
+ try {
227
+ const mongoService = services['mongodb-atlas'](app, {
228
+ rules,
229
+ user: resolvedUser !== null && resolvedUser !== void 0 ? resolvedUser : {},
230
+ run_as_system: runAsSystem
231
+ });
232
+ const collectionService = mongoService.db(constants_1.DB_NAME).collection(collection);
233
+ if (mode === 'insertMany') {
234
+ const documents = body.documents;
235
+ const result = yield collectionService.insertMany(documents);
236
+ const insertedIds = Array.isArray(result === null || result === void 0 ? void 0 : result.insertedIds)
237
+ ? result.insertedIds
238
+ : Object.values((result === null || result === void 0 ? void 0 : result.insertedIds) || {});
239
+ if (recordHistory) {
240
+ addCollectionHistory({
241
+ ts: Date.now(),
242
+ collection,
243
+ mode: 'insertMany',
244
+ documents: (0, utils_1.sanitize)(documents),
245
+ runAsSystem,
246
+ user: (0, utils_1.getUserInfo)(resolvedUser),
247
+ page: 1
248
+ });
249
+ }
250
+ return {
251
+ mode: 'insertMany',
252
+ acknowledged: !!(result === null || result === void 0 ? void 0 : result.acknowledged),
253
+ insertedCount: insertedIds.length,
254
+ insertedIds: (0, utils_1.sanitize)(insertedIds),
255
+ count: insertedIds.length
256
+ };
257
+ }
258
+ const document = body.document;
259
+ const result = yield collectionService.insertOne(document);
260
+ const insertedId = result === null || result === void 0 ? void 0 : result.insertedId;
261
+ if (recordHistory) {
262
+ addCollectionHistory({
263
+ ts: Date.now(),
264
+ collection,
265
+ mode: 'insertOne',
266
+ document: (0, utils_1.sanitize)(document),
267
+ runAsSystem,
268
+ user: (0, utils_1.getUserInfo)(resolvedUser),
269
+ page: 1
270
+ });
271
+ }
272
+ return {
273
+ mode: 'insertOne',
274
+ acknowledged: !!(result === null || result === void 0 ? void 0 : result.acknowledged),
275
+ insertedId: (0, utils_1.sanitize)(insertedId),
276
+ count: insertedId ? 1 : 0
277
+ };
278
+ }
279
+ catch (error) {
280
+ const details = (0, utils_1.getErrorDetails)(error);
281
+ reply.code(500);
282
+ return { error: details.message, stack: details.stack };
283
+ }
284
+ }));
196
285
  };
197
286
  exports.registerCollectionRoutes = registerCollectionRoutes;
@@ -23,9 +23,11 @@ export type FunctionHistoryItem = {
23
23
  export type CollectionHistoryItem = {
24
24
  ts: number;
25
25
  collection: string;
26
- mode: 'query' | 'aggregate';
26
+ mode: 'query' | 'aggregate' | 'insertOne' | 'insertMany';
27
27
  query?: unknown;
28
28
  pipeline?: unknown;
29
+ document?: unknown;
30
+ documents?: unknown;
29
31
  sort?: Record<string, unknown>;
30
32
  runAsSystem: boolean;
31
33
  user?: {
@@ -1 +1 @@
1
- {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/monitoring/utils.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/monitoring/utils.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/services/mongodb-atlas/index.ts"],"names":[],"mappings":"AAwBA,OAAO,EAGL,oBAAoB,EAErB,MAAM,SAAS,CAAA;AAk1ChB,QAAA,MAAM,YAAY,EAAE,oBA6BlB,CAAA;AAEF,eAAe,YAAY,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/services/mongodb-atlas/index.ts"],"names":[],"mappings":"AAwBA,OAAO,EAGL,oBAAoB,EAErB,MAAM,SAAS,CAAA;AAm0ChB,QAAA,MAAM,YAAY,EAAE,oBA6BlB,CAAA;AAEF,eAAe,YAAY,CAAA"}
@@ -908,20 +908,8 @@ const getOperators = (collection, { rules, collName, user, run_as_system, monito
908
908
  // Override the .on() method to apply validation before emitting events
909
909
  result.on = (eventType, listener) => {
910
910
  return originalOn(eventType, (change) => __awaiter(void 0, void 0, void 0, function* () {
911
- var _a, _b, _c, _d;
912
911
  const { document, updatedFieldsStatus, updatedFields, hasFullDocument, hasWinningRole } = yield isValidChange(change);
913
912
  const filteredChange = Object.assign(Object.assign({}, change), { fullDocument: document, updateDescription: Object.assign(Object.assign({}, change.updateDescription), { updatedFields: updatedFieldsStatus ? updatedFields : {} }) });
914
- console.log('[flowerbase watch] delivered change', {
915
- collection: collName,
916
- operationType: change === null || change === void 0 ? void 0 : change.operationType,
917
- eventType,
918
- hasFullDocument,
919
- hasWinningRole,
920
- updatedFieldsStatus,
921
- documentKey: ((_c = (_b = (_a = change === null || change === void 0 ? void 0 : change.documentKey) === null || _a === void 0 ? void 0 : _a._id) === null || _b === void 0 ? void 0 : _b.toString) === null || _c === void 0 ? void 0 : _c.call(_b)) ||
922
- ((_d = change === null || change === void 0 ? void 0 : change.documentKey) === null || _d === void 0 ? void 0 : _d._id) ||
923
- null
924
- });
925
913
  listener(filteredChange);
926
914
  }));
927
915
  };
@@ -1041,7 +1029,6 @@ const getOperators = (collection, { rules, collName, user, run_as_system, monito
1041
1029
  // Retrieve the document to check permissions before updating
1042
1030
  const result = yield collection.find({ $and: formattedQuery }).toArray();
1043
1031
  if (!result) {
1044
- console.log('check1 In updateMany --> (!result)');
1045
1032
  throw new Error('Update not permitted');
1046
1033
  }
1047
1034
  // Check if the update data contains MongoDB update operators (e.g., $set, $inc)
@@ -1062,7 +1049,6 @@ const getOperators = (collection, { rules, collName, user, run_as_system, monito
1062
1049
  // Ensure no unauthorized changes are made
1063
1050
  const areDocumentsEqual = docsToCheck.every((doc, index) => areUpdatedFieldsAllowed(filteredItems[index], doc, updatedPaths));
1064
1051
  if (!areDocumentsEqual) {
1065
- console.log('check1 In updateMany --> (!areDocumentsEqual)');
1066
1052
  throw new Error('Update not permitted');
1067
1053
  }
1068
1054
  const res = yield collection.updateMany({ $and: formattedQuery }, normalizedData, options);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@flowerforce/flowerbase",
3
- "version": "1.7.5-beta.5",
3
+ "version": "1.7.5-beta.6",
4
4
  "description": "",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -0,0 +1,163 @@
1
+ import Fastify, { FastifyInstance } from 'fastify'
2
+ import { registerCollectionRoutes } from '../collections'
3
+ import { StateManager } from '../../../state'
4
+
5
+ jest.mock('../../../state', () => ({
6
+ StateManager: {
7
+ select: jest.fn()
8
+ }
9
+ }))
10
+
11
+ describe('monitoring collections routes', () => {
12
+ let app: FastifyInstance
13
+ let addCollectionHistory: jest.Mock
14
+ let selectMock: jest.Mock
15
+ let insertOne: jest.Mock
16
+ let insertMany: jest.Mock
17
+
18
+ beforeEach(async () => {
19
+ app = Fastify()
20
+ addCollectionHistory = jest.fn()
21
+ selectMock = StateManager.select as unknown as jest.Mock
22
+ insertOne = jest.fn()
23
+ insertMany = jest.fn()
24
+
25
+ const services = {
26
+ 'mongodb-atlas': jest.fn(() => ({
27
+ db: jest.fn(() => ({
28
+ collection: jest.fn(() => ({
29
+ insertOne,
30
+ insertMany
31
+ }))
32
+ }))
33
+ }))
34
+ }
35
+
36
+ selectMock.mockImplementation((key: string) => {
37
+ if (key === 'rules') return {}
38
+ if (key === 'services') return services
39
+ return {}
40
+ })
41
+
42
+ registerCollectionRoutes(app, {
43
+ prefix: '/monit',
44
+ collectionHistory: [],
45
+ maxCollectionHistory: 20,
46
+ addCollectionHistory
47
+ })
48
+ await app.ready()
49
+ })
50
+
51
+ afterEach(async () => {
52
+ await app.close()
53
+ jest.clearAllMocks()
54
+ })
55
+
56
+ it('POST /collections/insert should insert one document', async () => {
57
+ insertOne.mockResolvedValue({
58
+ acknowledged: true,
59
+ insertedId: 'id-1'
60
+ })
61
+
62
+ const response = await app.inject({
63
+ method: 'POST',
64
+ url: '/monit/api/collections/insert',
65
+ payload: {
66
+ collection: 'todos',
67
+ mode: 'insertOne',
68
+ document: { title: 'Task 1' },
69
+ runAsSystem: true
70
+ }
71
+ })
72
+
73
+ expect(response.statusCode).toBe(200)
74
+ expect(JSON.parse(response.body)).toEqual({
75
+ mode: 'insertOne',
76
+ acknowledged: true,
77
+ insertedId: 'id-1',
78
+ count: 1
79
+ })
80
+ expect(insertOne).toHaveBeenCalledWith({ title: 'Task 1' })
81
+ expect(addCollectionHistory).toHaveBeenCalledWith(expect.objectContaining({
82
+ collection: 'todos',
83
+ mode: 'insertOne',
84
+ document: { title: 'Task 1' },
85
+ runAsSystem: true,
86
+ page: 1
87
+ }))
88
+ })
89
+
90
+ it('POST /collections/insert should insert many documents', async () => {
91
+ insertMany.mockResolvedValue({
92
+ acknowledged: true,
93
+ insertedIds: {
94
+ 0: 'id-1',
95
+ 1: 'id-2'
96
+ }
97
+ })
98
+
99
+ const response = await app.inject({
100
+ method: 'POST',
101
+ url: '/monit/api/collections/insert',
102
+ payload: {
103
+ collection: 'todos',
104
+ mode: 'insertMany',
105
+ documents: [{ title: 'Task 1' }, { title: 'Task 2' }],
106
+ runAsSystem: false
107
+ }
108
+ })
109
+
110
+ expect(response.statusCode).toBe(200)
111
+ expect(JSON.parse(response.body)).toEqual({
112
+ mode: 'insertMany',
113
+ acknowledged: true,
114
+ insertedCount: 2,
115
+ insertedIds: ['id-1', 'id-2'],
116
+ count: 2
117
+ })
118
+ expect(insertMany).toHaveBeenCalledWith([{ title: 'Task 1' }, { title: 'Task 2' }])
119
+ expect(addCollectionHistory).toHaveBeenCalledWith(expect.objectContaining({
120
+ collection: 'todos',
121
+ mode: 'insertMany',
122
+ documents: [{ title: 'Task 1' }, { title: 'Task 2' }],
123
+ runAsSystem: false,
124
+ page: 1
125
+ }))
126
+ })
127
+
128
+ it('POST /collections/insert should validate insertOne payload', async () => {
129
+ const response = await app.inject({
130
+ method: 'POST',
131
+ url: '/monit/api/collections/insert',
132
+ payload: {
133
+ collection: 'todos',
134
+ mode: 'insertOne',
135
+ document: ['invalid']
136
+ }
137
+ })
138
+
139
+ expect(response.statusCode).toBe(400)
140
+ expect(JSON.parse(response.body)).toEqual({
141
+ error: 'Document must be an object'
142
+ })
143
+ expect(insertOne).not.toHaveBeenCalled()
144
+ })
145
+
146
+ it('POST /collections/insert should validate insertMany payload', async () => {
147
+ const response = await app.inject({
148
+ method: 'POST',
149
+ url: '/monit/api/collections/insert',
150
+ payload: {
151
+ collection: 'todos',
152
+ mode: 'insertMany',
153
+ documents: [{ title: 'Task 1' }, 'invalid']
154
+ }
155
+ })
156
+
157
+ expect(response.statusCode).toBe(400)
158
+ expect(JSON.parse(response.body)).toEqual({
159
+ error: 'Every document must be an object'
160
+ })
161
+ expect(insertMany).not.toHaveBeenCalled()
162
+ })
163
+ })
@@ -215,4 +215,103 @@ export const registerCollectionRoutes = (app: FastifyInstance, deps: CollectionR
215
215
  return { error: details.message, stack: details.stack }
216
216
  }
217
217
  })
218
+
219
+ app.post(`${prefix}/api/collections/insert`, async (req, reply) => {
220
+ const body = req.body as {
221
+ collection?: string
222
+ mode?: 'insertOne' | 'insertMany'
223
+ document?: unknown
224
+ documents?: unknown
225
+ recordHistory?: boolean
226
+ runAsSystem?: boolean
227
+ userId?: string
228
+ }
229
+ const collection = body?.collection
230
+ if (!collection) {
231
+ reply.code(400)
232
+ return { error: 'Missing collection name' }
233
+ }
234
+ const mode = body?.mode === 'insertMany' ? 'insertMany' : 'insertOne'
235
+ if (mode === 'insertOne') {
236
+ if (!isPlainObject(body?.document)) {
237
+ reply.code(400)
238
+ return { error: 'Document must be an object' }
239
+ }
240
+ } else {
241
+ if (!Array.isArray(body?.documents) || !body.documents.length) {
242
+ reply.code(400)
243
+ return { error: 'Documents must be a non-empty array' }
244
+ }
245
+ const invalid = body.documents.some((entry) => !isPlainObject(entry))
246
+ if (invalid) {
247
+ reply.code(400)
248
+ return { error: 'Every document must be an object' }
249
+ }
250
+ }
251
+
252
+ const rules = StateManager.select('rules') as Rules
253
+ const services = StateManager.select('services') as typeof coreServices
254
+ const resolvedUser = await resolveUserContext(app, body?.userId)
255
+ const runAsSystem = body?.runAsSystem !== false
256
+ const recordHistory = body?.recordHistory !== false
257
+
258
+ try {
259
+ const mongoService = services['mongodb-atlas'](app, {
260
+ rules,
261
+ user: resolvedUser ?? {},
262
+ run_as_system: runAsSystem
263
+ })
264
+ const collectionService = mongoService.db(DB_NAME).collection(collection)
265
+ if (mode === 'insertMany') {
266
+ const documents = body.documents as Record<string, unknown>[]
267
+ const result = await collectionService.insertMany(documents)
268
+ const insertedIds = Array.isArray(result?.insertedIds)
269
+ ? result.insertedIds
270
+ : Object.values(result?.insertedIds || {})
271
+ if (recordHistory) {
272
+ addCollectionHistory({
273
+ ts: Date.now(),
274
+ collection,
275
+ mode: 'insertMany',
276
+ documents: sanitize(documents),
277
+ runAsSystem,
278
+ user: getUserInfo(resolvedUser as Record<string, unknown> | undefined),
279
+ page: 1
280
+ })
281
+ }
282
+ return {
283
+ mode: 'insertMany',
284
+ acknowledged: !!result?.acknowledged,
285
+ insertedCount: insertedIds.length,
286
+ insertedIds: sanitize(insertedIds),
287
+ count: insertedIds.length
288
+ }
289
+ }
290
+
291
+ const document = body.document as Record<string, unknown>
292
+ const result = await collectionService.insertOne(document)
293
+ const insertedId = result?.insertedId
294
+ if (recordHistory) {
295
+ addCollectionHistory({
296
+ ts: Date.now(),
297
+ collection,
298
+ mode: 'insertOne',
299
+ document: sanitize(document),
300
+ runAsSystem,
301
+ user: getUserInfo(resolvedUser as Record<string, unknown> | undefined),
302
+ page: 1
303
+ })
304
+ }
305
+ return {
306
+ mode: 'insertOne',
307
+ acknowledged: !!result?.acknowledged,
308
+ insertedId: sanitize(insertedId),
309
+ count: insertedId ? 1 : 0
310
+ }
311
+ } catch (error) {
312
+ const details = getErrorDetails(error)
313
+ reply.code(500)
314
+ return { error: details.message, stack: details.stack }
315
+ }
316
+ })
218
317
  }
@@ -42,6 +42,10 @@
42
42
  dom.collectionQueryHighlight = document.getElementById('collectionQueryHighlight');
43
43
  dom.collectionAggregate = document.getElementById('collectionAggregate');
44
44
  dom.collectionAggregateHighlight = document.getElementById('collectionAggregateHighlight');
45
+ dom.collectionInsertOne = document.getElementById('collectionInsertOne');
46
+ dom.collectionInsertOneHighlight = document.getElementById('collectionInsertOneHighlight');
47
+ dom.collectionInsertMany = document.getElementById('collectionInsertMany');
48
+ dom.collectionInsertManyHighlight = document.getElementById('collectionInsertManyHighlight');
45
49
  dom.runCollectionQuery = document.getElementById('runCollectionQuery');
46
50
  dom.collectionResult = document.getElementById('collectionResult');
47
51
  dom.collectionPrev = document.getElementById('collectionPrev');
@@ -71,6 +75,10 @@
71
75
  collectionQueryHighlight,
72
76
  collectionAggregate,
73
77
  collectionAggregateHighlight,
78
+ collectionInsertOne,
79
+ collectionInsertOneHighlight,
80
+ collectionInsertMany,
81
+ collectionInsertManyHighlight,
74
82
  runCollectionQuery,
75
83
  collectionResult,
76
84
  collectionPrev,
@@ -237,6 +245,22 @@
237
245
  collectionAggregateHighlight.scrollLeft = collectionAggregate.scrollLeft;
238
246
  };
239
247
 
248
+ const updateCollectionInsertOneHighlight = () => {
249
+ if (!collectionInsertOne || !collectionInsertOneHighlight) return;
250
+ const text = collectionInsertOne.value || '';
251
+ collectionInsertOneHighlight.innerHTML = highlightJson(text || '');
252
+ collectionInsertOneHighlight.scrollTop = collectionInsertOne.scrollTop;
253
+ collectionInsertOneHighlight.scrollLeft = collectionInsertOne.scrollLeft;
254
+ };
255
+
256
+ const updateCollectionInsertManyHighlight = () => {
257
+ if (!collectionInsertMany || !collectionInsertManyHighlight) return;
258
+ const text = collectionInsertMany.value || '';
259
+ collectionInsertManyHighlight.innerHTML = highlightJson(text || '');
260
+ collectionInsertManyHighlight.scrollTop = collectionInsertMany.scrollTop;
261
+ collectionInsertManyHighlight.scrollLeft = collectionInsertMany.scrollLeft;
262
+ };
263
+
240
264
  const formatCellValue = (value) => {
241
265
  if (value === null || value === undefined) return '';
242
266
  if (typeof value === 'string') {
@@ -483,6 +507,14 @@
483
507
  collectionAggregate.value = entry.pipeline ? JSON.stringify(entry.pipeline, null, 2) : '';
484
508
  updateCollectionAggregateHighlight();
485
509
  }
510
+ if (collectionInsertOne) {
511
+ collectionInsertOne.value = entry.document ? JSON.stringify(entry.document, null, 2) : '';
512
+ updateCollectionInsertOneHighlight();
513
+ }
514
+ if (collectionInsertMany) {
515
+ collectionInsertMany.value = entry.documents ? JSON.stringify(entry.documents, null, 2) : '';
516
+ updateCollectionInsertManyHighlight();
517
+ }
486
518
  if (entry.user && entry.user.id) {
487
519
  if (collectionUserInput) collectionUserInput.value = entry.user.id;
488
520
  setSelectedCollectionUser({
@@ -549,14 +581,16 @@
549
581
  setCollectionResult('Select a collection first', false);
550
582
  return;
551
583
  }
552
- const keepPage = options && options.keepPage;
584
+ const mode = collectionMode ? collectionMode.value : 'query';
585
+ const supportsPaging = mode === 'query' || mode === 'aggregate';
586
+ const keepPage = supportsPaging && options && options.keepPage;
553
587
  const recordHistory = !keepPage;
554
588
  if (!keepPage) {
555
589
  state.collectionPage = 1;
556
590
  }
557
- const shouldRefreshTotals = !keepPage || !state.collectionTotal;
591
+ const shouldRefreshTotals = supportsPaging && (!keepPage || !state.collectionTotal);
558
592
  state.collectionHasMore = false;
559
- if (shouldRefreshTotals) {
593
+ if (shouldRefreshTotals || !supportsPaging) {
560
594
  state.collectionTotal = 0;
561
595
  }
562
596
  state.collectionLoading = true;
@@ -568,11 +602,10 @@
568
602
  const userId = selectedUser
569
603
  ? String(selectedUser.id || (selectedUser.auth && selectedUser.auth._id) || '')
570
604
  : fallbackUserId;
571
- const mode = collectionMode ? collectionMode.value : 'query';
572
605
  try {
573
- const sortRaw = collectionSort ? collectionSort.value.trim() : '';
574
- const sort = parseJsonObject(sortRaw, 'Sort');
575
606
  if (mode === 'aggregate') {
607
+ const sortRaw = collectionSort ? collectionSort.value.trim() : '';
608
+ const sort = parseJsonObject(sortRaw, 'Sort');
576
609
  const raw = collectionAggregate ? collectionAggregate.value.trim() : '';
577
610
  const pipeline = raw ? JSON.parse(raw) : [];
578
611
  if (!Array.isArray(pipeline)) {
@@ -607,7 +640,58 @@
607
640
  updateCollectionPager();
608
641
  setCollectionTab('query');
609
642
  setCollectionResult(data, true);
643
+ } else if (mode === 'insertOne') {
644
+ const raw = collectionInsertOne ? collectionInsertOne.value.trim() : '';
645
+ const document = parseJsonObject(raw, 'Document');
646
+ if (!document) {
647
+ throw new Error('Document is required for insert one');
648
+ }
649
+ const data = await api('/collections/insert', {
650
+ method: 'POST',
651
+ body: JSON.stringify({
652
+ collection: name,
653
+ mode,
654
+ document,
655
+ runAsSystem,
656
+ userId: userId || undefined,
657
+ recordHistory
658
+ })
659
+ });
660
+ state.collectionHasMore = false;
661
+ state.collectionPage = 1;
662
+ state.collectionTotal = typeof data.count === 'number' ? data.count : 1;
663
+ updateCollectionPager();
664
+ setCollectionTab('query');
665
+ setCollectionResult(data, true);
666
+ } else if (mode === 'insertMany') {
667
+ const raw = collectionInsertMany ? collectionInsertMany.value.trim() : '';
668
+ const documents = raw ? JSON.parse(raw) : [];
669
+ if (!Array.isArray(documents)) {
670
+ throw new Error('Documents must be a JSON array for insert many');
671
+ }
672
+ if (!documents.length) {
673
+ throw new Error('Documents are required for insert many');
674
+ }
675
+ const data = await api('/collections/insert', {
676
+ method: 'POST',
677
+ body: JSON.stringify({
678
+ collection: name,
679
+ mode,
680
+ documents,
681
+ runAsSystem,
682
+ userId: userId || undefined,
683
+ recordHistory
684
+ })
685
+ });
686
+ state.collectionHasMore = false;
687
+ state.collectionPage = 1;
688
+ state.collectionTotal = typeof data.count === 'number' ? data.count : documents.length;
689
+ updateCollectionPager();
690
+ setCollectionTab('query');
691
+ setCollectionResult(data, true);
610
692
  } else {
693
+ const sortRaw = collectionSort ? collectionSort.value.trim() : '';
694
+ const sort = parseJsonObject(sortRaw, 'Sort');
611
695
  const raw = collectionQuery ? collectionQuery.value.trim() : '';
612
696
  const query = parseJsonObject(raw, 'Query') || {};
613
697
  const data = await api('/collections/query', {
@@ -806,6 +890,14 @@
806
890
  collectionAggregate.addEventListener('input', updateCollectionAggregateHighlight);
807
891
  collectionAggregate.addEventListener('scroll', updateCollectionAggregateHighlight);
808
892
  }
893
+ if (collectionInsertOne) {
894
+ collectionInsertOne.addEventListener('input', updateCollectionInsertOneHighlight);
895
+ collectionInsertOne.addEventListener('scroll', updateCollectionInsertOneHighlight);
896
+ }
897
+ if (collectionInsertMany) {
898
+ collectionInsertMany.addEventListener('input', updateCollectionInsertManyHighlight);
899
+ collectionInsertMany.addEventListener('scroll', updateCollectionInsertManyHighlight);
900
+ }
809
901
 
810
902
  if (collectionList) {
811
903
  collectionList.addEventListener('click', (event) => {
@@ -916,6 +1008,8 @@
916
1008
  setCollectionResultView('json');
917
1009
  updateCollectionQueryHighlight();
918
1010
  updateCollectionAggregateHighlight();
1011
+ updateCollectionInsertOneHighlight();
1012
+ updateCollectionInsertManyHighlight();
919
1013
  setRulesTabEnabled(false);
920
1014
  };
921
1015
 
@@ -929,12 +929,17 @@ button.small {
929
929
  align-items: stretch;
930
930
  }
931
931
 
932
- .collection-io[data-mode="query"] [data-collection-mode="aggregate"] {
932
+ .collection-io [data-collection-mode] {
933
933
  display: none;
934
+ min-height: 0;
934
935
  }
935
936
 
936
- .collection-io[data-mode="aggregate"] [data-collection-mode="query"] {
937
- display: none;
937
+ .collection-io[data-mode="query"] [data-collection-mode="query"],
938
+ .collection-io[data-mode="aggregate"] [data-collection-mode="aggregate"],
939
+ .collection-io[data-mode="insertOne"] [data-collection-mode="insertOne"],
940
+ .collection-io[data-mode="insertMany"] [data-collection-mode="insertMany"] {
941
+ display: flex;
942
+ flex-direction: column;
938
943
  }
939
944
 
940
945
  .collection-io {
@@ -1039,6 +1044,7 @@ button.small {
1039
1044
  border-right: 1px solid #2b2b2b;
1040
1045
  user-select: none;
1041
1046
  white-space: pre;
1047
+ overflow: hidden;
1042
1048
  }
1043
1049
 
1044
1050
  .code-surface {
@@ -78,7 +78,8 @@
78
78
  functionHighlight.innerHTML = highlightCode(code);
79
79
  }
80
80
  if (functionGutter) {
81
- const lines = Math.max(1, code.split('\n').length);
81
+ const lineBreaks = code.match(/\r\n|\r|\n/g);
82
+ const lines = Math.max(1, (lineBreaks ? lineBreaks.length : 0) + 1);
82
83
  let out = '';
83
84
  for (let i = 1; i <= lines; i += 1) {
84
85
  out += i + (i === lines ? '' : '\n');
@@ -371,6 +371,8 @@
371
371
  <select id="collectionMode">
372
372
  <option value="query" selected>query</option>
373
373
  <option value="aggregate">aggregate</option>
374
+ <option value="insertOne">insert one</option>
375
+ <option value="insertMany">insert many</option>
374
376
  </select>
375
377
  </div>
376
378
  <div class="control-group">
@@ -393,6 +395,20 @@
393
395
  <textarea id="collectionAggregate" placeholder='[{ "$match": { "field": "value" } }]'></textarea>
394
396
  </div>
395
397
  </div>
398
+ <div class="io-column" data-collection-mode="insertOne">
399
+ <label for="collectionInsertOne">document</label>
400
+ <div class="json-editor">
401
+ <pre id="collectionInsertOneHighlight" class="json-highlight"></pre>
402
+ <textarea id="collectionInsertOne" placeholder='{ "field": "value" }'></textarea>
403
+ </div>
404
+ </div>
405
+ <div class="io-column" data-collection-mode="insertMany">
406
+ <label for="collectionInsertMany">documents</label>
407
+ <div class="json-editor">
408
+ <pre id="collectionInsertManyHighlight" class="json-highlight"></pre>
409
+ <textarea id="collectionInsertMany" placeholder='[{ "field": "value" }]'></textarea>
410
+ </div>
411
+ </div>
396
412
  </div>
397
413
  </div>
398
414
  <div class="collection-actions">
@@ -29,9 +29,11 @@ export type FunctionHistoryItem = {
29
29
  export type CollectionHistoryItem = {
30
30
  ts: number
31
31
  collection: string
32
- mode: 'query' | 'aggregate'
32
+ mode: 'query' | 'aggregate' | 'insertOne' | 'insertMany'
33
33
  query?: unknown
34
34
  pipeline?: unknown
35
+ document?: unknown
36
+ documents?: unknown
35
37
  sort?: Record<string, unknown>
36
38
  runAsSystem: boolean
37
39
  user?: { id?: string; email?: string }
@@ -456,9 +456,9 @@ const getOperators: GetOperatorsFunction = (
456
456
  const resolvedOptions =
457
457
  projection || normalizedOptions
458
458
  ? {
459
- ...(normalizedOptions ?? {}),
460
- ...(projection ? { projection } : {})
461
- }
459
+ ...(normalizedOptions ?? {}),
460
+ ...(projection ? { projection } : {})
461
+ }
462
462
  : undefined
463
463
  const resolvedQuery = query ?? {}
464
464
  if (!run_as_system) {
@@ -496,15 +496,15 @@ const getOperators: GetOperatorsFunction = (
496
496
  })
497
497
  const { status, document } = winningRole
498
498
  ? await checkValidation(
499
- winningRole,
500
- {
501
- type: 'read',
502
- roles,
503
- cursor: result,
504
- expansions: {}
505
- },
506
- user
507
- )
499
+ winningRole,
500
+ {
501
+ type: 'read',
502
+ roles,
503
+ cursor: result,
504
+ expansions: {}
505
+ },
506
+ user
507
+ )
508
508
  : fallbackAccess(result)
509
509
 
510
510
  // Return validated document or empty object if not permitted
@@ -557,15 +557,15 @@ const getOperators: GetOperatorsFunction = (
557
557
  })
558
558
  const { status } = winningRole
559
559
  ? await checkValidation(
560
- winningRole,
561
- {
562
- type: 'delete',
563
- roles,
564
- cursor: result,
565
- expansions: {}
566
- },
567
- user
568
- )
560
+ winningRole,
561
+ {
562
+ type: 'delete',
563
+ roles,
564
+ cursor: result,
565
+ expansions: {}
566
+ },
567
+ user
568
+ )
569
569
  : fallbackAccess(result)
570
570
 
571
571
  if (!status) {
@@ -612,15 +612,15 @@ const getOperators: GetOperatorsFunction = (
612
612
 
613
613
  const { status, document } = winningRole
614
614
  ? await checkValidation(
615
- winningRole,
616
- {
617
- type: 'insert',
618
- roles,
619
- cursor: data,
620
- expansions: {}
621
- },
622
- user
623
- )
615
+ winningRole,
616
+ {
617
+ type: 'insert',
618
+ roles,
619
+ cursor: data,
620
+ expansions: {}
621
+ },
622
+ user
623
+ )
624
624
  : fallbackAccess(data)
625
625
 
626
626
  if (!status || !isEqual(data, document)) {
@@ -703,15 +703,15 @@ const getOperators: GetOperatorsFunction = (
703
703
  // Validate update permissions
704
704
  const { status, document } = winningRole
705
705
  ? await checkValidation(
706
- winningRole,
707
- {
708
- type: 'write',
709
- roles,
710
- cursor: docToCheck,
711
- expansions: {}
712
- },
713
- user
714
- )
706
+ winningRole,
707
+ {
708
+ type: 'write',
709
+ roles,
710
+ cursor: docToCheck,
711
+ expansions: {}
712
+ },
713
+ user
714
+ )
715
715
  : fallbackAccess(docToCheck)
716
716
  // Ensure no unauthorized changes are made
717
717
  const areDocumentsEqual = areUpdatedFieldsAllowed(document, docToCheck, updatedPaths)
@@ -818,15 +818,15 @@ const getOperators: GetOperatorsFunction = (
818
818
  const readRole = getWinningRole(updateResult, user, roles)
819
819
  const readResult = readRole
820
820
  ? await checkValidation(
821
- readRole,
822
- {
823
- type: 'read',
824
- roles,
825
- cursor: updateResult,
826
- expansions: {}
827
- },
828
- user
829
- )
821
+ readRole,
822
+ {
823
+ type: 'read',
824
+ roles,
825
+ cursor: updateResult,
826
+ expansions: {}
827
+ },
828
+ user
829
+ )
830
830
  : fallbackAccess(updateResult)
831
831
 
832
832
  const sanitizedDoc = readResult.status ? (readResult.document ?? updateResult) : {}
@@ -873,9 +873,9 @@ const getOperators: GetOperatorsFunction = (
873
873
  const resolvedOptions =
874
874
  projection || normalizedOptions
875
875
  ? {
876
- ...(normalizedOptions ?? {}),
877
- ...(projection ? { projection } : {})
878
- }
876
+ ...(normalizedOptions ?? {}),
877
+ ...(projection ? { projection } : {})
878
+ }
879
879
  : undefined
880
880
  if (!run_as_system) {
881
881
  checkDenyOperation(normalizedRules, collection.collectionName, CRUD_OPERATIONS.READ)
@@ -906,15 +906,15 @@ const getOperators: GetOperatorsFunction = (
906
906
  })
907
907
  const { status, document } = winningRole
908
908
  ? await checkValidation(
909
- winningRole,
910
- {
911
- type: 'read',
912
- roles,
913
- cursor: currentDoc,
914
- expansions: {}
915
- },
916
- user
917
- )
909
+ winningRole,
910
+ {
911
+ type: 'read',
912
+ roles,
913
+ cursor: currentDoc,
914
+ expansions: {}
915
+ },
916
+ user
917
+ )
918
918
  : fallbackAccess(currentDoc)
919
919
 
920
920
  return status ? document : undefined
@@ -1017,10 +1017,10 @@ const getOperators: GetOperatorsFunction = (
1017
1017
 
1018
1018
  const firstStep = watchFormattedQuery.length
1019
1019
  ? {
1020
- $match: {
1021
- $and: watchFormattedQuery
1022
- }
1020
+ $match: {
1021
+ $and: watchFormattedQuery
1023
1022
  }
1023
+ }
1024
1024
  : undefined
1025
1025
 
1026
1026
  const formattedPipeline = [firstStep, ...extraMatches, ...pipeline].filter(Boolean) as Document[]
@@ -1041,29 +1041,29 @@ const getOperators: GetOperatorsFunction = (
1041
1041
 
1042
1042
  const fullDocumentValidation = winningRole
1043
1043
  ? await checkValidation(
1044
- winningRole,
1045
- {
1046
- type: 'read',
1047
- roles,
1048
- cursor: fullDocument,
1049
- expansions: {}
1050
- },
1051
- user
1052
- )
1044
+ winningRole,
1045
+ {
1046
+ type: 'read',
1047
+ roles,
1048
+ cursor: fullDocument,
1049
+ expansions: {}
1050
+ },
1051
+ user
1052
+ )
1053
1053
  : fallbackAccess(fullDocument)
1054
1054
  const { status, document } = fullDocumentValidation
1055
1055
 
1056
1056
  const { status: updatedFieldsStatus, document: updatedFields } = winningRole
1057
1057
  ? await checkValidation(
1058
- winningRole,
1059
- {
1060
- type: 'read',
1061
- roles,
1062
- cursor: updateDescription?.updatedFields,
1063
- expansions: {}
1064
- },
1065
- user
1066
- )
1058
+ winningRole,
1059
+ {
1060
+ type: 'read',
1061
+ roles,
1062
+ cursor: updateDescription?.updatedFields,
1063
+ expansions: {}
1064
+ },
1065
+ user
1066
+ )
1067
1067
  : fallbackAccess(updateDescription?.updatedFields)
1068
1068
 
1069
1069
  return {
@@ -1099,18 +1099,6 @@ const getOperators: GetOperatorsFunction = (
1099
1099
  }
1100
1100
  }
1101
1101
 
1102
- console.log('[flowerbase watch] delivered change', {
1103
- collection: collName,
1104
- operationType: change?.operationType,
1105
- eventType,
1106
- hasFullDocument,
1107
- hasWinningRole,
1108
- updatedFieldsStatus,
1109
- documentKey:
1110
- change?.documentKey?._id?.toString?.() ||
1111
- change?.documentKey?._id ||
1112
- null
1113
- })
1114
1102
  listener(filteredChange)
1115
1103
  })
1116
1104
  }
@@ -1210,15 +1198,15 @@ const getOperators: GetOperatorsFunction = (
1210
1198
 
1211
1199
  const { status, document } = winningRole
1212
1200
  ? await checkValidation(
1213
- winningRole,
1214
- {
1215
- type: 'insert',
1216
- roles,
1217
- cursor: currentDoc,
1218
- expansions: {}
1219
- },
1220
- user
1221
- )
1201
+ winningRole,
1202
+ {
1203
+ type: 'insert',
1204
+ roles,
1205
+ cursor: currentDoc,
1206
+ expansions: {}
1207
+ },
1208
+ user
1209
+ )
1222
1210
  : fallbackAccess(currentDoc)
1223
1211
 
1224
1212
  return status ? document : undefined
@@ -1255,7 +1243,6 @@ const getOperators: GetOperatorsFunction = (
1255
1243
  // Retrieve the document to check permissions before updating
1256
1244
  const result = await collection.find({ $and: formattedQuery }).toArray()
1257
1245
  if (!result) {
1258
- console.log('check1 In updateMany --> (!result)')
1259
1246
  throw new Error('Update not permitted')
1260
1247
  }
1261
1248
 
@@ -1271,15 +1258,15 @@ const getOperators: GetOperatorsFunction = (
1271
1258
 
1272
1259
  const { status, document } = winningRole
1273
1260
  ? await checkValidation(
1274
- winningRole,
1275
- {
1276
- type: 'write',
1277
- roles,
1278
- cursor: currentDoc,
1279
- expansions: {}
1280
- },
1281
- user
1282
- )
1261
+ winningRole,
1262
+ {
1263
+ type: 'write',
1264
+ roles,
1265
+ cursor: currentDoc,
1266
+ expansions: {}
1267
+ },
1268
+ user
1269
+ )
1283
1270
  : fallbackAccess(currentDoc)
1284
1271
 
1285
1272
  return status ? document : undefined
@@ -1292,8 +1279,6 @@ const getOperators: GetOperatorsFunction = (
1292
1279
  )
1293
1280
 
1294
1281
  if (!areDocumentsEqual) {
1295
- console.log('check1 In updateMany --> (!areDocumentsEqual)')
1296
-
1297
1282
  throw new Error('Update not permitted')
1298
1283
  }
1299
1284
 
@@ -1341,15 +1326,15 @@ const getOperators: GetOperatorsFunction = (
1341
1326
 
1342
1327
  const { status, document } = winningRole
1343
1328
  ? await checkValidation(
1344
- winningRole,
1345
- {
1346
- type: 'delete',
1347
- roles,
1348
- cursor: currentDoc,
1349
- expansions: {}
1350
- },
1351
- user
1352
- )
1329
+ winningRole,
1330
+ {
1331
+ type: 'delete',
1332
+ roles,
1333
+ cursor: currentDoc,
1334
+ expansions: {}
1335
+ },
1336
+ user
1337
+ )
1353
1338
  : fallbackAccess(currentDoc)
1354
1339
 
1355
1340
  return status ? document : undefined