@forestadmin/agent 1.95.2 → 1.97.0

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 (34) hide show
  1. package/dist/agent.d.ts +4 -0
  2. package/dist/agent.js +57 -6
  3. package/dist/audit-trail/action-capture.d.ts +17 -0
  4. package/dist/audit-trail/action-capture.js +97 -0
  5. package/dist/audit-trail/index.d.ts +8 -0
  6. package/dist/audit-trail/index.js +44 -0
  7. package/dist/audit-trail/instrument.d.ts +12 -0
  8. package/dist/audit-trail/instrument.js +393 -0
  9. package/dist/audit-trail/migrations.d.ts +34 -0
  10. package/dist/audit-trail/migrations.js +213 -0
  11. package/dist/audit-trail/revert.d.ts +8 -0
  12. package/dist/audit-trail/revert.js +81 -0
  13. package/dist/audit-trail/scope.d.ts +20 -0
  14. package/dist/audit-trail/scope.js +33 -0
  15. package/dist/audit-trail/sql-store.d.ts +30 -0
  16. package/dist/audit-trail/sql-store.js +316 -0
  17. package/dist/audit-trail/types.d.ts +129 -0
  18. package/dist/audit-trail/types.js +3 -0
  19. package/dist/routes/access/audit-trail-correlation.d.ts +18 -0
  20. package/dist/routes/access/audit-trail-correlation.js +84 -0
  21. package/dist/routes/access/audit-trail.d.ts +23 -0
  22. package/dist/routes/access/audit-trail.js +293 -0
  23. package/dist/routes/capabilities.js +5 -1
  24. package/dist/routes/index.js +14 -1
  25. package/dist/routes/modification/action/action.d.ts +3 -0
  26. package/dist/routes/modification/action/action.js +106 -2
  27. package/dist/types.d.ts +39 -1
  28. package/dist/types.js +1 -1
  29. package/dist/utils/correlation-id.d.ts +5 -0
  30. package/dist/utils/correlation-id.js +26 -0
  31. package/dist/utils/options-validator.js +19 -1
  32. package/dist/utils/query-string.d.ts +3 -1
  33. package/dist/utils/query-string.js +5 -5
  34. package/package.json +8 -7
package/dist/agent.d.ts CHANGED
@@ -209,6 +209,10 @@ export default class Agent<S extends TSchema = TSchema> extends FrameworkMounter
209
209
  * their configuration from the Forest API so the generated schema includes them,
210
210
  * which requires connectivity to Forest.
211
211
  *
212
+ * Note: when `auditTrail` is configured, its hooks are not installed here, so the audit
213
+ * database is never connected to or migrated — only the collection structure is needed to
214
+ * generate the schema.
215
+ *
212
216
  * Unlike `start()`, this always rebuilds the schema — even when `isProduction` is
213
217
  * true — and writes the typings whenever `typingsPath` is set, regardless of
214
218
  * `isProduction`.
package/dist/agent.js CHANGED
@@ -42,11 +42,13 @@ const cors_1 = __importDefault(require("@koa/cors"));
42
42
  const router_1 = __importDefault(require("@koa/router"));
43
43
  const promises_1 = require("fs/promises");
44
44
  const json_stringify_pretty_compact_1 = __importDefault(require("json-stringify-pretty-compact"));
45
+ const audit_trail_1 = require("./audit-trail");
45
46
  const embedded_workflow_executor_1 = __importDefault(require("./embedded-workflow-executor"));
46
47
  const framework_mounter_1 = __importDefault(require("./framework-mounter"));
47
48
  const routes_1 = __importDefault(require("./routes"));
48
49
  const services_1 = __importDefault(require("./services"));
49
50
  const customization_1 = __importDefault(require("./services/model-customizations/customization"));
51
+ const correlation_id_1 = require("./utils/correlation-id");
50
52
  const generator_1 = __importDefault(require("./utils/forest-schema/generator"));
51
53
  const options_validator_1 = __importDefault(require("./utils/options-validator"));
52
54
  /**
@@ -95,12 +97,14 @@ class Agent extends framework_mounter_1.default {
95
97
  * Start the agent.
96
98
  */
