@flowerforce/flowerbase 1.8.3 → 1.8.4-beta.1

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":"utils.d.ts","sourceRoot":"","sources":["../../../src/features/triggers/utils.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,aAAa,EAAW,QAAQ,EAAE,MAAM,aAAa,CAAA;AA0E9D;;;;;;;GAOG;AACH,eAAO,MAAM,YAAY,GAAU,gBAAuB,KAAG,OAAO,CAAC,QAAQ,CAkB5E,CAAA;AA2qBD,eAAO,MAAM,gBAAgB;kHAppB1B,aAAa;iHA4jBb,aAAa;uHA1cb,aAAa;CAsiBf,CAAA"}
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../../src/features/triggers/utils.ts"],"names":[],"mappings":"AASA,OAAO,EAAE,aAAa,EAAW,QAAQ,EAAE,MAAM,aAAa,CAAA;AA6E9D;;;;;;;GAOG;AACH,eAAO,MAAM,YAAY,GAAU,gBAAuB,KAAG,OAAO,CAAC,QAAQ,CAkB5E,CAAA;AAmrBD,eAAO,MAAM,gBAAgB;kHA5pB1B,aAAa;iHAmkBb,aAAa;uHAhdb,aAAa;CA6iBf,CAAA"}
@@ -27,11 +27,13 @@ exports.TRIGGER_HANDLERS = exports.loadTriggers = void 0;
27
27
  const fs_1 = __importDefault(require("fs"));
28
28
  const node_path_1 = __importDefault(require("node:path"));
29
29
  const node_cron_1 = __importDefault(require("node-cron"));
30
+ const bson_1 = require("bson");
30
31
  const constants_1 = require("../../constants");
31
32
  const utils_1 = require("../../monitoring/utils");
32
33
  const state_1 = require("../../state");
33
34
  const utils_2 = require("../../utils");
34
35
  const context_1 = require("../../utils/context");
36
+ const normalizeTriggerPayload = (value) => bson_1.EJSON.deserialize(bson_1.EJSON.serialize(value, { relaxed: false }));
35
37
  const registerOnClose = (app, handler, label) => {
36
38
  if (app.server) {
37
39
  app.server.once('close', () => {
@@ -148,7 +150,8 @@ const handleCronTrigger = (_a) => __awaiter(void 0, [_a], void 0, function* ({ c
148
150
  currentFunction: triggerHandler,
149
151
  functionName,
150
152
  functionsList,
151
- services
153
+ services,
154
+ deserializeArgs: false
152
155
  });
153
156
  }
154
157
  catch (error) {
@@ -332,7 +335,7 @@ const handleAuthenticationTrigger = (_a) => __awaiter(void 0, [_a], void 0, func
332
335
  meta: Object.assign(Object.assign({}, baseMeta), { event: 'LOGOUT' })
333
336
  });
334
337
  yield (0, context_1.GenerateContext)({
335
- args: [Object.assign({ user: userData }, op)],
338
+ args: [normalizeTriggerPayload(Object.assign({ user: userData }, op))],
336
339
  app,
337
340
  rules: state_1.StateManager.select("rules"),
338
341
  user: {}, // TODO from currentUser ??
@@ -340,7 +343,8 @@ const handleAuthenticationTrigger = (_a) => __awaiter(void 0, [_a], void 0, func
340
343
  functionName,
341
344
  functionsList,
342
345
  services,
343
- runAsSystem: true
346
+ runAsSystem: true,
347
+ deserializeArgs: false
344
348
  });
345
349
  }
346
350
  catch (error) {
@@ -352,7 +356,6 @@ const handleAuthenticationTrigger = (_a) => __awaiter(void 0, [_a], void 0, func
352
356
  meta: Object.assign(Object.assign({}, baseMeta), { event: 'LOGOUT' }),
353
357
  error
354
358
  });
355
- console.log("🚀 ~ handleAuthenticationTrigger ~ error:", error);
356
359
  }
357
360
  return;
358
361
  }
@@ -389,7 +392,7 @@ const handleAuthenticationTrigger = (_a) => __awaiter(void 0, [_a], void 0, func
389
392
  meta: Object.assign(Object.assign({}, baseMeta), { event: 'LOGIN' })
390
393
  });
391
394
  yield (0, context_1.GenerateContext)({
392
- args: [Object.assign({ user: userData }, op)],
395
+ args: [normalizeTriggerPayload(Object.assign({ user: userData }, op))],
393
396
  app,
394
397
  rules: state_1.StateManager.select("rules"),
395
398
  user: {}, // TODO from currentUser ??
@@ -397,7 +400,8 @@ const handleAuthenticationTrigger = (_a) => __awaiter(void 0, [_a], void 0, func
397
400
  functionName,
398
401
  functionsList,
399
402
  services,
400
- runAsSystem: true
403
+ runAsSystem: true,
404
+ deserializeArgs: false
401
405
  });
402
406
  }
403
407
  catch (error) {
@@ -409,7 +413,6 @@ const handleAuthenticationTrigger = (_a) => __awaiter(void 0, [_a], void 0, func
409
413
  meta: Object.assign(Object.assign({}, baseMeta), { event: 'LOGIN' }),
410
414
  error
411
415
  });
412
- console.log("🚀 ~ handleAuthenticationTrigger ~ error:", error);
413
416
  }
