@flowerforce/flowerbase 1.7.6-beta.0 → 1.7.6-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.
Files changed (63) hide show
  1. package/README.md +125 -1
  2. package/dist/auth/providers/custom-function/controller.d.ts.map +1 -1
  3. package/dist/auth/providers/custom-function/controller.js +3 -8
  4. package/dist/constants.d.ts +10 -0
  5. package/dist/constants.d.ts.map +1 -1
  6. package/dist/constants.js +11 -1
  7. package/dist/features/encryption/interface.d.ts +36 -0
  8. package/dist/features/encryption/interface.d.ts.map +1 -0
  9. package/dist/features/encryption/interface.js +2 -0
  10. package/dist/features/encryption/utils.d.ts +9 -0
  11. package/dist/features/encryption/utils.d.ts.map +1 -0
  12. package/dist/features/encryption/utils.js +34 -0
  13. package/dist/features/rules/utils.d.ts.map +1 -1
  14. package/dist/features/rules/utils.js +1 -11
  15. package/dist/features/triggers/index.d.ts.map +1 -1
  16. package/dist/features/triggers/index.js +4 -0
  17. package/dist/features/triggers/utils.d.ts.map +1 -1
  18. package/dist/features/triggers/utils.js +30 -38
  19. package/dist/index.d.ts +3 -1
  20. package/dist/index.d.ts.map +1 -1
  21. package/dist/index.js +9 -4
  22. package/dist/monitoring/plugin.d.ts.map +1 -1
  23. package/dist/monitoring/plugin.js +31 -0
  24. package/dist/services/mongodb-atlas/index.d.ts.map +1 -1
  25. package/dist/services/mongodb-atlas/index.js +9 -7
  26. package/dist/services/mongodb-atlas/model.d.ts +2 -1
  27. package/dist/services/mongodb-atlas/model.d.ts.map +1 -1
  28. package/dist/utils/index.d.ts +1 -0
  29. package/dist/utils/index.d.ts.map +1 -1
  30. package/dist/utils/index.js +14 -3
  31. package/dist/utils/initializer/mongodbCSFLE.d.ts +69 -0
  32. package/dist/utils/initializer/mongodbCSFLE.d.ts.map +1 -0
  33. package/dist/utils/initializer/mongodbCSFLE.js +131 -0
  34. package/dist/utils/initializer/registerPlugins.d.ts +5 -1
  35. package/dist/utils/initializer/registerPlugins.d.ts.map +1 -1
  36. package/dist/utils/initializer/registerPlugins.js +27 -5
  37. package/package.json +4 -2
  38. package/src/auth/providers/custom-function/controller.ts +4 -10
  39. package/src/constants.ts +11 -2
  40. package/src/features/encryption/interface.ts +46 -0
  41. package/src/features/encryption/utils.ts +22 -0
  42. package/src/features/rules/utils.ts +1 -11
  43. package/src/features/triggers/index.ts +5 -1
  44. package/src/features/triggers/utils.ts +31 -42
  45. package/src/index.ts +10 -2
  46. package/src/monitoring/plugin.ts +33 -0
  47. package/src/monitoring/ui.collections.js +7 -10
  48. package/src/monitoring/ui.css +378 -0
  49. package/src/monitoring/ui.endpoints.js +5 -10
  50. package/src/monitoring/ui.events.js +2 -4
  51. package/src/monitoring/ui.functions.js +64 -71
  52. package/src/monitoring/ui.html +8 -0
  53. package/src/monitoring/ui.js +189 -0
  54. package/src/monitoring/ui.shared.js +237 -2
  55. package/src/monitoring/ui.triggers.js +2 -3
  56. package/src/monitoring/ui.users.js +5 -9
  57. package/src/services/mongodb-atlas/index.ts +10 -13
  58. package/src/services/mongodb-atlas/model.ts +3 -1
  59. package/src/types/fastify-raw-body.d.ts +0 -9
  60. package/src/utils/__tests__/mongodbCSFLE.test.ts +105 -0
  61. package/src/utils/index.ts +12 -1
  62. package/src/utils/initializer/mongodbCSFLE.ts +224 -0
  63. package/src/utils/initializer/registerPlugins.ts +45 -10
@@ -1,7 +1,7 @@
1
1
  import fs from 'fs'
2
2
  import path from 'node:path'
3
3
  import cron from 'node-cron'
4
- import { AUTH_CONFIG, AUTH_DB_NAME, DB_NAME } from '../../constants'
4
+ import { AUTH_CONFIG, AUTH_DB_NAME, DB_NAME, CHANGESTREAM } from '../../constants'
5
5
  import { createEventId, sanitize } from '../../monitoring/utils'
