@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.
- package/README.md +125 -1
- package/dist/auth/providers/custom-function/controller.d.ts.map +1 -1
- package/dist/auth/providers/custom-function/controller.js +3 -8
- package/dist/constants.d.ts +10 -0
- package/dist/constants.d.ts.map +1 -1
- package/dist/constants.js +11 -1
- package/dist/features/encryption/interface.d.ts +36 -0
- package/dist/features/encryption/interface.d.ts.map +1 -0
- package/dist/features/encryption/interface.js +2 -0
- package/dist/features/encryption/utils.d.ts +9 -0
- package/dist/features/encryption/utils.d.ts.map +1 -0
- package/dist/features/encryption/utils.js +34 -0
- package/dist/features/rules/utils.d.ts.map +1 -1
- package/dist/features/rules/utils.js +1 -11
- package/dist/features/triggers/index.d.ts.map +1 -1
- package/dist/features/triggers/index.js +4 -0
- package/dist/features/triggers/utils.d.ts.map +1 -1
- package/dist/features/triggers/utils.js +30 -38
- package/dist/index.d.ts +3 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +9 -4
- package/dist/monitoring/plugin.d.ts.map +1 -1
- package/dist/monitoring/plugin.js +31 -0
- package/dist/services/mongodb-atlas/index.d.ts.map +1 -1
- package/dist/services/mongodb-atlas/index.js +9 -7
- package/dist/services/mongodb-atlas/model.d.ts +2 -1
- package/dist/services/mongodb-atlas/model.d.ts.map +1 -1
- package/dist/utils/index.d.ts +1 -0
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/index.js +14 -3
- package/dist/utils/initializer/mongodbCSFLE.d.ts +69 -0
- package/dist/utils/initializer/mongodbCSFLE.d.ts.map +1 -0
- package/dist/utils/initializer/mongodbCSFLE.js +131 -0
- package/dist/utils/initializer/registerPlugins.d.ts +5 -1
- package/dist/utils/initializer/registerPlugins.d.ts.map +1 -1
- package/dist/utils/initializer/registerPlugins.js +27 -5
- package/package.json +4 -2
- package/src/auth/providers/custom-function/controller.ts +4 -10
- package/src/constants.ts +11 -2
- package/src/features/encryption/interface.ts +46 -0
- package/src/features/encryption/utils.ts +22 -0
- package/src/features/rules/utils.ts +1 -11
- package/src/features/triggers/index.ts +5 -1
- package/src/features/triggers/utils.ts +31 -42
- package/src/index.ts +10 -2
- package/src/monitoring/plugin.ts +33 -0
- package/src/monitoring/ui.collections.js +7 -10
- package/src/monitoring/ui.css +378 -0
- package/src/monitoring/ui.endpoints.js +5 -10
- package/src/monitoring/ui.events.js +2 -4
- package/src/monitoring/ui.functions.js +64 -71
- package/src/monitoring/ui.html +8 -0
- package/src/monitoring/ui.js +189 -0
- package/src/monitoring/ui.shared.js +237 -2
- package/src/monitoring/ui.triggers.js +2 -3
- package/src/monitoring/ui.users.js +5 -9
- package/src/services/mongodb-atlas/index.ts +10 -13
- package/src/services/mongodb-atlas/model.ts +3 -1
- package/src/types/fastify-raw-body.d.ts +0 -9
- package/src/utils/__tests__/mongodbCSFLE.test.ts +105 -0
- package/src/utils/index.ts +12 -1
- package/src/utils/initializer/mongodbCSFLE.ts +224 -0
- 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')
|
package/src/monitoring/plugin.ts
CHANGED
|
@@ -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
|
|
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
|
|
351
|
-
collectionResult.innerHTML = highlightJson(text || '');
|
|
351
|
+
renderJsonViewer(collectionResult, text || '', { collapsible: true });
|
|
352
352
|
return;
|
|
353
353
|
}
|
|
354
|
-
collectionResult
|
|
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
|
|
369
|
-
collectionRules.innerHTML = highlightJson(text || '');
|
|
367
|
+
renderJsonViewer(collectionRules, text || '', { collapsible: true });
|
|
370
368
|
return;
|
|
371
369
|
}
|
|
372
|
-
collectionRules
|
|
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 = () => {
|