414
417
  return;
415
418
  }
@@ -441,7 +444,9 @@ const handleAuthenticationTrigger = (_a) => __awaiter(void 0, [_a], void 0, func
441
444
  meta: Object.assign(Object.assign({}, baseMeta), { event: 'DELETE' })
442
445
  });
443
446
  yield (0, context_1.GenerateContext)({
444
- args: isAutoTrigger ? [userData] : [Object.assign({ user: userData }, op)],
447
+ args: isAutoTrigger
448
+ ? [normalizeTriggerPayload(userData)]
449
+ : [normalizeTriggerPayload(Object.assign({ user: userData }, op))],
445
450
  app,
446
451
  rules: state_1.StateManager.select("rules"),
447
452
  user: {}, // TODO from currentUser ??
@@ -449,7 +454,8 @@ const handleAuthenticationTrigger = (_a) => __awaiter(void 0, [_a], void 0, func
449
454
  functionName,
450
455
  functionsList,
451
456
  services,
452
- runAsSystem: true
457
+ runAsSystem: true,
458
+ deserializeArgs: false
453
459
  });
454
460
  }
455
461
  catch (error) {
@@ -461,7 +467,6 @@ const handleAuthenticationTrigger = (_a) => __awaiter(void 0, [_a], void 0, func
461
467
  meta: Object.assign(Object.assign({}, baseMeta), { event: 'DELETE' }),
462
468
  error
463
469
  });
464
- console.log("🚀 ~ handleAuthenticationTrigger ~ error:", error);
465
470
  }
466
471
  return;
467
472
  }
@@ -495,7 +500,9 @@ const handleAuthenticationTrigger = (_a) => __awaiter(void 0, [_a], void 0, func
495
500
  meta: Object.assign(Object.assign({}, baseMeta), { event: 'UPDATE' })
496
501
  });
497
502
  yield (0, context_1.GenerateContext)({
498
- args: isAutoTrigger ? [userData] : [Object.assign({ user: userData }, op)],
503
+ args: isAutoTrigger
504
+ ? [normalizeTriggerPayload(userData)]
505
+ : [normalizeTriggerPayload(Object.assign({ user: userData }, op))],
499
506
  app,
500
507
  rules: state_1.StateManager.select("rules"),
501
508
  user: {}, // TODO from currentUser ??
@@ -503,7 +510,8 @@ const handleAuthenticationTrigger = (_a) => __awaiter(void 0, [_a], void 0, func
503
510
  functionName,
504
511
  functionsList,
505
512
  services,
506
- runAsSystem: true
513
+ runAsSystem: true,
514
+ deserializeArgs: false
507
515
  });
508
516
  }
