@eleven-am/golem-core 0.1.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.
@@ -0,0 +1,484 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.GolemEngine = void 0;
4
+ const authorization_1 = require("./authorization");
5
+ const errors_1 = require("./errors");
6
+ const concurrency_1 = require("./concurrency");
7
+ const event_buffer_1 = require("./event-buffer");
8
+ const naming_1 = require("./naming");
9
+ const model_meta_1 = require("./model-meta");
10
+ const nested_writes_1 = require("./nested-writes");
11
+ const readtree_1 = require("./readtree");
12
+ const verify_1 = require("./verify");
13
+ const PRISMA_CODE_PATTERN = /^P\d+$/;
14
+ function translateError(error, model) {
15
+ if (error instanceof Error) {
16
+ if (error.name === 'PrismaClientValidationError') {
17
+ throw new errors_1.GolemValidationError(error.message);
18
+ }
19
+ const code = error.code;
20
+ if (typeof code === 'string' && PRISMA_CODE_PATTERN.test(code)) {
21
+ if (code === 'P2025') {
22
+ throw new errors_1.GolemNotFoundError(`${model} not found`);
23
+ }
24
+ if (code === 'P2002') {
25
+ throw new errors_1.GolemConflictError(`Unique constraint violation on ${model}`);
26
+ }
27
+ if (code === 'P2003' || code === 'P2014') {
28
+ throw new errors_1.GolemValidationError(`The requested change violates a relation constraint on ${model}`);
29
+ }
30
+ }
31
+ }
32
+ throw error;
33
+ }
34
+ class GolemEngine {
35
+ client;
36
+ modelsByName;
37
+ metadata;
38
+ hooks;
39
+ takeLimits;
40
+ authorization;
41
+ maxDepth;
42
+ checkWriteResults;
43
+ checkReadFields;
44
+ authorizationSessions = new WeakMap();
45
+ constructor(client, models, options = {}) {
46
+ this.client = client;
47
+ this.modelsByName = new Map(models.map((m) => [m.name, m]));
48
+ this.metadata = (0, model_meta_1.buildModelMetadata)(models);
49
+ this.hooks = options.hooks;
50
+ this.takeLimits = options.takeLimits ?? new Map();
51
+ this.authorization = options.authorization;
52
+ this.maxDepth = options.maxDepth ?? 5;
53
+ this.checkWriteResults = options.checkWriteResults ?? false;
54
+ this.checkReadFields = options.checkReadFields ?? false;
55
+ if (this.checkReadFields && this.authorization) {
56
+ const missing = [
57
+ !this.authorization.classifyFields ? 'classifyFields' : null,
58
+ !this.authorization.checkField ? 'checkField' : null,
59
+ ].filter(Boolean);
60
+ if (missing.length > 0) {
61
+ throw new Error(`checkReadFields is enabled but the authorization provider does not implement ${missing.join(' and ')}`);
62
+ }
63
+ }
64
+ if (this.checkWriteResults && this.authorization) {
65
+ const missing = [
66
+ !this.authorization.check ? 'check' : null,
67
+ !this.authorization.checkField ? 'checkField' : null,
68
+ ].filter(Boolean);
69
+ if (missing.length > 0) {
70
+ throw new Error(`checkWriteResults is enabled but the authorization provider does not implement ${missing.join(' and ')}`);
71
+ }
72
+ }
73
+ }
74
+ verifyContext(context) {
75
+ return {
76
+ modelsByName: this.modelsByName,
77
+ metadata: this.metadata,
78
+ provider: this.enforced(context),
79
+ context,
80
+ };
81
+ }
82
+ pkOf(model) {
83
+ const pk = this.metadata.get(model)?.primaryKey;
84
+ if (!pk) {
85
+ throw new errors_1.GolemValidationError(`Model ${model} has no primary key field`);
86
+ }
87
+ return pk;
88
+ }
89
+ async prepareRead(request) {
90
+ return (0, readtree_1.prepareReadTree)({
91
+ model: this.modelsByName.get(request.model),
92
+ modelsByName: this.modelsByName,
93
+ select: request.select,
94
+ include: request.include,
95
+ provider: this.enforced(request.context),
96
+ context: request.context,
97
+ maxDepth: this.maxDepth,
98
+ readFieldChecks: this.checkReadFields,
99
+ metadata: this.metadata,
100
+ });
101
+ }
102
+ async finishRead(result, prepared, context) {
103
+ if (!result) {
104
+ return result;
105
+ }
106
+ if (prepared.toOneChecks.length > 0) {
107
+ await (0, readtree_1.applyToOneChecks)(result, prepared.toOneChecks, this.authorization, context);
108
+ }
109
+ if (prepared.maskChecks.length > 0) {
110
+ await (0, readtree_1.applyFieldMasks)(result, prepared.maskChecks, this.authorization, context);
111
+ }
112
+ if (prepared.injected.length > 0) {
113
+ await (0, readtree_1.stripInjectedFields)(result, prepared.injected);
114
+ }
115
+ return result;
116
+ }
117
+ enforced(context) {
118
+ if (!this.authorization || context === undefined) {
119
+ return undefined;
120
+ }
121
+ if (!context || typeof context !== 'object')
122
+ return this.authorization;
123
+ const cached = this.authorizationSessions.get(context);
124
+ if (cached)
125
+ return cached;
126
+ const source = this.authorization;
127
+ const values = new Map();
128
+ const memo = (key, load) => {
129
+ const existing = values.get(key);
130
+ if (existing)
131
+ return existing;
132
+ const pending = load();
133
+ values.set(key, pending);
134
+ return pending;
135
+ };
136
+ const session = {
137
+ authorize: (action, model, ctx) => memo(`authorize:${action}:${model}`, () => source.authorize(action, model, ctx)),
138
+ constrain: (action, model, ctx) => memo(`constrain:${action}:${model}`, () => source.constrain(action, model, ctx)),
139
+ check: source.check?.bind(source),
140
+ checkField: source.checkField?.bind(source),
141
+ classifyFields: source.classifyFields
142
+ ? (action, model, fields, ctx) => memo(`classify:${action}:${model}:${[...fields].sort().join('\u0000')}`, () => source.classifyFields(action, model, fields, ctx))
143
+ : undefined,
144
+ freshContext: source.freshContext?.bind(source),
145
+ };
146
+ this.authorizationSessions.set(context, session);
147
+ return session;
148
+ }
149
+ async constraintFor(action, model, context) {
150
+ const provider = this.enforced(context);
151
+ if (!provider) {
152
+ return undefined;
153
+ }
154
+ return provider.constrain(action, model, context);
155
+ }
156
+ async authorizeNestedWrites(model, data, context) {
157
+ const provider = this.enforced(context);
158
+ if (!provider) {
159
+ return;
160
+ }
161
+ await this.walkNestedWrites(provider, model, data, context);
162
+ }
163
+ async walkNestedWrites(provider, model, data, context) {
164
+ if (!data || typeof data !== 'object') {
165
+ return;
166
+ }
167
+ const definition = this.modelsByName.get(model);
168
+ if (!definition) {
169
+ return;
170
+ }
171
+ for (const relation of (0, nested_writes_1.planNestedWrites)(this.metadata, definition, data)) {
172
+ for (const action of relation.modelActions) {
173
+ await provider.authorize(action, relation.target.name, context);
174
+ }
175
+ for (const nested of [...relation.createPayloads, ...relation.updatePayloads]) {
176
+ await this.walkNestedWrites(provider, relation.target.name, nested, context);
177
+ }
178
+ }
179
+ }
180
+ async resolveConstrainedTarget(action, request) {
181
+ const constraint = await this.constraintFor(action, request.model, request.context);
182
+ if (constraint === undefined) {
183
+ return { where: request.where };
184
+ }
185
+ const pkField = this.metadata.get(request.model)?.primaryKey;
186
+ if (!pkField) {
187
+ throw new errors_1.GolemValidationError(`Model ${request.model} has no primary key field`);
188
+ }
189
+ const delegate = this.delegate(request.model);
190
+ const found = (await this.run(request.model, () => delegate.findFirst({
191
+ where: (0, authorization_1.mergeConstraint)(request.where, constraint),
192
+ select: { [pkField.name]: true },
193
+ })));
194
+ if (!found) {
195
+ throw new errors_1.GolemNotFoundError(`${request.model} not found`);
196
+ }
197
+ return { where: { [pkField.name]: found[pkField.name] }, row: found };
198
+ }
199
+ async runBefore(operation, request) {
200
+ if (!this.hooks) {
201
+ return request;
202
+ }
203
+ let current = request;
204
+ for (const hook of this.hooks.beforeFor(request.model, operation)) {
205
+ const result = await hook(current, {
206
+ model: request.model,
207
+ operation,
208
+ context: request.context,
209
+ });
210
+ if (result !== undefined) {
211
+ current = result;
212
+ }
213
+ }
214
+ return current;
215
+ }
216
+ async runAfter(operation, model, result, context) {
217
+ if (!this.hooks) {
218
+ return;
219
+ }
220
+ for (const hook of this.hooks.afterFor(model, operation)) {
221
+ await hook(result, { model, operation, context });
222
+ }
223
+ }
224
+ enforceTakeLimit(request) {
225
+ const limit = this.takeLimits.get(request.model);
226
+ if (limit !== undefined && request.take !== undefined && Math.abs(request.take) > limit) {
227
+ throw new errors_1.GolemValidationError(`take ${request.take} exceeds the maximum of ${limit} for ${request.model}`);
228
+ }
229
+ }
230
+ delegate(model) {
231
+ if (!this.modelsByName.has(model)) {
232
+ throw new errors_1.GolemValidationError(`Unknown model ${model}`);
233
+ }
234
+ const delegate = this.client[(0, naming_1.lcFirst)(model)];
235
+ if (!delegate) {
236
+ throw new errors_1.GolemValidationError(`Prisma client has no delegate for model ${model}`);
237
+ }
238
+ return delegate;
239
+ }
240
+ async run(model, action) {
241
+ try {
242
+ return await action();
243
+ }
244
+ catch (error) {
245
+ translateError(error, model);
246
+ }
247
+ }
248
+ async findOne(request) {
249
+ const delegate = this.delegate(request.model);
250
+ const req = await this.runBefore('findOne', request);
251
+ const prepared = await this.prepareRead(req);
252
+ const constraint = await this.constraintFor('read', req.model, req.context);
253
+ const found = await this.run(req.model, () => constraint === undefined
254
+ ? delegate.findUnique({ where: req.where, select: prepared.select, include: prepared.include })
255
+ : delegate.findFirst({
256
+ where: (0, authorization_1.mergeConstraint)(req.where, constraint),
257
+ select: prepared.select,
258
+ include: prepared.include,
259
+ }));
260
+ await this.finishRead(found, prepared, req.context);
261
+ await this.runAfter('findOne', req.model, found, req.context);
262
+ return found;
263
+ }
264
+ async findMany(request) {
265
+ const delegate = this.delegate(request.model);
266
+ const req = await this.runBefore('findMany', request);
267
+ this.enforceTakeLimit(req);
268
+ const prepared = await this.prepareRead(req);
269
+ const constraint = await this.constraintFor('read', req.model, req.context);
270
+ const found = (await this.run(req.model, () => delegate.findMany({
271
+ where: (0, authorization_1.mergeConstraint)(req.where, constraint),
272
+ orderBy: req.orderBy,
273
+ take: req.take,
274
+ skip: req.skip,
275
+ cursor: req.cursor,
276
+ distinct: req.distinct,
277
+ select: prepared.select,
278
+ include: prepared.include,
279
+ })));
280
+ await this.finishRead(found, prepared, req.context);
281
+ await this.runAfter('findMany', req.model, found, req.context);
282
+ return found;
283
+ }
284
+ async findFirst(request) {
285
+ const delegate = this.delegate(request.model);
286
+ const prepared = await this.prepareRead(request);
287
+ const constraint = await this.constraintFor('read', request.model, request.context);
288
+ const found = await this.run(request.model, () => delegate.findFirst({
289
+ where: (0, authorization_1.mergeConstraint)(request.where, constraint),
290
+ select: prepared.select,
291
+ include: prepared.include,
292
+ }));
293
+ return this.finishRead(found, prepared, request.context);
294
+ }
295
+ async create(request) {
296
+ const delegate = this.delegate(request.model);
297
+ const req = await this.runBefore('create', request);
298
+ const provider = this.enforced(req.context);
299
+ if (provider) {
300
+ await provider.authorize('create', req.model, req.context);
301
+ await this.authorizeNestedWrites(req.model, req.data, req.context);
302
+ }
303
+ const prepared = await this.prepareRead(req);
304
+ let created;
305
+ let createPlanFast = false;
306
+ let createPlan;
307
+ if (provider && this.checkWriteResults) {
308
+ const model = this.modelsByName.get(req.model);
309
+ const vctx = this.verifyContext(req.context);
310
+ const constraint = await this.constraintFor('create', req.model, req.context);
311
+ createPlan = await (0, verify_1.planVerification)(vctx, model, req.data, constraint, 'create');
312
+ createPlanFast = createPlan.fastPath;
313
+ }
314
+ if (provider && this.checkWriteResults && !createPlanFast) {
315
+ const model = this.modelsByName.get(req.model);
316
+ const pk = this.pkOf(req.model);
317
+ const vctx = this.verifyContext(req.context);
318
+ created = await (0, event_buffer_1.withBufferedEvents)(() => this.run(req.model, () => this.client.$transaction(async (tx) => {
319
+ const txDelegate = tx[(0, naming_1.lcFirst)(req.model)];
320
+ const wide = await txDelegate.create({
321
+ data: req.data,
322
+ select: { ...createPlan.select, [pk.name]: true },
323
+ });
324
+ await (0, verify_1.verifyCreatedTree)(vctx, model, wide, req.data);
325
+ return txDelegate.findUnique({
326
+ where: { [pk.name]: wide[pk.name] },
327
+ select: prepared.select,
328
+ include: prepared.include,
329
+ });
330
+ })));
331
+ }
332
+ else {
333
+ created = await this.run(req.model, () => delegate.create({ data: req.data, select: prepared.select, include: prepared.include }));
334
+ }
335
+ await this.finishRead(created, prepared, req.context);
336
+ await this.runAfter('create', req.model, created, req.context);
337
+ return created;
338
+ }
339
+ async update(request) {
340
+ const delegate = this.delegate(request.model);
341
+ const req = await this.runBefore('update', request);
342
+ await this.authorizeNestedWrites(req.model, req.data, req.context);
343
+ const provider = this.enforced(req.context);
344
+ const prepared = await this.prepareRead(req);
345
+ let updated;
346
+ let updatePlan;
347
+ let updateConstraint;
348
+ if (provider && this.checkWriteResults) {
349
+ const model = this.modelsByName.get(req.model);
350
+ const vctx = this.verifyContext(req.context);
351
+ updateConstraint = await this.constraintFor('update', req.model, req.context);
352
+ updatePlan = await (0, verify_1.planVerification)(vctx, model, req.data, updateConstraint, 'update');
353
+ }
354
+ if (provider && this.checkWriteResults && updatePlan && !updatePlan.fastPath) {
355
+ const model = this.modelsByName.get(req.model);
356
+ const pk = this.pkOf(req.model);
357
+ const vctx = this.verifyContext(req.context);
358
+ const constraint = updateConstraint;
359
+ const wide = { ...updatePlan.select, [pk.name]: true };
360
+ updated = await (0, event_buffer_1.withBufferedEvents)(() => this.run(req.model, () => this.client.$transaction(async (tx) => {
361
+ const txDelegate = tx[(0, naming_1.lcFirst)(req.model)];
362
+ const before = await txDelegate.findFirst({
363
+ where: (0, authorization_1.mergeConstraint)(req.where, constraint),
364
+ select: wide,
365
+ });
366
+ if (!before) {
367
+ throw new errors_1.GolemNotFoundError(`${req.model} not found`);
368
+ }
369
+ const after = await txDelegate.update({
370
+ where: { [pk.name]: before[pk.name] },
371
+ data: req.data,
372
+ select: wide,
373
+ });
374
+ await (0, verify_1.verifyUpdatedRow)(vctx, model, before, after, req.data);
375
+ return txDelegate.findUnique({
376
+ where: { [pk.name]: before[pk.name] },
377
+ select: prepared.select,
378
+ include: prepared.include,
379
+ });
380
+ })));
381
+ }
382
+ else {
383
+ const target = await this.resolveConstrainedTarget('update', req);
384
+ updated = await this.run(req.model, () => delegate.update({
385
+ where: target.where,
386
+ data: req.data,
387
+ select: prepared.select,
388
+ include: prepared.include,
389
+ }));
390
+ }
391
+ await this.finishRead(updated, prepared, req.context);
392
+ await this.runAfter('update', req.model, updated, req.context);
393
+ return updated;
394
+ }
395
+ async updateMany(request) {
396
+ const delegate = this.delegate(request.model);
397
+ const req = await this.runBefore('updateMany', request);
398
+ await this.authorizeNestedWrites(req.model, req.data, req.context);
399
+ const constraint = await this.constraintFor('update', req.model, req.context);
400
+ const provider = this.enforced(req.context);
401
+ let result;
402
+ let manyPlan;
403
+ if (provider && this.checkWriteResults) {
404
+ const vctx = this.verifyContext(req.context);
405
+ manyPlan = await (0, verify_1.planVerification)(vctx, this.modelsByName.get(req.model), req.data, constraint, 'update');
406
+ }
407
+ if (provider && this.checkWriteResults && manyPlan && !manyPlan.fastPath) {
408
+ const model = this.modelsByName.get(req.model);
409
+ const pk = this.pkOf(req.model);
410
+ const vctx = this.verifyContext(req.context);
411
+ const scalars = { ...manyPlan.select, [pk.name]: true };
412
+ result = (await (0, event_buffer_1.withBufferedEvents)(() => this.run(req.model, () => this.client.$transaction(async (tx) => {
413
+ const txDelegate = tx[(0, naming_1.lcFirst)(req.model)];
414
+ const beforeRows = (await txDelegate.findMany({
415
+ where: (0, authorization_1.mergeConstraint)(req.where, constraint),
416
+ select: scalars,
417
+ }));
418
+ const ids = beforeRows.map((row) => row[pk.name]);
419
+ await txDelegate.updateMany({ where: { [pk.name]: { in: ids } }, data: req.data });
420
+ const afterRows = (await txDelegate.findMany({
421
+ where: { [pk.name]: { in: ids } },
422
+ select: scalars,
423
+ }));
424
+ const afterById = new Map(afterRows.map((row) => [row[pk.name], row]));
425
+ await (0, concurrency_1.runPolicyChecks)(beforeRows.map((before) => async () => {
426
+ const after = afterById.get(before[pk.name]);
427
+ if (after) {
428
+ await (0, verify_1.verifyUpdatedRow)(vctx, model, before, after, req.data);
429
+ }
430
+ }));
431
+ return { count: ids.length };
432
+ }))));
433
+ }
434
+ else {
435
+ result = (await this.run(req.model, () => delegate.updateMany({ where: (0, authorization_1.mergeConstraint)(req.where, constraint), data: req.data })));
436
+ }
437
+ await this.runAfter('updateMany', req.model, result, req.context);
438
+ return result;
439
+ }
440
+ async delete(request) {
441
+ const delegate = this.delegate(request.model);
442
+ const req = await this.runBefore('delete', request);
443
+ const { where } = await this.resolveConstrainedTarget('delete', req);
444
+ const prepared = await this.prepareRead(req);
445
+ const deleted = await this.run(req.model, () => delegate.delete({ where, select: prepared.select, include: prepared.include }));
446
+ await this.finishRead(deleted, prepared, req.context);
447
+ await this.runAfter('delete', req.model, deleted, req.context);
448
+ return deleted;
449
+ }
450
+ async upsert(request) {
451
+ const delegate = this.delegate(request.model);
452
+ const pkField = this.metadata.get(request.model)?.primaryKey;
453
+ if (!pkField) {
454
+ throw new errors_1.GolemValidationError(`Model ${request.model} has no primary key field`);
455
+ }
456
+ const existing = await this.run(request.model, () => delegate.findFirst({ where: request.where, select: { [pkField.name]: true } }));
457
+ if (existing) {
458
+ return this.update({
459
+ model: request.model,
460
+ where: request.where,
461
+ data: request.update,
462
+ select: request.select,
463
+ include: request.include,
464
+ context: request.context,
465
+ });
466
+ }
467
+ return this.create({
468
+ model: request.model,
469
+ data: request.create,
470
+ select: request.select,
471
+ include: request.include,
472
+ context: request.context,
473
+ });
474
+ }
475
+ async deleteMany(request) {
476
+ const delegate = this.delegate(request.model);
477
+ const req = await this.runBefore('deleteMany', request);
478
+ const constraint = await this.constraintFor('delete', req.model, req.context);
479
+ const result = (await this.run(req.model, () => delegate.deleteMany({ where: (0, authorization_1.mergeConstraint)(req.where, constraint) })));
480
+ await this.runAfter('deleteMany', req.model, result, req.context);
481
+ return result;
482
+ }
483
+ }
484
+ exports.GolemEngine = GolemEngine;
@@ -0,0 +1,16 @@
1
+ import { DatamodelDocument } from './datamodel';
2
+ import { GolemEventBus } from './events';
3
+ export interface GolemQueryParams {
4
+ model?: string;
5
+ operation: string;
6
+ args: any;
7
+ query: (args: any) => Promise<any>;
8
+ findExisting?: (where: unknown, select: Record<string, true>) => Promise<unknown>;
9
+ }
10
+ export type GolemQueryInterceptor = (params: GolemQueryParams) => Promise<any>;
11
+ export interface CreateEventPublisherOptions {
12
+ datamodel: DatamodelDocument<any>;
13
+ eventBus: GolemEventBus;
14
+ models: ReadonlySet<string>;
15
+ }
16
+ export declare function createEventPublisher(options: CreateEventPublisherOptions): GolemQueryInterceptor;
@@ -0,0 +1,55 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createEventPublisher = createEventPublisher;
4
+ const event_buffer_1 = require("./event-buffer");
5
+ const events_1 = require("./events");
6
+ const OPERATION_EVENTS = {
7
+ create: 'CREATED',
8
+ update: 'UPDATED',
9
+ delete: 'DELETED',
10
+ };
11
+ function createEventPublisher(options) {
12
+ const pkByModel = new Map();
13
+ for (const model of options.datamodel.models) {
14
+ const pk = model.fields.find((f) => f.isId);
15
+ if (pk) {
16
+ pkByModel.set(model.name, pk.name);
17
+ }
18
+ }
19
+ return async ({ model, operation, args, query, findExisting }) => {
20
+ let type = OPERATION_EVENTS[operation];
21
+ if (operation === 'upsert') {
22
+ if (!model || !options.models.has(model))
23
+ return query(args);
24
+ const pk = pkByModel.get(model);
25
+ if (!pk || !findExisting)
26
+ return query(args);
27
+ const existing = await findExisting(args?.where, { [pk]: true });
28
+ type = existing ? 'UPDATED' : 'CREATED';
29
+ }
30
+ if (!type || !model || !options.models.has(model)) {
31
+ return query(args);
32
+ }
33
+ const pk = pkByModel.get(model);
34
+ if (!pk) {
35
+ return query(args);
36
+ }
37
+ const finalArgs = args?.select ? { ...args, select: { ...args.select, [pk]: true } } : args;
38
+ const result = await query(finalArgs);
39
+ const payload = {
40
+ type,
41
+ model,
42
+ id: result[pk],
43
+ ...(type === 'DELETED' && result && typeof result === 'object'
44
+ ? { entity: result }
45
+ : {}),
46
+ };
47
+ const deferred = (0, event_buffer_1.bufferEvent)({
48
+ publish: () => options.eventBus.publish((0, events_1.eventTopic)(model), payload),
49
+ });
50
+ if (!deferred) {
51
+ await options.eventBus.publish((0, events_1.eventTopic)(model), payload);
52
+ }
53
+ return result;
54
+ };
55
+ }
@@ -0,0 +1,40 @@
1
+ import { AuthorizationProvider } from './authorization';
2
+ import { DatamodelModel } from './datamodel';
3
+ import { ModelMetadataIndex } from './model-meta';
4
+ export interface ToOneCheck {
5
+ path: readonly string[];
6
+ model: string;
7
+ }
8
+ export interface FieldMaskCheck {
9
+ path: readonly string[];
10
+ model: string;
11
+ field: string;
12
+ }
13
+ export interface InjectedField {
14
+ path: readonly string[];
15
+ field: string;
16
+ }
17
+ export interface PreparedReadTree {
18
+ select?: Record<string, unknown>;
19
+ include?: Record<string, unknown>;
20
+ toOneChecks: ToOneCheck[];
21
+ maskChecks: FieldMaskCheck[];
22
+ injected: InjectedField[];
23
+ }
24
+ interface PrepareOptions {
25
+ model: DatamodelModel;
26
+ modelsByName: Map<string, DatamodelModel>;
27
+ select?: Record<string, unknown>;
28
+ include?: Record<string, unknown>;
29
+ provider?: AuthorizationProvider;
30
+ context?: unknown;
31
+ maxDepth: number;
32
+ readFieldChecks?: boolean;
33
+ metadata?: ModelMetadataIndex;
34
+ }
35
+ export declare function constraintFieldNames(constraint: unknown, into?: Set<string>): Set<string>;
36
+ export declare function prepareReadTree(options: PrepareOptions): Promise<PreparedReadTree>;
37
+ export declare function applyToOneChecks(data: unknown, checks: readonly ToOneCheck[], provider: AuthorizationProvider, context: unknown): Promise<void>;
38
+ export declare function applyFieldMasks(data: unknown, checks: readonly FieldMaskCheck[], provider: AuthorizationProvider, context: unknown): Promise<void>;
39
+ export declare function stripInjectedFields(data: unknown, injected: readonly InjectedField[]): Promise<void>;
40
+ export {};