97
99
  async start() {
100
+ let mounted = false;
98
101
  try {
99
102
  const { router, mcpHttpCallback, mcpIsMcpRoute } = await this.buildRouterAndSendSchema();
100
103
  await this.options.forestAdminClient.subscribeToServerEvents();
101
104
  this.options.forestAdminClient.onRefreshCustomizations(this.restart.bind(this));
102
105
  this.setMcpCallback(mcpHttpCallback ?? null, mcpIsMcpRoute);
103
106
  await this.mount(router);
107
+ mounted = true;
104
108
  // Boot after mount(): the embedded executor reaches the agent over HTTP, and the
105
109
  // standalone server's host/port (used to derive that URL) are only known once mounted.
106
110
  await this.embeddedExecutor?.start(this.standaloneServerHost, this.standaloneServerPort);
@@ -108,6 +112,20 @@ class Agent extends framework_mounter_1.default {
108
112
  catch (error) {
109
113
  const { message } = error;
110
114
  this.options.logger('Error', `Forest Admin agent startup failure: ${message}`);
115
+ // buildRouterAndSendSchema() may already have opened the audit-trail connection even
116
+ // though a later startup step failed; close it so a failed start doesn't leak the pool
117
+ // (e.g. across restart retries) — but only when that failure happened before mount(): once
118
+ // the router is mounted, the host framework is already serving requests against this same
119
+ // connection, and closing it here would break those instead of freeing an unused pool.
120
+ if (!mounted) {
121
+ try {
122
+ await this.options.auditTrail?.close();
123
+ }
124
+ catch (closeError) {
125
+ const { message: closeMessage } = closeError;
126
+ this.options.logger('Error', `Failed to close the audit-trail database connection: ${closeMessage}`);
127
+ }
128
+ }
111
129
  throw error;
112
130
  }
113
131
  }
@@ -119,8 +137,19 @@ class Agent extends framework_mounter_1.default {
119
137
  await this.embeddedExecutor?.stop();
120
138
  // Close anything related to ForestAdmin client
121
139
  this.options.forestAdminClient.close();
122
- // Stop at framework level
140
+ // Stop at framework level: this drains in-flight requests (e.g. the standalone server waits
141
+ // for open connections to finish before resolving). The audit trail is closed only after,
142
+ // so a create/update/delete still being handled at shutdown can still reach its after-hook
143
+ // and append its entry, instead of that write failing against an already-closed store.
123
144
  await super.stop();
145
+ // A failure closing the audit-trail connection must not prevent the rest of shutdown.
146
+ try {
147
+ await this.options.auditTrail?.close();
148
+ }
149
+ catch (error) {
150
+ const { message } = error;
151
+ this.options.logger('Error', `Failed to close the audit-trail database connection: ${message}`);
152
+ }
124
153
  }
125
154
  /**
126
155
  * Restart the agent at runtime (remount routes).
@@ -312,13 +341,19 @@ class Agent extends framework_mounter_1.default {
312
341
  }
313
342
  // Build main router
314
343
  const router = new router_1.default();
315
- router.all('(.*)', (0, cors_1.default)({ credentials: true, maxAge: 24 * 3600, privateNetworkAccess: true }));
344
+ router.all('(.*)', (0, cors_1.default)({
345
+ credentials: true,
346
+ maxAge: 24 * 3600,
347
+ privateNetworkAccess: true,
348
+ exposeHeaders: [correlation_id_1.CORRELATION_ID_HEADER],
349
+ }));
316
350
  router.use((0, bodyparser_1.default)({
317
351
  encoding: 'utf-8',
318
352
  jsonLimit: this.options.maxBodySize,
319
353
  parsedMethods: ['POST', 'PUT', 'PATCH', 'DELETE'],
320
354
  ...this.options.bodyParserOptions,
321
355
  }));
356
+ router.use(correlation_id_1.correlationIdMiddleware);
322
357
  routes.forEach(route => route.setupRoutes(router));
323
358
  return { router, mcpHttpCallback, mcpIsMcpRoute };
324
359
  }
@@ -332,7 +367,7 @@ class Agent extends framework_mounter_1.default {
332
367
  try {
333
368
  // Dynamic import to defer loading until actually needed
334
369
  const { ForestMCPServer, ForestServerClientImpl, makeIsMcpRoute } = await Promise.resolve().then(() => __importStar(require('@forestadmin/mcp-server')));
335
- const forestServerClient = new ForestServerClientImpl(this.options.forestAdminClient.schemaService, this.options.forestAdminClient.activityLogsService, this.options.forestServerUrl);
370
+ const forestServerClient = new ForestServerClientImpl(this.options.forestAdminClient.schemaService, this.options.forestAdminClient.activityLogsService, this.options.forestAdminClient.workflowsService, this.options.forestServerUrl);
336
371
  const mcpServer = new ForestMCPServer({
337
372
  forestServerUrl: this.options.forestServerUrl,
338
373
  forestAppUrl: this.options.forestAppUrl,
@@ -359,7 +394,10 @@ class Agent extends framework_mounter_1.default {
359
394
  throw error;
360
395
  }
361
396
  }
362
- async buildNoCodeDataSource() {
397
+ // `installAuditTrail: false` skips wiring the audit hooks (and, with them, the store's DB
398
+ // connection/migration) — used by `generateSchemaOnly()`, which only needs the collection
399
+ // structure and must not depend on the audit database being reachable.
400
+ async buildNoCodeDataSource({ installAuditTrail = true } = {}) {
363
401
  // It allows to rebuild the full customization stack with no code customizations
364
402
  this.nocodeCustomizer = new datasource_customizer_1.DataSourceCustomizer({
365
403
  ignoreMissingSchemaElementErrors: this.options.ignoreMissingSchemaElementErrors || false,
@@ -367,6 +405,15 @@ class Agent extends framework_mounter_1.default {
367
405
  });
368
406
  this.nocodeCustomizer.addDataSource(this.customizer.getFactory());
369
407
  this.nocodeCustomizer.use(this.customizationService.addCustomizations);
408
+ if (installAuditTrail && this.options.auditTrail) {
409
+ const { store, redact, critical } = this.options.auditTrail;
410
+ this.nocodeCustomizer.use(audit_trail_1.installAuditTrailHooks, {
411
+ store,
412
+ redact,
413
+ critical,
414
+ logger: this.options.logger,
415
+ });
416
+ }
370
417
  return this.nocodeCustomizer.getDataSource(this.options.logger);
371
418
  }
372
419
  buildSchemaMeta() {
@@ -425,6 +472,10 @@ class Agent extends framework_mounter_1.default {
425
472
  * their configuration from the Forest API so the generated schema includes them,
426
473
  * which requires connectivity to Forest.
427
474
  *
475
+ * Note: when `auditTrail` is configured, its hooks are not installed here, so the audit
476
+ * database is never connected to or migrated — only the collection structure is needed to
477
+ * generate the schema.
478
+ *
428
479
  * Unlike `start()`, this always rebuilds the schema — even when `isProduction` is
429
480
  * true — and writes the typings whenever `typingsPath` is set, regardless of
430
481
  * `isProduction`.
@@ -437,7 +488,7 @@ class Agent extends framework_mounter_1.default {
437
488
  async generateSchemaOnly() {
438
489
  const { logger, schemaPath, typingsPath, typingsMaxDepth } = this.options;
439
490
  try {
440
- const dataSource = await this.buildNoCodeDataSource();
491
+ const dataSource = await this.buildNoCodeDataSource({ installAuditTrail: false });
441
492
  const schema = await this.schemaGenerator.buildSchema(dataSource);
442
493
  const meta = this.buildSchemaMeta();
443
494
  await (0, promises_1.writeFile)(schemaPath, (0, json_stringify_pretty_compact_1.default)({ ...schema, meta }, { maxLength: 100 }), {
@@ -456,4 +507,4 @@ class Agent extends framework_mounter_1.default {
456
507
  }
457
508
  }
458
509
  exports.default = Agent;
459
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYWdlbnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvYWdlbnQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7QUFxQkEsOEVBQTBFO0FBQzFFLGlFQUF5QztBQUN6QyxxREFBNkI7QUFDN0IseURBQWlDO0FBQ2pDLDBDQUFrRDtBQUNsRCxrR0FBc0Q7QUFFdEQsOEZBQW9FO0FBQ3BFLDRFQUFtRDtBQUNuRCxzREFBa0M7QUFDbEMsMERBQXNDO0FBQ3RDLGtHQUFpRjtBQUNqRixnRkFBOEQ7QUFDOUQsa0ZBQXlEO0FBRXpEOzs7Ozs7Ozs7R0FTRztBQUNILE1BQXFCLEtBQW1DLFNBQVEsMkJBQWdCO0lBb0I5RTs7Ozs7Ozs7Ozs7Ozs7O09BZUc7SUFDSCxZQUFZLE9BQXFCO1FBQy9CLE1BQU0sVUFBVSxHQUFHLDJCQUFnQixDQUFDLFFBQVEsQ0FBQywyQkFBZ0IsQ0FBQyxZQUFZLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQztRQUNyRixLQUFLLENBQUMsVUFBVSxDQUFDLE1BQU0sRUFBRSxVQUFVLENBQUMsTUFBTSxDQUFDLENBQUM7UUEvQjlDLDJDQUEyQztRQUNuQyxlQUFVLEdBQUcsS0FBSyxDQUFDO1FBTzNCLHVGQUF1RjtRQUMvRSxxQkFBZ0IsR0FBb0MsSUFBSSxDQUFDO1FBRXpELGlCQUFZLEdBQUcsS0FBSyxDQUFDO1FBc0IzQixJQUFJLENBQUMsT0FBTyxHQUFHLFVBQVUsQ0FBQztRQUMxQixJQUFJLENBQUMsVUFBVSxHQUFHLElBQUksNENBQW9CLENBQUk7WUFDNUMsZ0NBQWdDLEVBQUUsT0FBTyxDQUFDLGdDQUFnQyxJQUFJLEtBQUs7U0FDcEYsQ0FBQyxDQUFDO1FBQ0gsSUFBSSxDQUFDLG9CQUFvQixHQUFHLElBQUksdUJBQW9CLENBQUMsVUFBVSxDQUFDLENBQUM7UUFDakUsSUFBSSxDQUFDLGVBQWUsR0FBRyxJQUFJLG1CQUFlLENBQUMsVUFBVSxD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
510
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYWdlbnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvYWdlbnQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7QUFxQkEsOEVBQTBFO0FBQzFFLGlFQUF5QztBQUN6QyxxREFBNkI7QUFDN0IseURBQWlDO0FBQ2pDLDBDQUFrRDtBQUNsRCxrR0FBc0Q7QUFFdEQsK0NBQXVEO0FBQ3ZELDhGQUFvRTtBQUNwRSw0RUFBbUQ7QUFDbkQsc0RBQWtDO0FBQ2xDLDBEQUFzQztBQUN0QyxrR0FBaUY7QUFDakYsMkRBQXdGO0FBQ3hGLGdGQUE4RDtBQUM5RCxrRkFBeUQ7QUFFekQ7Ozs7Ozs7OztHQVNHO0FBQ0gsTUFBcUIsS0FBbUMsU0FBUSwyQkFBZ0I7SUFvQjlFOzs7Ozs7Ozs7Ozs7Ozs7T0FlRztJQUNILFlBQVksT0FBcUI7UUFDL0IsTUFBTSxVQUFVLEdBQUcsMkJBQWdCLENBQUMsUUFBUSxDQUFDLDJCQUFnQixDQUFDLFlBQVksQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDO1FBQ3JGLEtBQUssQ0FBQyxVQUFVLENBQUMsTUFBTSxFQUFFLFVBQVUsQ0FBQyxNQUFNLENBQUMsQ0FBQztRQS9COUMsMkNBQTJDO1FBQ25DLGVBQVUsR0FBRyxLQUFLLENBQUM7UUFPM0IsdUZBQXVGO1FBQy9FLHFCQUFnQixHQUFvQyxJQUFJLENBQUM7UUFFekQsaUJBQVksR0FBRyxLQUFLLENBQUM7UUFzQjNCLElBQUksQ0FBQyxPQUFPLEdBQUcsVUFBVSxDQUFDO1FBQzFCLElBQUksQ0FBQyxVQUFVLEdBQUcsSUFBSSw0Q0FBb0IsQ0FBSTtZQUM1QyxnQ0FBZ0MsRUFBRSxPQUFPLENBQUMsZ0NBQWdDLElBQUksS0FBSztTQUNwRixDQUFDLENBQUM7UUFDSCxJQUFJLENBQUMsb0JBQW9CLEdBQUcsSUFBSSx1QkFBb0IsQ0FBQyxVQUFVLENBQUMsQ0FBQztRQUNqRSxJQUFJLENBQUMsZUFBZSxHQUFHLElBQUksbUJBQWUsQ0FBQyxVQUFVLENBQUMsQ0FBQztJQUN6RCxDQUFDO0lBRUQ7O09BRUc7SUFDSCxLQUFLLENBQUMsS0FBSztRQUNULElBQUksT0FBTyxHQUFHLEtBQUssQ0FBQztRQUVwQixJQUFJLENBQUM7WUFDSCxNQUFNLEVBQUUsTUFBTSxFQUFFLGVBQWUsRUFBRSxhQUFhLEVBQUUsR0FBRyxNQUFNLElBQUksQ0FBQyx3QkFBd0IsRUFBRSxDQUFDO1lBRXpGLE1BQU0sSUFBSSxDQUFDLE9BQU8sQ0FBQyxpQkFBaUIsQ0FBQyx1QkFBdUIsRUFBRSxDQUFDO1lBQy9ELElBQUksQ0FBQyxPQUFPLENBQUMsaUJBQWlCLENBQUMsdUJBQXVCLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQztZQUVoRixJQUFJLENBQUMsY0FBYyxDQUFDLGVBQWUsSUFBSSxJQUFJLEVBQUUsYUFBYSxDQUFDLENBQUM7WUFDNUQsTUFBTSxJQUFJLENBQUMsS0FBSyxDQUFDLE1BQU0sQ0FBQyxDQUFDO1lBQ3pCLE9BQU8sR0FBRyxJQUFJLENBQUM7WUFFZixpRkFBaUY7WUFDakYsdUZBQXVGO1lBQ3ZGLE1BQU0sSUFBSSxDQUFDLGdCQUFnQixFQUFFLEtBQUssQ0FBQyxJQUFJLENBQUMsb0JBQW9CLEVBQUUsSUFBSSxDQUFDLG9CQUFvQixDQUFDLENBQUM7UUFDM0YsQ0FBQztRQUFDLE9BQU8sS0FBSyxFQUFFLENBQUM7WUFDZixNQUFNLEVBQUUsT0FBTyxFQUFFLEdBQUcsS0FBYyxDQUFDO1lBQ25DLElBQUksQ0FBQyxPQUFPLENBQUMsTUFBTSxDQUFDLE9BQU8sRUFBRSx1Q0FBdUMsT0FBTyxFQUFFLENBQUMsQ0FBQztZQUUvRSxxRkFBcUY7WUFDckYsdUZBQXVGO1lBQ3ZGLDJGQUEyRjtZQUMzRiwwRkFBMEY7WUFDMUYsdUZBQXVGO1lBQ3ZGLElBQUksQ0FBQyxPQUFPLEVBQUUsQ0FBQztnQkFDYixJQUFJLENBQUM7b0JBQ0gsTUFBTSxJQUFJLENBQUMsT0FBTyxDQUFDLFVBQVUsRUFBRSxLQUFLLEVBQUUsQ0FBQztnQkFDekMsQ0FBQztnQkFBQyxPQUFPLFVBQVUsRUFBRSxDQUFDO29CQUNwQixNQUFNLEVBQUUsT0FBTyxFQUFFLFlBQVksRUFBRSxHQUFHLFVBQW1CLENBQUM7b0JBQ3RELElBQUksQ0FBQyxPQUFPLENBQUMsTUFBTSxDQUNqQixPQUFPLEVBQ1Asd0RBQXdELFlBQVksRUFBRSxDQUN2RSxDQUFDO2dCQUNKLENBQUM7WUFDSCxDQUFDO1lBRUQsTUFBTSxLQUFLLENBQUM7UUFDZCxDQUFDO0lBQ0gsQ0FBQztJQUVEOztPQUVHO0lBQ00sS0FBSyxDQUFDLElBQUk7UUFDakIscUZBQXFGO1FBQ3JGLE1BQU0sSUFBSSxDQUFDLGdCQUFnQixFQUFFLElBQUksRUFBRSxDQUFDO1FBQ3BDLCtDQUErQztRQUMvQyxJQUFJLENBQUMsT0FBTyxDQUFDLGlCQUFpQixDQUFDLEtBQUssRUFBRSxDQUFDO1FBQ3ZDLDRGQUE0RjtRQUM1RiwwRkFBMEY7UUFDMUYsMkZBQTJGO1FBQzNGLHVGQUF1RjtRQUN2RixNQUFNLEtBQUssQ0FBQyxJQUFJLEVBQUUsQ0FBQztRQUVuQixzRkFBc0Y7UUFDdEYsSUFBSSxDQUFDO1lBQ0gsTUFBTSxJQUFJLENBQUMsT0FBTyxDQUFDLFVBQVUsRUFBRSxLQUFLLEVBQUUsQ0FBQztRQUN6QyxDQUFDO1FBQUMsT0FBTyxLQUFLLEVBQUUsQ0FBQztZQUNmLE1BQU0sRUFBRSxPQUFPLEVBQUUsR0FBRyxLQUFjLENBQUM7WUFDbkMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxNQUFNLENBQ2pCLE9BQU8sRUFDUCx3REFBd0QsT0FBTyxFQUFFLENBQ2xFLENBQUM7UUFDSixDQUFDO0lBQ0gsQ0FBQztJQUVEOztPQUVHO0lBQ0gsS0FBSyxDQUFDLE9BQU87UUFDWCxJQUFJLElBQUksQ0FBQyxZQUFZLEVBQUUsQ0FBQztZQUN0QixJQUFJLENBQUMsT0FBTyxDQUFDLE1BQU0sQ0FBQyxPQUFPLEVBQUUsMENBQTBDLENBQUMsQ0FBQztZQUV6RSxPQUFPO1FBQ1QsQ0FBQztRQUVELElBQUksQ0FBQyxPQUFPLENBQUMsTUFBTSxDQUFDLE1BQU0sRUFBRSx3QkFBd0IsQ0FBQyxDQUFDO1FBRXRELElBQUksQ0FBQyxZQUFZLEdBQUcsSUFBSSxDQUFDO1FBRXpCLElBQUksQ0FBQztZQUNILDBDQUEwQztZQUMxQyxNQUFNLEVBQUUsTUFBTSxFQUFFLGVBQWUsRUFBRSxhQUFhLEVBQUUsR0FBRyxNQUFNLElBQUksQ0FBQyx3QkFBd0IsRUFBRSxDQUFDO1lBRXpGLElBQUksQ0FBQyxjQUFjLENBQUMsZUFBZSxJQUFJLElBQUksRUFBRSxhQUFhLENBQUMsQ0FBQztZQUM1RCxNQUFNLElBQUksQ0FBQyxPQUFPLENBQUMsTUFBTSxDQUFDLENBQUM7UUFDN0IsQ0FBQztnQkFBUyxDQUFDO1lBQ1QsSUFBSSxDQUFDLFlBQVksR0FBRyxLQUFLLENBQUM7UUFDNUIsQ0FBQztJQUNILENBQUM7SUFFRDs7Ozs7T0FLRztJQUNILGFBQWEsQ0FBQyxPQUEwQixFQUFFLE9BQTJCO1FBQ25FLElBQUksQ0FBQyxVQUFVLENBQUMsYUFBYSxDQUFDLE9BQU8sRUFBRSxPQUFPLEVBQUUsSUFBSSxDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQztRQUV6RSxPQUFPLElBQUksQ0FBQztJQUNkLENBQUM7SUFFRDs7Ozs7T0FLRztJQUNILEtBQUssQ0FBQyx1QkFBdUIsQ0FBQyxXQUFtQixFQUFFLGVBQXVCO1FBQ3hFLE1BQU0sRUFBRSxNQUFNLEVBQUUsR0FBRyxJQUFJLENBQUMsT0FBTyxDQUFDO1FBQ2hDLE1BQU0sSUFBSSxDQUFDLFVBQVUsQ0FBQyxhQUFhLENBQUMsTUFBTSxDQUFDLENBQUM7UUFDNUMsTUFBTSxJQUFJLENBQUMsVUFBVSxDQUFDLHVCQUF1QixDQUFDLFdBQVcsRUFBRSxlQUFlLENBQUMsQ0FBQztJQUM5RSxDQUFDO0lBRUQ7Ozs7Ozs7Ozs7Ozs7T0FhRztJQUNILFFBQVEsQ0FBQyxJQUFZLEVBQUUsVUFBd0M7UUFDN0QsSUFBSSxDQUFDLFVBQVUsQ0FBQyxRQUFRLENBQUMsSUFBSSxFQUFFLFVBQVUsQ0FBQyxDQUFDO1FBRTNDLE9BQU8sSUFBSSxDQUFDO0lBQ2QsQ0FBQztJQUVEOzs7Ozs7O09BT0c7SUFDSCxtQkFBbUIsQ0FDakIsSUFBTyxFQUNQLE1BQTJEO1FBRTNELElBQUksQ0FBQyxVQUFVLENBQUMsbUJBQW1CLENBQUMsSUFBSSxFQUFFLE1BQU0sQ0FBQyxDQUFDO1FBRWxELE9BQU8sSUFBSSxDQUFDO0lBQ2QsQ0FBQztJQUVEOzs7OztPQUtHO0lBQ0gsZ0JBQWdCLENBQUMsR0FBRyxLQUEyQjtRQUM3QyxJQUFJLENBQUMsVUFBVSxDQUFDLGdCQUFnQixDQUFDLEdBQUcsS0FBSyxDQUFDLENBQUM7UUFFM0MsT0FBTyxJQUFJLENBQUM7SUFDZCxDQUFDO0lBRUQ7Ozs7Ozs7OztPQVNHO0lBQ0gsR0FBRyxDQUFVLE1BQXVCLEVBQUUsT0FBaUI7UUFDckQsSUFBSSxDQUFDLFVBQVUsQ0FBQyxHQUFHLENBQUMsTUFBTSxFQUFFLE9BQU8sQ0FBQyxDQUFDO1FBRXJDLE9BQU8sSUFBSSxDQUFDO0lBQ2QsQ0FBQztJQUVEOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztPQTZCRztJQUNILGdCQUFnQixDQUFDLE9BTWhCO1FBQ0MsSUFBSSxDQUFDLFVBQVUsR0FBRyxJQUFJLENBQUM7UUFDdkIsSUFBSSxDQUFDLGVBQWUsR0FBRyxPQUFPLEVBQUUsWUFBWSxDQUFDO1FBQzdDLElBQUksQ0FBQyxXQUFXLEdBQUcsT0FBTyxFQUFFLFFBQVEsQ0FBQztRQUNyQyxJQUFJLENBQUMsV0FBVyxHQUFHLE9BQU8sRUFBRSxRQUFRLENBQUM7UUFDckMsSUFBSSxDQUFDLHNCQUFzQixHQUFHLE9BQU8sRUFBRSxtQkFBbUIsQ0FBQztRQUMzRCxJQUFJLENBQUMsY0FBYyxHQUFHLE9BQU8sRUFBRSxXQUFXLENBQUM7UUFFM0MsT0FBTyxJQUFJLENBQUM7SUFDZCxDQUFDO0lBRUQ7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7T0FzQkc7SUFDSCxtQkFBbUIsQ0FBQyxVQUF3QyxFQUFFO1FBQzVELElBQUksSUFBSSxDQUFDLGdCQUFnQixFQUFFLENBQUM7WUFDMUIsTUFBTSxJQUFJLEtBQUssQ0FBQyw4Q0FBOEMsQ0FBQyxDQUFDO1FBQ2xFLENBQUM7UUFFRCxNQUFNLFFBQVEsR0FBRyxJQUFJLG9DQUF3QixDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsQ0FBQztRQUM1RCw4RkFBOEY7UUFDOUYsd0ZBQXdGO1FBQ3hGLGlGQUFpRjtRQUNoRixJQUFJLENBQUMsT0FBd0IsQ0FBQyxtQkFBbUIsR0FBRyxRQUFRLENBQUMsU0FBUyxDQUFDLE9BQU8sQ0FBQyxDQUFDO1FBQ2pGLElBQUksQ0FBQyxnQkFBZ0IsR0FBRyxRQUFRLENBQUM7UUFFakMsT0FBTyxJQUFJLENBQUM7SUFDZCxDQUFDO0lBRVMsU0FBUyxDQUFDLFVBQXNCLEVBQUUsUUFBdUM7UUFDakYsT0FBTyxJQUFBLGdCQUFVLEVBQUMsVUFBVSxFQUFFLElBQUksQ0FBQyxPQUFPLEVBQUUsUUFBUSxDQUFDLENBQUM7SUFDeEQsQ0FBQztJQUVEOzs7T0FHRztJQUNLLEtBQUssQ0FBQyxTQUFTLENBQUMsVUFBc0I7UUFLNUMsZ0JBQWdCO1FBQ2hCLE1BQU0sUUFBUSxHQUFHLElBQUEsa0JBQVksRUFBQyxJQUFJLENBQUMsT0FBTyxDQUFDLENBQUM7UUFDNUMsTUFBTSxNQUFNLEdBQUcsSUFBSSxDQUFDLFNBQVMsQ0FBQyxVQUFVLEVBQUUsUUFBUSxDQUFDLENBQUM7UUFFcEQsTUFBTSxPQUFPLENBQUMsR0FBRyxDQUFDLE1BQU0sQ0FBQyxHQUFHLENBQUMsS0FBSyxDQUFDLEVBQUUsQ0FBQyxLQUFLLENBQUMsU0FBUyxFQUFFLENBQUMsQ0FBQyxDQUFDO1FBRTFELDBEQUEwRDtRQUMxRCxJQUFJLGVBQXlDLENBQUM7UUFDOUMsSUFBSSxhQUEwQyxDQUFDO1FBRS9DLElBQUksSUFBSSxDQUFDLFVBQVUsRUFBRSxDQUFDO1lBQ3BCLENBQUMsRUFBRSxZQUFZLEVBQUUsZUFBZSxFQUFFLFVBQVUsRUFBRSxhQUFhLEVBQUU7Z0JBQzNELE1BQU0sSUFBSSxDQUFDLG1CQUFtQixFQUFFLENBQUMsQ0FBQztRQUN0QyxDQUFDO1FBRUQsb0JBQW9CO1FBQ3BCLE1BQU0sTUFBTSxHQUFHLElBQUksZ0JBQU0sRUFBRSxDQUFDO1FBQzVCLE1BQU0sQ0FBQyxHQUFHLENBQ1IsTUFBTSxFQUNOLElBQUEsY0FBSSxFQUFDO1lBQ0gsV0FBVyxFQUFFLElBQUk7WUFDakIsTUFBTSxFQUFFLEVBQUUsR0FBRyxJQUFJO1lBQ2pCLG9CQUFvQixFQUFFLElBQUk7WUFDMUIsYUFBYSxFQUFFLENBQUMsc0NBQXFCLENBQUM7U0FDdkMsQ0FBQyxDQUNILENBQUM7UUFDRixNQUFNLENBQUMsR0FBRyxDQUNSLElBQUEsb0JBQVUsRUFBQztZQUNULFFBQVEsRUFBRSxPQUFPO1lBQ2pCLFNBQVMsRUFBRSxJQUFJLENBQUMsT0FBTyxDQUFDLFdBQVc7WUFDbkMsYUFBYSxFQUFFLENBQUMsTUFBTSxFQUFFLEtBQUssRUFBRSxPQUFPLEVBQUUsUUFBUSxDQUFDO1lBQ2pELEdBQUcsSUFBSSxDQUFDLE9BQU8sQ0FBQyxpQkFBaUI7U0FDbEMsQ0FBQyxDQUNILENBQUM7UUFDRixNQUFNLENBQUMsR0FBRyxDQUFDLHdDQUF1QixDQUFDLENBQUM7UUFDcEMsTUFBTSxDQUFDLE9BQU8sQ0FBQyxLQUFLLENBQUMsRUFBRSxDQUFDLEtBQUssQ0FBQyxXQUFXLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQztRQUVuRCxPQUFPLEVBQUUsTUFBTSxFQUFFLGVBQWUsRUFBRSxhQUFhLEVBQUUsQ0FBQztJQUNwRCxDQUFDO0lBRUQ7Ozs7T0FJRztJQUNLLEtBQUssQ0FBQyxtQkFBbUI7UUFJL0IsTUFBTSxTQUFTLEdBQUcsQ0FBQyxLQUFLLEVBQUUsT0FBTyxFQUFFLEVBQUUsQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLE1BQU0sQ0FBQyxLQUFLLEVBQUUsU0FBUyxPQUFPLEVBQUUsQ0FBQyxDQUFDO1FBRXJGLElBQUksQ0FBQztZQUNILHdEQUF3RDtZQUN4RCxNQUFNLEVBQUUsZUFBZSxFQUFFLHNCQUFzQixFQUFFLGNBQWMsRUFBRSxHQUFHLHdEQUNsRSx5QkFBeUIsR0FDMUIsQ0FBQztZQUVGLE1BQU0sa0JBQWtCLEdBQUcsSUFBSSxzQkFBc0IsQ0FDbkQsSUFBSSxDQUFDLE9BQU8sQ0FBQyxpQkFBaUIsQ0FBQyxhQUFhLEVBQzVDLElBQUksQ0FBQyxPQUFPLENBQUMsaUJBQWlCLENBQUMsbUJBQW1CLEVBQ2xELElBQUksQ0FBQyxPQUFPLENBQUMsaUJBQWlCLENBQUMsZ0JBQWdCLEVBQy9DLElBQUksQ0FBQyxPQUFPLENBQUMsZUFBZSxDQUM3QixDQUFDO1lBRUYsTUFBTSxTQUFTLEdBQUcsSUFBSSxlQUFlLENBQUM7Z0JBQ3BDLGVBQWUsRUFBRSxJQUFJLENBQUMsT0FBTyxDQUFDLGVBQWU7Z0JBQzdDLFlBQVksRUFBRSxJQUFJLENBQUMsT0FBTyxDQUFDLFlBQVk7Z0JBQ3ZDLFNBQVMsRUFBRSxJQUFJLENBQUMsT0FBTyxDQUFDLFNBQVM7Z0JBQ2pDLFVBQVUsRUFBRSxJQUFJLENBQUMsT0FBTyxDQUFDLFVBQVU7Z0JBQ25DLE1BQU0sRUFBRSxTQUFTO2dCQUNqQixrQkFBa0I7Z0JBQ2xCLFlBQVksRUFBRSxJQUFJLENBQUMsZUFBZTtnQkFDbEMsUUFBUSxFQUFFLElBQUksQ0FBQyxXQUFXO2dCQUMxQixRQUFRLEVBQUUsSUFBSSxDQUFDLFdBQVc7Z0JBQzFCLG1CQUFtQixFQUFFLElBQUksQ0FBQyxzQkFBc0I7Z0JBQ2hELFdBQVcsRUFBRSxJQUFJLENBQUMsY0FBYztnQkFDaEMsZUFBZSxFQUFFLElBQUksQ0FBQyxzQkFBc0IsRUFBRTthQUMvQyxDQUFDLENBQUM7WUFFSCxNQUFNLFlBQVksR0FBRyxNQUFNLFNBQVMsQ0FBQyxlQUFlLEVBQUUsQ0FBQztZQUN2RCxNQUFNLFVBQVUsR0FBRyxjQUFjLENBQUMsSUFBSSxDQUFDLFdBQVcsQ0FBQyxDQUFDO1lBRXBELFNBQVMsQ0FBQyxNQUFNLEVBQUUsaUNBQWlDLENBQUMsQ0FBQztZQUNyRCxTQUFTLENBQ1AsTUFBTSxFQUNOLHNGQUFzRixDQUN2RixDQUFDO1lBRUYsT0FBTyxFQUFFLFlBQVksRUFBRSxVQUFVLEVBQUUsQ0FBQztRQUN0QyxDQUFDO1FBQUMsT0FBTyxLQUFLLEVBQUUsQ0FBQztZQUNmLE1BQU0sRUFBRSxPQUFPLEVBQUUsR0FBRyxLQUFjLENBQUM7WUFDbkMsU0FBUyxDQUFDLE9BQU8sRUFBRSxvQ0FBb0MsT0FBTyxFQUFFLENBQUMsQ0FBQztZQUNsRSxNQUFNLEtBQUssQ0FBQztRQUNkLENBQUM7SUFDSCxDQUFDO0lBRUQsMEZBQTBGO0lBQzFGLDBGQUEwRjtJQUMxRix1RUFBdUU7SUFDL0QsS0FBSyxDQUFDLHFCQUFxQixDQUFDLEVBQUUsaUJBQWlCLEdBQUcsSUFBSSxFQUFFLEdBQUcsRUFBRTtRQUNuRSxnRkFBZ0Y7UUFDaEYsSUFBSSxDQUFDLGdCQUFnQixHQUFHLElBQUksNENBQW9CLENBQUk7WUFDbEQsZ0NBQWdDLEVBQUUsSUFBSSxDQUFDLE9BQU8sQ0FBQyxnQ0FBZ0MsSUFBSSxLQUFLO1lBQ3hGLFFBQVEsRUFBRSxRQUFRO1NBQ25CLENBQUMsQ0FBQztRQUNILElBQUksQ0FBQyxnQkFBZ0IsQ0FBQyxhQUFhLENBQUMsSUFBSSxDQUFDLFVBQVUsQ0FBQyxVQUFVLEVBQUUsQ0FBQyxDQUFDO1FBQ2xFLElBQUksQ0FBQyxnQkFBZ0IsQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDLG9CQUFvQixDQUFDLGlCQUFpQixDQUFDLENBQUM7UUFFdkUsSUFBSSxpQkFBaUIsSUFBSSxJQUFJLENBQUMsT0FBTyxDQUFDLFVBQVUsRUFBRSxDQUFDO1lBQ2pELE1BQU0sRUFBRSxLQUFLLEVBQUUsTUFBTSxFQUFFLFFBQVEsRUFBRSxHQUFHLElBQUksQ0FBQyxPQUFPLENBQUMsVUFBVSxDQUFDO1lBQzVELElBQUksQ0FBQyxnQkFBZ0IsQ0FBQyxHQUFHLENBQUMsb0NBQXNCLEVBQUU7Z0JBQ2hELEtBQUs7Z0JBQ0wsTUFBTTtnQkFDTixRQUFRO2dCQUNSLE1BQU0sRUFBRSxJQUFJLENBQUMsT0FBTyxDQUFDLE1BQU07YUFDNUIsQ0FBQyxDQUFDO1FBQ0wsQ0FBQztRQUVELE9BQU8sSUFBSSxDQUFDLGdCQUFnQixDQUFDLGFBQWEsQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLE1BQU0sQ0FBQyxDQUFDO0lBQ2xFLENBQUM7SUFFTyxlQUFlO1FBQ3JCLE9BQU8sbUJBQWUsQ0FBQyxhQUFhLENBQUMsSUFBSSxDQUFDLG9CQUFvQixDQUFDLGFBQWEsRUFBRSxDQUFDLENBQUMsSUFBSSxDQUFDO0lBQ3ZGLENBQUM7SUFFTyxLQUFLLENBQUMsd0JBQXdCO1FBS3BDLE1BQU0sRUFBRSxZQUFZLEVBQUUsTUFBTSxFQUFFLFdBQVcsRUFBRSxlQUFlLEVBQUUsR0FBRyxJQUFJLENBQUMsT0FBTyxDQUFDO1FBRTVFLE1BQU0sVUFBVSxHQUFHLE1BQU0sSUFBSSxDQUFDLHFCQUFxQixFQUFFLENBQUM7UUFDdEQsTUFBTSxDQUFDLE9BQU8sQ0FBQyxHQUFHLE1BQU0sT0FBTyxDQUFDLEdBQUcsQ0FBQztZQUNsQyxJQUFJLENBQUMsU0FBUyxDQUFDLFVBQVUsQ0FBQztZQUMxQixJQUFJLENBQUMsVUFBVSxDQUFDLFVBQVUsQ0FBQztZQUMzQixDQUFDLFlBQVksSUFBSSxXQUFXO2dCQUMxQixDQUFDLENBQUMsSUFBSSxDQUFDLFVBQVUsQ0FBQyx1QkFBdUIsQ0FBQyxXQUFXLEVBQUUsZUFBZSxFQUFFLE1BQU0sQ0FBQztnQkFDL0UsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxPQUFPLEVBQUU7U0FDdEIsQ0FBQyxDQUFDO1FBRUgsT0FBTyxPQUFPLENBQUM7SUFDakIsQ0FBQztJQUVEOztPQUVHO0lBQ08sS0FBSyxDQUFDLFVBQVUsQ0FBQyxVQUFzQjtRQUMvQyxNQUFNLEVBQUUsVUFBVSxFQUFFLGdCQUFnQixFQUFFLFlBQVksRUFBRSxZQUFZLEVBQUUsR0FBRyxJQUFJLENBQUMsT0FBTyxDQUFDO1FBRWxGLG1EQUFtRDtRQUNuRCxJQUFJLGdCQUFnQixFQUFFLENBQUM7WUFDckIsSUFBSSxDQUFDLE9BQU8sQ0FBQyxNQUFNLENBQ2pCLE1BQU0sRUFDTixxRUFBcUUsQ0FDdEUsQ0FBQztZQUVGLE9BQU87UUFDVCxDQUFDO1FBRUQsMERBQTBEO1FBQzFELElBQUksTUFBeUMsQ0FBQztRQUM5QyxNQUFNLElBQUksR0FBRyxJQUFJLENBQUMsZUFBZSxFQUFFLENBQUM7UUFFcEMsNEZBQTRGO1FBQzVGLElBQUksQ0FBQyxZQUFZLEVBQUUsb0JBQW9CLElBQUksWUFBWSxFQUFFLENBQUM7WUFDeEQsSUFBSSxDQUFDO2dCQUNILE1BQU0sR0FBRyxJQUFJLENBQUMsS0FBSyxDQUFDLE1BQU0sSUFBQSxtQkFBUSxFQUFDLFVBQVUsRUFBRSxFQUFFLFFBQVEsRUFBRSxPQUFPLEVBQUUsQ0FBQyxDQUFDLENBQUM7WUFDekUsQ0FBQztZQUFDLE9BQU8sQ0FBQyxFQUFFLENBQUM7Z0JBQ1gsTUFBTSxJQUFJLEtBQUssQ0FBQyxjQUFjLFVBQVUsa0RBQWtELENBQUMsQ0FBQztZQUM5RixDQUFDO1FBQ0gsQ0FBQzthQUFNLENBQUM7WUFDTixNQUFNLEdBQUcsTUFBTSxJQUFJLENBQUMsZUFBZSxDQUFDLFdBQVcsQ0FBQyxVQUFVLENBQUMsQ0FBQztZQUU1RCxNQUFNLE1BQU0sR0FBRyxJQUFBLHVDQUFTLEVBQUMsRUFBRSxHQUFHLE1BQU0sRUFBRSxJQUFJLEVBQUUsRUFBRSxFQUFFLFNBQVMsRUFBRSxHQUFHLEVBQUUsQ0FBQyxDQUFDO1lBQ2xFLE1BQU0sSUFBQSxvQkFBUyxFQUFDLFVBQVUsRUFBRSxNQUFNLEVBQUUsRUFBRSxRQUFRLEVBQUUsT0FBTyxFQUFFLENBQUMsQ0FBQztRQUM3RCxDQUFDO1FBRUQsZ0NBQWdDO1FBQ2hDLE1BQU0sSUFBSSxDQUFDLE9BQU8sQ0FBQyxpQkFBaUIsQ0FBQyxVQUFVLENBQUMsRUFBRSxHQUFHLE1BQU0sRUFBRSxJQUFJLEVBQUUsQ0FBQyxDQUFDO0lBQ3ZFLENBQUM7SUFFRDs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7T0F1Qkc7SUFDSCxLQUFLLENBQUMsa0JBQWtCO1FBQ3RCLE1BQU0sRUFBRSxNQUFNLEVBQUUsVUFBVSxFQUFFLFdBQVcsRUFBRSxlQUFlLEVBQUUsR0FBRyxJQUFJLENBQUMsT0FBTyxDQUFDO1FBRTFFLElBQUksQ0FBQztZQUNILE1BQU0sVUFBVSxHQUFHLE1BQU0sSUFBSSxDQUFDLHFCQUFxQixDQUFDLEVBQUUsaUJBQWlCLEVBQUUsS0FBSyxFQUFFLENBQUMsQ0FBQztZQUNsRixNQUFNLE1BQU0sR0FBRyxNQUFNLElBQUksQ0FBQyxlQUFlLENBQUMsV0FBVyxDQUFDLFVBQVUsQ0FBQyxDQUFDO1lBQ2xFLE1BQU0sSUFBSSxHQUFHLElBQUksQ0FBQyxlQUFlLEVBQUUsQ0FBQztZQUVwQyxNQUFNLElBQUEsb0JBQVMsRUFBQyxVQUFVLEVBQUUsSUFBQSx1Q0FBUyxFQUFDLEVBQUUsR0FBRyxNQUFNLEVBQUUsSUFBSSxFQUFFLEVBQUUsRUFBRSxTQUFTLEVBQUUsR0FBRyxFQUFFLENBQUMsRUFBRTtnQkFDOUUsUUFBUSxFQUFFLE9BQU87YUFDbEIsQ0FBQyxDQUFDO1lBRUgsSUFBSSxXQUFXLEVBQUUsQ0FBQztnQkFDaEIsTUFBTSxJQUFJLENBQUMsVUFBVSxDQUFDLHVCQUF1QixDQUFDLFdBQVcsRUFBRSxlQUFlLEVBQUUsTUFBTSxDQUFDLENBQUM7WUFDdEYsQ0FBQztZQUVELE1BQU0sQ0FBQyxNQUFNLEVBQUUscUJBQXFCLFVBQVUsRUFBRSxDQUFDLENBQUM7UUFDcEQsQ0FBQztRQUFDLE9BQU8sS0FBSyxFQUFFLENBQUM7WUFDZixNQUFNLEVBQUUsT0FBTyxFQUFFLEdBQUcsS0FBYyxDQUFDO1lBQ25DLE1BQU0sQ0FBQyxPQUFPLEVBQUUsMENBQTBDLE9BQU8sRUFBRSxDQUFDLENBQUM7WUFDckUsTUFBTSxLQUFLLENBQUM7UUFDZCxDQUFDO0lBQ0gsQ0FBQztDQUNGO0FBL2lCRCx3QkEraUJDIn0=
@@ -0,0 +1,17 @@
1
+ import type { Recorder } from './instrument';
2
+ import type { ActionResult, Caller } from '@forestadmin/datasource-toolkit';
3
+ export type ActionCaptureParams = {
4
+ caller: Caller;
5
+ collection: string;
6
+ actionName: string;
7
+ formValues: Record<string, unknown>;
8
+ recordIds: string[];
9
+ };
10
+ export type PendingActionAudit = {
11
+ pendingIds: Array<number | null>;
12
+ recordIds: string[];
13
+ previousValues: Record<string, unknown>;
14
+ };
15
+ export declare function captureActionPending(recorder: Recorder, redactedFields: string[], params: ActionCaptureParams): Promise<PendingActionAudit>;
16
+ export declare function captureActionConfirm(recorder: Recorder, pending: PendingActionAudit, result: ActionResult | undefined, failed: boolean): Promise<void>;
17
+ //# sourceMappingURL=action-capture.d.ts.map
@@ -0,0 +1,97 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.captureActionPending = captureActionPending;
4
+ exports.captureActionConfirm = captureActionConfirm;
5
+ const instrument_1 = require("./instrument");
6
+ // A bulk run over a select-all selection only tells us which ids were *excluded*, and a global
7
+ // action targets none at all: naming the targets would mean querying the whole selection, so those
8
+ // runs are recorded once, attached to no record, rather than not at all.
9
+ const NO_RECORD = '';
10
+ const redactValues = (values, redactedFields) => {
11
+ if (!redactedFields.length)
12
+ return values;
13
+ const result = { ...values };
14
+ for (const field of redactedFields)
15
+ if (field in result)
16
+ result[field] = instrument_1.REDACTED;
17
+ return result;
18
+ };
19
+ // A Webhook's target URL and a Redirect's path are otherwise untouched user/action-supplied data,
20
+ // so either can carry credentials (userinfo) or a signed/one-time token (query string) that must
21
+ // not be written permanently to the audit database — only the origin and path are kept. Falls back
22
+ // to a plain string split for a relative or otherwise unparseable URL — including one whose userinfo
23
+ // itself is what made it unparseable to `new URL` (e.g. an invalid host next to valid credentials),
24
+ // which is exactly where such a token would still live.
25
+ const sanitizeUrl = (url) => {
26
+ try {
27
+ const parsed = new URL(url);
28
+ parsed.username = '';
29
+ parsed.password = '';
30
+ parsed.search = '';
31
+ parsed.hash = '';
32
+ return parsed.toString();
33
+ }
34
+ catch {
35
+ return url.split(/[?#]/)[0].replace(/^([a-z][a-z\d+.-]*:\/\/)[^/]*@/i, '$1');
36
+ }
37
+ };
38
+ // Only a safe summary of the answer is kept: `html` (Success/Error), `invalidated` (Success),
39
+ // `headers`/`body` (Webhook, which routinely carry credentials) and a File result's `stream` (file
40
+ // bytes don't belong in an audit table) are all dropped. Absent when `execute()` threw rather than
41
+ // resolving — there is no answer to summarize.
42
+ const summarizeActionResult = (result) => {
43
+ if (!result)
44
+ return {};
45
+ const summary = { type: result.type };
46
+ if ('message' in result)
47
+ summary.message = result.message;
48
+ if ('name' in result)
49
+ summary.name = result.name;
50
+ if ('mimeType' in result)
51
+ summary.mimeType = result.mimeType;
52
+ if ('method' in result)
53
+ summary.method = result.method;
54
+ if ('url' in result)
55
+ summary.url = sanitizeUrl(result.url);
56
+ if ('path' in result)
57
+ summary.path = sanitizeUrl(result.path);
58
+ return summary;
59
+ };
60
+ // Records smart-action invocations into the same store as the field-level history. The Create/Update/
61
+ // Delete hooks (instrument.ts) cannot see them: an action's writes are only audited when they go
62
+ // through the Forest data layer, so a direct write inside the action's own `execute()` is invisible
63
+ // and never recorded. What lands here is the invocation itself — on which records, with the form that
64
+ // was submitted and (once confirmed) a summary of what the action answered. Which action ran is
65
+ // captured directly (`actionName`), unlike a create/update/delete row.
66
+ async function captureActionPending(recorder, redactedFields, params) {
67
+ const timestamp = new Date().toISOString();
68
+ const previousValues = redactValues(params.formValues ?? {}, redactedFields);
69
+ const recordIds = params.recordIds.length > 0 ? params.recordIds : [NO_RECORD];
70
+ const pendingRecords = recordIds.map(recordId => ({
71
+ timestamp,
72
+ operation: 'action',
73
+ collection: params.collection,
74
+ recordId,
75
+ userId: params.caller.id,
76
+ userFirstName: params.caller.firstName,
77
+ userLastName: params.caller.lastName,
78
+ userEmail: params.caller.email,
79
+ actionName: params.actionName,
80
+ correlationKey: params.caller.requestId,
81
+ previousValues,
82
+ newValues: {},
83
+ }));
84
+ const pendingIds = await recorder.insertPendingBatch(pendingRecords);
85
+ return { pendingIds, recordIds, previousValues };
86
+ }
87
+ async function captureActionConfirm(recorder, pending, result, failed) {
88
+ const newValues = summarizeActionResult(result);
89
+ const operation = failed ? 'action_failed' : 'action';
90
+ await Promise.all(pending.pendingIds.map((pendingId, index) => recorder.confirm(pendingId, {
91
+ operation,
92
+ recordId: pending.recordIds[index],
93
+ previousValues: pending.previousValues,
94
+ newValues,
95
+ })));
96
+ }
97
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYWN0aW9uLWNhcHR1cmUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvYXVkaXQtdHJhaWwvYWN0aW9uLWNhcHR1cmUudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7QUFxRkEsb0RBMkJDO0FBRUQsb0RBbUJDO0FBaklELDZDQUF3QztBQUV4QywrRkFBK0Y7QUFDL0YsbUdBQW1HO0FBQ25HLHlFQUF5RTtBQUN6RSxNQUFNLFNBQVMsR0FBRyxFQUFFLENBQUM7QUFFckIsTUFBTSxZQUFZLEdBQUcsQ0FDbkIsTUFBK0IsRUFDL0IsY0FBd0IsRUFDQyxFQUFFO0lBQzNCLElBQUksQ0FBQyxjQUFjLENBQUMsTUFBTTtRQUFFLE9BQU8sTUFBTSxDQUFDO0lBRTFDLE1BQU0sTUFBTSxHQUFHLEVBQUUsR0FBRyxNQUFNLEVBQUUsQ0FBQztJQUM3QixLQUFLLE1BQU0sS0FBSyxJQUFJLGNBQWM7UUFBRSxJQUFJLEtBQUssSUFBSSxNQUFNO1lBQUUsTUFBTSxDQUFDLEtBQUssQ0FBQyxHQUFHLHFCQUFRLENBQUM7SUFFbEYsT0FBTyxNQUFNLENBQUM7QUFDaEIsQ0FBQyxDQUFDO0FBRUYsa0dBQWtHO0FBQ2xHLGlHQUFpRztBQUNqRyxtR0FBbUc7QUFDbkcscUdBQXFHO0FBQ3JHLG9HQUFvRztBQUNwRyx3REFBd0Q7QUFDeEQsTUFBTSxXQUFXLEdBQUcsQ0FBQyxHQUFXLEVBQVUsRUFBRTtJQUMxQyxJQUFJLENBQUM7UUFDSCxNQUFNLE1BQU0sR0FBRyxJQUFJLEdBQUcsQ0FBQyxHQUFHLENBQUMsQ0FBQztRQUM1QixNQUFNLENBQUMsUUFBUSxHQUFHLEVBQUUsQ0FBQztRQUNyQixNQUFNLENBQUMsUUFBUSxHQUFHLEVBQUUsQ0FBQztRQUNyQixNQUFNLENBQUMsTUFBTSxHQUFHLEVBQUUsQ0FBQztRQUNuQixNQUFNLENBQUMsSUFBSSxHQUFHLEVBQUUsQ0FBQztRQUVqQixPQUFPLE1BQU0sQ0FBQyxRQUFRLEVBQUUsQ0FBQztJQUMzQixD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
@@ -0,0 +1,8 @@
1
+ export { default as installAuditTrailHooks, buildRecorder, MAX_SNAPSHOT_RECORDS, REDACTED, } from './instrument';
2
+ export type { Recorder } from './instrument';
3
+ export { captureActionPending, captureActionConfirm } from './action-capture';
4
+ export { createSqlAuditStore, ensureAuditStorage, defineAuditLogModel, fieldsChangedCondition, searchCondition, toRow, fromRow, DEFAULT_SCHEMA, DEFAULT_TABLE, } from './sql-store';
5
+ export { runAuditMigrations } from './migrations';
6
+ export { default as revertRecord } from './revert';
7
+ export * from './types';
8
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1,44 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ var __importDefault = (this && this.__importDefault) || function (mod) {
17
+ return (mod && mod.__esModule) ? mod : { "default": mod };
18
+ };
19
+ Object.defineProperty(exports, "__esModule", { value: true });
20
+ exports.revertRecord = exports.runAuditMigrations = exports.DEFAULT_TABLE = exports.DEFAULT_SCHEMA = exports.fromRow = exports.toRow = exports.searchCondition = exports.fieldsChangedCondition = exports.defineAuditLogModel = exports.ensureAuditStorage = exports.createSqlAuditStore = exports.captureActionConfirm = exports.captureActionPending = exports.REDACTED = exports.MAX_SNAPSHOT_RECORDS = exports.buildRecorder = exports.installAuditTrailHooks = void 0;
21
+ var instrument_1 = require("./instrument");
22
+ Object.defineProperty(exports, "installAuditTrailHooks", { enumerable: true, get: function () { return __importDefault(instrument_1).default; } });
23
+ Object.defineProperty(exports, "buildRecorder", { enumerable: true, get: function () { return instrument_1.buildRecorder; } });
24
+ Object.defineProperty(exports, "MAX_SNAPSHOT_RECORDS", { enumerable: true, get: function () { return instrument_1.MAX_SNAPSHOT_RECORDS; } });
25
+ Object.defineProperty(exports, "REDACTED", { enumerable: true, get: function () { return instrument_1.REDACTED; } });
26
+ var action_capture_1 = require("./action-capture");
27
+ Object.defineProperty(exports, "captureActionPending", { enumerable: true, get: function () { return action_capture_1.captureActionPending; } });
28
+ Object.defineProperty(exports, "captureActionConfirm", { enumerable: true, get: function () { return action_capture_1.captureActionConfirm; } });
29
+ var sql_store_1 = require("./sql-store");
30
+ Object.defineProperty(exports, "createSqlAuditStore", { enumerable: true, get: function () { return sql_store_1.createSqlAuditStore; } });
31
+ Object.defineProperty(exports, "ensureAuditStorage", { enumerable: true, get: function () { return sql_store_1.ensureAuditStorage; } });
32
+ Object.defineProperty(exports, "defineAuditLogModel", { enumerable: true, get: function () { return sql_store_1.defineAuditLogModel; } });
33
+ Object.defineProperty(exports, "fieldsChangedCondition", { enumerable: true, get: function () { return sql_store_1.fieldsChangedCondition; } });
34
+ Object.defineProperty(exports, "searchCondition", { enumerable: true, get: function () { return sql_store_1.searchCondition; } });
35
+ Object.defineProperty(exports, "toRow", { enumerable: true, get: function () { return sql_store_1.toRow; } });
36
+ Object.defineProperty(exports, "fromRow", { enumerable: true, get: function () { return sql_store_1.fromRow; } });
37
+ Object.defineProperty(exports, "DEFAULT_SCHEMA", { enumerable: true, get: function () { return sql_store_1.DEFAULT_SCHEMA; } });
38
+ Object.defineProperty(exports, "DEFAULT_TABLE", { enumerable: true, get: function () { return sql_store_1.DEFAULT_TABLE; } });
39
+ var migrations_1 = require("./migrations");
40
+ Object.defineProperty(exports, "runAuditMigrations", { enumerable: true, get: function () { return migrations_1.runAuditMigrations; } });
41
+ var revert_1 = require("./revert");
42
+ Object.defineProperty(exports, "revertRecord", { enumerable: true, get: function () { return __importDefault(revert_1).default; } });
43
+ __exportStar(require("./types"), exports);
44
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvYXVkaXQtdHJhaWwvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7QUFBQSwyQ0FLc0I7QUFKcEIscUlBQUEsT0FBTyxPQUEwQjtBQUNqQywyR0FBQSxhQUFhLE9BQUE7QUFDYixrSEFBQSxvQkFBb0IsT0FBQTtBQUNwQixzR0FBQSxRQUFRLE9BQUE7QUFHVixtREFBOEU7QUFBckUsc0hBQUEsb0JBQW9CLE9BQUE7QUFBRSxzSEFBQSxvQkFBb0IsT0FBQTtBQUNuRCx5Q0FVcUI7QUFUbkIsZ0hBQUEsbUJBQW1CLE9BQUE7QUFDbkIsK0dBQUEsa0JBQWtCLE9BQUE7QUFDbEIsZ0hBQUEsbUJBQW1CLE9BQUE7QUFDbkIsbUhBQUEsc0JBQXNCLE9BQUE7QUFDdEIsNEdBQUEsZUFBZSxPQUFBO0FBQ2Ysa0dBQUEsS0FBSyxPQUFBO0FBQ0wsb0dBQUEsT0FBTyxPQUFBO0FBQ1AsMkdBQUEsY0FBYyxPQUFBO0FBQ2QsMEdBQUEsYUFBYSxPQUFBO0FBRWYsMkNBQWtEO0FBQXpDLGdIQUFBLGtCQUFrQixPQUFBO0FBQzNCLG1DQUFtRDtBQUExQyx1SEFBQSxPQUFPLE9BQWdCO0FBQ2hDLDBDQUF3QiJ9
@@ -0,0 +1,12 @@
1
+ import type { AuditRecordConfirmation, AuditSink, AuditStore, AuditTrailInstrumentOptions, PendingAuditRecord } from './types';
2
+ import type { CollectionCustomizer, DataSourceCustomizer } from '@forestadmin/datasource-customizer';
3
+ import type { Logger } from '@forestadmin/datasource-toolkit';
4
+ export declare const MAX_SNAPSHOT_RECORDS = 1000;
5
+ export declare const REDACTED = "[redacted]";
6
+ export type Recorder = {
7
+ insertPendingBatch(records: PendingAuditRecord[]): Promise<Array<number | null>>;
8
+ confirm(id: number | null, patch: AuditRecordConfirmation): Promise<void>;
9
+ };
10
+ export declare function buildRecorder(store: AuditStore | undefined, sink: AuditSink | undefined, critical: boolean, logger: Logger | undefined): Recorder;
11
+ export default function installAuditTrailHooks(dataSourceCustomizer: DataSourceCustomizer, _collectionCustomizer: CollectionCustomizer | null, options?: AuditTrailInstrumentOptions): Promise<void> | void;
12
+ //# sourceMappingURL=instrument.d.ts.map