509
517
  catch (error) {
@@ -515,7 +523,6 @@ const handleAuthenticationTrigger = (_a) => __awaiter(void 0, [_a], void 0, func
515
523
  meta: Object.assign(Object.assign({}, baseMeta), { event: 'UPDATE' }),
516
524
  error
517
525
  });
518
- console.log("🚀 ~ handleAuthenticationTrigger ~ error:", error);
519
526
  }
520
527
  return;
521
528
  }
@@ -586,7 +593,9 @@ const handleAuthenticationTrigger = (_a) => __awaiter(void 0, [_a], void 0, func
586
593
  meta: Object.assign(Object.assign({}, baseMeta), { event: 'CREATE' })
587
594
  });
588
595
  yield (0, context_1.GenerateContext)({
589
- args: isAutoTrigger ? [userData] : [Object.assign({ user: userData }, op)],
596
+ args: isAutoTrigger
597
+ ? [normalizeTriggerPayload(userData)]
598
+ : [normalizeTriggerPayload(Object.assign({ user: userData }, op))],
590
599
  app,
591
600
  rules: state_1.StateManager.select("rules"),
592
601
  user: {}, // TODO from currentUser ??
@@ -594,7 +603,8 @@ const handleAuthenticationTrigger = (_a) => __awaiter(void 0, [_a], void 0, func
594
603
  functionName,
595
604
  functionsList,
596
605
  services,
597
- runAsSystem: true
606
+ runAsSystem: true,
607
+ deserializeArgs: false
598
608
  });
599
609
  }
600
610
  catch (error) {
@@ -606,7 +616,6 @@ const handleAuthenticationTrigger = (_a) => __awaiter(void 0, [_a], void 0, func
606
616
  meta: Object.assign(Object.assign({}, baseMeta), { event: 'CREATE' }),
607
617
  error
608
618
  });
609
- console.log("🚀 ~ handleAuthenticationTrigger ~ error:", error);
610
619
  }
611
620
  });
612
621
  });
@@ -677,14 +686,15 @@ const handleDataBaseTrigger = (_a) => __awaiter(void 0, [_a], void 0, function*
677
686
  });
678
687
  try {
679
688
  yield (0, context_1.GenerateContext)({
680
- args: [change],
689
+ args: [normalizeTriggerPayload(change)],
681
690
  app,
682
691
  rules: state_1.StateManager.select("rules"),
683
692
  user: {}, // TODO add from?
684
693
  currentFunction: triggerHandler,
685
694
  functionName,
686
695
  functionsList,
687
- services
696
+ services,
697
+ deserializeArgs: false
688
698
  });
689
699
  }
690
700
  catch (error) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@flowerforce/flowerbase",
3
- "version": "1.8.3",
3
+ "version": "1.8.4-beta.1",
4
4
  "description": "",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -0,0 +1,112 @@