6
6
  import { StateManager } from '../../state'
7
7
  import { readJsonContent } from '../../utils'
@@ -246,7 +246,7 @@ const handleAuthenticationTrigger = async ({
246
246
  const { database, isAutoTrigger, operation_types = [], operation_type } = config
247
247
  const providerFilter = normalizeProviders(config.providers ?? [])
248
248
  const authCollection = AUTH_CONFIG.authCollection ?? 'auth_users'
249
- const collection = app.mongo.client.db(database || AUTH_DB_NAME).collection(authCollection)
249
+ const collection = app.mongo[CHANGESTREAM].client.db(database || AUTH_DB_NAME).collection(authCollection)
250
250
  const operationCandidates = operation_type ? mapOpInverse[operation_type] : operation_types
251
251
  const normalizedOps = normalizeOperationTypes(operationCandidates)
252
252
  const baseMeta = {
@@ -277,17 +277,6 @@ const handleAuthenticationTrigger = async ({
277
277
  changeStream.on('error', (error) => {
278
278
  if (shouldIgnoreStreamError(error)) return
279
279
  console.error('Authentication trigger change stream error', error)
280
- emitTriggerEvent({
281
- status: 'error',
282
- triggerName,
283
- triggerType,
284
- functionName,
285
- meta: {
286
- ...baseMeta,
287
- event: 'CHANGE_STREAM'
288
- },
289
- error
290
- })
291
280
  })
292
281
  changeStream.on('change', async function (change) {
293
282
  const operationType = change['operationType' as keyof typeof change] as
@@ -376,6 +365,13 @@ const handleAuthenticationTrigger = async ({
376
365
  updateDescription
377
366
  }
378
367
  try {
368
+ emitTriggerEvent({
369
+ status: 'fired',
370
+ triggerName,
371
+ triggerType,
372
+ functionName,
373
+ meta: { ...baseMeta, event: 'LOGOUT' }
374
+ })
379
375
  await GenerateContext({
380
376
  args: [{ user: userData, ...op }],
381
377
  app,
@@ -387,13 +383,6 @@ const handleAuthenticationTrigger = async ({
387
383
  services,
388
384
  runAsSystem: true
389
385
  })
390
- emitTriggerEvent({
391
- status: 'fired',
392
- triggerName,
393
- triggerType,
394
- functionName,
395
- meta: { ...baseMeta, event: 'LOGOUT' }
396
- })
397
386
  } catch (error) {
398
387
  emitTriggerEvent({
399
388
  status: 'error',
@@ -428,6 +417,13 @@ const handleAuthenticationTrigger = async ({
428
417
  updateDescription
429
418
  }
430
419
  try {
420
+ emitTriggerEvent({
421
+ status: 'fired',
422
+ triggerName,
423
+ triggerType,
424
+ functionName,
425
+ meta: { ...baseMeta, event: 'DELETE' }
426
+ })
431
427
  await GenerateContext({
432
428
  args: isAutoTrigger ? [userData] : [{ user: userData, ...op }],
433
429
  app,
@@ -439,13 +435,6 @@ const handleAuthenticationTrigger = async ({
439
435
  services,
440
436
  runAsSystem: true
441
437
  })
442
- emitTriggerEvent({
443
- status: 'fired',
444
- triggerName,
445
- triggerType,
446
- functionName,
447
- meta: { ...baseMeta, event: 'DELETE' }
448
- })
449
438
  } catch (error) {
450
439
  emitTriggerEvent({
451
440
  status: 'error',
@@ -482,6 +471,13 @@ const handleAuthenticationTrigger = async ({
482
471
  updateDescription
483
472
  }
484
473
  try {
474
+ emitTriggerEvent({
475
+ status: 'fired',
476
+ triggerName,
477
+ triggerType,
478
+ functionName,
479
+ meta: { ...baseMeta, event: 'UPDATE' }
480
+ })
485
481
  await GenerateContext({
486
482
  args: isAutoTrigger ? [userData] : [{ user: userData, ...op }],
487
483
  app,
@@ -493,13 +489,6 @@ const handleAuthenticationTrigger = async ({
493
489
  services,
494
490
  runAsSystem: true
495
491
  })
496
- emitTriggerEvent({
497
- status: 'fired',
498
- triggerName,
499
- triggerType,
500
- functionName,
501
- meta: { ...baseMeta, event: 'UPDATE' }
502
- })
503
492
  } catch (error) {
504
493
  emitTriggerEvent({
505
494
  status: 'error',
@@ -586,6 +575,13 @@ const handleAuthenticationTrigger = async ({
586
575
  }
587
576
 
588
577
  try {
578
+ emitTriggerEvent({
579
+ status: 'fired',
580
+ triggerName,
581
+ triggerType,
582
+ functionName,
583
+ meta: { ...baseMeta, event: 'CREATE' }
584
+ })
589
585
  await GenerateContext({
590
586
  args: isAutoTrigger ? [userData] : [{ user: userData, ...op }],
591
587
  app,
@@ -597,13 +593,6 @@ const handleAuthenticationTrigger = async ({
597
593
  services,
598
594
  runAsSystem: true
599
595
  })
600
- emitTriggerEvent({
601
- status: 'fired',
602
- triggerName,
603
- triggerType,
604
- functionName,
605
- meta: { ...baseMeta, event: 'CREATE' }
606
- })
607
596
  } catch (error) {
608
597
  emitTriggerEvent({
609
598
  status: 'error',
@@ -663,7 +652,7 @@ const handleDataBaseTrigger = async ({
663
652
 
664
653
  const normalizedOperations = normalizeOperationTypes(operation_types)
665
654
 
666
- const collection = app.mongo.client.db(database).collection(collectionName)
655
+ const collection = app.mongo[CHANGESTREAM].client.db(database).collection(collectionName)
667
656
  const pipeline = [
668
657
  {
669
658
  $match: {
package/src/index.ts CHANGED
@@ -6,12 +6,14 @@ import { loadEndpoints } from './features/endpoints/utils'
6
6
  import { registerFunctions } from './features/functions'
7
7
  import { loadFunctions } from './features/functions/utils'
8
8
  import { loadRules } from './features/rules/utils'
9
+ import { loadEncryptionSchemas } from './features/encryption/utils'
9
10
  import { activateTriggers } from './features/triggers'
10
11
  import { loadTriggers } from './features/triggers/utils'
11
12
  import { services } from './services'
12
13
  import { StateManager } from './state'
13
14
  import { exposeRoutes } from './utils/initializer/exposeRoutes'
14
15
  import { registerPlugins } from './utils/initializer/registerPlugins'
16
+ import { type MongoDbEncryptionConfig } from './utils/initializer/mongodbCSFLE'
15
17
  export * from './model'
16
18
 
17
19
 
@@ -30,6 +32,7 @@ export type InitializeConfig = {
30
32
  host?: string
31
33
  corsConfig?: CorsConfig
32
34
  basePath?: string
35
+ mongodbEncryptionConfig?: MongoDbEncryptionConfig
33
36
  }
34
37
 
35
38
  /**
@@ -47,7 +50,8 @@ export async function initialize({
47
50
  port = DEFAULT_CONFIG.PORT,
48
51
  mongodbUrl = DEFAULT_CONFIG.MONGODB_URL,
49
52
  corsConfig = DEFAULT_CONFIG.CORS_OPTIONS,
50
- basePath
53
+ basePath,
54
+ mongodbEncryptionConfig
51
55
  }: InitializeConfig) {
52
56
  if (!jwtSecret || jwtSecret.trim().length === 0) {
53
57
  throw new Error('JWT secret missing: set JWT_SECRET or pass jwtSecret to initialize()')
@@ -77,6 +81,8 @@ export async function initialize({
77
81
  logInfo("Endpoints LOADED")
78
82
  const rulesList = await loadRules(resolvedBasePath)
79
83
  logInfo("Rules LOADED")
84
+ const encryptionSchemas = await loadEncryptionSchemas(resolvedBasePath)
85
+ logInfo("Encryption schemas LOADED")
80
86
 
81
87
  const stateConfig = {
82
88
  functions: functionsList,
@@ -152,7 +158,9 @@ export async function initialize({
152
158
  mongodbUrl,
153
159
  jwtSecret,
154
160
  functionsList,
155
- corsConfig
161
+ corsConfig,
162
+ encryptionSchemas,
163
+ mongodbEncryptionConfig
156
164
  })
157
165
 
158
166
  logInfo('Plugins registration COMPLETED')
@@ -2,6 +2,7 @@ import fastifyWebsocket from '@fastify/websocket'
2
2
  import type { FastifyInstance, FastifyReply, FastifyRequest } from 'fastify'
3
3
  import fp from 'fastify-plugin'
4
4
  import '@fastify/websocket'
5
+ import fs from 'fs'
5
6
  import { DEFAULT_CONFIG } from '../constants'
6
7
  import { StateManager } from '../state'
7
8
  import { registerCollectionRoutes } from './routes/collections'
@@ -316,6 +317,38 @@ const createMonitoringPlugin = fp(async (
316
317
  })
317
318
  })
318
319
 
320
+ const resolveCodeMirrorAsset = (internalPath: string) => {
321
+ try {
322
+ return require.resolve(`codemirror/${internalPath}`)
323
+ } catch {
324
+ return ''
325
+ }
326
+ }
327
+
328
+ const codemirrorAssets: Record<string, string> = {
329
+ 'codemirror.js': resolveCodeMirrorAsset('lib/codemirror.js'),
330
+ 'codemirror.css': resolveCodeMirrorAsset('lib/codemirror.css'),
331
+ 'javascript.js': resolveCodeMirrorAsset('mode/javascript/javascript.js'),
332
+ 'foldcode.js': resolveCodeMirrorAsset('addon/fold/foldcode.js'),
333
+ 'foldgutter.js': resolveCodeMirrorAsset('addon/fold/foldgutter.js'),
334
+ 'brace-fold.js': resolveCodeMirrorAsset('addon/fold/brace-fold.js'),
335
+ 'comment-fold.js': resolveCodeMirrorAsset('addon/fold/comment-fold.js'),
336
+ 'foldgutter.css': resolveCodeMirrorAsset('addon/fold/foldgutter.css')
337
+ }
338
+
339
+ Object.entries(codemirrorAssets).forEach(([assetName, relativePath]) => {
340
+ app.get(`${prefix}/vendor/codemirror/${assetName}`, async (_req, reply) => {
341
+ const assetPath = relativePath || ''
342
+ if (!assetPath || !fs.existsSync(assetPath)) {
343
+ reply.code(404).send(`${assetName} not found`)
344
+ return
345
+ }
346
+ const asset = fs.readFileSync(assetPath, 'utf8')
347
+ reply.header('Cache-Control', 'no-store')
348
+ reply.type(assetName.endsWith('.css') ? 'text/css' : 'application/javascript').send(asset)
349
+ })
350
+ })
351
+
319
352
  app.get(`${prefix}/ws`, { websocket: true }, (connection) => {
320
353
  const socket =
321
354
  (connection as {
@@ -91,7 +91,7 @@
91
91
  collectionTabButtons,
92
92
  collectionTabPanels
93
93
  } = dom;
94
- const { api, parseJsonObject, highlightJson, safeStringify } = utils;
94
+ const { api, parseJsonObject, highlightJson, renderJsonViewer, clearJsonViewer, safeStringify } = utils;
95
95
 
96
96
  const TABLE_TRUNCATE_LIMIT = 200;
97
97
 
@@ -337,22 +337,21 @@
337
337
  const highlight = state.collectionResultHighlight;
338
338
  if (payload === null || payload === undefined) {
339
339
  collectionResult.classList.remove('table-view', 'json-highlight');
340
- collectionResult.textContent = '';
340
+ clearJsonViewer(collectionResult, '');
341
341
  return;
342
342
  }
343
343
  if (state.collectionResultView === 'table') {
344
+ clearJsonViewer(collectionResult, '');
344
345
  renderCollectionTable(payload);
345
346
  return;
346
347
  }
347
348
  collectionResult.classList.remove('table-view');
348
349
  if (highlight) {
349
350
  const text = typeof payload === 'string' ? payload : JSON.stringify(payload, null, 2);
350
- collectionResult.classList.add('json-highlight');
351
- collectionResult.innerHTML = highlightJson(text || '');
351
+ renderJsonViewer(collectionResult, text || '', { collapsible: true });
352
352
  return;
353
353
  }
354
- collectionResult.classList.remove('json-highlight');
355
- collectionResult.textContent = typeof payload === 'string' ? payload : String(payload ?? '');
354
+ clearJsonViewer(collectionResult, typeof payload === 'string' ? payload : String(payload ?? ''));
356
355
  };
357
356
 
358
357
  const setCollectionResult = (value, highlight) => {
@@ -365,12 +364,10 @@
365
364
  if (!collectionRules) return;
366
365
  if (highlight) {
367
366
  const text = typeof value === 'string' ? value : JSON.stringify(value, null, 2);
368
- collectionRules.classList.add('json-highlight');
369
- collectionRules.innerHTML = highlightJson(text || '');
367
+ renderJsonViewer(collectionRules, text || '', { collapsible: true });
370
368
  return;
371
369
  }
372
- collectionRules.classList.remove('json-highlight');
373
- collectionRules.textContent = typeof value === 'string' ? value : String(value ?? '');
370
+ clearJsonViewer(collectionRules, typeof value === 'string' ? value : String(value ?? ''));
374
371
  };
375
372
 
376
373
  const updateCollectionModeView = () => {