@forestadmin/agent 1.95.2 → 1.96.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.
- package/dist/agent.d.ts +4 -0
- package/dist/agent.js +56 -5
- package/dist/audit-trail/action-capture.d.ts +17 -0
- package/dist/audit-trail/action-capture.js +97 -0
- package/dist/audit-trail/index.d.ts +8 -0
- package/dist/audit-trail/index.js +44 -0
- package/dist/audit-trail/instrument.d.ts +12 -0
- package/dist/audit-trail/instrument.js +393 -0
- package/dist/audit-trail/migrations.d.ts +34 -0
- package/dist/audit-trail/migrations.js +213 -0
- package/dist/audit-trail/revert.d.ts +8 -0
- package/dist/audit-trail/revert.js +81 -0
- package/dist/audit-trail/scope.d.ts +20 -0
- package/dist/audit-trail/scope.js +33 -0
- package/dist/audit-trail/sql-store.d.ts +30 -0
- package/dist/audit-trail/sql-store.js +316 -0
- package/dist/audit-trail/types.d.ts +129 -0
- package/dist/audit-trail/types.js +3 -0
- package/dist/routes/access/audit-trail-correlation.d.ts +18 -0
- package/dist/routes/access/audit-trail-correlation.js +84 -0
- package/dist/routes/access/audit-trail.d.ts +23 -0
- package/dist/routes/access/audit-trail.js +293 -0
- package/dist/routes/capabilities.js +5 -1
- package/dist/routes/index.js +14 -1
- package/dist/routes/modification/action/action.d.ts +3 -0
- package/dist/routes/modification/action/action.js +106 -2
- package/dist/types.d.ts +39 -1
- package/dist/types.js +1 -1
- package/dist/utils/correlation-id.d.ts +5 -0
- package/dist/utils/correlation-id.js +26 -0
- package/dist/utils/options-validator.js +19 -1
- package/dist/utils/query-string.d.ts +3 -1
- package/dist/utils/query-string.js +5 -5
- package/package.json +4 -3
|
@@ -0,0 +1,293 @@
|
|
|
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 __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
36
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
|
+
};
|
|
38
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
+
const datasource_toolkit_1 = require("@forestadmin/datasource-toolkit");
|
|
40
|
+
const luxon_1 = require("luxon");
|
|
41
|
+
const audit_trail_1 = require("../../audit-trail");
|
|
42
|
+
const scope_1 = __importStar(require("../../audit-trail/scope"));
|
|
43
|
+
const types_1 = require("../../types");
|
|
44
|
+
const id_1 = __importDefault(require("../../utils/id"));
|
|
45
|
+
const query_string_1 = __importDefault(require("../../utils/query-string"));
|
|
46
|
+
const collection_route_1 = __importDefault(require("../collection-route"));
|
|
47
|
+
const DATE_ONLY = /^\d{4}-\d{2}-\d{2}$/;
|
|
48
|
+
const DATE_TIME = /^(\d{4}-\d{2}-\d{2})[T ](\d{2}):(\d{2})(?::(\d{2}))?$/;
|
|
49
|
+
// ISO 8601 instant: carries its own timezone designator (`Z` or `±HH:mm` / `±HHMM`).
|
|
50
|
+
const ISO_INSTANT = /[Zz]$|[+-]\d{2}:?\d{2}$/;
|
|
51
|
+
const DEFAULT_PAGE_SIZE = 20;
|
|
52
|
+
const MAX_PAGE_SIZE = 100;
|
|
53
|
+
class AuditTrailRoute extends collection_route_1.default {
|
|
54
|
+
setupRoutes(router) {
|
|
55
|
+
router.get(`/_audit-trail/${this.collectionUrlSlug}/:id`, this.handleHistory.bind(this));
|
|
56
|
+
router.get(`/_audit-trail/${this.collectionUrlSlug}/:id/state`, this.handleStateAt.bind(this));
|
|
57
|
+
}
|
|
58
|
+
async handleHistory(context) {
|
|
59
|
+
await this.services.authorization.assertCanRead(context, this.collection.name);
|
|
60
|
+
const scope = await this.services.authorization.getScope(this.collection, context);
|
|
61
|
+
const { visible, goneEntirely } = await (0, scope_1.default)(this.services, this.collection, context.params.id, context);
|
|
62
|
+
if (!visible) {
|
|
63
|
+
context.throw(types_1.HttpCode.NotFound, 'Record does not exists');
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
const { store } = this.options.auditTrail;
|
|
67
|
+
const { skip, limit } = AuditTrailRoute.parsePagination(context);
|
|
68
|
+
const order = AuditTrailRoute.parseSort(context);
|
|
69
|
+
const { userIds, startTimestamp, endTimestamp, fields, search } = AuditTrailRoute.parseFilters(context);
|
|
70
|
+
const filters = {
|
|
71
|
+
collection: this.collection.name,
|
|
72
|
+
recordId: context.params.id,
|
|
73
|
+
...(userIds && { userIds }),
|
|
74
|
+
...(startTimestamp && { startTimestamp }),
|
|
75
|
+
...(endTimestamp && { endTimestamp }),
|
|
76
|
+
...(fields && { fields }),
|
|
77
|
+
...(search && { search }),
|
|
78
|
+
};
|
|
79
|
+
// Distinct authors are scoped to the active filters but independent of the page — returned
|
|
80
|
+
// only on the first fetch (no explicit page[number]) so the front keeps the list it already
|
|
81
|
+
// saw rather than it silently drifting across pages, mirroring Forest's activity-logs route.
|
|
82
|
+
const isFirstFetch = context.request.query['page[number]'] === undefined;
|
|
83
|
+
// `count` reflects the active filters and is independent of the page.
|
|
84
|
+
const [rawData, count, availableUsers] = await Promise.all([
|
|
85
|
+
store.listByRecord({ ...filters, skip, limit, order }),
|
|
86
|
+
store.countByRecord(filters),
|
|
87
|
+
isFirstFetch ? store.listDistinctUsers(filters) : undefined,
|
|
88
|
+
]);
|
|
89
|
+
// A genuinely deleted record bypasses the scope check above — there's nothing left to check
|
|
90
|
+
// existence against — but create/update/delete rows still carry captured column values from
|
|
91
|
+
// when the record existed. If those values themselves would have failed the caller's scope,
|
|
92
|
+
// withhold them while still surfacing that the row happened, by whom and when: that part
|
|
93
|
+
// stays visible regardless.
|
|
94
|
+
const data = scope && goneEntirely ? this.withholdOutOfScopeValues(rawData, scope, context) : rawData;
|
|
95
|
+
context.response.body = {
|
|
96
|
+
data,
|
|
97
|
+
meta: { count, ...(availableUsers && { availableUsers }) },
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
withholdOutOfScopeValues(entries, scope, context) {
|
|
101
|
+
const { timezone } = query_string_1.default.parseCaller(context, { defaultTimezone: 'UTC' });
|
|
102
|
+
return entries.map(entry => {
|
|
103
|
+
// `delete`'s previousValues and `create`'s newValues both capture every writable column
|
|
104
|
+
// (see instrument.ts's pickColumns), so the scope can be evaluated against them directly.
|
|
105
|
+
if (entry.operation === 'delete') {
|
|
106
|
+
if (scope.match(entry.previousValues, this.collection, timezone))
|
|
107
|
+
return entry;
|
|
108
|
+
return { ...entry, previousValues: {} };
|
|
109
|
+
}
|
|
110
|
+
if (entry.operation === 'create') {
|
|
111
|
+
if (scope.match(entry.newValues, this.collection, timezone))
|
|
112
|
+
return entry;
|
|
113
|
+
return { ...entry, newValues: {} };
|
|
114
|
+
}
|
|
115
|
+
// `update`'s previousValues/newValues are a partial diff (only the columns that changed) —
|
|
116
|
+
// a scope condition referencing a column this particular update didn't touch can't be
|
|
117
|
+
// evaluated reliably against it, so withhold unconditionally rather than risk a false
|
|
118
|
+
// negative. `action`/`action_failed` rows hold a submitted form and a result summary, not
|
|
119
|
+
// column values, so the scope doesn't apply to them at all.
|
|
120
|
+
if (entry.operation === 'update') {
|
|
121
|
+
return { ...entry, previousValues: {}, newValues: {} };
|
|
122
|
+
}
|
|
123
|
+
return entry;
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
// Only audited columns are returned; read-only/computed fields are not captured in the log.
|
|
127
|
+
async handleStateAt(context) {
|
|
128
|
+
await this.services.authorization.assertCanRead(context, this.collection.name);
|
|
129
|
+
const at = AuditTrailRoute.parseAt(context);
|
|
130
|
+
const auditedColumns = AuditTrailRoute.auditedColumns(this.collection.schema);
|
|
131
|
+
const scope = await this.services.authorization.getScope(this.collection, context);
|
|
132
|
+
const current = await this.fetchCurrentRecord(context, auditedColumns, scope);
|
|
133
|
+
// A missing current record is ambiguous (deleted vs. out-of-scope) once a scope applies; only
|
|
134
|
+
// deny when the id still exists outside that scope. If it's genuinely gone there's nothing
|
|
135
|
+
// left to evaluate the scope against, so the revert walk below proceeds — including, possibly,
|
|
136
|
+
// surfacing a delete entry's snapshot, which is the point once nothing exists to protect.
|
|
137
|
+
if (!current && scope) {
|
|
138
|
+
const stillExists = await (0, scope_1.recordExists)(this.collection, context.params.id, context, null);
|
|
139
|
+
if (stillExists) {
|
|
140
|
+
context.throw(types_1.HttpCode.NotFound, 'Record did not exist at this timestamp');
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
const { store } = this.options.auditTrail;
|
|
145
|
+
const fetched = await store.listByRecord({
|
|
146
|
+
collection: this.collection.name,
|
|
147
|
+
recordId: context.params.id,
|
|
148
|
+
startTimestamp: at,
|
|
149
|
+
order: 'desc',
|
|
150
|
+
});
|
|
151
|
+
// `startTimestamp` is an inclusive lower bound, so an entry timestamped exactly `at` comes
|
|
152
|
+
// back too — but the record already reflects that entry's change at instant `at`, so it must
|
|
153
|
+
// be kept rather than reverted (which would wrongly return the state just *before* it).
|
|
154
|
+
//
|
|
155
|
+
// Action rows are excluded outright: their previousValues/newValues hold a submitted form and a
|
|
156
|
+
// summary of the action's answer, not column values, so replaying them as a diff would corrupt
|
|
157
|
+
// the reconstructed record. An action's effect on the data still shows up through the
|
|
158
|
+
// create/update/delete rows it produced under the same correlation key.
|
|
159
|
+
//
|
|
160
|
+
// A `pending` row is also excluded: its write may or may not have landed (that's the whole
|
|
161
|
+
// point of the status), and if it hasn't, its previousValues/newValues aren't the write's
|
|
162
|
+
// actual result — a concurrent request could otherwise revert a mutation that never happened,
|
|
163
|
+
// or a row left permanently `pending` (e.g. the process crashed between write and confirm)
|
|
164
|
+
// would permanently corrupt every state-at-a-past-timestamp reconstruction for this record.
|
|
165
|
+
const entries = fetched.filter(entry => entry.timestamp !== at &&
|
|
166
|
+
entry.operation !== 'action' &&
|
|
167
|
+
entry.operation !== 'action_failed' &&
|
|
168
|
+
entry.status !== 'pending');
|
|
169
|
+
const state = (0, audit_trail_1.revertRecord)(current, entries);
|
|
170
|
+
if (!state)
|
|
171
|
+
context.throw(types_1.HttpCode.NotFound, 'Record did not exist at this timestamp');
|
|
172
|
+
context.response.body = { data: state };
|
|
173
|
+
}
|
|
174
|
+
async fetchCurrentRecord(context, auditedColumns, scope) {
|
|
175
|
+
const id = id_1.default.unpackId(this.collection.schema, context.params.id);
|
|
176
|
+
const filter = new datasource_toolkit_1.PaginatedFilter({
|
|
177
|
+
conditionTree: datasource_toolkit_1.ConditionTreeFactory.intersect(datasource_toolkit_1.ConditionTreeFactory.matchIds(this.collection.schema, [id]), scope),
|
|
178
|
+
});
|
|
179
|
+
const records = await this.collection.list(query_string_1.default.parseCaller(context, { defaultTimezone: 'UTC' }), filter, new datasource_toolkit_1.Projection(...auditedColumns));
|
|
180
|
+
return records[0] ?? null;
|
|
181
|
+
}
|
|
182
|
+
// Must mirror the audit log's column selection (writable + primary keys, including read-only
|
|
183
|
+
// PKs) so the reconstructed record carries the same columns the log captured.
|
|
184
|
+
static auditedColumns(schema) {
|
|
185
|
+
const writable = Object.keys(schema.fields).filter(name => {
|
|
186
|
+
const field = schema.fields[name];
|
|
187
|
+
return field.type === 'Column' && !field.isReadOnly;
|
|
188
|
+
});
|
|
189
|
+
return [...new Set([...datasource_toolkit_1.SchemaUtils.getPrimaryKeys(schema), ...writable])];
|
|
190
|
+
}
|
|
191
|
+
static parseAt(context) {
|
|
192
|
+
const query = context.request.query;
|
|
193
|
+
const raw = query.at?.toString();
|
|
194
|
+
if (!raw)
|
|
195
|
+
throw new datasource_toolkit_1.ValidationError('Missing "at" query parameter');
|
|
196
|
+
const timezone = query.timezone?.toString() || 'UTC';
|
|
197
|
+
return AuditTrailRoute.parseDateBoundary(raw, timezone, 'start');
|
|
198
|
+
}
|
|
199
|
+
// JSON:API `sort=timestamp` → oldest first, anything else (or absent) → newest first.
|
|
200
|
+
static parseSort(context) {
|
|
201
|
+
const sort = context.request.query.sort?.toString();
|
|
202
|
+
return sort === 'timestamp' ? 'asc' : 'desc';
|
|
203
|
+
}
|
|
204
|
+
// 1-based `page[number]` (default 1) and `page[size]` (default 20, capped at 100). Invalid values
|
|
205
|
+
// fall back to the defaults rather than erroring.
|
|
206
|
+
static parsePagination(context) {
|
|
207
|
+
const query = context.request.query;
|
|
208
|
+
const size = AuditTrailRoute.parsePageSize(query['page[size]']?.toString());
|
|
209
|
+
const number = AuditTrailRoute.parsePageNumber(query['page[number]']?.toString());
|
|
210
|
+
return { skip: (number - 1) * size, limit: size };
|
|
211
|
+
}
|
|
212
|
+
static parsePageSize(raw) {
|
|
213
|
+
const size = Number.parseInt(raw ?? '', 10);
|
|
214
|
+
if (Number.isNaN(size) || size < 1)
|
|
215
|
+
return DEFAULT_PAGE_SIZE;
|
|
216
|
+
return Math.min(size, MAX_PAGE_SIZE);
|
|
217
|
+
}
|
|
218
|
+
static parsePageNumber(raw) {
|
|
219
|
+
const number = Number.parseInt(raw ?? '', 10);
|
|
220
|
+
return Number.isNaN(number) || number < 1 ? 1 : number;
|
|
221
|
+
}
|
|
222
|
+
static parseFilters(context) {
|
|
223
|
+
const query = context.request.query;
|
|
224
|
+
const timezone = query.timezone?.toString() || 'UTC';
|
|
225
|
+
return {
|
|
226
|
+
userIds: AuditTrailRoute.parseUserIds(query.userIds?.toString()),
|
|
227
|
+
startTimestamp: AuditTrailRoute.parseDateBoundary(query.startDate?.toString(), timezone, 'start'),
|
|
228
|
+
endTimestamp: AuditTrailRoute.parseDateBoundary(query.endDate?.toString(), timezone, 'end'),
|
|
229
|
+
fields: AuditTrailRoute.parseFields(query.fields?.toString()),
|
|
230
|
+
search: AuditTrailRoute.parseSearch(query.search?.toString()),
|
|
231
|
+
};
|
|
232
|
+
}
|
|
233
|
+
// Comma-separated integer ids; non-numeric tokens are dropped. Empty after parsing → no filter.
|
|
234
|
+
static parseUserIds(raw) {
|
|
235
|
+
if (!raw)
|
|
236
|
+
return undefined;
|
|
237
|
+
const ids = raw
|
|
238
|
+
.split(',')
|
|
239
|
+
.map(token => token.trim())
|
|
240
|
+
.filter(token => /^\d+$/.test(token))
|
|
241
|
+
.map(token => Number.parseInt(token, 10));
|
|
242
|
+
return ids.length > 0 ? ids : undefined;
|
|
243
|
+
}
|
|
244
|
+
static parseFields(raw) {
|
|
245
|
+
if (!raw)
|
|
246
|
+
return undefined;
|
|
247
|
+
const fields = raw
|
|
248
|
+
.split(',')
|
|
249
|
+
.map(token => token.trim())
|
|
250
|
+
.filter(token => token.length > 0);
|
|
251
|
+
return fields.length > 0 ? fields : undefined;
|
|
252
|
+
}
|
|
253
|
+
// Trimmed; empty after trimming is treated the same as absent.
|
|
254
|
+
static parseSearch(raw) {
|
|
255
|
+
const trimmed = raw?.trim();
|
|
256
|
+
return trimmed || undefined;
|
|
257
|
+
}
|
|
258
|
+
// Bare day (`YYYY-MM-DD`) or wall-clock datetime (`YYYY-MM-DD[T| ]HH:mm[:ss]`), interpreted as
|
|
259
|
+
// local time in the request timezone and returned as a UTC instant so the store can compare it
|
|
260
|
+
// to stored timestamps.
|
|
261
|
+
static parseDateBoundary(raw, timezone, boundary) {
|
|
262
|
+
if (!raw)
|
|
263
|
+
return undefined;
|
|
264
|
+
const instant = AuditTrailRoute.toLocalInstant(raw, timezone, boundary);
|
|
265
|
+
if (!instant.isValid) {
|
|
266
|
+
throw new datasource_toolkit_1.ValidationError(instant.invalidReason === 'unsupported zone'
|
|
267
|
+
? `Invalid timezone: "${timezone}"`
|
|
268
|
+
: `Invalid date: "${raw}" (expected YYYY-MM-DD, YYYY-MM-DDTHH:mm, or an ISO 8601 instant)`);
|
|
269
|
+
}
|
|
270
|
+
return instant.toUTC().toISO() ?? undefined;
|
|
271
|
+
}
|
|
272
|
+
static toLocalInstant(raw, timezone, boundary) {
|
|
273
|
+
// An embedded offset already pins the instant — the request timezone and start/end boundary
|
|
274
|
+
// don't apply.
|
|
275
|
+
if (ISO_INSTANT.test(raw))
|
|
276
|
+
return luxon_1.DateTime.fromISO(raw, { setZone: true });
|
|
277
|
+
if (DATE_ONLY.test(raw)) {
|
|
278
|
+
const day = luxon_1.DateTime.fromISO(raw, { zone: timezone });
|
|
279
|
+
return boundary === 'end' ? day.endOf('day') : day.startOf('day');
|
|
280
|
+
}
|
|
281
|
+
const match = DATE_TIME.exec(raw);
|
|
282
|
+
if (!match)
|
|
283
|
+
return luxon_1.DateTime.invalid('unparsable');
|
|
284
|
+
const [, date, hours, minutes, seconds] = match;
|
|
285
|
+
const base = luxon_1.DateTime.fromISO(`${date}T${hours}:${minutes}`, { zone: timezone });
|
|
286
|
+
if (seconds !== undefined)
|
|
287
|
+
return base.set({ second: Number(seconds), millisecond: 0 });
|
|
288
|
+
// Minutes-only: end snaps to :59.999 to stay inclusive; start stays at :00.000.
|
|
289
|
+
return boundary === 'end' ? base.set({ second: 59, millisecond: 999 }) : base;
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
exports.default = AuditTrailRoute;
|
|
293
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYXVkaXQtdHJhaWwuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvcm91dGVzL2FjY2Vzcy9hdWRpdC10cmFpbC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztBQUtBLHdFQU15QztBQUN6QyxpQ0FBaUM7QUFFakMsbURBQWlEO0FBQ2pELGlFQUE4RTtBQUM5RSx1Q0FBdUM7QUFDdkMsd0RBQXFDO0FBQ3JDLDRFQUF5RDtBQUN6RCwyRUFBa0Q7QUFFbEQsTUFBTSxTQUFTLEdBQUcscUJBQXFCLENBQUM7QUFDeEMsTUFBTSxTQUFTLEdBQUcsdURBQXVELENBQUM7QUFDMUUscUZBQXFGO0FBQ3JGLE1BQU0sV0FBVyxHQUFHLHlCQUF5QixDQUFDO0FBRTlDLE1BQU0saUJBQWlCLEdBQUcsRUFBRSxDQUFDO0FBQzdCLE1BQU0sYUFBYSxHQUFHLEdBQUcsQ0FBQztBQVUxQixNQUFxQixlQUFnQixTQUFRLDBCQUFlO0lBQzFELFdBQVcsQ0FBQyxNQUFjO1FBQ3hCLE1BQU0sQ0FBQyxHQUFHLENBQUMsaUJBQWlCLElBQUksQ0FBQyxpQkFBaUIsTUFBTSxFQUFFLElBQUksQ0FBQyxhQUFhLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUM7UUFDekYsTUFBTSxDQUFDLEdBQUcsQ0FBQyxpQkFBaUIsSUFBSSxDQUFDLGlCQUFpQixZQUFZLEVBQUUsSUFBSSxDQUFDLGFBQWEsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQztJQUNqRyxDQUFDO0lBRU0sS0FBSyxDQUFDLGFBQWEsQ0FBQyxPQUFnQjtRQUN6QyxNQUFNLElBQUksQ0FBQyxRQUFRLENBQUMsYUFBYSxDQUFDLGFBQWEsQ0FBQyxPQUFPLEVBQUUsSUFBSSxDQUFDLFVBQVUsQ0FBQyxJQUFJLENBQUMsQ0FBQztRQUUvRSxNQUFNLEtBQUssR0FBRyxNQUFNLElBQUksQ0FBQyxRQUFRLENB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
|
|
@@ -24,6 +24,10 @@ class Capabilities extends base_route_1.default {
|
|
|
24
24
|
canUseProjectionViaHeader: true,
|
|
25
25
|
canUseProjectionViaHeaderOnList: true,
|
|
26
26
|
canUseMultipleFieldsProjectionOnRelation: true,
|
|
27
|
+
// The audit-trail routes are only mounted when `auditTrail` is configured, but
|
|
28
|
+
// `x-forest-correlation-id` is emitted on every response regardless — the frontend must
|
|
29
|
+
// gate the History tab on this flag rather than inferring the feature from that header.
|
|
30
|
+
canUseAuditTrail: this.options.auditTrail !== null,
|
|
27
31
|
},
|
|
28
32
|
collections: collections?.map(collection => {
|
|
29
33
|
const { aggregationCapabilities } = collection.schema;
|
|
@@ -74,4 +78,4 @@ class Capabilities extends base_route_1.default {
|
|
|
74
78
|
}
|
|
75
79
|
}
|
|
76
80
|
exports.default = Capabilities;
|
|
77
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
81
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2FwYWJpbGl0aWVzLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL3JvdXRlcy9jYXBhYmlsaXRpZXMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7QUFNQSx3RUFBNkQ7QUFFN0QsOERBQXFDO0FBQ3JDLG9DQUErQztBQUUvQyxNQUFxQixZQUFhLFNBQVEsb0JBQVM7SUFJakQsWUFDRSxRQUF1QyxFQUN2QyxPQUFpQyxFQUNqQyxVQUFzQjtRQUV0QixLQUFLLENBQUMsUUFBUSxFQUFFLE9BQU8sQ0FBQyxDQUFDO1FBUmxCLFNBQUksR0FBRyxpQkFBUyxDQUFDLFlBQVksQ0FBQztRQVNyQyxJQUFJLENBQUMsVUFBVSxHQUFHLFVBQVUsQ0FBQztJQUMvQixDQUFDO0lBRUQsV0FBVyxDQUFDLE1BQWM7UUFDeEIsTUFBTSxDQUFDLElBQUksQ0FBQyx5QkFBeUIsRUFBRSxJQUFJLENBQUMsaUJBQWlCLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUM7SUFDNUUsQ0FBQztJQUVPLEtBQUssQ0FBQyxpQkFBaUIsQ0FBQyxPQUFnQjtRQUM5QyxNQUFNLFdBQVcsR0FBRyxJQUFJLENBQUMsVUFBVSxDQUFDLFdBQVcsQ0FBQyxNQUFNLENBQUMsVUFBVSxDQUFDLEVBQUUsQ0FDakUsT0FBTyxDQUFDLE9BQU8sQ0FBQyxJQUFzQyxDQUFDLGVBQWUsRUFBRSxRQUFRLENBQy9FLFVBQVUsQ0FBQyxJQUFJLENBQ2hCLENBQ0YsQ0FBQztRQUVGLE9BQU8sQ0FBQyxRQUFRLENBQUMsSUFBSSxHQUFHO1lBQ3RCLHNCQUFzQixFQUFFLE1BQU0sQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLFVBQVUsQ0FBQyxzQkFBc0IsQ0FBQyxDQUFDLEdBQUcsQ0FDN0UsY0FBYyxDQUFDLEVBQUUsQ0FBQyxDQUFDLEVBQUUsSUFBSSxFQUFFLGNBQWMsRUFBRSxDQUFDLENBQzdDO1lBQ0QsaUJBQWlCLEVBQUU7Z0JBQ2pCLHdCQUF3QixFQUFFLElB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
|
package/dist/routes/index.js
CHANGED
|
@@ -7,6 +7,8 @@ exports.NATIVE_QUERY_ROUTES_CTOR = exports.CAPABILITIES_ROUTES_CTOR = exports.RE
|
|
|
7
7
|
exports.default = makeRoutes;
|
|
8
8
|
const api_chart_collection_1 = __importDefault(require("./access/api-chart-collection"));
|
|
9
9
|
const api_chart_datasource_1 = __importDefault(require("./access/api-chart-datasource"));
|
|
10
|
+
const audit_trail_1 = __importDefault(require("./access/audit-trail"));
|
|
11
|
+
const audit_trail_correlation_1 = __importDefault(require("./access/audit-trail-correlation"));
|
|
10
12
|
const chart_1 = __importDefault(require("./access/chart"));
|
|
11
13
|
const count_1 = __importDefault(require("./access/count"));
|
|
12
14
|
const count_related_1 = __importDefault(require("./access/count-related"));
|
|
@@ -118,6 +120,16 @@ function getWorkflowExecutorRoutes(options, services) {
|
|
|
118
120
|
return [];
|
|
119
121
|
return [new workflow_executor_proxy_1.default(services, options)];
|
|
120
122
|
}
|
|
123
|
+
function getAuditTrailRoutes(dataSource, options, services) {
|
|
124
|
+
if (!options.auditTrail)
|
|
125
|
+
return [];
|
|
126
|
+
return [
|
|
127
|
+
// Registered before the per-collection routes: if a collection is named "correlation", its
|
|
128
|
+
// `/_audit-trail/correlation/:id` route would otherwise shadow this one.
|
|
129
|
+
new audit_trail_correlation_1.default(services, options, dataSource),
|
|
130
|
+
...dataSource.collections.map(collection => new audit_trail_1.default(services, options, dataSource, collection.name)),
|
|
131
|
+
];
|
|
132
|
+
}
|
|
121
133
|
function makeRoutes(dataSource, options, services) {
|
|
122
134
|
const routes = [
|
|
123
135
|
...getRootRoutes(options, services),
|
|
@@ -128,8 +140,9 @@ function makeRoutes(dataSource, options, services) {
|
|
|
128
140
|
...getRelatedRoutes(dataSource, options, services),
|
|
129
141
|
...getActionRoutes(dataSource, options, services),
|
|
130
142
|
...getWorkflowExecutorRoutes(options, services),
|
|
143
|
+
...getAuditTrailRoutes(dataSource, options, services),
|
|
131
144
|
];
|
|
132
145
|
// Ensure routes and middlewares are loaded in the right order.
|
|
133
146
|
return routes.sort((a, b) => a.type - b.type);
|
|
134
147
|
}
|
|
135
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
148
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvcm91dGVzL2luZGV4LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7OztBQWdNQSw2QkFtQkM7QUE5TUQseUZBQW9FO0FBQ3BFLHlGQUFvRTtBQUNwRSx1RUFBbUQ7QUFDbkQsK0ZBQTBFO0FBQzFFLDJEQUFtQztBQUNuQywyREFBbUM7QUFDbkMsMkVBQWtEO0FBQ2xELHVEQUErQjtBQUMvQix1RUFBOEM7QUFDOUMsdURBQStCO0FBQy9CLHlEQUFpQztBQUNqQyx5RUFBZ0Q7QUFDaEQsK0ZBQXFFO0FBQ3JFLGtFQUEwQztBQUMxQywwRUFBdUQ7QUFDdkQseUZBQWdFO0FBQ2hFLG1FQUEyQztBQUMzQyxtRUFBMkM7QUFDM0MseUdBQStFO0FBQy9FLG1FQUEyQztBQUMzQywrRUFBc0Q7QUFDdEQscUZBQTREO0FBQzVELCtFQUF1RDtBQUN2RCwyRUFBa0Q7QUFDbEQsdUZBQThEO0FBQzlELDZFQUFvRDtBQUNwRCx1RUFBK0M7QUFDL0MsNkRBQXFDO0FBQ3JDLGlHQUE0RTtBQUUvRCxRQUFBLGdCQUFnQixHQUFHO0lBQzlCLHdCQUFjO0lBQ2Qsd0JBQWE7SUFDYixxQkFBVztJQUNYLHNCQUFXO0lBQ1gsZ0JBQU07SUFDTiw0QkFBaUI7Q0FDbEIsQ0FBQztBQUNXLFFBQUEsc0JBQXNCLEdBQUc7SUFDcEMsZUFBSztJQUNMLGVBQUs7SUFDTCxnQkFBTTtJQUNOLGFBQUc7SUFDSCxnQkFBTTtJQUNOLGFBQUc7SUFDSCxjQUFJO0lBQ0osZ0JBQU07SUFDTixzQkFBVztDQUNaLENBQUM7QUFDVyxRQUFBLG1CQUFtQixHQUFHO0lBQ2pDLDJCQUFnQjtJQUNoQix1QkFBWTtJQUNaLHFCQUFVO0lBQ1YsbUNBQXVCO0lBQ3ZCLHNCQUFXO0NBQ1osQ0FBQztBQUNXLFFBQUEsNEJBQTRCLEdBQUcsQ0FBQyx5QkFBYyxDQUFDLENBQUM7QUFDaEQsUUFBQSx3QkFBd0IsR0FBRyxDQUFDLHNC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
|
|
@@ -9,6 +9,9 @@ export default class ActionRoute extends CollectionRoute {
|
|
|
9
9
|
constructor(services: ForestAdminHttpDriverServices, options: AgentOptionsWithDefaults, dataSource: DataSource, collectionName: string, actionName: string);
|
|
10
10
|
setupRoutes(router: Router): void;
|
|
11
11
|
private handleExecute;
|
|
12
|
+
private executeAndAudit;
|
|
13
|
+
private resolveAuditedRecordIds;
|
|
14
|
+
private auditedRecordIds;
|
|
12
15
|
private handleHook;
|
|
13
16
|
private middlewareCustomActionApprovalRequestData;
|
|
14
17
|
private getRecordSelection;
|
|
@@ -5,6 +5,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
const datasource_toolkit_1 = require("@forestadmin/datasource-toolkit");
|
|
7
7
|
const action_authorization_1 = __importDefault(require("./action-authorization"));
|
|
8
|
+
const audit_trail_1 = require("../../../audit-trail");
|
|
8
9
|
const types_1 = require("../../../types");
|
|
9
10
|
const body_parser_1 = __importDefault(require("../../../utils/body-parser"));
|
|
10
11
|
const context_filter_factory_1 = __importDefault(require("../../../utils/context-filter-factory"));
|
|
@@ -65,7 +66,7 @@ class ActionRoute extends collection_route_1.default {
|
|
|
65
66
|
const { fields } = generator_actions_1.default.extractFieldsAndLayout(form);
|
|
66
67
|
// Now that we have the field list, we can parse the data again.
|
|
67
68
|
const data = action_values_1.default.makeFormData(dataSource, rawData, fields);
|
|
68
|
-
const result = await this.
|
|
69
|
+
const result = await this.executeAndAudit(context, caller, data, filterForCaller);
|
|
69
70
|
if (result.responseHeaders) {
|
|
70
71
|
context.response.set(result.responseHeaders);
|
|
71
72
|
}
|
|
@@ -97,6 +98,109 @@ class ActionRoute extends collection_route_1.default {
|
|
|
97
98
|
throw new Error('Unexpected Action result.');
|
|
98
99
|
}
|
|
99
100
|
}
|
|
101
|
+
// A failed run is worth recording too: "who tried to run this" is usually the interesting part.
|
|
102
|
+
// A resolved `{ type: 'Error' }` result counts as failed as well — the customer-declared action
|
|
103
|
+
// rejected the request (HTTP 400 below), it just didn't throw to say so.
|
|
104
|
+
//
|
|
105
|
+
// Record ids are resolved *before* `execute()` runs, not after: the action itself may delete the
|
|
106
|
+
// targeted records or change a field their own selection filter matched on, so resolving them
|
|
107
|
+
// afterward could find nothing and silently lose the association between the audit entry and the
|
|
108
|
+
// records it actually affected. The pending audit entry is inserted before `execute()` too, for the
|
|
109
|
+
// same reason `instrument.ts` inserts pending rows before a create/update/delete runs: a broken
|
|
110
|
+
// store fails the request *before* the action has any effect, instead of 500ing after it already
|
|
111
|
+
// ran (`critical: true`), or is swallowed and the action proceeds unaudited (`critical: false`,
|
|
112
|
+
// default) — see `captureActionPending`.
|
|
113
|
+
async executeAndAudit(context, caller, data, filter) {
|
|
114
|
+
const { auditTrail } = this.options;
|
|
115
|
+
const recordIds = await this.resolveAuditedRecordIds(context, caller, filter);
|
|
116
|
+
const audit = auditTrail
|
|
117
|
+
? {
|
|
118
|
+
recorder: (0, audit_trail_1.buildRecorder)(auditTrail.store, undefined, auditTrail.critical ?? false, this.options.logger),
|
|
119
|
+
redactedFields: auditTrail.redact?.[this.collection.name] ?? [],
|
|
120
|
+
}
|
|
121
|
+
: null;
|
|
122
|
+
const pending = audit
|
|
123
|
+
? await (0, audit_trail_1.captureActionPending)(audit.recorder, audit.redactedFields, {
|
|
124
|
+
caller,
|
|
125
|
+
collection: this.collection.name,
|
|
126
|
+
actionName: this.actionName,
|
|
127
|
+
formValues: data,
|
|
128
|
+
recordIds,
|
|
129
|
+
})
|
|
130
|
+
: null;
|
|
131
|
+
try {
|
|
132
|
+
const result = await this.collection.execute(caller, this.actionName, data, filter);
|
|
133
|
+
if (audit && pending) {
|
|
134
|
+
await (0, audit_trail_1.captureActionConfirm)(audit.recorder, pending, result, result.type === 'Error');
|
|
135
|
+
}
|
|
136
|
+
return result;
|
|
137
|
+
}
|
|
138
|
+
catch (error) {
|
|
139
|
+
if (audit && pending)
|
|
140
|
+
await (0, audit_trail_1.captureActionConfirm)(audit.recorder, pending, undefined, true);
|
|
141
|
+
throw error;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
// Best-effort under `critical: false`: resolving the audited ids is itself an extra query (see
|
|
145
|
+
// auditedRecordIds), and a transient failure there must not prevent the action from running at
|
|
146
|
+
// all — same principle the pending-capture step below applies. Under `critical: true`, falling
|
|
147
|
+
// back to `[]` would let a record-scoped action run with only a no-record audit entry instead of
|
|
148
|
+
// per-record coverage, which is exactly what `critical` exists to refuse — so this rethrows
|
|
149
|
+
// there instead, refusing the action before execute() runs.
|
|
150
|
+
async resolveAuditedRecordIds(context, caller, filter) {
|
|
151
|
+
if (!this.options.auditTrail)
|
|
152
|
+
return [];
|
|
153
|
+
try {
|
|
154
|
+
return await this.auditedRecordIds(context, caller, filter);
|
|
155
|
+
}
|
|
156
|
+
catch (error) {
|
|
157
|
+
if (this.options.auditTrail.critical)
|
|
158
|
+
throw error;
|
|
159
|
+
this.options.logger('Error', `[ForestAdmin] Unable to resolve audited record ids, continuing: ${error}`);
|
|
160
|
+
return [];
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
// Packed ids, the form the audit store keys on. A global action targets nothing, and a select-all
|
|
164
|
+
// selection only tells us which ids were *excluded*: naming the targets would mean querying the
|
|
165
|
+
// whole selection, so those runs are recorded once, attached to no record. An explicit selection
|
|
166
|
+
// is narrowed down to the caller's own authorized subset — via `filterForCaller`, the same filter
|
|
167
|
+
// `execute()` itself was given — so an id excluded by scope doesn't get an entry for an action that
|
|
168
|
+
// never touched it.
|
|
169
|
+
//
|
|
170
|
+
// The selection is capped at MAX_SNAPSHOT_RECORDS, same as a bulk update/delete's before-write
|
|
171
|
+
// snapshot (instrument.ts) and the same value the Ruby agent uses for this exact check — one shared
|
|
172
|
+
// constant so the two can't drift apart. Fetching cap+1 is what makes "matched more than the cap"
|
|
173
|
+
// distinguishable from "matched exactly the cap". Over the cap, recording one row per id would be a
|
|
174
|
+
// partial audit of the run, which is what `critical` exists to refuse; non-critical falls back to
|
|
175
|
+
// the existing no-record-attached recording instead of naming a subset of the targets.
|
|
176
|
+
//
|
|
177
|
+
// `filterForCaller` can carry a live-query segment with unresolved `$contextVariable` placeholders
|
|
178
|
+
// — the same filter reaches `getForm`/`execute` unresolved too, but those hand it to the collection
|
|
179
|
+
// as-is; this method calls `collection.list` directly, so it must run the filter through
|
|
180
|
+
// `segmentQueryHandler.handleLiveQuerySegmentFilter` itself first, the same step `list`/`count`
|
|
181
|
+
// apply before their own `collection.list` call.
|
|
182
|
+
async auditedRecordIds(context, caller, filterForCaller) {
|
|
183
|
+
if (this.collection.schema.actions[this.actionName].scope === 'Global')
|
|
184
|
+
return [];
|
|
185
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
186
|
+
const attributes = context.request.body?.data?.attributes;
|
|
187
|
+
if (attributes?.all_records)
|
|
188
|
+
return [];
|
|
189
|
+
if (!attributes?.ids?.length)
|
|
190
|
+
return [];
|
|
191
|
+
const paginatedFilter = await this.services.segmentQueryHandler.handleLiveQuerySegmentFilter(context, new datasource_toolkit_1.PaginatedFilter({ ...filterForCaller, page: new datasource_toolkit_1.Page(0, audit_trail_1.MAX_SNAPSHOT_RECORDS + 1) }));
|
|
192
|
+
const authorized = await this.collection.list(caller, paginatedFilter, new datasource_toolkit_1.Projection(...datasource_toolkit_1.SchemaUtils.getPrimaryKeys(this.collection.schema)));
|
|
193
|
+
if (authorized.length <= audit_trail_1.MAX_SNAPSHOT_RECORDS) {
|
|
194
|
+
return id_1.default.packIds(this.collection.schema, authorized);
|
|
195
|
+
}
|
|
196
|
+
const message = `[ForestAdmin] Audit trail: "${this.collection.name}" action "${this.actionName}" targets ` +
|
|
197
|
+
`more than ${audit_trail_1.MAX_SNAPSHOT_RECORDS} records — recorded as one entry attached to no record.`;
|
|
198
|
+
if (this.options.auditTrail.critical) {
|
|
199
|
+
throw new Error(`${message} Refusing the action because "critical" is enabled.`);
|
|
200
|
+
}
|
|
201
|
+
this.options.logger('Warn', message);
|
|
202
|
+
return [];
|
|
203
|
+
}
|
|
100
204
|
async handleHook(context) {
|
|
101
205
|
const body = context.request.body;
|
|
102
206
|
const { id: userId } = context.state.user;
|
|
@@ -170,4 +274,4 @@ class ActionRoute extends collection_route_1.default {
|
|
|
170
274
|
}
|
|
171
275
|
}
|
|
172
276
|
exports.default = ActionRoute;
|
|
173
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYWN0aW9uLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vc3JjL3JvdXRlcy9tb2RpZmljYXRpb24vYWN0aW9uL2FjdGlvbi50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7OztBQVlBLHdFQUl5QztBQUV6QyxrRkFBZ0U7QUFDaEUsMENBQTBDO0FBQzFDLDZFQUFvRDtBQUNwRCxtR0FBeUU7QUFDekUsK0ZBQThFO0FBQzlFLHVHQUFvRjtBQUNwRiwyREFBd0M7QUFDeEMsK0VBQTREO0FBQzVELDhFQUFxRDtBQUVyRCxNQUFxQixXQUFZLFNBQVEsMEJBQWU7SUFLdEQsWUFDRSxRQUF1QyxFQUN2QyxPQUFpQyxFQUNqQyxVQUFzQixFQUN0QixjQUFzQixFQUN0QixVQUFrQjtRQUVsQixLQUFLLENBQUMsUUFBUSxFQUFFLE9BQU8sRUFBRSxVQUFVLEVBQUUsY0FBYyxDQUFDLENBQUM7UUFDckQsSUFBSSxDQUFDLFVBQVUsR0FBRyxVQUFVLENBQUM7UUFFN0IsSUFBSSxDQUFDLDBCQUEwQixHQUFHLElBQUksOEJBQTBCLENBQUMsT0FBTyxDQUFDLGlCQUFpQixDQUFDLENBQUM7SUFDOUYsQ0FBQztJQUVELFdBQVcsQ0FBQyxNQUFjO1FBQ3hCLGtGQUFrRjtRQUNsRixNQUFNLFdBQVcsR0FBRyxNQUFNLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxVQUFVLENBQUMsTUFBTSxDQUFDLE9BQU8sQ0FBQyxDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMsVUFBVSxDQUFDLENBQUM7UUFDekYsTUFBTSxJQUFJLEdBQUcsMkJBQXNCLENBQUMsYUFBYSxDQUFDLElBQUksQ0FBQyxVQUFVLENBQUMsQ0FBQztRQUVuRSxJQUFJLElBQUksR0FBRyxhQUFhLElBQUksQ0FBQyxpQkFBaUIsR0FBRyxDQUFDO1FBRWxELElBQUksQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLHVCQUF1QixFQUFFLENBQUM7WUFDMUMsSUFBSSxJQUFJLEdBQUcsV0FBVyxH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
|
|
277
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYWN0aW9uLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vc3JjL3JvdXRlcy9tb2RpZmljYXRpb24vYWN0aW9uL2FjdGlvbi50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7OztBQVlBLHdFQVF5QztBQUV6QyxrRkFBZ0U7QUFDaEUsc0RBSzhCO0FBQzlCLDBDQUEwQztBQUMxQyw2RUFBb0Q7QUFDcEQsbUdBQXlFO0FBQ3pFLCtGQUE4RTtBQUM5RSx1R0FBb0Y7QUFDcEYsMkRBQXdDO0FBQ3hDLCtFQUE0RDtBQUM1RCw4RUFBcUQ7QUFFckQsTUFBcUIsV0FBWSxTQUFRLDBCQUFlO0lBS3RELFlBQ0UsUUFBdUMsRUFDdkMsT0FBaUMsRUFDakMsVUFBc0IsRUFDdEIsY0FBc0IsRUFDdEIsVUFBa0I7UUFFbEIsS0FBSyxDQUFDLFFBQVEsRUFBRSxPQUFPLEVBQUUsVUFBVSxFQUFFLGNBQWMsQ0FBQyxDQUFDO1FBQ3JELElBQUksQ0FBQyxVQUFVLEdBQUcsVUFBVSxDQUFDO1FBRTdCLElBQUksQ0FBQywwQkFBMEIsR0FBRyxJQUFJLDhCQUEwQixDQUFDLE9BQU8sQ0FBQyxpQkFBaUIsQ0FBQyxDQUFDO0lBQzlGLENBQUM7SUFFRCxXQUFXLENBQUMsTUFBYztRQUN4QixrRkFBa0Y7UUFDbEYsTUFBTSxXQUFXLEdBQUcsTUFBTSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsVUFBVSxDQUFDLE1BQU0sQ0FBQyxPQUFPLENBQUMsQ0FBQyxPQUFPLENBQUMsSUFBSSxDQUFDLFVBQVUsQ0FBQyxDQUFDO1FBQ3pGLE1BQU0sSUFBSSxHQUFHLDJCQUFzQixDQUFDLGFBQWEsQ0FBQyxJQUFJLENBQUMsVUFBVSxDQUFDLENBQUM7UUFFbkUsSUFBSSxJQUFJLEdBQUcsYUFBYSxJQUFJLENBQUMsaUJBQWlCLEdBQUcsQ0FBQztRQUVsRCxJQUFJLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyx1QkFBdUIsRUFBRSxDQUFDO1lBQzFDLElBQUksSUFB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
|