1
+ import { ObjectId } from 'bson'
2
+ import { GenerateContext } from '../../../utils/context'
3
+ import { StateManager } from '../../../state'
4
+ import { TRIGGER_HANDLERS } from '../utils'
5
+
6
+ jest.mock('../../../utils/context', () => ({
7
+ GenerateContext: jest.fn()
8
+ }))
9
+
10
+ jest.mock('../../../state', () => ({
11
+ StateManager: {
12
+ select: jest.fn()
13
+ }
14
+ }))
15
+
16
+ const mockedGenerateContext = jest.mocked(GenerateContext)
17
+ const mockedStateSelect = StateManager.select as jest.Mock
18
+
19
+ describe('TRIGGER_HANDLERS.DATABASE', () => {
20
+ beforeEach(() => {
21
+ mockedGenerateContext.mockReset()
22
+ mockedGenerateContext.mockResolvedValue(undefined)
23
+ mockedStateSelect.mockReset()
24
+ mockedStateSelect.mockReturnValue(undefined)
25
+ })
26
+
27
+ it('preserves BSON ObjectId values in fullDocument before invoking the trigger function', async () => {
28
+ const changeListeners: Record<string, (...args: any[]) => unknown> = {}
29
+ const close = jest.fn(async () => undefined)
30
+ const watch = jest.fn(() => ({
31
+ on: jest.fn((event: string, listener: (...args: any[]) => unknown) => {
32
+ changeListeners[event] = listener
33
+ }),
34
+ close
35
+ }))
36
+
37
+ const collection = { watch }
38
+ const db = jest.fn(() => ({ collection: jest.fn(() => collection) }))
39
+ const client = { db }
40
+
41
+ const app = {
42
+ mongo: {
43
+ changestream: { client }
44
+ },
45
+ server: {
46
+ once: jest.fn()
47
+ }
48
+ } as any
49
+
50
+ await TRIGGER_HANDLERS.DATABASE({
51
+ config: {
52
+ database: 'flowerbase-test',
53
+ collection: 'activityLogs',
54
+ operation_types: ['INSERT'],
55
+ full_document: true,
56
+ full_document_before_change: false,
57
+ match: {},
58
+ project: {}
59
+ } as any,
60
+ triggerHandler: { code: 'module.exports = async function () {}' } as any,
61
+ functionsList: {
62
+ logTriggerEvent: { code: 'module.exports = async function () {}' }
63
+ } as any,
64
+ services: {} as any,
65
+ app,
66
+ triggerName: 'log-trigger-event',
67
+ triggerType: 'DATABASE',
68
+ functionName: 'logTriggerEvent'
69
+ })
70
+
71
+ const documentId = new ObjectId('507f1f77bcf86cd799439011')
72
+ const ownerId = new ObjectId('507f191e810c19729de860ea')
73
+
74
+ await changeListeners.change({
75
+ clusterTime: new Date(),
76
+ operationType: 'insert',
77
+ ns: { db: 'flowerbase-test', coll: 'activityLogs' },
78
+ documentKey: { _id: documentId },
79
+ fullDocument: {
80
+ _id: documentId,
81
+ ownerId
82
+ }
83
+ })
84
+
85
+ expect(mockedGenerateContext).toHaveBeenCalledTimes(1)
86
+ expect(mockedGenerateContext).toHaveBeenCalledWith(
87
+ expect.objectContaining({
88
+ deserializeArgs: false,
89
+ args: [
90
+ expect.objectContaining({
91
+ documentKey: expect.objectContaining({
92
+ _id: expect.any(ObjectId)
93
+ }),
94
+ fullDocument: expect.objectContaining({
95
+ _id: expect.any(ObjectId),
96
+ ownerId: expect.any(ObjectId)
97
+ })
98
+ })
99
+ ]
100
+ })
101
+ )
102
+
103
+ const payload = mockedGenerateContext.mock.calls[0][0].args[0] as {
104
+ documentKey: { _id: ObjectId }
105
+ fullDocument: { _id: ObjectId; ownerId: ObjectId }
106
+ }
107
+
108
+ expect(payload.documentKey._id.toHexString()).toBe(documentId.toHexString())
109
+ expect(payload.fullDocument._id.toHexString()).toBe(documentId.toHexString())
110
+ expect(payload.fullDocument.ownerId.toHexString()).toBe(ownerId.toHexString())
111
+ })
112
+ })
@@ -1,6 +1,7 @@
1
1
  import fs from 'fs'
2
2
  import path from 'node:path'
3
3
  import cron from 'node-cron'
4
+ import { EJSON } from 'bson'
4
5
  import { AUTH_CONFIG, AUTH_DB_NAME, DB_NAME, CHANGESTREAM } from '../../constants'
5
6
  import { createEventId, sanitize } from '../../monitoring/utils'
6
7
  import { StateManager } from '../../state'
@@ -8,6 +9,9 @@ import { readJsonContent } from '../../utils'
8
9
  import { GenerateContext } from '../../utils/context'
9
10
  import { HandlerParams, Trigger, Triggers } from './interface'
10
11
 
12
+ const normalizeTriggerPayload = <T>(value: T): T =>
13
+ EJSON.deserialize(EJSON.serialize(value, { relaxed: false })) as T
14
+
11
15
  const registerOnClose = (
12
16
  app: HandlerParams['app'],
13
17
  handler: () => Promise<void> | void,
@@ -150,7 +154,8 @@ const handleCronTrigger = async ({
150
154
  currentFunction: triggerHandler,
151
155
  functionName,
152
156
  functionsList,
153
- services
157
+ services,
158
+ deserializeArgs: false
154
159
  })
155
160
  } catch (error) {
156
161
  emitTriggerEvent({
@@ -376,7 +381,7 @@ const handleAuthenticationTrigger = async ({
376
381
  meta: { ...baseMeta, event: 'LOGOUT' }
377
382
  })
378
383
  await GenerateContext({
379
- args: [{ user: userData, ...op }],
384
+ args: [normalizeTriggerPayload({ user: userData, ...op })],
380
385
  app,
381
386
  rules: StateManager.select("rules"),
382
387
  user: {}, // TODO from currentUser ??
@@ -384,7 +389,8 @@ const handleAuthenticationTrigger = async ({
384
389
  functionName,
385
390
  functionsList,
386
391
  services,
387
- runAsSystem: true
392
+ runAsSystem: true,
393
+ deserializeArgs: false
388
394
  })
389
395
  } catch (error) {
390
396
  emitTriggerEvent({
@@ -395,7 +401,6 @@ const handleAuthenticationTrigger = async ({
395
401
  meta: { ...baseMeta, event: 'LOGOUT' },
396
402
  error
397
403
  })
398
- console.log("🚀 ~ handleAuthenticationTrigger ~ error:", error)
399
404
  }
400
405
  return
401
406
  }
@@ -433,7 +438,7 @@ const handleAuthenticationTrigger = async ({
433
438
  meta: { ...baseMeta, event: 'LOGIN' }
434
439
  })
435
440
  await GenerateContext({
436
- args: [{ user: userData, ...op }],
441
+ args: [normalizeTriggerPayload({ user: userData, ...op })],
437
442
  app,
438
443
  rules: StateManager.select("rules"),
439
444
  user: {}, // TODO from currentUser ??
@@ -441,7 +446,8 @@ const handleAuthenticationTrigger = async ({
441
446
  functionName,
442
447
  functionsList,
443
448
  services,
444
- runAsSystem: true
449
+ runAsSystem: true,
450
+ deserializeArgs: false
445
451
  })
446
452
  } catch (error) {
447
453
  emitTriggerEvent({
@@ -452,7 +458,6 @@ const handleAuthenticationTrigger = async ({
452
458
  meta: { ...baseMeta, event: 'LOGIN' },
453
459
  error
454
460
  })
455
- console.log("🚀 ~ handleAuthenticationTrigger ~ error:", error)
456
461
  }
457
462
  return
458
463
  }
@@ -485,7 +490,9 @@ const handleAuthenticationTrigger = async ({
485
490
  meta: { ...baseMeta, event: 'DELETE' }
486
491
  })
487
492
  await GenerateContext({
488
- args: isAutoTrigger ? [userData] : [{ user: userData, ...op }],
493
+ args: isAutoTrigger
494
+ ? [normalizeTriggerPayload(userData)]
495
+ : [normalizeTriggerPayload({ user: userData, ...op })],
489
496
  app,
490
497
  rules: StateManager.select("rules"),
491
498
  user: {}, // TODO from currentUser ??
@@ -493,7 +500,8 @@ const handleAuthenticationTrigger = async ({
493
500
  functionName,
494
501
  functionsList,
495
502
  services,
496
- runAsSystem: true
503
+ runAsSystem: true,
504
+ deserializeArgs: false
497
505
  })
498
506
  } catch (error) {
499
507
  emitTriggerEvent({
@@ -504,7 +512,6 @@ const handleAuthenticationTrigger = async ({
504
512
  meta: { ...baseMeta, event: 'DELETE' },
505
513
  error
506
514
  })
507
- console.log("🚀 ~ handleAuthenticationTrigger ~ error:", error)
508
515
  }
509
516
  return
510
517
  }
@@ -539,7 +546,9 @@ const handleAuthenticationTrigger = async ({
539
546
  meta: { ...baseMeta, event: 'UPDATE' }
540
547
  })
541
548
  await GenerateContext({
542
- args: isAutoTrigger ? [userData] : [{ user: userData, ...op }],
549
+ args: isAutoTrigger
550
+ ? [normalizeTriggerPayload(userData)]
551
+ : [normalizeTriggerPayload({ user: userData, ...op })],
543
552
  app,
544
553
  rules: StateManager.select("rules"),
545
554
  user: {}, // TODO from currentUser ??
@@ -547,7 +556,8 @@ const handleAuthenticationTrigger = async ({
547
556
  functionName,
548
557
  functionsList,
549
558
  services,
550
- runAsSystem: true
559
+ runAsSystem: true,
560
+ deserializeArgs: false
551
561
  })
552
562
  } catch (error) {
553
563
  emitTriggerEvent({
@@ -558,7 +568,6 @@ const handleAuthenticationTrigger = async ({
558
568
  meta: { ...baseMeta, event: 'UPDATE' },
559
569
  error
560
570
  })
561
- console.log("🚀 ~ handleAuthenticationTrigger ~ error:", error)
562
571
  }
563
572
  return
564
573
  }
@@ -643,7 +652,9 @@ const handleAuthenticationTrigger = async ({
643
652
  meta: { ...baseMeta, event: 'CREATE' }
644
653
  })
645
654
  await GenerateContext({
646
- args: isAutoTrigger ? [userData] : [{ user: userData, ...op }],
655
+ args: isAutoTrigger
656
+ ? [normalizeTriggerPayload(userData)]
657
+ : [normalizeTriggerPayload({ user: userData, ...op })],
647
658
  app,
648
659
  rules: StateManager.select("rules"),
649
660
  user: {}, // TODO from currentUser ??
@@ -651,7 +662,8 @@ const handleAuthenticationTrigger = async ({
651
662
  functionName,
652
663
  functionsList,
653
664
  services,
654
- runAsSystem: true
665
+ runAsSystem: true,
666
+ deserializeArgs: false
655
667
  })
656
668
  } catch (error) {
657
669
  emitTriggerEvent({
@@ -662,7 +674,6 @@ const handleAuthenticationTrigger = async ({
662
674
  meta: { ...baseMeta, event: 'CREATE' },
663
675
  error
664
676
  })
665
- console.log("🚀 ~ handleAuthenticationTrigger ~ error:", error)
666
677
  }
667
678
  })
668
679
  registerOnClose(
@@ -755,14 +766,15 @@ const handleDataBaseTrigger = async ({
755
766
  })
756
767
  try {
757
768
  await GenerateContext({
758
- args: [change],
769
+ args: [normalizeTriggerPayload(change)],
759
770
  app,
760
771
  rules: StateManager.select("rules"),
761
772
  user: {}, // TODO add from?
762
773
  currentFunction: triggerHandler,
763
774
  functionName,
764
775
  functionsList,
765
- services
776
+ services,
777
+ deserializeArgs: false
766
778
  })
767
779
  } catch (error) {
768
780
  emitTriggerEvent({