@stndrds/schema 0.1.0-alpha.63 → 0.1.0-alpha.65
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/{chunk-MUJVBSBL.mjs → chunk-A6T4UUZ2.mjs} +1308 -970
- package/dist/{chunk-KMAKDHCL.js → chunk-TOTUS3YS.js} +1615 -1277
- package/dist/index.d.mts +240 -326
- package/dist/index.d.ts +240 -326
- package/dist/index.js +51 -64
- package/dist/index.mjs +61 -74
- package/dist/{runtime-7G9tZJYC.d.ts → runtime-BgtwoMx5.d.ts} +359 -213
- package/dist/{runtime-C4U2ppAk.d.mts → runtime-DQlTgVZJ.d.mts} +359 -213
- package/dist/runtime.d.mts +2 -2
- package/dist/runtime.d.ts +2 -2
- package/dist/runtime.js +2 -4
- package/dist/runtime.mjs +1 -3
- package/dist/validation/validators.d.mts +1 -1
- package/dist/validation/validators.d.ts +1 -1
- package/dist/{validators-BIAmz0CD.d.mts → validators-BROsLGn4.d.mts} +47 -122
- package/dist/{validators-BPIB7Miq.d.ts → validators-CEzdvxEq.d.ts} +47 -122
- package/package.json +2 -2
|
@@ -10,6 +10,7 @@ var _chunkNEVERCM3js = require('./chunk-NEVERCM3.js');
|
|
|
10
10
|
|
|
11
11
|
|
|
12
12
|
|
|
13
|
+
|
|
13
14
|
var _chunkU4AB53AMjs = require('./chunk-U4AB53AM.js');
|
|
14
15
|
|
|
15
16
|
|
|
@@ -4133,7 +4134,6 @@ function createMockRelationAttributesRepository(stores) {
|
|
|
4133
4134
|
}
|
|
4134
4135
|
const results = [];
|
|
4135
4136
|
for (const item of items) {
|
|
4136
|
-
const _key = `${context.tenantId}:${item.fromObject}:${item.fromId}:${item.fromAttribute}:${item.toId}`;
|
|
4137
4137
|
const existing = Array.from(stores.relationAttributes.values()).find(
|
|
4138
4138
|
(row) => row.tenantId === context.tenantId && row.fromObject === item.fromObject && row.fromId === item.fromId && row.fromAttribute === item.fromAttribute && row.toId === item.toId
|
|
4139
4139
|
);
|
|
@@ -4180,6 +4180,36 @@ function createMockRelationAttributesRepository(stores) {
|
|
|
4180
4180
|
(row) => row.tenantId === context.tenantId && row.toId === toId
|
|
4181
4181
|
);
|
|
4182
4182
|
},
|
|
4183
|
+
async findBySourceBatch(fromObject, fromIds, fromAttribute) {
|
|
4184
|
+
const context = getContext2();
|
|
4185
|
+
if (!context) {
|
|
4186
|
+
throw new Error("Context required for relationAttributes operations");
|
|
4187
|
+
}
|
|
4188
|
+
return Array.from(stores.relationAttributes.values()).filter(
|
|
4189
|
+
(row) => row.tenantId === context.tenantId && row.fromObject === fromObject && fromIds.includes(row.fromId) && row.fromAttribute === fromAttribute
|
|
4190
|
+
);
|
|
4191
|
+
},
|
|
4192
|
+
async findByTargetBatch(toIds) {
|
|
4193
|
+
const context = getContext2();
|
|
4194
|
+
if (!context) {
|
|
4195
|
+
throw new Error("Context required for relationAttributes operations");
|
|
4196
|
+
}
|
|
4197
|
+
return Array.from(stores.relationAttributes.values()).filter(
|
|
4198
|
+
(row) => row.tenantId === context.tenantId && toIds.includes(row.toId)
|
|
4199
|
+
);
|
|
4200
|
+
},
|
|
4201
|
+
async deleteBySourceAndTarget(fromObject, fromId, fromAttribute, toId) {
|
|
4202
|
+
const context = getContext2();
|
|
4203
|
+
if (!context) {
|
|
4204
|
+
throw new Error("Context required for relationAttributes operations");
|
|
4205
|
+
}
|
|
4206
|
+
const toDelete = Array.from(stores.relationAttributes.entries()).filter(
|
|
4207
|
+
([_id, row]) => row.tenantId === context.tenantId && row.fromObject === fromObject && row.fromId === fromId && row.fromAttribute === fromAttribute && row.toId === toId
|
|
4208
|
+
);
|
|
4209
|
+
for (const [id] of toDelete) {
|
|
4210
|
+
stores.relationAttributes.delete(id);
|
|
4211
|
+
}
|
|
4212
|
+
},
|
|
4183
4213
|
async deleteBySource(fromObject, fromId, fromAttribute) {
|
|
4184
4214
|
const context = getContext2();
|
|
4185
4215
|
if (!context) {
|
|
@@ -5244,92 +5274,6 @@ var PolicyRegistry = class {
|
|
|
5244
5274
|
};
|
|
5245
5275
|
var defaultPolicyRegistry = new PolicyRegistry();
|
|
5246
5276
|
|
|
5247
|
-
// src/runtime/policies/notes.policy.ts
|
|
5248
|
-
var notesPolicy = {
|
|
5249
|
-
objectName: "notes",
|
|
5250
|
-
/**
|
|
5251
|
-
* Inject visibility filter for list/search operations.
|
|
5252
|
-
*
|
|
5253
|
-
* Creates: (visibility = 'shared') OR (createdBy = userId)
|
|
5254
|
-
*
|
|
5255
|
-
* This filters at the SQL level for better performance.
|
|
5256
|
-
* canAccessRecord provides defense-in-depth as a secondary check.
|
|
5257
|
-
*
|
|
5258
|
-
* Note: When user filters exist, we preserve linkedTo filter (common for notes)
|
|
5259
|
-
* but the visibility OR filter takes precedence. Full filter merging would require
|
|
5260
|
-
* AdvancedFilterState support in the adapter.
|
|
5261
|
-
*/
|
|
5262
|
-
applyListFilter(ctx, options) {
|
|
5263
|
-
const visibilityRules = [
|
|
5264
|
-
{ attribute: "visibility", operator: "is", value: "shared" },
|
|
5265
|
-
{ attribute: "createdBy", operator: "is", value: ctx.userId }
|
|
5266
|
-
];
|
|
5267
|
-
if (!_optionalChain([options, 'optionalAccess', _113 => _113.filters]) || options.filters.rules.length === 0) {
|
|
5268
|
-
return {
|
|
5269
|
-
...options,
|
|
5270
|
-
filters: { combinator: "or", rules: visibilityRules }
|
|
5271
|
-
};
|
|
5272
|
-
}
|
|
5273
|
-
const linkedToFilter = options.filters.rules.find((r) => r.attribute === "linkedTo");
|
|
5274
|
-
if (linkedToFilter) {
|
|
5275
|
-
return {
|
|
5276
|
-
...options,
|
|
5277
|
-
filters: {
|
|
5278
|
-
combinator: "and",
|
|
5279
|
-
rules: [linkedToFilter]
|
|
5280
|
-
}
|
|
5281
|
-
};
|
|
5282
|
-
}
|
|
5283
|
-
return {
|
|
5284
|
-
...options,
|
|
5285
|
-
filters: { combinator: "or", rules: visibilityRules }
|
|
5286
|
-
};
|
|
5287
|
-
},
|
|
5288
|
-
/**
|
|
5289
|
-
* Check if user can access a specific note.
|
|
5290
|
-
*
|
|
5291
|
-
* Rules:
|
|
5292
|
-
* - Shared notes: accessible by anyone in the tenant
|
|
5293
|
-
* - Private notes: only accessible by the author (createdBy)
|
|
5294
|
-
*/
|
|
5295
|
-
canAccessRecord(ctx, record) {
|
|
5296
|
-
const visibility = record.values.visibility;
|
|
5297
|
-
if (visibility === "shared") {
|
|
5298
|
-
return true;
|
|
5299
|
-
}
|
|
5300
|
-
if (visibility === "private") {
|
|
5301
|
-
return record.createdBy === ctx.userId;
|
|
5302
|
-
}
|
|
5303
|
-
return false;
|
|
5304
|
-
},
|
|
5305
|
-
/**
|
|
5306
|
-
* Check if user can modify a note.
|
|
5307
|
-
*
|
|
5308
|
-
* Rules:
|
|
5309
|
-
* - Private notes: only the author can modify
|
|
5310
|
-
* - Shared notes: anyone can modify
|
|
5311
|
-
*/
|
|
5312
|
-
canModifyRecord(ctx, record) {
|
|
5313
|
-
const visibility = record.values.visibility;
|
|
5314
|
-
if (visibility === "private") {
|
|
5315
|
-
return record.createdBy === ctx.userId;
|
|
5316
|
-
}
|
|
5317
|
-
return true;
|
|
5318
|
-
},
|
|
5319
|
-
/**
|
|
5320
|
-
* Check if user can delete a note.
|
|
5321
|
-
*
|
|
5322
|
-
* Rules:
|
|
5323
|
-
* - Only the author (createdBy) can delete a note, regardless of visibility
|
|
5324
|
-
*/
|
|
5325
|
-
canDeleteRecord(ctx, record) {
|
|
5326
|
-
return record.createdBy === ctx.userId;
|
|
5327
|
-
}
|
|
5328
|
-
};
|
|
5329
|
-
|
|
5330
|
-
// src/runtime/policies/index.ts
|
|
5331
|
-
defaultPolicyRegistry.register(notesPolicy);
|
|
5332
|
-
|
|
5333
5277
|
// src/runtime/services/base.service.ts
|
|
5334
5278
|
var BaseService = class {
|
|
5335
5279
|
constructor(adapter) {
|
|
@@ -5410,7 +5354,7 @@ var BaseService = class {
|
|
|
5410
5354
|
* @param key - Cache key to invalidate
|
|
5411
5355
|
*/
|
|
5412
5356
|
async invalidateCache(key) {
|
|
5413
|
-
await _optionalChain([this, 'access',
|
|
5357
|
+
await _optionalChain([this, 'access', _113 => _113.cache, 'optionalAccess', _114 => _114.delete, 'call', _115 => _115(key)]);
|
|
5414
5358
|
}
|
|
5415
5359
|
/**
|
|
5416
5360
|
* Invalidate all cache keys matching a pattern.
|
|
@@ -5418,7 +5362,7 @@ var BaseService = class {
|
|
|
5418
5362
|
* @param pattern - Glob-style pattern (e.g., "schema:tenant-123:*")
|
|
5419
5363
|
*/
|
|
5420
5364
|
async invalidateCachePattern(pattern) {
|
|
5421
|
-
await _optionalChain([this, 'access',
|
|
5365
|
+
await _optionalChain([this, 'access', _116 => _116.cache, 'optionalAccess', _117 => _117.deletePattern, 'call', _118 => _118(pattern)]);
|
|
5422
5366
|
}
|
|
5423
5367
|
/**
|
|
5424
5368
|
* Invalidate all cached lists for a resource.
|
|
@@ -5543,6 +5487,23 @@ var RELATION_TARGET_ANY = "*";
|
|
|
5543
5487
|
function isUniversalRelation(attr) {
|
|
5544
5488
|
return attr.targets.length === 1 && attr.targets[0].object === RELATION_TARGET_ANY;
|
|
5545
5489
|
}
|
|
5490
|
+
function isBilateralRelation(attr) {
|
|
5491
|
+
return attr.bilateral !== void 0;
|
|
5492
|
+
}
|
|
5493
|
+
function inferInverseCardinality(cardinality) {
|
|
5494
|
+
return cardinality === "one" ? "many" : "many";
|
|
5495
|
+
}
|
|
5496
|
+
|
|
5497
|
+
// src/types/relation-properties.ts
|
|
5498
|
+
var FORBIDDEN_PROPERTY_TYPES = [
|
|
5499
|
+
"formula",
|
|
5500
|
+
"rollup",
|
|
5501
|
+
"relation",
|
|
5502
|
+
"file",
|
|
5503
|
+
"user",
|
|
5504
|
+
"document",
|
|
5505
|
+
"richtext"
|
|
5506
|
+
];
|
|
5546
5507
|
|
|
5547
5508
|
// src/builders/attribute-validators.ts
|
|
5548
5509
|
|
|
@@ -5616,17 +5577,17 @@ function validateOptions(options, attributeName) {
|
|
|
5616
5577
|
const ids = /* @__PURE__ */ new Set();
|
|
5617
5578
|
const values = /* @__PURE__ */ new Set();
|
|
5618
5579
|
for (const option of options) {
|
|
5619
|
-
if (!_optionalChain([option, 'access',
|
|
5580
|
+
if (!_optionalChain([option, 'access', _119 => _119.id, 'optionalAccess', _120 => _120.trim, 'call', _121 => _121()])) {
|
|
5620
5581
|
throw new Error(
|
|
5621
5582
|
`[AttributeBuilder] Option in "${attributeName}" has an empty or missing id.`
|
|
5622
5583
|
);
|
|
5623
5584
|
}
|
|
5624
|
-
if (!_optionalChain([option, 'access',
|
|
5585
|
+
if (!_optionalChain([option, 'access', _122 => _122.value, 'optionalAccess', _123 => _123.trim, 'call', _124 => _124()])) {
|
|
5625
5586
|
throw new Error(
|
|
5626
5587
|
`[AttributeBuilder] Option "${option.id}" in "${attributeName}" has an empty or missing value.`
|
|
5627
5588
|
);
|
|
5628
5589
|
}
|
|
5629
|
-
if (!_optionalChain([option, 'access',
|
|
5590
|
+
if (!_optionalChain([option, 'access', _125 => _125.label, 'optionalAccess', _126 => _126.trim, 'call', _127 => _127()])) {
|
|
5630
5591
|
throw new Error(
|
|
5631
5592
|
`[AttributeBuilder] Option "${option.id}" in "${attributeName}" has an empty or missing label.`
|
|
5632
5593
|
);
|
|
@@ -5649,292 +5610,6 @@ function validateOptions(options, attributeName) {
|
|
|
5649
5610
|
}
|
|
5650
5611
|
}
|
|
5651
5612
|
|
|
5652
|
-
// src/types/relation-properties.ts
|
|
5653
|
-
var FORBIDDEN_PROPERTY_TYPES = [
|
|
5654
|
-
"formula",
|
|
5655
|
-
"rollup",
|
|
5656
|
-
"relation",
|
|
5657
|
-
"file",
|
|
5658
|
-
"user",
|
|
5659
|
-
"document",
|
|
5660
|
-
"richtext"
|
|
5661
|
-
];
|
|
5662
|
-
|
|
5663
|
-
// src/builders/property-schema-builder.ts
|
|
5664
|
-
var PropertySchemaBuilder = class {
|
|
5665
|
-
constructor() {
|
|
5666
|
-
this.definitions = [];
|
|
5667
|
-
}
|
|
5668
|
-
/**
|
|
5669
|
-
* Add a property to the schema
|
|
5670
|
-
* The type of property is automatically detected based on the builder methods used
|
|
5671
|
-
*/
|
|
5672
|
-
add(name, configure) {
|
|
5673
|
-
const builder = new PropertyTypeBuilder(name);
|
|
5674
|
-
const configured = configure(builder);
|
|
5675
|
-
const definition = configured.build();
|
|
5676
|
-
this.definitions.push(definition);
|
|
5677
|
-
return this;
|
|
5678
|
-
}
|
|
5679
|
-
/**
|
|
5680
|
-
* Build the final PropertySchema
|
|
5681
|
-
*/
|
|
5682
|
-
build() {
|
|
5683
|
-
return {
|
|
5684
|
-
definitions: this.definitions
|
|
5685
|
-
};
|
|
5686
|
-
}
|
|
5687
|
-
};
|
|
5688
|
-
var PropertyTypeBuilder = class {
|
|
5689
|
-
constructor(name) {
|
|
5690
|
-
this.name = name;
|
|
5691
|
-
}
|
|
5692
|
-
// Explicit type constructors
|
|
5693
|
-
text() {
|
|
5694
|
-
return new TextPropertyBuilder(this.name);
|
|
5695
|
-
}
|
|
5696
|
-
textarea() {
|
|
5697
|
-
return new TextareaPropertyBuilder(this.name);
|
|
5698
|
-
}
|
|
5699
|
-
number() {
|
|
5700
|
-
return new NumberPropertyBuilder(this.name);
|
|
5701
|
-
}
|
|
5702
|
-
checkbox() {
|
|
5703
|
-
return new CheckboxPropertyBuilder(this.name);
|
|
5704
|
-
}
|
|
5705
|
-
date() {
|
|
5706
|
-
return new DatePropertyBuilder(this.name);
|
|
5707
|
-
}
|
|
5708
|
-
phone() {
|
|
5709
|
-
return new PhonePropertyBuilder(this.name);
|
|
5710
|
-
}
|
|
5711
|
-
currency() {
|
|
5712
|
-
return new CurrencyPropertyBuilder(this.name);
|
|
5713
|
-
}
|
|
5714
|
-
status() {
|
|
5715
|
-
return new StatusPropertyBuilder(this.name);
|
|
5716
|
-
}
|
|
5717
|
-
select() {
|
|
5718
|
-
return new SelectPropertyBuilder(this.name);
|
|
5719
|
-
}
|
|
5720
|
-
multiselect() {
|
|
5721
|
-
return new MultiselectPropertyBuilder(this.name);
|
|
5722
|
-
}
|
|
5723
|
-
rating() {
|
|
5724
|
-
return new RatingPropertyBuilder(this.name);
|
|
5725
|
-
}
|
|
5726
|
-
location() {
|
|
5727
|
-
return new LocationPropertyBuilder(this.name);
|
|
5728
|
-
}
|
|
5729
|
-
};
|
|
5730
|
-
var BasePropertyBuilder = class {
|
|
5731
|
-
constructor(name) {
|
|
5732
|
-
this.definition = { name };
|
|
5733
|
-
}
|
|
5734
|
-
/**
|
|
5735
|
-
* Set the label
|
|
5736
|
-
*/
|
|
5737
|
-
label(label) {
|
|
5738
|
-
this.definition.label = label;
|
|
5739
|
-
return this;
|
|
5740
|
-
}
|
|
5741
|
-
/**
|
|
5742
|
-
* Mark as required
|
|
5743
|
-
*/
|
|
5744
|
-
required() {
|
|
5745
|
-
this.definition.required = true;
|
|
5746
|
-
return this;
|
|
5747
|
-
}
|
|
5748
|
-
/**
|
|
5749
|
-
* Set description
|
|
5750
|
-
*/
|
|
5751
|
-
description(description) {
|
|
5752
|
-
this.definition.description = description;
|
|
5753
|
-
return this;
|
|
5754
|
-
}
|
|
5755
|
-
/**
|
|
5756
|
-
* Build the final definition
|
|
5757
|
-
*/
|
|
5758
|
-
build() {
|
|
5759
|
-
return this.definition;
|
|
5760
|
-
}
|
|
5761
|
-
};
|
|
5762
|
-
var TextPropertyBuilder = class extends BasePropertyBuilder {
|
|
5763
|
-
constructor(name) {
|
|
5764
|
-
super(name);
|
|
5765
|
-
this.definition.type = "text";
|
|
5766
|
-
}
|
|
5767
|
-
minLength(value) {
|
|
5768
|
-
this.definition.minLength = value;
|
|
5769
|
-
return this;
|
|
5770
|
-
}
|
|
5771
|
-
maxLength(value) {
|
|
5772
|
-
this.definition.maxLength = value;
|
|
5773
|
-
return this;
|
|
5774
|
-
}
|
|
5775
|
-
pattern(pattern) {
|
|
5776
|
-
this.definition.pattern = pattern;
|
|
5777
|
-
return this;
|
|
5778
|
-
}
|
|
5779
|
-
placeholder(value) {
|
|
5780
|
-
this.definition.placeholder = value;
|
|
5781
|
-
return this;
|
|
5782
|
-
}
|
|
5783
|
-
};
|
|
5784
|
-
var TextareaPropertyBuilder = class extends BasePropertyBuilder {
|
|
5785
|
-
constructor(name) {
|
|
5786
|
-
super(name);
|
|
5787
|
-
this.definition.type = "textarea";
|
|
5788
|
-
}
|
|
5789
|
-
minLength(value) {
|
|
5790
|
-
this.definition.minLength = value;
|
|
5791
|
-
return this;
|
|
5792
|
-
}
|
|
5793
|
-
maxLength(value) {
|
|
5794
|
-
this.definition.maxLength = value;
|
|
5795
|
-
return this;
|
|
5796
|
-
}
|
|
5797
|
-
placeholder(value) {
|
|
5798
|
-
this.definition.placeholder = value;
|
|
5799
|
-
return this;
|
|
5800
|
-
}
|
|
5801
|
-
};
|
|
5802
|
-
var NumberPropertyBuilder = class extends BasePropertyBuilder {
|
|
5803
|
-
constructor(name) {
|
|
5804
|
-
super(name);
|
|
5805
|
-
this.definition.type = "number";
|
|
5806
|
-
}
|
|
5807
|
-
min(value) {
|
|
5808
|
-
this.definition.min = value;
|
|
5809
|
-
return this;
|
|
5810
|
-
}
|
|
5811
|
-
max(value) {
|
|
5812
|
-
this.definition.max = value;
|
|
5813
|
-
return this;
|
|
5814
|
-
}
|
|
5815
|
-
decimal(places) {
|
|
5816
|
-
this.definition.decimal = places;
|
|
5817
|
-
return this;
|
|
5818
|
-
}
|
|
5819
|
-
integer() {
|
|
5820
|
-
this.definition.integer = true;
|
|
5821
|
-
return this;
|
|
5822
|
-
}
|
|
5823
|
-
placeholder(value) {
|
|
5824
|
-
this.definition.placeholder = value;
|
|
5825
|
-
return this;
|
|
5826
|
-
}
|
|
5827
|
-
};
|
|
5828
|
-
var CheckboxPropertyBuilder = class extends BasePropertyBuilder {
|
|
5829
|
-
constructor(name) {
|
|
5830
|
-
super(name);
|
|
5831
|
-
this.definition.type = "checkbox";
|
|
5832
|
-
}
|
|
5833
|
-
};
|
|
5834
|
-
var DatePropertyBuilder = class extends BasePropertyBuilder {
|
|
5835
|
-
constructor(name) {
|
|
5836
|
-
super(name);
|
|
5837
|
-
this.definition.type = "date";
|
|
5838
|
-
}
|
|
5839
|
-
includeTime() {
|
|
5840
|
-
this.definition.includeTime = true;
|
|
5841
|
-
return this;
|
|
5842
|
-
}
|
|
5843
|
-
min(date2) {
|
|
5844
|
-
this.definition.min = date2;
|
|
5845
|
-
return this;
|
|
5846
|
-
}
|
|
5847
|
-
max(date2) {
|
|
5848
|
-
this.definition.max = date2;
|
|
5849
|
-
return this;
|
|
5850
|
-
}
|
|
5851
|
-
};
|
|
5852
|
-
var PhonePropertyBuilder = class extends BasePropertyBuilder {
|
|
5853
|
-
constructor(name) {
|
|
5854
|
-
super(name);
|
|
5855
|
-
this.definition.type = "phone";
|
|
5856
|
-
}
|
|
5857
|
-
};
|
|
5858
|
-
var CurrencyPropertyBuilder = class extends BasePropertyBuilder {
|
|
5859
|
-
constructor(name) {
|
|
5860
|
-
super(name);
|
|
5861
|
-
this.definition.type = "currency";
|
|
5862
|
-
}
|
|
5863
|
-
currency(code) {
|
|
5864
|
-
this.definition.currency = code;
|
|
5865
|
-
return this;
|
|
5866
|
-
}
|
|
5867
|
-
min(value) {
|
|
5868
|
-
this.definition.min = value;
|
|
5869
|
-
return this;
|
|
5870
|
-
}
|
|
5871
|
-
max(value) {
|
|
5872
|
-
this.definition.max = value;
|
|
5873
|
-
return this;
|
|
5874
|
-
}
|
|
5875
|
-
};
|
|
5876
|
-
var StatusPropertyBuilder = class extends BasePropertyBuilder {
|
|
5877
|
-
constructor(name) {
|
|
5878
|
-
super(name);
|
|
5879
|
-
this.definition.type = "status";
|
|
5880
|
-
}
|
|
5881
|
-
options(options) {
|
|
5882
|
-
this.definition.options = options;
|
|
5883
|
-
return this;
|
|
5884
|
-
}
|
|
5885
|
-
};
|
|
5886
|
-
var SelectPropertyBuilder = class extends BasePropertyBuilder {
|
|
5887
|
-
constructor(name) {
|
|
5888
|
-
super(name);
|
|
5889
|
-
this.definition.type = "select";
|
|
5890
|
-
}
|
|
5891
|
-
options(options) {
|
|
5892
|
-
this.definition.options = options;
|
|
5893
|
-
return this;
|
|
5894
|
-
}
|
|
5895
|
-
};
|
|
5896
|
-
var MultiselectPropertyBuilder = class extends BasePropertyBuilder {
|
|
5897
|
-
constructor(name) {
|
|
5898
|
-
super(name);
|
|
5899
|
-
this.definition.type = "multiselect";
|
|
5900
|
-
}
|
|
5901
|
-
options(options) {
|
|
5902
|
-
this.definition.options = options;
|
|
5903
|
-
return this;
|
|
5904
|
-
}
|
|
5905
|
-
maxSelections(value) {
|
|
5906
|
-
this.definition.maxSelections = value;
|
|
5907
|
-
return this;
|
|
5908
|
-
}
|
|
5909
|
-
};
|
|
5910
|
-
var RatingPropertyBuilder = class extends BasePropertyBuilder {
|
|
5911
|
-
constructor(name) {
|
|
5912
|
-
super(name);
|
|
5913
|
-
this.definition.type = "rating";
|
|
5914
|
-
}
|
|
5915
|
-
max(value) {
|
|
5916
|
-
this.definition.max = value;
|
|
5917
|
-
return this;
|
|
5918
|
-
}
|
|
5919
|
-
icon(icon) {
|
|
5920
|
-
this.definition.icon = icon;
|
|
5921
|
-
return this;
|
|
5922
|
-
}
|
|
5923
|
-
};
|
|
5924
|
-
var LocationPropertyBuilder = class extends BasePropertyBuilder {
|
|
5925
|
-
constructor(name) {
|
|
5926
|
-
super(name);
|
|
5927
|
-
this.definition.type = "location";
|
|
5928
|
-
}
|
|
5929
|
-
};
|
|
5930
|
-
function validatePropertyType(type) {
|
|
5931
|
-
if (FORBIDDEN_PROPERTY_TYPES.includes(type)) {
|
|
5932
|
-
throw new Error(
|
|
5933
|
-
`Property type "${type}" is not supported in .qualifyWith(). Only simple types (text, number, date, select, etc.) are allowed. Complex types (formula, rollup, relation, file, user, document) would require duplicating backend behavior.`
|
|
5934
|
-
);
|
|
5935
|
-
}
|
|
5936
|
-
}
|
|
5937
|
-
|
|
5938
5613
|
// src/builders/attribute-builders.ts
|
|
5939
5614
|
var BaseAttributeBuilder = class {
|
|
5940
5615
|
constructor(type, name, label) {
|
|
@@ -6010,8 +5685,8 @@ var BaseAttributeBuilder = class {
|
|
|
6010
5685
|
featureGate(flagName, options) {
|
|
6011
5686
|
this.attr.featureGate = {
|
|
6012
5687
|
flag: flagName,
|
|
6013
|
-
expectedValue: _optionalChain([options, 'optionalAccess',
|
|
6014
|
-
fallback: _optionalChain([options, 'optionalAccess',
|
|
5688
|
+
expectedValue: _optionalChain([options, 'optionalAccess', _128 => _128.expectedValue]),
|
|
5689
|
+
fallback: _optionalChain([options, 'optionalAccess', _129 => _129.fallback])
|
|
6015
5690
|
};
|
|
6016
5691
|
return this;
|
|
6017
5692
|
}
|
|
@@ -6443,12 +6118,7 @@ var UserAttributeBuilder = class extends BaseAttributeBuilder {
|
|
|
6443
6118
|
function user(config) {
|
|
6444
6119
|
return new UserAttributeBuilder(config.name, config.label);
|
|
6445
6120
|
}
|
|
6446
|
-
var
|
|
6447
|
-
constructor(name, label) {
|
|
6448
|
-
super("relation", name, label);
|
|
6449
|
-
this.attr.cardinality = "one";
|
|
6450
|
-
this.attr.targets = [];
|
|
6451
|
-
}
|
|
6121
|
+
var BaseRelationAttributeBuilder = class extends BaseAttributeBuilder {
|
|
6452
6122
|
/**
|
|
6453
6123
|
* Add a target object that can be linked
|
|
6454
6124
|
* @param objectName - Name of the object (e.g., "companies")
|
|
@@ -6459,111 +6129,110 @@ var SingleRelationAttributeBuilder = class extends BaseAttributeBuilder {
|
|
|
6459
6129
|
object: objectName,
|
|
6460
6130
|
...options
|
|
6461
6131
|
};
|
|
6462
|
-
_optionalChain([this, 'access',
|
|
6132
|
+
_optionalChain([this, 'access', _130 => _130.attr, 'access', _131 => _131.targets, 'optionalAccess', _132 => _132.push, 'call', _133 => _133(target)]);
|
|
6463
6133
|
return this;
|
|
6464
6134
|
}
|
|
6465
6135
|
/**
|
|
6466
6136
|
* Allow linking to any object in the tenant (universal polymorphic)
|
|
6467
6137
|
* Creates a relation with `targets: [{ object: "*" }]`
|
|
6468
|
-
*
|
|
6469
|
-
* @example
|
|
6470
|
-
* ```typescript
|
|
6471
|
-
* relation({ name: "linkedTo", label: "Linked To" })
|
|
6472
|
-
* .toAny()
|
|
6473
|
-
* .hidden()
|
|
6474
|
-
* ```
|
|
6475
6138
|
*/
|
|
6476
6139
|
toAny() {
|
|
6477
6140
|
this.attr.targets = [{ object: RELATION_TARGET_ANY }];
|
|
6478
6141
|
return this;
|
|
6479
6142
|
}
|
|
6480
6143
|
/**
|
|
6481
|
-
*
|
|
6482
|
-
|
|
6483
|
-
many() {
|
|
6484
|
-
const multiBuilder = new MultiRelationAttributeBuilder(
|
|
6485
|
-
this.attr.name,
|
|
6486
|
-
_nullishCoalesce(this.attr.label, () => ( "")),
|
|
6487
|
-
{
|
|
6488
|
-
targets: this.attr.targets,
|
|
6489
|
-
isRequired: this.attr.required
|
|
6490
|
-
}
|
|
6491
|
-
);
|
|
6492
|
-
return multiBuilder;
|
|
6493
|
-
}
|
|
6494
|
-
/**
|
|
6495
|
-
* Add properties to qualify the relation
|
|
6496
|
-
* Must be called AFTER .to() to ensure targets are defined
|
|
6144
|
+
* Add properties to qualify the relation using existing attribute builders.
|
|
6145
|
+
* Must be called AFTER .to() to ensure targets are defined.
|
|
6497
6146
|
*
|
|
6498
6147
|
* @example
|
|
6499
6148
|
* ```typescript
|
|
6500
|
-
* relation({ name: "
|
|
6501
|
-
* .to("companies")
|
|
6502
|
-
* .qualifyWith(
|
|
6503
|
-
*
|
|
6504
|
-
*
|
|
6149
|
+
* relation({ name: "companies", label: "Companies" })
|
|
6150
|
+
* .to("companies").many()
|
|
6151
|
+
* .qualifyWith(
|
|
6152
|
+
* select({ name: "role", label: "Role" }).options([...]).required(),
|
|
6153
|
+
* number({ name: "shares", label: "Shares" }).min(0),
|
|
6505
6154
|
* )
|
|
6506
6155
|
* ```
|
|
6507
6156
|
*/
|
|
6508
|
-
qualifyWith(
|
|
6157
|
+
qualifyWith(...builders) {
|
|
6509
6158
|
const targets = this.attr.targets;
|
|
6510
6159
|
if (!targets || targets.length === 0) {
|
|
6511
6160
|
throw new Error(
|
|
6512
|
-
'.qualifyWith() must be called AFTER .to(). Example: relation({ name: "
|
|
6161
|
+
'.qualifyWith() must be called AFTER .to(). Example: relation({ name: "companies" }).to("companies").qualifyWith(...)'
|
|
6513
6162
|
);
|
|
6514
6163
|
}
|
|
6515
|
-
const
|
|
6516
|
-
|
|
6517
|
-
|
|
6518
|
-
|
|
6519
|
-
|
|
6520
|
-
|
|
6521
|
-
|
|
6164
|
+
const definitions = builders.map((builder) => {
|
|
6165
|
+
const attr = builder.build();
|
|
6166
|
+
if (FORBIDDEN_PROPERTY_TYPES.includes(attr.type)) {
|
|
6167
|
+
throw new Error(`Property type "${attr.type}" is not supported in .qualifyWith()`);
|
|
6168
|
+
}
|
|
6169
|
+
return attr;
|
|
6170
|
+
});
|
|
6171
|
+
this.attr.properties = { definitions };
|
|
6522
6172
|
return this;
|
|
6523
6173
|
}
|
|
6524
|
-
|
|
6525
|
-
|
|
6526
|
-
|
|
6174
|
+
/**
|
|
6175
|
+
* Enable bilateral synchronization for this relation.
|
|
6176
|
+
* Must be called AFTER .to() to ensure targets are defined.
|
|
6177
|
+
*/
|
|
6178
|
+
bilateral(config) {
|
|
6179
|
+
const targets = this.attr.targets;
|
|
6180
|
+
if (!targets || targets.length === 0) {
|
|
6181
|
+
throw new Error(
|
|
6182
|
+
'.bilateral() must be called AFTER .to(). Example: relation({ name: "company" }).to("companies").bilateral({ ... })'
|
|
6183
|
+
);
|
|
6184
|
+
}
|
|
6185
|
+
if (targets.length > 1) {
|
|
6186
|
+
throw new Error(
|
|
6187
|
+
"Bilateral relations are not supported for polymorphic relations (multiple .to() targets)."
|
|
6188
|
+
);
|
|
6189
|
+
}
|
|
6190
|
+
if (isUniversalRelation(this.attr)) {
|
|
6191
|
+
throw new Error("Bilateral relations are not supported for universal relations (.toAny()).");
|
|
6192
|
+
}
|
|
6193
|
+
this.attr.bilateral = config;
|
|
6194
|
+
return this;
|
|
6527
6195
|
}
|
|
6528
6196
|
};
|
|
6529
|
-
var
|
|
6530
|
-
constructor(name, label
|
|
6197
|
+
var SingleRelationAttributeBuilder = class extends BaseRelationAttributeBuilder {
|
|
6198
|
+
constructor(name, label) {
|
|
6531
6199
|
super("relation", name, label);
|
|
6532
|
-
this.attr.cardinality = "
|
|
6533
|
-
this.attr.targets =
|
|
6534
|
-
this.attr.defaultValue = [];
|
|
6535
|
-
if (_optionalChain([initOptions, 'optionalAccess', _136 => _136.isRequired])) {
|
|
6536
|
-
this.setRequired(true);
|
|
6537
|
-
}
|
|
6200
|
+
this.attr.cardinality = "one";
|
|
6201
|
+
this.attr.targets = [];
|
|
6538
6202
|
}
|
|
6539
6203
|
/**
|
|
6540
|
-
*
|
|
6541
|
-
* @param objectName - Name of the object (e.g., "companies")
|
|
6542
|
-
* @param options - Display template and filter options
|
|
6204
|
+
* Convert to a multi-relation (cardinality: "many")
|
|
6543
6205
|
*/
|
|
6544
|
-
|
|
6545
|
-
const
|
|
6546
|
-
|
|
6547
|
-
|
|
6548
|
-
|
|
6549
|
-
|
|
6206
|
+
many() {
|
|
6207
|
+
const multiBuilder = new MultiRelationAttributeBuilder(
|
|
6208
|
+
this.attr.name,
|
|
6209
|
+
_nullishCoalesce(this.attr.label, () => ( "")),
|
|
6210
|
+
{
|
|
6211
|
+
targets: this.attr.targets,
|
|
6212
|
+
isRequired: this.attr.required
|
|
6213
|
+
}
|
|
6214
|
+
);
|
|
6215
|
+
return multiBuilder;
|
|
6216
|
+
}
|
|
6217
|
+
required() {
|
|
6218
|
+
this.setRequired(true);
|
|
6550
6219
|
return this;
|
|
6551
6220
|
}
|
|
6552
|
-
|
|
6553
|
-
|
|
6554
|
-
* Creates a relation with `targets: [{ object: "*" }]`
|
|
6555
|
-
*
|
|
6556
|
-
* @example
|
|
6557
|
-
* ```typescript
|
|
6558
|
-
* relation({ name: "linkedItems", label: "Linked Items" })
|
|
6559
|
-
* .toAny()
|
|
6560
|
-
* .many()
|
|
6561
|
-
* ```
|
|
6562
|
-
*/
|
|
6563
|
-
toAny() {
|
|
6564
|
-
this.attr.targets = [{ object: RELATION_TARGET_ANY }];
|
|
6221
|
+
optional() {
|
|
6222
|
+
this.setRequired(false);
|
|
6565
6223
|
return this;
|
|
6566
6224
|
}
|
|
6225
|
+
};
|
|
6226
|
+
var MultiRelationAttributeBuilder = class extends BaseRelationAttributeBuilder {
|
|
6227
|
+
constructor(name, label, initOptions) {
|
|
6228
|
+
super("relation", name, label);
|
|
6229
|
+
this.attr.cardinality = "many";
|
|
6230
|
+
this.attr.targets = _nullishCoalesce(_optionalChain([initOptions, 'optionalAccess', _134 => _134.targets]), () => ( []));
|
|
6231
|
+
this.attr.defaultValue = [];
|
|
6232
|
+
if (_optionalChain([initOptions, 'optionalAccess', _135 => _135.isRequired])) {
|
|
6233
|
+
this.setRequired(true);
|
|
6234
|
+
}
|
|
6235
|
+
}
|
|
6567
6236
|
/**
|
|
6568
6237
|
* Set minimum number of relations required
|
|
6569
6238
|
*/
|
|
@@ -6578,33 +6247,6 @@ var MultiRelationAttributeBuilder = class extends BaseAttributeBuilder {
|
|
|
6578
6247
|
this.attr.maxItems = count;
|
|
6579
6248
|
return this;
|
|
6580
6249
|
}
|
|
6581
|
-
/**
|
|
6582
|
-
* Add properties to qualify the relation
|
|
6583
|
-
* Must be called AFTER .to() or .many() to ensure targets are defined
|
|
6584
|
-
*
|
|
6585
|
-
* @example
|
|
6586
|
-
* ```typescript
|
|
6587
|
-
* relation({ name: "companies", label: "Companies" })
|
|
6588
|
-
* .to("companies")
|
|
6589
|
-
* .many()
|
|
6590
|
-
* .qualifyWith(props => props
|
|
6591
|
-
* .add("role", select => select.options([...]).required())
|
|
6592
|
-
* .add("shares", number => number.min(0))
|
|
6593
|
-
* )
|
|
6594
|
-
* ```
|
|
6595
|
-
*/
|
|
6596
|
-
qualifyWith(configure) {
|
|
6597
|
-
const targets = this.attr.targets;
|
|
6598
|
-
if (!targets || targets.length === 0) {
|
|
6599
|
-
throw new Error(
|
|
6600
|
-
'.qualifyWith() must be called AFTER .to() or .many(). Example: relation({ name: "companies" }).to("companies").many().qualifyWith(...)'
|
|
6601
|
-
);
|
|
6602
|
-
}
|
|
6603
|
-
const builder = new PropertySchemaBuilder();
|
|
6604
|
-
const schema = configure(builder).build();
|
|
6605
|
-
this.attr.properties = schema;
|
|
6606
|
-
return this;
|
|
6607
|
-
}
|
|
6608
6250
|
required() {
|
|
6609
6251
|
this.setRequired(true);
|
|
6610
6252
|
return this;
|
|
@@ -6672,8 +6314,9 @@ var FormulaAttributeBuilder = class extends BaseAttributeBuilder {
|
|
|
6672
6314
|
// Override to prevent making formulas required
|
|
6673
6315
|
// biome-ignore lint/suspicious/noExplicitAny: intentional override
|
|
6674
6316
|
required() {
|
|
6675
|
-
|
|
6676
|
-
|
|
6317
|
+
throw new Error(
|
|
6318
|
+
"Formula attributes cannot be required: they are computed read-only values. Remove .required() from this attribute definition."
|
|
6319
|
+
);
|
|
6677
6320
|
}
|
|
6678
6321
|
// biome-ignore lint/suspicious/noExplicitAny: intentional override
|
|
6679
6322
|
optional() {
|
|
@@ -6747,8 +6390,9 @@ var RollupAttributeBuilder = class extends BaseAttributeBuilder {
|
|
|
6747
6390
|
// Override to prevent making rollups required
|
|
6748
6391
|
// biome-ignore lint/suspicious/noExplicitAny: intentional override
|
|
6749
6392
|
required() {
|
|
6750
|
-
|
|
6751
|
-
|
|
6393
|
+
throw new Error(
|
|
6394
|
+
"Rollup attributes cannot be required: they are computed read-only values. Remove .required() from this attribute definition."
|
|
6395
|
+
);
|
|
6752
6396
|
}
|
|
6753
6397
|
// biome-ignore lint/suspicious/noExplicitAny: intentional override
|
|
6754
6398
|
optional() {
|
|
@@ -7026,7 +6670,7 @@ var GroupBuilder = class {
|
|
|
7026
6670
|
*/
|
|
7027
6671
|
fields(...names) {
|
|
7028
6672
|
for (const name of names) {
|
|
7029
|
-
_optionalChain([this, 'access',
|
|
6673
|
+
_optionalChain([this, 'access', _136 => _136.data, 'access', _137 => _137.fields, 'optionalAccess', _138 => _138.push, 'call', _139 => _139({ attribute: name })]);
|
|
7030
6674
|
}
|
|
7031
6675
|
return this;
|
|
7032
6676
|
}
|
|
@@ -7035,7 +6679,7 @@ var GroupBuilder = class {
|
|
|
7035
6679
|
* @example .field("name", { span: 8, readOnly: true })
|
|
7036
6680
|
*/
|
|
7037
6681
|
field(attribute, options) {
|
|
7038
|
-
_optionalChain([this, 'access',
|
|
6682
|
+
_optionalChain([this, 'access', _140 => _140.data, 'access', _141 => _141.fields, 'optionalAccess', _142 => _142.push, 'call', _143 => _143({ attribute, ...options })]);
|
|
7039
6683
|
return this;
|
|
7040
6684
|
}
|
|
7041
6685
|
/**
|
|
@@ -7044,7 +6688,7 @@ var GroupBuilder = class {
|
|
|
7044
6688
|
* @example .attributeGroup({ id: "address", label: "Address", attributes: ["street", "city", "postal_code"], displayTemplate: "{street}, {city}" })
|
|
7045
6689
|
*/
|
|
7046
6690
|
attributeGroup(config, options) {
|
|
7047
|
-
_optionalChain([this, 'access',
|
|
6691
|
+
_optionalChain([this, 'access', _144 => _144.data, 'access', _145 => _145.fields, 'optionalAccess', _146 => _146.push, 'call', _147 => _147({ attributeGroup: config, ...options })]);
|
|
7048
6692
|
return this;
|
|
7049
6693
|
}
|
|
7050
6694
|
/**
|
|
@@ -7063,7 +6707,87 @@ var GroupBuilder = class {
|
|
|
7063
6707
|
return this.data;
|
|
7064
6708
|
}
|
|
7065
6709
|
};
|
|
7066
|
-
var
|
|
6710
|
+
var RelationGroupBuilder = class {
|
|
6711
|
+
constructor(id, label, attribute) {
|
|
6712
|
+
this.data = { type: "relation" };
|
|
6713
|
+
this.data.id = id;
|
|
6714
|
+
this.data.label = label;
|
|
6715
|
+
this.data.attribute = attribute;
|
|
6716
|
+
}
|
|
6717
|
+
/**
|
|
6718
|
+
* Set group description
|
|
6719
|
+
*/
|
|
6720
|
+
description(value) {
|
|
6721
|
+
this.data.description = value;
|
|
6722
|
+
return this;
|
|
6723
|
+
}
|
|
6724
|
+
/**
|
|
6725
|
+
* Make group collapsible
|
|
6726
|
+
* @param collapsed - Initial collapsed state (default: false)
|
|
6727
|
+
*/
|
|
6728
|
+
collapsible(collapsed = false) {
|
|
6729
|
+
this.data.collapsible = true;
|
|
6730
|
+
this.data.collapsed = collapsed;
|
|
6731
|
+
return this;
|
|
6732
|
+
}
|
|
6733
|
+
/**
|
|
6734
|
+
* Set display order
|
|
6735
|
+
*/
|
|
6736
|
+
order(value) {
|
|
6737
|
+
this.data.order = value;
|
|
6738
|
+
return this;
|
|
6739
|
+
}
|
|
6740
|
+
/**
|
|
6741
|
+
* Set columns to display in the relations table
|
|
6742
|
+
* @example .columns("name", "email", "phone")
|
|
6743
|
+
*/
|
|
6744
|
+
columns(...names) {
|
|
6745
|
+
this.data.columns = names;
|
|
6746
|
+
return this;
|
|
6747
|
+
}
|
|
6748
|
+
/**
|
|
6749
|
+
* Set the group as read-only (no add/remove/edit)
|
|
6750
|
+
*/
|
|
6751
|
+
readOnly(value = true) {
|
|
6752
|
+
this.data.readOnly = value;
|
|
6753
|
+
return this;
|
|
6754
|
+
}
|
|
6755
|
+
/**
|
|
6756
|
+
* Allow creating new related records inline
|
|
6757
|
+
*/
|
|
6758
|
+
allowCreate(value = true) {
|
|
6759
|
+
this.data.allowCreate = value;
|
|
6760
|
+
return this;
|
|
6761
|
+
}
|
|
6762
|
+
/**
|
|
6763
|
+
* Enable two-level traversal (through mode).
|
|
6764
|
+
* Parent rows become grouping headers; sub-rows from `attribute` are the primary display.
|
|
6765
|
+
*
|
|
6766
|
+
* @param attribute - Relation attribute on the first-level target object
|
|
6767
|
+
* @example .through("companies") — display companies linked via each member
|
|
6768
|
+
*/
|
|
6769
|
+
through(attribute) {
|
|
6770
|
+
this.data.through = { attribute };
|
|
6771
|
+
return this;
|
|
6772
|
+
}
|
|
6773
|
+
/**
|
|
6774
|
+
* Build the relation group definition
|
|
6775
|
+
*/
|
|
6776
|
+
build() {
|
|
6777
|
+
if (!this.data.id) {
|
|
6778
|
+
throw new Error("[RelationGroupBuilder] id is required");
|
|
6779
|
+
}
|
|
6780
|
+
if (!this.data.label) {
|
|
6781
|
+
throw new Error("[RelationGroupBuilder] label is required");
|
|
6782
|
+
}
|
|
6783
|
+
if (!this.data.attribute) {
|
|
6784
|
+
throw new Error("[RelationGroupBuilder] attribute is required");
|
|
6785
|
+
}
|
|
6786
|
+
return this.data;
|
|
6787
|
+
}
|
|
6788
|
+
};
|
|
6789
|
+
var TableTabConfig = class {
|
|
6790
|
+
/** @internal */
|
|
7067
6791
|
constructor(view2, tabData) {
|
|
7068
6792
|
this.view = view2;
|
|
7069
6793
|
this.tabData = tabData;
|
|
@@ -7141,6 +6865,29 @@ var BaseTableTabConfig = class {
|
|
|
7141
6865
|
this.tabData.sorts.push({ attribute, direction });
|
|
7142
6866
|
return this;
|
|
7143
6867
|
}
|
|
6868
|
+
/**
|
|
6869
|
+
* Traverse a 2nd-level relation to display nested data.
|
|
6870
|
+
* When active, `tab.columns` stores the 2nd-level object's attribute names.
|
|
6871
|
+
*
|
|
6872
|
+
* @param attribute - Relation attribute on the first-level target object
|
|
6873
|
+
* @example .table("members").through("companies").columns(["name", "sector"])
|
|
6874
|
+
*/
|
|
6875
|
+
through(attribute) {
|
|
6876
|
+
this.tabData.through = { attribute };
|
|
6877
|
+
return this;
|
|
6878
|
+
}
|
|
6879
|
+
/**
|
|
6880
|
+
* Show _source and _target columns in flattened (through) view
|
|
6881
|
+
*/
|
|
6882
|
+
showSourceTarget(value = true) {
|
|
6883
|
+
if (!this.tabData.through) {
|
|
6884
|
+
throw new Error(
|
|
6885
|
+
`[TableTabConfig] showSourceTarget() requires through() to be called first for tab "${this.tabData.name}"`
|
|
6886
|
+
);
|
|
6887
|
+
}
|
|
6888
|
+
this.tabData.through.showSourceTarget = value;
|
|
6889
|
+
return this;
|
|
6890
|
+
}
|
|
7144
6891
|
/**
|
|
7145
6892
|
* Continue building with a new tab
|
|
7146
6893
|
*/
|
|
@@ -7169,31 +6916,6 @@ var BaseTableTabConfig = class {
|
|
|
7169
6916
|
this.view._addTab(this.tabData);
|
|
7170
6917
|
}
|
|
7171
6918
|
};
|
|
7172
|
-
var DirectTableTabConfig = class extends BaseTableTabConfig {
|
|
7173
|
-
/** @internal */
|
|
7174
|
-
constructor(view2, base, relationAttribute) {
|
|
7175
|
-
super(view2, {
|
|
7176
|
-
...base,
|
|
7177
|
-
type: "table",
|
|
7178
|
-
relationMode: "direct",
|
|
7179
|
-
relationAttribute,
|
|
7180
|
-
columns: []
|
|
7181
|
-
});
|
|
7182
|
-
}
|
|
7183
|
-
};
|
|
7184
|
-
var InverseTableTabConfig = class extends BaseTableTabConfig {
|
|
7185
|
-
/** @internal */
|
|
7186
|
-
constructor(view2, base, sourceObject, relationAttribute) {
|
|
7187
|
-
super(view2, {
|
|
7188
|
-
...base,
|
|
7189
|
-
type: "table",
|
|
7190
|
-
relationMode: "inverse",
|
|
7191
|
-
sourceObject,
|
|
7192
|
-
relationAttribute,
|
|
7193
|
-
columns: []
|
|
7194
|
-
});
|
|
7195
|
-
}
|
|
7196
|
-
};
|
|
7197
6919
|
var CustomTabConfig = class {
|
|
7198
6920
|
/** @internal */
|
|
7199
6921
|
constructor(view2, base, component) {
|
|
@@ -7229,24 +6951,17 @@ var CustomTabConfig = class {
|
|
|
7229
6951
|
return this.view.build();
|
|
7230
6952
|
}
|
|
7231
6953
|
};
|
|
7232
|
-
var
|
|
6954
|
+
var RichtextTabConfig = class {
|
|
7233
6955
|
/** @internal */
|
|
7234
|
-
constructor(view2, base) {
|
|
6956
|
+
constructor(view2, base, attribute) {
|
|
7235
6957
|
this.view = view2;
|
|
7236
|
-
this.tabData = { ...base, type: "
|
|
7237
|
-
}
|
|
7238
|
-
/**
|
|
7239
|
-
* Show only private notes of the current user
|
|
7240
|
-
*/
|
|
7241
|
-
privateOnly() {
|
|
7242
|
-
this.tabData.privateOnly = true;
|
|
7243
|
-
return this;
|
|
6958
|
+
this.tabData = { ...base, type: "richtext", attribute };
|
|
7244
6959
|
}
|
|
7245
6960
|
/**
|
|
7246
|
-
*
|
|
6961
|
+
* Set a text attribute to display as an editable title above the editor
|
|
7247
6962
|
*/
|
|
7248
|
-
|
|
7249
|
-
this.tabData.
|
|
6963
|
+
titleAttribute(name) {
|
|
6964
|
+
this.tabData.titleAttribute = name;
|
|
7250
6965
|
return this;
|
|
7251
6966
|
}
|
|
7252
6967
|
/**
|
|
@@ -7469,7 +7184,7 @@ var TabBuilder = class {
|
|
|
7469
7184
|
// ─────────────────────────────────────────────────────────────────────────
|
|
7470
7185
|
/**
|
|
7471
7186
|
* Create a form tab with groups
|
|
7472
|
-
* @example .form(group("info", "Info").fields("name", "email"))
|
|
7187
|
+
* @example .form(group("info", "Info").fields("name", "email"), relationGroup("contacts", "Contacts", "contacts"))
|
|
7473
7188
|
*/
|
|
7474
7189
|
form(...groups) {
|
|
7475
7190
|
if (groups.length === 0) {
|
|
@@ -7480,32 +7195,44 @@ var TabBuilder = class {
|
|
|
7480
7195
|
const tab = {
|
|
7481
7196
|
...this.base,
|
|
7482
7197
|
type: "form",
|
|
7483
|
-
groups: groups.map(
|
|
7198
|
+
groups: groups.map(
|
|
7199
|
+
(g) => g instanceof GroupBuilder || g instanceof RelationGroupBuilder ? g.build() : g
|
|
7200
|
+
)
|
|
7484
7201
|
};
|
|
7485
7202
|
return this.view._addTab(tab);
|
|
7486
7203
|
}
|
|
7487
7204
|
/**
|
|
7488
|
-
* Create a
|
|
7205
|
+
* Create a table tab for a relation attribute on the current object
|
|
7489
7206
|
*
|
|
7490
7207
|
* Use this when the current object has a relation attribute pointing to another object.
|
|
7491
7208
|
*
|
|
7492
7209
|
* @param relationAttribute - Name of the relation attribute on the current object
|
|
7493
|
-
* @example .table("members").columns("name", "email").crud()
|
|
7210
|
+
* @example .table("members").columns("name", "email").crud()
|
|
7494
7211
|
*/
|
|
7495
7212
|
table(relationAttribute) {
|
|
7496
|
-
return new
|
|
7213
|
+
return new TableTabConfig(this.view, {
|
|
7214
|
+
...this.base,
|
|
7215
|
+
type: "table",
|
|
7216
|
+
source: { type: "relation", attribute: relationAttribute },
|
|
7217
|
+
columns: []
|
|
7218
|
+
});
|
|
7497
7219
|
}
|
|
7498
7220
|
/**
|
|
7499
|
-
* Create
|
|
7221
|
+
* Create a table tab showing records from another object that have a relation to us
|
|
7500
7222
|
*
|
|
7501
7223
|
* Use this when another object has a relation attribute pointing to the current object.
|
|
7502
7224
|
*
|
|
7503
7225
|
* @param sourceObject - Name of the object that has the relation to us
|
|
7504
7226
|
* @param relationAttribute - Name of the relation attribute on the source object
|
|
7505
|
-
* @example .tableFrom("contacts", "company").columns("firstName", "lastName")
|
|
7227
|
+
* @example .tableFrom("contacts", "company").columns("firstName", "lastName")
|
|
7506
7228
|
*/
|
|
7507
7229
|
tableFrom(sourceObject, relationAttribute) {
|
|
7508
|
-
return new
|
|
7230
|
+
return new TableTabConfig(this.view, {
|
|
7231
|
+
...this.base,
|
|
7232
|
+
type: "table",
|
|
7233
|
+
source: { type: "inverse", object: sourceObject, attribute: relationAttribute },
|
|
7234
|
+
columns: []
|
|
7235
|
+
});
|
|
7509
7236
|
}
|
|
7510
7237
|
/**
|
|
7511
7238
|
* Create a custom tab with a component
|
|
@@ -7515,11 +7242,11 @@ var TabBuilder = class {
|
|
|
7515
7242
|
return new CustomTabConfig(this.view, this.base, component);
|
|
7516
7243
|
}
|
|
7517
7244
|
/**
|
|
7518
|
-
* Create a
|
|
7519
|
-
* @example .
|
|
7245
|
+
* Create a richtext tab for a richtext attribute
|
|
7246
|
+
* @example .richtext("content").titleAttribute("title")
|
|
7520
7247
|
*/
|
|
7521
|
-
|
|
7522
|
-
return new
|
|
7248
|
+
richtext(attribute) {
|
|
7249
|
+
return new RichtextTabConfig(this.view, this.base, attribute);
|
|
7523
7250
|
}
|
|
7524
7251
|
/**
|
|
7525
7252
|
* Create an activity tab
|
|
@@ -7606,6 +7333,16 @@ var DetailViewBuilder = class {
|
|
|
7606
7333
|
this.data.metadata = value;
|
|
7607
7334
|
return this;
|
|
7608
7335
|
}
|
|
7336
|
+
/**
|
|
7337
|
+
* Configure a side panel with flat attribute fields displayed alongside tab content.
|
|
7338
|
+
* Not available for modal layout.
|
|
7339
|
+
*
|
|
7340
|
+
* @example .sidePanel({ attributes: ["visibility", "linkedTo"] })
|
|
7341
|
+
*/
|
|
7342
|
+
sidePanel(config) {
|
|
7343
|
+
this.data.sidePanel = config;
|
|
7344
|
+
return this;
|
|
7345
|
+
}
|
|
7609
7346
|
/**
|
|
7610
7347
|
* Start building a new tab
|
|
7611
7348
|
*/
|
|
@@ -7650,10 +7387,14 @@ var DetailViewBuilder = class {
|
|
|
7650
7387
|
if (this.data.tabs[0].type !== "form") {
|
|
7651
7388
|
throw new Error("[DetailViewBuilder] Modal views must have a form tab");
|
|
7652
7389
|
}
|
|
7390
|
+
if (this.data.sidePanel) {
|
|
7391
|
+
throw new Error("[DetailViewBuilder] Modal views cannot have a side panel");
|
|
7392
|
+
}
|
|
7653
7393
|
}
|
|
7654
7394
|
const config = {
|
|
7655
7395
|
layout: this.data.layout,
|
|
7656
|
-
tabs: this.data.tabs
|
|
7396
|
+
tabs: this.data.tabs,
|
|
7397
|
+
sidePanel: this.data.sidePanel
|
|
7657
7398
|
};
|
|
7658
7399
|
return {
|
|
7659
7400
|
name: this.data.name,
|
|
@@ -7988,6 +7729,9 @@ function listView(name, label) {
|
|
|
7988
7729
|
function group(id, label) {
|
|
7989
7730
|
return new GroupBuilder(id, label);
|
|
7990
7731
|
}
|
|
7732
|
+
function relationGroup(id, label, attribute) {
|
|
7733
|
+
return new RelationGroupBuilder(id, label, attribute);
|
|
7734
|
+
}
|
|
7991
7735
|
|
|
7992
7736
|
// src/builders/workflow-builder.ts
|
|
7993
7737
|
|
|
@@ -8012,8 +7756,8 @@ var WorkflowFormRowBuilder = class {
|
|
|
8012
7756
|
id: `${this.rowData.id}-${slotId}-${attribute}`,
|
|
8013
7757
|
slotId,
|
|
8014
7758
|
attribute,
|
|
8015
|
-
label: _optionalChain([options, 'optionalAccess',
|
|
8016
|
-
required: _optionalChain([options, 'optionalAccess',
|
|
7759
|
+
label: _optionalChain([options, 'optionalAccess', _148 => _148.label]),
|
|
7760
|
+
required: _optionalChain([options, 'optionalAccess', _149 => _149.required])
|
|
8017
7761
|
};
|
|
8018
7762
|
this.rowData.fields.push(field);
|
|
8019
7763
|
return this;
|
|
@@ -8304,7 +8048,7 @@ var WorkflowBuilder = class {
|
|
|
8304
8048
|
* @param options - Slot configuration
|
|
8305
8049
|
*/
|
|
8306
8050
|
slot(id, objectName, options) {
|
|
8307
|
-
if (_optionalChain([this, 'access',
|
|
8051
|
+
if (_optionalChain([this, 'access', _150 => _150.data, 'access', _151 => _151.slots, 'optionalAccess', _152 => _152.some, 'call', _153 => _153((s) => s.id === id)])) {
|
|
8308
8052
|
throw new Error(`[WorkflowBuilder] Duplicate slot id: "${id}"`);
|
|
8309
8053
|
}
|
|
8310
8054
|
const slot = {
|
|
@@ -8315,7 +8059,7 @@ var WorkflowBuilder = class {
|
|
|
8315
8059
|
color: options.color,
|
|
8316
8060
|
icon: options.icon
|
|
8317
8061
|
};
|
|
8318
|
-
_optionalChain([this, 'access',
|
|
8062
|
+
_optionalChain([this, 'access', _154 => _154.data, 'access', _155 => _155.slots, 'optionalAccess', _156 => _156.push, 'call', _157 => _157(slot)]);
|
|
8319
8063
|
return this;
|
|
8320
8064
|
}
|
|
8321
8065
|
// ============================================================================
|
|
@@ -8447,7 +8191,7 @@ var WorkflowBuilder = class {
|
|
|
8447
8191
|
}
|
|
8448
8192
|
}
|
|
8449
8193
|
validateSlotReferences() {
|
|
8450
|
-
const slotIds = _nullishCoalesce(_optionalChain([this, 'access',
|
|
8194
|
+
const slotIds = _nullishCoalesce(_optionalChain([this, 'access', _158 => _158.data, 'access', _159 => _159.slots, 'optionalAccess', _160 => _160.reduce, 'call', _161 => _161((set, s) => set.add(s.id), /* @__PURE__ */ new Set())]), () => ( /* @__PURE__ */ new Set()));
|
|
8451
8195
|
for (const node of Object.values(_nullishCoalesce(this.data.nodes, () => ( {})))) {
|
|
8452
8196
|
if (node.type === "form") {
|
|
8453
8197
|
const referencedSlots = /* @__PURE__ */ new Set();
|
|
@@ -8648,12 +8392,125 @@ function buildAuditChanges(oldValues, newValues, fieldsToCheck) {
|
|
|
8648
8392
|
return changes;
|
|
8649
8393
|
}
|
|
8650
8394
|
|
|
8395
|
+
// src/runtime/services/bilateral/bilateral-validation.service.ts
|
|
8396
|
+
var BilateralValidationService = class extends BaseService {
|
|
8397
|
+
constructor(adapter, schemaService) {
|
|
8398
|
+
super(adapter);
|
|
8399
|
+
this.schemaService = schemaService;
|
|
8400
|
+
}
|
|
8401
|
+
/**
|
|
8402
|
+
* Validate a bilateral relation configuration.
|
|
8403
|
+
*
|
|
8404
|
+
* Performs comprehensive checks:
|
|
8405
|
+
* 1. Verifies target object exists
|
|
8406
|
+
* 2. Verifies inverse attribute exists on target object
|
|
8407
|
+
* 3. Verifies inverse attribute targets the source object
|
|
8408
|
+
* 4. Detects invalid circular bilateral declarations
|
|
8409
|
+
*
|
|
8410
|
+
* @param sourceSchema - Schema containing the relation attribute
|
|
8411
|
+
* @param sourceAttr - Relation attribute to validate
|
|
8412
|
+
* @returns Validation result with errors if any
|
|
8413
|
+
*/
|
|
8414
|
+
async validateBilateralRelation(sourceSchema, sourceAttr) {
|
|
8415
|
+
const errors = [];
|
|
8416
|
+
if (!(isBilateralRelation(sourceAttr) && sourceAttr.bilateral)) {
|
|
8417
|
+
return { valid: true, errors: [] };
|
|
8418
|
+
}
|
|
8419
|
+
const { object: targetObjectName, attribute: inverseAttrName } = sourceAttr.bilateral;
|
|
8420
|
+
let targetSchema = null;
|
|
8421
|
+
try {
|
|
8422
|
+
targetSchema = await this.schemaService.getObjectSchemaByName(targetObjectName);
|
|
8423
|
+
} catch (e12) {
|
|
8424
|
+
targetSchema = null;
|
|
8425
|
+
}
|
|
8426
|
+
if (!targetSchema) {
|
|
8427
|
+
errors.push({
|
|
8428
|
+
code: "INVERSE_ATTR_NOT_FOUND",
|
|
8429
|
+
message: `Target object "${targetObjectName}" not found`,
|
|
8430
|
+
context: {
|
|
8431
|
+
sourceObject: sourceSchema.name,
|
|
8432
|
+
sourceAttribute: sourceAttr.name,
|
|
8433
|
+
targetObject: targetObjectName,
|
|
8434
|
+
targetAttribute: inverseAttrName
|
|
8435
|
+
}
|
|
8436
|
+
});
|
|
8437
|
+
return { valid: false, errors };
|
|
8438
|
+
}
|
|
8439
|
+
const inverseAttr = targetSchema.attributes.find(
|
|
8440
|
+
(a) => a.name === inverseAttrName && a.type === "relation"
|
|
8441
|
+
);
|
|
8442
|
+
if (!inverseAttr) {
|
|
8443
|
+
errors.push({
|
|
8444
|
+
code: "INVERSE_ATTR_NOT_FOUND",
|
|
8445
|
+
message: `Inverse attribute "${inverseAttrName}" not found on "${targetObjectName}"`,
|
|
8446
|
+
context: {
|
|
8447
|
+
sourceObject: sourceSchema.name,
|
|
8448
|
+
sourceAttribute: sourceAttr.name,
|
|
8449
|
+
targetObject: targetObjectName,
|
|
8450
|
+
targetAttribute: inverseAttrName
|
|
8451
|
+
}
|
|
8452
|
+
});
|
|
8453
|
+
return { valid: false, errors };
|
|
8454
|
+
}
|
|
8455
|
+
const inverseTargetsSource = inverseAttr.targets.some(
|
|
8456
|
+
(target) => target.object === sourceSchema.name
|
|
8457
|
+
);
|
|
8458
|
+
if (!inverseTargetsSource) {
|
|
8459
|
+
errors.push({
|
|
8460
|
+
code: "INVERSE_TARGET_MISMATCH",
|
|
8461
|
+
message: `Inverse attribute doesn't target source object`,
|
|
8462
|
+
context: {
|
|
8463
|
+
sourceObject: sourceSchema.name,
|
|
8464
|
+
sourceAttribute: sourceAttr.name,
|
|
8465
|
+
targetObject: targetObjectName,
|
|
8466
|
+
targetAttribute: inverseAttrName
|
|
8467
|
+
}
|
|
8468
|
+
});
|
|
8469
|
+
}
|
|
8470
|
+
if (isBilateralRelation(inverseAttr)) {
|
|
8471
|
+
const inverseBilateral = inverseAttr.bilateral;
|
|
8472
|
+
if (inverseBilateral.object === sourceSchema.name && inverseBilateral.attribute !== sourceAttr.name) {
|
|
8473
|
+
errors.push({
|
|
8474
|
+
code: "CIRCULAR_BILATERAL",
|
|
8475
|
+
message: "Both sides declare bilateral but point to different attributes",
|
|
8476
|
+
context: {
|
|
8477
|
+
sourceObject: sourceSchema.name,
|
|
8478
|
+
sourceAttribute: sourceAttr.name,
|
|
8479
|
+
targetObject: targetObjectName,
|
|
8480
|
+
targetAttribute: inverseAttrName
|
|
8481
|
+
}
|
|
8482
|
+
});
|
|
8483
|
+
}
|
|
8484
|
+
}
|
|
8485
|
+
return { valid: errors.length === 0, errors };
|
|
8486
|
+
}
|
|
8487
|
+
/**
|
|
8488
|
+
* Validate all bilateral relations in a schema.
|
|
8489
|
+
*
|
|
8490
|
+
* Iterates through all relation attributes and validates each bilateral configuration.
|
|
8491
|
+
*
|
|
8492
|
+
* @param schema - Object schema to validate
|
|
8493
|
+
* @returns Combined validation result with all errors
|
|
8494
|
+
*/
|
|
8495
|
+
async validateAllBilateralRelations(schema) {
|
|
8496
|
+
const allErrors = [];
|
|
8497
|
+
for (const attr of schema.attributes) {
|
|
8498
|
+
if (attr.type === "relation" && isBilateralRelation(attr)) {
|
|
8499
|
+
const result = await this.validateBilateralRelation(schema, attr);
|
|
8500
|
+
allErrors.push(...result.errors);
|
|
8501
|
+
}
|
|
8502
|
+
}
|
|
8503
|
+
return { valid: allErrors.length === 0, errors: allErrors };
|
|
8504
|
+
}
|
|
8505
|
+
};
|
|
8506
|
+
|
|
8651
8507
|
// src/runtime/services/schema/object-schema.service.ts
|
|
8652
8508
|
var ObjectSchemaService = class extends BaseService {
|
|
8653
8509
|
constructor(adapter, nativeRegistry, options) {
|
|
8654
8510
|
super(adapter);
|
|
8655
8511
|
this.nativeRegistry = nativeRegistry;
|
|
8656
|
-
this.auditService = _optionalChain([options, 'optionalAccess',
|
|
8512
|
+
this.auditService = _optionalChain([options, 'optionalAccess', _162 => _162.auditService]);
|
|
8513
|
+
this.bilateralValidationService = new BilateralValidationService(adapter, this);
|
|
8657
8514
|
}
|
|
8658
8515
|
/**
|
|
8659
8516
|
* Create a new custom object.
|
|
@@ -8677,6 +8534,15 @@ var ObjectSchemaService = class extends BaseService {
|
|
|
8677
8534
|
builder.attributes(definition.attributes);
|
|
8678
8535
|
}
|
|
8679
8536
|
const objectDef = builder.build();
|
|
8537
|
+
const bilateralValidation = await this.bilateralValidationService.validateAllBilateralRelations(objectDef);
|
|
8538
|
+
if (!bilateralValidation.valid) {
|
|
8539
|
+
const errorMessages = bilateralValidation.errors.map((e) => `${e.code}: ${e.message}`).join("; ");
|
|
8540
|
+
throw new SchemaError(
|
|
8541
|
+
`Bilateral relation validation failed: ${errorMessages}`,
|
|
8542
|
+
SchemaErrorCode.VALIDATION_FAILED,
|
|
8543
|
+
{ errors: bilateralValidation.errors }
|
|
8544
|
+
);
|
|
8545
|
+
}
|
|
8680
8546
|
const existing = await this.adapter.objects.findByName(objectDef.name);
|
|
8681
8547
|
if (existing) {
|
|
8682
8548
|
throw new Error(`Object with name "${objectDef.name}" already exists`);
|
|
@@ -8766,6 +8632,28 @@ var ObjectSchemaService = class extends BaseService {
|
|
|
8766
8632
|
);
|
|
8767
8633
|
}
|
|
8768
8634
|
const config = await this.validateAttributeInput(attribute);
|
|
8635
|
+
if (attribute.type === "relation" && attribute.bilateral) {
|
|
8636
|
+
const tempSchema = await this.getObjectSchema(objectId);
|
|
8637
|
+
const tempAttr = {
|
|
8638
|
+
...attribute,
|
|
8639
|
+
id: "temp-id",
|
|
8640
|
+
// Temporary ID for validation
|
|
8641
|
+
system: false,
|
|
8642
|
+
config
|
|
8643
|
+
};
|
|
8644
|
+
const validation = await this.bilateralValidationService.validateBilateralRelation(
|
|
8645
|
+
tempSchema,
|
|
8646
|
+
tempAttr
|
|
8647
|
+
);
|
|
8648
|
+
if (!validation.valid) {
|
|
8649
|
+
const errorMessages = validation.errors.map((e) => `${e.code}: ${e.message}`).join("; ");
|
|
8650
|
+
throw new SchemaError(
|
|
8651
|
+
`Bilateral relation validation failed: ${errorMessages}`,
|
|
8652
|
+
SchemaErrorCode.VALIDATION_FAILED,
|
|
8653
|
+
{ errors: validation.errors }
|
|
8654
|
+
);
|
|
8655
|
+
}
|
|
8656
|
+
}
|
|
8769
8657
|
const dbAttr = await this.adapter.attributes.create({
|
|
8770
8658
|
objectId,
|
|
8771
8659
|
name: attribute.name,
|
|
@@ -8866,7 +8754,7 @@ var ObjectSchemaService = class extends BaseService {
|
|
|
8866
8754
|
resourceType: "attribute",
|
|
8867
8755
|
resourceId: attributeId,
|
|
8868
8756
|
resourceLabel: updatedDbAttr.label,
|
|
8869
|
-
objectName: _optionalChain([dbObject, 'optionalAccess',
|
|
8757
|
+
objectName: _optionalChain([dbObject, 'optionalAccess', _163 => _163.name]),
|
|
8870
8758
|
objectId: dbAttr.objectId,
|
|
8871
8759
|
changes
|
|
8872
8760
|
});
|
|
@@ -8899,7 +8787,7 @@ var ObjectSchemaService = class extends BaseService {
|
|
|
8899
8787
|
);
|
|
8900
8788
|
}
|
|
8901
8789
|
const dbObject = await this.adapter.objects.findById(dbAttr.objectId);
|
|
8902
|
-
if (_optionalChain([dbObject, 'optionalAccess',
|
|
8790
|
+
if (_optionalChain([dbObject, 'optionalAccess', _164 => _164.labelExpression])) {
|
|
8903
8791
|
const usedAttributes = extractAttributeNames(dbObject.labelExpression);
|
|
8904
8792
|
if (usedAttributes.includes(dbAttr.name)) {
|
|
8905
8793
|
throw new AttributeInUseError(dbAttr.name, "labelExpression");
|
|
@@ -8915,7 +8803,7 @@ var ObjectSchemaService = class extends BaseService {
|
|
|
8915
8803
|
resourceType: "attribute",
|
|
8916
8804
|
resourceId: attributeId,
|
|
8917
8805
|
resourceLabel: dbAttr.label,
|
|
8918
|
-
objectName: _optionalChain([dbObject, 'optionalAccess',
|
|
8806
|
+
objectName: _optionalChain([dbObject, 'optionalAccess', _165 => _165.name]),
|
|
8919
8807
|
objectId: dbAttr.objectId
|
|
8920
8808
|
});
|
|
8921
8809
|
}
|
|
@@ -8930,9 +8818,9 @@ var ObjectSchemaService = class extends BaseService {
|
|
|
8930
8818
|
async listAttributes(objectId, options) {
|
|
8931
8819
|
const dbAttributes = await this.adapter.attributes.findByObjectId(objectId);
|
|
8932
8820
|
let filtered = dbAttributes;
|
|
8933
|
-
if (_optionalChain([options, 'optionalAccess',
|
|
8821
|
+
if (_optionalChain([options, 'optionalAccess', _166 => _166.systemOnly])) {
|
|
8934
8822
|
filtered = dbAttributes.filter((attr) => attr.system);
|
|
8935
|
-
} else if (_optionalChain([options, 'optionalAccess',
|
|
8823
|
+
} else if (_optionalChain([options, 'optionalAccess', _167 => _167.customOnly])) {
|
|
8936
8824
|
filtered = dbAttributes.filter((attr) => !attr.system);
|
|
8937
8825
|
}
|
|
8938
8826
|
return filtered.map((attr) => this.convertDBAttributeToAttribute(attr));
|
|
@@ -8968,14 +8856,14 @@ var ObjectSchemaService = class extends BaseService {
|
|
|
8968
8856
|
pluralLabel: dbObject.pluralLabel,
|
|
8969
8857
|
description: dbObject.description,
|
|
8970
8858
|
labelExpression: dbObject.labelExpression,
|
|
8971
|
-
icon: _optionalChain([dbObject, 'access',
|
|
8859
|
+
icon: _optionalChain([dbObject, 'access', _168 => _168.metadata, 'optionalAccess', _169 => _169.icon])
|
|
8972
8860
|
};
|
|
8973
8861
|
let metadata = dbObject.metadata;
|
|
8974
8862
|
if (updates.icon !== void 0 || updates.metadata !== void 0) {
|
|
8975
8863
|
metadata = {
|
|
8976
8864
|
...dbObject.metadata,
|
|
8977
8865
|
...updates.metadata,
|
|
8978
|
-
icon: _nullishCoalesce(updates.icon, () => ( _optionalChain([dbObject, 'access',
|
|
8866
|
+
icon: _nullishCoalesce(updates.icon, () => ( _optionalChain([dbObject, 'access', _170 => _170.metadata, 'optionalAccess', _171 => _171.icon])))
|
|
8979
8867
|
};
|
|
8980
8868
|
}
|
|
8981
8869
|
const updatedDbObject = await this.adapter.objects.update(objectId, {
|
|
@@ -9190,19 +9078,71 @@ Reserved names: ${RESERVED_ATTRIBUTE_NAMES.join(", ")}`
|
|
|
9190
9078
|
async buildObjectDefinition(dbObject) {
|
|
9191
9079
|
const dbAttributes = await this.adapter.attributes.findByObjectId(dbObject.id);
|
|
9192
9080
|
const baseDef = dbObject.system ? this.mergeNativeObject(dbObject, dbAttributes) : this.convertDBObjectToDefinition(dbObject, dbAttributes);
|
|
9193
|
-
|
|
9081
|
+
const enriched = await this.enrichBilateralProperties(baseDef);
|
|
9082
|
+
return this.withSystemAttributes(enriched);
|
|
9194
9083
|
}
|
|
9195
9084
|
/**
|
|
9196
|
-
*
|
|
9197
|
-
*
|
|
9085
|
+
* Enrich bilateral relation attributes that don't own property definitions.
|
|
9086
|
+
* Copies `properties` from the canonical side (the one with `.qualifyWith()`)
|
|
9087
|
+
* and sets `storageOwner: false` so the storage layer knows direction.
|
|
9088
|
+
*
|
|
9089
|
+
* Uses direct DB lookups to avoid circular recursion through `getObjectSchema`.
|
|
9198
9090
|
* @internal
|
|
9199
9091
|
*/
|
|
9200
|
-
|
|
9092
|
+
async enrichBilateralProperties(def) {
|
|
9093
|
+
const toEnrich = def.attributes.filter(
|
|
9094
|
+
(attr) => attr.type === "relation" && !!attr.bilateral && !attr.properties
|
|
9095
|
+
);
|
|
9096
|
+
if (toEnrich.length === 0) return def;
|
|
9097
|
+
const enrichedMap = /* @__PURE__ */ new Map();
|
|
9098
|
+
for (const attr of toEnrich) {
|
|
9099
|
+
const { bilateral } = attr;
|
|
9100
|
+
if (!bilateral) continue;
|
|
9101
|
+
const inverseObject = await this.adapter.objects.findByName(bilateral.object);
|
|
9102
|
+
if (!inverseObject) continue;
|
|
9103
|
+
const inverseDbAttrs = await this.adapter.attributes.findByObjectId(inverseObject.id);
|
|
9104
|
+
const inverseDbAttr = inverseDbAttrs.find((a) => a.name === bilateral.attribute);
|
|
9105
|
+
if (!inverseDbAttr) continue;
|
|
9106
|
+
let properties = inverseDbAttr.config.properties;
|
|
9107
|
+
if (!properties) {
|
|
9108
|
+
const nativeObj = this.nativeRegistry.getByName(bilateral.object);
|
|
9109
|
+
const nativeAttr = _optionalChain([nativeObj, 'optionalAccess', _172 => _172.attributes, 'access', _173 => _173.find, 'call', _174 => _174((a) => a.name === bilateral.attribute)]);
|
|
9110
|
+
if (nativeAttr && "properties" in nativeAttr) {
|
|
9111
|
+
properties = nativeAttr.properties;
|
|
9112
|
+
}
|
|
9113
|
+
}
|
|
9114
|
+
if (properties) {
|
|
9115
|
+
enrichedMap.set(attr.name, {
|
|
9116
|
+
properties,
|
|
9117
|
+
bilateral: { ...bilateral, storageOwner: false }
|
|
9118
|
+
});
|
|
9119
|
+
}
|
|
9120
|
+
}
|
|
9121
|
+
if (enrichedMap.size === 0) return def;
|
|
9201
9122
|
return {
|
|
9202
9123
|
...def,
|
|
9203
|
-
attributes:
|
|
9204
|
-
|
|
9205
|
-
|
|
9124
|
+
attributes: def.attributes.map((attr) => {
|
|
9125
|
+
const enrichment = enrichedMap.get(attr.name);
|
|
9126
|
+
if (!enrichment) return attr;
|
|
9127
|
+
return {
|
|
9128
|
+
...attr,
|
|
9129
|
+
properties: enrichment.properties,
|
|
9130
|
+
bilateral: enrichment.bilateral
|
|
9131
|
+
};
|
|
9132
|
+
})
|
|
9133
|
+
};
|
|
9134
|
+
}
|
|
9135
|
+
/**
|
|
9136
|
+
* Append system attributes to an ObjectDefinition
|
|
9137
|
+
* System attributes are always available on all records (createdAt, updatedAt, createdBy, lastUpdatedBy)
|
|
9138
|
+
* @internal
|
|
9139
|
+
*/
|
|
9140
|
+
withSystemAttributes(def) {
|
|
9141
|
+
return {
|
|
9142
|
+
...def,
|
|
9143
|
+
attributes: [...def.attributes, ...getSystemAttributeList()]
|
|
9144
|
+
};
|
|
9145
|
+
}
|
|
9206
9146
|
/**
|
|
9207
9147
|
* Merge native object from registry with custom attributes from DB
|
|
9208
9148
|
* @internal
|
|
@@ -9255,7 +9195,7 @@ Reserved names: ${RESERVED_ATTRIBUTE_NAMES.join(", ")}`
|
|
|
9255
9195
|
label: dbObject.label,
|
|
9256
9196
|
pluralLabel: dbObject.pluralLabel,
|
|
9257
9197
|
description: dbObject.description,
|
|
9258
|
-
icon: _optionalChain([dbObject, 'access',
|
|
9198
|
+
icon: _optionalChain([dbObject, 'access', _175 => _175.metadata, 'optionalAccess', _176 => _176.icon]),
|
|
9259
9199
|
labelExpression: dbObject.labelExpression,
|
|
9260
9200
|
attributes,
|
|
9261
9201
|
system: dbObject.system,
|
|
@@ -9355,7 +9295,7 @@ Reserved names: ${RESERVED_ATTRIBUTE_NAMES.join(", ")}`
|
|
|
9355
9295
|
const hasRelationToTarget = attrs.some((attr) => {
|
|
9356
9296
|
if (attr.type !== "relation") return false;
|
|
9357
9297
|
const config = attr.config;
|
|
9358
|
-
return _nullishCoalesce(_optionalChain([config, 'optionalAccess',
|
|
9298
|
+
return _nullishCoalesce(_optionalChain([config, 'optionalAccess', _177 => _177.targets, 'optionalAccess', _178 => _178.some, 'call', _179 => _179((t) => t.object === targetObjectName)]), () => ( false));
|
|
9359
9299
|
});
|
|
9360
9300
|
if (hasRelationToTarget) {
|
|
9361
9301
|
referencing.push(obj.name);
|
|
@@ -9433,7 +9373,7 @@ Native objects must have system=true. Did you forget to call .system() in your b
|
|
|
9433
9373
|
const existing = this.objects.get(object2.name);
|
|
9434
9374
|
throw new Error(
|
|
9435
9375
|
`[NativeObjectRegistry] Duplicate object name "${object2.name}":
|
|
9436
|
-
- Existing: "${_optionalChain([existing, 'optionalAccess',
|
|
9376
|
+
- Existing: "${_optionalChain([existing, 'optionalAccess', _180 => _180.label])}" (id: ${_optionalChain([existing, 'optionalAccess', _181 => _181.id])})
|
|
9437
9377
|
- New: "${object2.label}" (id: ${object2.id})
|
|
9438
9378
|
Please use unique names for each native object.`
|
|
9439
9379
|
);
|
|
@@ -9550,7 +9490,7 @@ var AuditService = class extends BaseService {
|
|
|
9550
9490
|
this.isFlushing = false;
|
|
9551
9491
|
/** Pending flush promise to allow waiting on concurrent flush */
|
|
9552
9492
|
this.flushPromise = null;
|
|
9553
|
-
if (_optionalChain([options, 'optionalAccess',
|
|
9493
|
+
if (_optionalChain([options, 'optionalAccess', _182 => _182.async]) && options.flushIntervalMs) {
|
|
9554
9494
|
this.startFlushTimer();
|
|
9555
9495
|
}
|
|
9556
9496
|
}
|
|
@@ -9747,7 +9687,7 @@ var AuditService = class extends BaseService {
|
|
|
9747
9687
|
if (!this.adapter.audit) {
|
|
9748
9688
|
return;
|
|
9749
9689
|
}
|
|
9750
|
-
if (_optionalChain([this, 'access',
|
|
9690
|
+
if (_optionalChain([this, 'access', _183 => _183.options, 'optionalAccess', _184 => _184.async])) {
|
|
9751
9691
|
this.buffer.push(entry);
|
|
9752
9692
|
const batchSize = _nullishCoalesce(this.options.batchSize, () => ( 10));
|
|
9753
9693
|
if (this.buffer.length >= batchSize) {
|
|
@@ -9761,7 +9701,7 @@ var AuditService = class extends BaseService {
|
|
|
9761
9701
|
* Start the flush timer for async mode
|
|
9762
9702
|
*/
|
|
9763
9703
|
startFlushTimer() {
|
|
9764
|
-
const intervalMs = _nullishCoalesce(_optionalChain([this, 'access',
|
|
9704
|
+
const intervalMs = _nullishCoalesce(_optionalChain([this, 'access', _185 => _185.options, 'optionalAccess', _186 => _186.flushIntervalMs]), () => ( 1e3));
|
|
9765
9705
|
this.flushTimer = setInterval(() => {
|
|
9766
9706
|
this.flush().catch(() => {
|
|
9767
9707
|
});
|
|
@@ -9785,6 +9725,303 @@ var AuditService = class extends BaseService {
|
|
|
9785
9725
|
}
|
|
9786
9726
|
};
|
|
9787
9727
|
|
|
9728
|
+
// src/runtime/services/bilateral/bilateral-sync.service.ts
|
|
9729
|
+
var browserStub4 = {
|
|
9730
|
+
getStore: () => void 0,
|
|
9731
|
+
run: (_store, callback) => callback()
|
|
9732
|
+
};
|
|
9733
|
+
var AsyncLocalStorageClass4 = null;
|
|
9734
|
+
if (typeof process !== "undefined" && _optionalChain([process, 'access', _187 => _187.versions, 'optionalAccess', _188 => _188.node])) {
|
|
9735
|
+
try {
|
|
9736
|
+
if (typeof _chunk3RG5ZIWIjs.__require !== "undefined") {
|
|
9737
|
+
const asyncHooks = _chunk3RG5ZIWIjs.__require.call(void 0, "async_hooks");
|
|
9738
|
+
AsyncLocalStorageClass4 = asyncHooks.AsyncLocalStorage;
|
|
9739
|
+
}
|
|
9740
|
+
} catch (e13) {
|
|
9741
|
+
try {
|
|
9742
|
+
const dynamicRequire = new Function(
|
|
9743
|
+
"m",
|
|
9744
|
+
'return typeof require!=="undefined"?require(m):null'
|
|
9745
|
+
);
|
|
9746
|
+
const asyncHooks = dynamicRequire("node:async_hooks");
|
|
9747
|
+
if (asyncHooks) {
|
|
9748
|
+
AsyncLocalStorageClass4 = asyncHooks.AsyncLocalStorage;
|
|
9749
|
+
}
|
|
9750
|
+
} catch (e14) {
|
|
9751
|
+
}
|
|
9752
|
+
}
|
|
9753
|
+
}
|
|
9754
|
+
var bilateralSyncContext = null;
|
|
9755
|
+
function getSyncContext() {
|
|
9756
|
+
if (bilateralSyncContext !== null) {
|
|
9757
|
+
return bilateralSyncContext;
|
|
9758
|
+
}
|
|
9759
|
+
if (AsyncLocalStorageClass4) {
|
|
9760
|
+
bilateralSyncContext = new AsyncLocalStorageClass4();
|
|
9761
|
+
return bilateralSyncContext;
|
|
9762
|
+
}
|
|
9763
|
+
bilateralSyncContext = browserStub4;
|
|
9764
|
+
return bilateralSyncContext;
|
|
9765
|
+
}
|
|
9766
|
+
var BilateralSyncService = class extends BaseService {
|
|
9767
|
+
constructor(adapter, schemaService, relationPropertiesService) {
|
|
9768
|
+
super(adapter);
|
|
9769
|
+
this.schemaService = schemaService;
|
|
9770
|
+
this.relationPropertiesService = relationPropertiesService;
|
|
9771
|
+
}
|
|
9772
|
+
// ============================================================================
|
|
9773
|
+
// PUBLIC API
|
|
9774
|
+
// ============================================================================
|
|
9775
|
+
/**
|
|
9776
|
+
* Synchronize a bilateral relation after modification.
|
|
9777
|
+
*
|
|
9778
|
+
* @param sourceSchema - Schema of the object containing the relation
|
|
9779
|
+
* @param sourceRecordId - ID of the record being modified
|
|
9780
|
+
* @param attributeName - Name of the relation attribute
|
|
9781
|
+
* @param newValue - New value (ID, array of IDs, or hybrid format with properties)
|
|
9782
|
+
* @param oldValue - Old value (ID, array of IDs, or hybrid format with properties)
|
|
9783
|
+
*/
|
|
9784
|
+
async syncBilateralRelation(sourceSchema, sourceRecordId, attributeName, newValue, oldValue) {
|
|
9785
|
+
const attribute = sourceSchema.attributes.find(
|
|
9786
|
+
(a) => a.name === attributeName && a.type === "relation"
|
|
9787
|
+
);
|
|
9788
|
+
if (!(attribute && isBilateralRelation(attribute))) {
|
|
9789
|
+
return;
|
|
9790
|
+
}
|
|
9791
|
+
const ctx = getSyncContext().getStore();
|
|
9792
|
+
const syncKey = `${sourceSchema.name}:${sourceRecordId}:${attributeName}`;
|
|
9793
|
+
if (_optionalChain([ctx, 'optionalAccess', _189 => _189.syncing, 'access', _190 => _190.has, 'call', _191 => _191(syncKey)])) {
|
|
9794
|
+
return;
|
|
9795
|
+
}
|
|
9796
|
+
await this.runWithSyncContext(syncKey, async () => {
|
|
9797
|
+
await this.performBilateralSync(sourceSchema, sourceRecordId, attribute, newValue, oldValue);
|
|
9798
|
+
});
|
|
9799
|
+
}
|
|
9800
|
+
// ============================================================================
|
|
9801
|
+
// PRIVATE METHODS
|
|
9802
|
+
// ============================================================================
|
|
9803
|
+
/**
|
|
9804
|
+
* Perform the bidirectional synchronization.
|
|
9805
|
+
* @private
|
|
9806
|
+
*/
|
|
9807
|
+
async performBilateralSync(sourceSchema, sourceRecordId, sourceAttr, newValue, oldValue) {
|
|
9808
|
+
const bilateral = sourceAttr.bilateral;
|
|
9809
|
+
const targetSchema = await this.schemaService.getObjectSchemaByName(bilateral.object);
|
|
9810
|
+
if (!targetSchema) {
|
|
9811
|
+
throw new Error(`Target object "${bilateral.object}" not found`);
|
|
9812
|
+
}
|
|
9813
|
+
const inverseAttr = targetSchema.attributes.find(
|
|
9814
|
+
(a) => a.name === bilateral.attribute && a.type === "relation"
|
|
9815
|
+
);
|
|
9816
|
+
if (!inverseAttr) {
|
|
9817
|
+
throw new Error(
|
|
9818
|
+
`Inverse attribute "${bilateral.attribute}" not found on "${bilateral.object}"`
|
|
9819
|
+
);
|
|
9820
|
+
}
|
|
9821
|
+
const newData = this.extractRelationData(newValue);
|
|
9822
|
+
const oldData = this.extractRelationData(oldValue);
|
|
9823
|
+
const addedIds = newData.ids.filter((id) => !oldData.ids.includes(id));
|
|
9824
|
+
const removedIds = oldData.ids.filter((id) => !newData.ids.includes(id));
|
|
9825
|
+
const commonIds = newData.ids.filter((id) => oldData.ids.includes(id));
|
|
9826
|
+
await Promise.all([
|
|
9827
|
+
// Add new relations
|
|
9828
|
+
...addedIds.map(
|
|
9829
|
+
(targetId) => this.addInverseRelation(
|
|
9830
|
+
targetId,
|
|
9831
|
+
inverseAttr,
|
|
9832
|
+
sourceRecordId,
|
|
9833
|
+
sourceSchema.name,
|
|
9834
|
+
sourceAttr.name,
|
|
9835
|
+
newData.properties.get(targetId)
|
|
9836
|
+
)
|
|
9837
|
+
),
|
|
9838
|
+
// Remove deleted relations
|
|
9839
|
+
...removedIds.map(
|
|
9840
|
+
(targetId) => this.removeInverseRelation(targetId, inverseAttr, sourceRecordId)
|
|
9841
|
+
),
|
|
9842
|
+
// Update properties for common IDs
|
|
9843
|
+
...commonIds.map(
|
|
9844
|
+
(targetId) => this.updateInverseRelationProperties(
|
|
9845
|
+
targetId,
|
|
9846
|
+
inverseAttr,
|
|
9847
|
+
sourceRecordId,
|
|
9848
|
+
sourceSchema.name,
|
|
9849
|
+
sourceAttr.name,
|
|
9850
|
+
newData.properties.get(targetId),
|
|
9851
|
+
oldData.properties.get(targetId)
|
|
9852
|
+
)
|
|
9853
|
+
)
|
|
9854
|
+
]);
|
|
9855
|
+
}
|
|
9856
|
+
/**
|
|
9857
|
+
* Extract IDs and properties from hybrid relation value.
|
|
9858
|
+
* @private
|
|
9859
|
+
*/
|
|
9860
|
+
extractRelationData(value) {
|
|
9861
|
+
const ids = [];
|
|
9862
|
+
const properties = /* @__PURE__ */ new Map();
|
|
9863
|
+
if (value === null || value === void 0) {
|
|
9864
|
+
return { ids, properties };
|
|
9865
|
+
}
|
|
9866
|
+
if (typeof value === "string") {
|
|
9867
|
+
ids.push(value);
|
|
9868
|
+
return { ids, properties };
|
|
9869
|
+
}
|
|
9870
|
+
if (!Array.isArray(value) && typeof value === "object" && "id" in value) {
|
|
9871
|
+
ids.push(value.id);
|
|
9872
|
+
if (value.props) {
|
|
9873
|
+
properties.set(value.id, value.props);
|
|
9874
|
+
}
|
|
9875
|
+
return { ids, properties };
|
|
9876
|
+
}
|
|
9877
|
+
if (Array.isArray(value)) {
|
|
9878
|
+
for (const item of value) {
|
|
9879
|
+
if (typeof item === "string") {
|
|
9880
|
+
ids.push(item);
|
|
9881
|
+
} else if (typeof item === "object" && item !== null && "id" in item) {
|
|
9882
|
+
ids.push(item.id);
|
|
9883
|
+
if (item.props) {
|
|
9884
|
+
properties.set(item.id, item.props);
|
|
9885
|
+
}
|
|
9886
|
+
}
|
|
9887
|
+
}
|
|
9888
|
+
}
|
|
9889
|
+
return { ids, properties };
|
|
9890
|
+
}
|
|
9891
|
+
/**
|
|
9892
|
+
* Add an ID to an inverse relation (with properties).
|
|
9893
|
+
* @private
|
|
9894
|
+
*/
|
|
9895
|
+
async addInverseRelation(targetRecordId, inverseAttr, sourceRecordId, sourceObject, sourceAttribute, properties) {
|
|
9896
|
+
const targetRecord = await this.adapter.objectRecords.findById(targetRecordId);
|
|
9897
|
+
if (!targetRecord) {
|
|
9898
|
+
return;
|
|
9899
|
+
}
|
|
9900
|
+
const currentValue = targetRecord.values[inverseAttr.name];
|
|
9901
|
+
let newValue;
|
|
9902
|
+
if (inverseAttr.cardinality === "one") {
|
|
9903
|
+
newValue = sourceRecordId;
|
|
9904
|
+
} else {
|
|
9905
|
+
const currentArray = this.normalizeToArray(currentValue);
|
|
9906
|
+
if (currentArray.includes(sourceRecordId)) {
|
|
9907
|
+
return;
|
|
9908
|
+
}
|
|
9909
|
+
newValue = [...currentArray, sourceRecordId];
|
|
9910
|
+
}
|
|
9911
|
+
await this.adapter.objectRecords.update(targetRecordId, {
|
|
9912
|
+
[inverseAttr.name]: newValue
|
|
9913
|
+
});
|
|
9914
|
+
await this.invalidateTargetRecordCaches(targetRecordId, targetRecord.objectId);
|
|
9915
|
+
if (properties && Object.keys(properties).length > 0 && this.adapter.relationAttributes) {
|
|
9916
|
+
const sourceSchema = await this.schemaService.getObjectSchemaByName(sourceObject);
|
|
9917
|
+
if (sourceSchema) {
|
|
9918
|
+
await this.relationPropertiesService.syncRelationProperties(
|
|
9919
|
+
sourceSchema,
|
|
9920
|
+
sourceRecordId,
|
|
9921
|
+
sourceAttribute,
|
|
9922
|
+
[{ id: targetRecordId, props: properties }],
|
|
9923
|
+
this.adapter
|
|
9924
|
+
);
|
|
9925
|
+
}
|
|
9926
|
+
}
|
|
9927
|
+
}
|
|
9928
|
+
/**
|
|
9929
|
+
* Update properties of an existing inverse relation.
|
|
9930
|
+
* @private
|
|
9931
|
+
*/
|
|
9932
|
+
async updateInverseRelationProperties(targetRecordId, _inverseAttr, sourceRecordId, sourceObject, sourceAttribute, newProperties, oldProperties) {
|
|
9933
|
+
if (JSON.stringify(newProperties) === JSON.stringify(oldProperties)) {
|
|
9934
|
+
return;
|
|
9935
|
+
}
|
|
9936
|
+
if (!this.adapter.relationAttributes) {
|
|
9937
|
+
return;
|
|
9938
|
+
}
|
|
9939
|
+
const sourceSchema = await this.schemaService.getObjectSchemaByName(sourceObject);
|
|
9940
|
+
if (!sourceSchema) {
|
|
9941
|
+
return;
|
|
9942
|
+
}
|
|
9943
|
+
if (newProperties && Object.keys(newProperties).length > 0) {
|
|
9944
|
+
await this.relationPropertiesService.syncRelationProperties(
|
|
9945
|
+
sourceSchema,
|
|
9946
|
+
sourceRecordId,
|
|
9947
|
+
sourceAttribute,
|
|
9948
|
+
[{ id: targetRecordId, props: newProperties }],
|
|
9949
|
+
this.adapter
|
|
9950
|
+
);
|
|
9951
|
+
} else {
|
|
9952
|
+
await this.adapter.relationAttributes.deleteBySource(
|
|
9953
|
+
sourceObject,
|
|
9954
|
+
sourceRecordId,
|
|
9955
|
+
sourceAttribute
|
|
9956
|
+
);
|
|
9957
|
+
}
|
|
9958
|
+
}
|
|
9959
|
+
/**
|
|
9960
|
+
* Remove an ID from an inverse relation.
|
|
9961
|
+
* @private
|
|
9962
|
+
*/
|
|
9963
|
+
async removeInverseRelation(targetRecordId, inverseAttr, sourceRecordId) {
|
|
9964
|
+
const targetRecord = await this.adapter.objectRecords.findById(targetRecordId);
|
|
9965
|
+
if (!targetRecord) {
|
|
9966
|
+
return;
|
|
9967
|
+
}
|
|
9968
|
+
const currentValue = targetRecord.values[inverseAttr.name];
|
|
9969
|
+
let newValue;
|
|
9970
|
+
if (inverseAttr.cardinality === "one") {
|
|
9971
|
+
if (currentValue === sourceRecordId) {
|
|
9972
|
+
newValue = null;
|
|
9973
|
+
} else {
|
|
9974
|
+
return;
|
|
9975
|
+
}
|
|
9976
|
+
} else {
|
|
9977
|
+
const currentArray = this.normalizeToArray(currentValue);
|
|
9978
|
+
newValue = currentArray.filter((id) => id !== sourceRecordId);
|
|
9979
|
+
if (newValue.length === currentArray.length) {
|
|
9980
|
+
return;
|
|
9981
|
+
}
|
|
9982
|
+
}
|
|
9983
|
+
await this.adapter.objectRecords.update(targetRecordId, {
|
|
9984
|
+
[inverseAttr.name]: newValue
|
|
9985
|
+
});
|
|
9986
|
+
await this.invalidateTargetRecordCaches(targetRecordId, targetRecord.objectId);
|
|
9987
|
+
}
|
|
9988
|
+
/**
|
|
9989
|
+
* Normalize a relation value to an array of IDs.
|
|
9990
|
+
* @private
|
|
9991
|
+
*/
|
|
9992
|
+
normalizeToArray(value) {
|
|
9993
|
+
if (value === null || value === void 0) return [];
|
|
9994
|
+
if (typeof value === "string") return [value];
|
|
9995
|
+
if (Array.isArray(value)) return value;
|
|
9996
|
+
return [];
|
|
9997
|
+
}
|
|
9998
|
+
/**
|
|
9999
|
+
* Invalidate caches for a target record after bilateral update.
|
|
10000
|
+
* Mirrors RecordService.invalidateRecordCaches to ensure consistency.
|
|
10001
|
+
* @private
|
|
10002
|
+
*/
|
|
10003
|
+
async invalidateTargetRecordCaches(recordId, objectId) {
|
|
10004
|
+
await this.invalidateCache(cacheKeys.record(this.tenantId, recordId));
|
|
10005
|
+
await this.invalidateLists("allRecordLists", objectId);
|
|
10006
|
+
await this.invalidateLists("allSearchResults", objectId);
|
|
10007
|
+
await this.invalidateCachePattern(cacheKeys.allGlobalSearch(this.tenantId));
|
|
10008
|
+
await this.invalidateCachePattern(cacheKeys.resolvedRelationsByRecord(this.tenantId, recordId));
|
|
10009
|
+
}
|
|
10010
|
+
/**
|
|
10011
|
+
* Execute a function with sync context.
|
|
10012
|
+
* @private
|
|
10013
|
+
*/
|
|
10014
|
+
async runWithSyncContext(syncKey, fn) {
|
|
10015
|
+
const storage = getSyncContext();
|
|
10016
|
+
const existingCtx = storage.getStore();
|
|
10017
|
+
const ctx = {
|
|
10018
|
+
syncing: new Set(_nullishCoalesce(_optionalChain([existingCtx, 'optionalAccess', _192 => _192.syncing]), () => ( [])))
|
|
10019
|
+
};
|
|
10020
|
+
ctx.syncing.add(syncKey);
|
|
10021
|
+
return await storage.run(ctx, fn);
|
|
10022
|
+
}
|
|
10023
|
+
};
|
|
10024
|
+
|
|
9788
10025
|
// src/runtime/services/user/user.service.ts
|
|
9789
10026
|
var UserService = class extends BaseService {
|
|
9790
10027
|
constructor(adapter) {
|
|
@@ -9869,7 +10106,7 @@ var UserService = class extends BaseService {
|
|
|
9869
10106
|
if (roleErrors.length > 0) {
|
|
9870
10107
|
errors.push({
|
|
9871
10108
|
attribute: attrName,
|
|
9872
|
-
message: `Users do not have required role for ${attr.label}. Allowed roles: ${_optionalChain([attr, 'access',
|
|
10109
|
+
message: `Users do not have required role for ${attr.label}. Allowed roles: ${_optionalChain([attr, 'access', _193 => _193.allowedRoles, 'optionalAccess', _194 => _194.join, 'call', _195 => _195(", ")])}`,
|
|
9873
10110
|
invalidIds: roleErrors
|
|
9874
10111
|
});
|
|
9875
10112
|
}
|
|
@@ -10185,122 +10422,473 @@ async function recalculateParentRollups(record, schema, ctx) {
|
|
|
10185
10422
|
}
|
|
10186
10423
|
}
|
|
10187
10424
|
|
|
10188
|
-
// src/runtime/services/record/
|
|
10189
|
-
|
|
10190
|
-
|
|
10425
|
+
// src/runtime/services/record/relation-properties.service.ts
|
|
10426
|
+
|
|
10427
|
+
var RelationPropertiesService = class extends BaseService {
|
|
10428
|
+
constructor(adapter) {
|
|
10191
10429
|
super(adapter);
|
|
10192
|
-
this.schemaService = schemaService;
|
|
10193
|
-
this.options = options;
|
|
10194
|
-
this.policyRegistry = _optionalChain([options, 'optionalAccess', _192 => _192.policyRegistry]) === null ? null : _nullishCoalesce(_optionalChain([options, 'optionalAccess', _193 => _193.policyRegistry]), () => ( defaultPolicyRegistry));
|
|
10195
10430
|
}
|
|
10196
10431
|
// ============================================================================
|
|
10197
|
-
//
|
|
10432
|
+
// PUBLIC API
|
|
10198
10433
|
// ============================================================================
|
|
10199
10434
|
/**
|
|
10200
|
-
*
|
|
10435
|
+
* Get relation properties for a given attribute.
|
|
10201
10436
|
*
|
|
10202
|
-
*
|
|
10203
|
-
*
|
|
10204
|
-
*
|
|
10437
|
+
* Supports bidirectional relations: searches for properties in both directions
|
|
10438
|
+
* (forward: from_object/from_id → to_id, and inverse: to_id → from_id).
|
|
10439
|
+
*
|
|
10440
|
+
* This ensures that qualified properties are SHARED between both directions
|
|
10441
|
+
* of a bilateral relation, as they are stored in a single row in relation_attributes.
|
|
10442
|
+
*
|
|
10443
|
+
* @param objectName - Source object name
|
|
10444
|
+
* @param recordId - Source record ID
|
|
10445
|
+
* @param attributeName - Relation attribute name
|
|
10446
|
+
* @param targetIds - Array of target record IDs
|
|
10447
|
+
* @returns Map of target ID → properties
|
|
10205
10448
|
*
|
|
10206
10449
|
* @example
|
|
10207
10450
|
* ```typescript
|
|
10208
|
-
*
|
|
10209
|
-
*
|
|
10210
|
-
*
|
|
10211
|
-
*
|
|
10212
|
-
*
|
|
10451
|
+
* // Properties stored as: contacts/A/companies → X with { role: "CEO" }
|
|
10452
|
+
*
|
|
10453
|
+
* // Read from Contact A → Company X
|
|
10454
|
+
* const propsFromContact = await service.getRelationProperties(
|
|
10455
|
+
* "contacts", "A", "companies", ["X"]
|
|
10456
|
+
* );
|
|
10457
|
+
* // → Map { "X" => { role: "CEO" } }
|
|
10458
|
+
*
|
|
10459
|
+
* // Read from Company X → Contact A (inverse)
|
|
10460
|
+
* const propsFromCompany = await service.getRelationProperties(
|
|
10461
|
+
* "companies", "X", "contacts", ["A"]
|
|
10462
|
+
* );
|
|
10463
|
+
* // → Map { "A" => { role: "CEO" } } (same properties!)
|
|
10213
10464
|
* ```
|
|
10214
10465
|
*/
|
|
10215
|
-
async
|
|
10216
|
-
const
|
|
10217
|
-
|
|
10218
|
-
|
|
10219
|
-
objectId,
|
|
10220
|
-
{ ...options, _userId: this.userId },
|
|
10221
|
-
() => this.executeListQuery(schema, objectId, options)
|
|
10222
|
-
);
|
|
10223
|
-
}
|
|
10224
|
-
/**
|
|
10225
|
-
* List records using a pre-fetched schema.
|
|
10226
|
-
* Useful when the caller already has the schema to avoid redundant lookups.
|
|
10227
|
-
*/
|
|
10228
|
-
async listRecordsWithSchema(schema, options) {
|
|
10229
|
-
if (!schema.id) {
|
|
10230
|
-
throw new Error("Schema must have an ID to list records");
|
|
10466
|
+
async getRelationProperties(objectName, recordId, attributeName, targetIds) {
|
|
10467
|
+
const properties = /* @__PURE__ */ new Map();
|
|
10468
|
+
if (!this.adapter.relationAttributes) {
|
|
10469
|
+
return properties;
|
|
10231
10470
|
}
|
|
10232
|
-
const
|
|
10233
|
-
|
|
10234
|
-
|
|
10235
|
-
|
|
10236
|
-
{ ...options, _userId: this.userId },
|
|
10237
|
-
() => this.executeListQuery(schema, objectId, options)
|
|
10471
|
+
const forwardProps = await this.adapter.relationAttributes.findBySource(
|
|
10472
|
+
objectName,
|
|
10473
|
+
recordId,
|
|
10474
|
+
attributeName
|
|
10238
10475
|
);
|
|
10476
|
+
for (const prop of forwardProps) {
|
|
10477
|
+
if (targetIds.includes(prop.toId)) {
|
|
10478
|
+
properties.set(prop.toId, prop.properties);
|
|
10479
|
+
}
|
|
10480
|
+
}
|
|
10481
|
+
const inverseProps = await this.adapter.relationAttributes.findByTarget(recordId);
|
|
10482
|
+
for (const prop of inverseProps) {
|
|
10483
|
+
if (targetIds.includes(prop.fromId) && !properties.has(prop.fromId)) {
|
|
10484
|
+
properties.set(prop.fromId, prop.properties);
|
|
10485
|
+
}
|
|
10486
|
+
}
|
|
10487
|
+
return properties;
|
|
10239
10488
|
}
|
|
10240
10489
|
/**
|
|
10241
|
-
*
|
|
10490
|
+
* Batch enrich records with qualified relation properties.
|
|
10491
|
+
*
|
|
10492
|
+
* Detects qualified attributes in the schema and fetches their properties
|
|
10493
|
+
* using batch queries (1 query per qualified attribute, not per record).
|
|
10494
|
+
* Returns records with values in hybrid format `{ id, props }`.
|
|
10495
|
+
*
|
|
10496
|
+
* For bilateral relations, also checks the inverse direction.
|
|
10497
|
+
*
|
|
10498
|
+
* @param records - Records to enrich
|
|
10499
|
+
* @param schema - Object schema
|
|
10500
|
+
* @returns Records with relation values enriched with properties
|
|
10242
10501
|
*/
|
|
10243
|
-
async
|
|
10244
|
-
if (
|
|
10245
|
-
|
|
10246
|
-
|
|
10247
|
-
|
|
10248
|
-
let effectiveOptions = options;
|
|
10249
|
-
if (_optionalChain([policy, 'optionalAccess', _197 => _197.applyListFilter]) && this.userId) {
|
|
10250
|
-
const ctx = buildPolicyContext(schema.name, this.userId, this.tenantId);
|
|
10251
|
-
effectiveOptions = policy.applyListFilter(ctx, options);
|
|
10252
|
-
}
|
|
10253
|
-
const result = await runWithSchemaContext(
|
|
10254
|
-
[schema],
|
|
10255
|
-
() => this.adapter.objectRecords.list(objectId, effectiveOptions)
|
|
10502
|
+
async enrichRecordsBatch(records, schema) {
|
|
10503
|
+
if (!this.adapter.relationAttributes) return records;
|
|
10504
|
+
if (records.length === 0) return records;
|
|
10505
|
+
const qualifiedAttrs = schema.attributes.filter(
|
|
10506
|
+
(a) => a.type === "relation" && (!!a.properties || !!a.bilateral)
|
|
10256
10507
|
);
|
|
10257
|
-
|
|
10258
|
-
|
|
10259
|
-
|
|
10260
|
-
|
|
10261
|
-
|
|
10262
|
-
|
|
10263
|
-
|
|
10264
|
-
|
|
10265
|
-
|
|
10266
|
-
const collected = [];
|
|
10267
|
-
let dbOffset = 0;
|
|
10268
|
-
let totalScanned = 0;
|
|
10269
|
-
let exhausted = false;
|
|
10270
|
-
const target = requestedOffset + requestedLimit;
|
|
10271
|
-
while (collected.length < target && totalScanned < maxScanRecords) {
|
|
10272
|
-
const batch = await runWithSchemaContext(
|
|
10273
|
-
[schema],
|
|
10274
|
-
() => this.adapter.objectRecords.list(objectId, {
|
|
10275
|
-
...effectiveOptions,
|
|
10276
|
-
limit: batchSize,
|
|
10277
|
-
offset: dbOffset
|
|
10278
|
-
})
|
|
10508
|
+
if (qualifiedAttrs.length === 0) return records;
|
|
10509
|
+
const recordIds = records.map((r) => r.id);
|
|
10510
|
+
const relationAttrsRepo = this.adapter.relationAttributes;
|
|
10511
|
+
await Promise.all(
|
|
10512
|
+
qualifiedAttrs.map(async (attr) => {
|
|
10513
|
+
const forwardRows = await relationAttrsRepo.findBySourceBatch(
|
|
10514
|
+
schema.name,
|
|
10515
|
+
recordIds,
|
|
10516
|
+
attr.name
|
|
10279
10517
|
);
|
|
10280
|
-
|
|
10281
|
-
|
|
10282
|
-
|
|
10518
|
+
const inverseRows = attr.bilateral ? await relationAttrsRepo.findByTargetBatch(recordIds) : [];
|
|
10519
|
+
const byRecord = /* @__PURE__ */ new Map();
|
|
10520
|
+
for (const row of forwardRows) {
|
|
10521
|
+
let recordMap = byRecord.get(row.fromId);
|
|
10522
|
+
if (!recordMap) {
|
|
10523
|
+
recordMap = /* @__PURE__ */ new Map();
|
|
10524
|
+
byRecord.set(row.fromId, recordMap);
|
|
10525
|
+
}
|
|
10526
|
+
recordMap.set(row.toId, row.properties);
|
|
10283
10527
|
}
|
|
10284
|
-
const
|
|
10285
|
-
|
|
10286
|
-
|
|
10287
|
-
|
|
10288
|
-
|
|
10289
|
-
|
|
10290
|
-
|
|
10528
|
+
for (const row of inverseRows) {
|
|
10529
|
+
let recordMap = byRecord.get(row.toId);
|
|
10530
|
+
if (!recordMap) {
|
|
10531
|
+
recordMap = /* @__PURE__ */ new Map();
|
|
10532
|
+
byRecord.set(row.toId, recordMap);
|
|
10533
|
+
}
|
|
10534
|
+
if (!recordMap.has(row.fromId)) {
|
|
10535
|
+
recordMap.set(row.fromId, row.properties);
|
|
10536
|
+
}
|
|
10291
10537
|
}
|
|
10292
|
-
|
|
10293
|
-
|
|
10294
|
-
|
|
10295
|
-
|
|
10296
|
-
|
|
10297
|
-
|
|
10298
|
-
|
|
10299
|
-
|
|
10300
|
-
|
|
10301
|
-
|
|
10538
|
+
for (const record of records) {
|
|
10539
|
+
const propsForRecord = byRecord.get(record.id);
|
|
10540
|
+
if (!propsForRecord) continue;
|
|
10541
|
+
const value = record.values[attr.name];
|
|
10542
|
+
if (Array.isArray(value)) {
|
|
10543
|
+
record.values = {
|
|
10544
|
+
...record.values,
|
|
10545
|
+
[attr.name]: value.map((id) => {
|
|
10546
|
+
const props = propsForRecord.get(id);
|
|
10547
|
+
return props ? { id, props } : id;
|
|
10548
|
+
})
|
|
10549
|
+
};
|
|
10550
|
+
} else if (typeof value === "string") {
|
|
10551
|
+
const props = propsForRecord.get(value);
|
|
10552
|
+
if (props) {
|
|
10553
|
+
record.values = {
|
|
10554
|
+
...record.values,
|
|
10555
|
+
[attr.name]: { id: value, props }
|
|
10556
|
+
};
|
|
10557
|
+
}
|
|
10558
|
+
}
|
|
10559
|
+
}
|
|
10560
|
+
})
|
|
10561
|
+
);
|
|
10562
|
+
return records;
|
|
10563
|
+
}
|
|
10564
|
+
/**
|
|
10565
|
+
* Normalize relation values for storage in object_records table.
|
|
10566
|
+
*
|
|
10567
|
+
* Extracts IDs from hybrid format ({ id, props }) and returns legacy format (string[] or string).
|
|
10568
|
+
* This ensures object_records.values only contains IDs, while properties are in relation_attributes.
|
|
10569
|
+
*
|
|
10570
|
+
* @param schema - Object schema
|
|
10571
|
+
* @param data - Record data with hybrid relation values
|
|
10572
|
+
* @returns Data with relation values normalized to ID-only format
|
|
10573
|
+
*/
|
|
10574
|
+
normalizeRelationValuesForStorage(schema, data) {
|
|
10575
|
+
const normalized = { ...data };
|
|
10576
|
+
for (const attr of schema.attributes) {
|
|
10577
|
+
if (attr.type !== "relation") {
|
|
10578
|
+
continue;
|
|
10579
|
+
}
|
|
10580
|
+
const value = data[attr.name];
|
|
10581
|
+
if (value === null || value === void 0) {
|
|
10582
|
+
continue;
|
|
10583
|
+
}
|
|
10584
|
+
if (attr.cardinality === "many" && Array.isArray(value)) {
|
|
10585
|
+
normalized[attr.name] = value.map((item) => {
|
|
10586
|
+
if (typeof item === "string") return item;
|
|
10587
|
+
if (typeof item === "object" && item !== null && "id" in item) {
|
|
10588
|
+
return item.id;
|
|
10589
|
+
}
|
|
10590
|
+
return item;
|
|
10591
|
+
});
|
|
10592
|
+
} else if (typeof value === "object" && value !== null && "id" in value) {
|
|
10593
|
+
normalized[attr.name] = value.id;
|
|
10594
|
+
}
|
|
10595
|
+
}
|
|
10596
|
+
return normalized;
|
|
10597
|
+
}
|
|
10598
|
+
/**
|
|
10599
|
+
* Synchronize relation properties for a given attribute.
|
|
10600
|
+
*
|
|
10601
|
+
* Handles:
|
|
10602
|
+
* - Format normalization (legacy → new)
|
|
10603
|
+
* - Validation of properties
|
|
10604
|
+
* - Upsert for present IDs
|
|
10605
|
+
* - Delete for absent IDs
|
|
10606
|
+
*
|
|
10607
|
+
* @param schema - Object schema
|
|
10608
|
+
* @param recordId - Source record ID
|
|
10609
|
+
* @param attributeName - Relation attribute name
|
|
10610
|
+
* @param relationValue - Relation value (hybrid format)
|
|
10611
|
+
* @param adapter - Database adapter
|
|
10612
|
+
*/
|
|
10613
|
+
async syncRelationProperties(schema, recordId, attributeName, relationValue, adapter) {
|
|
10614
|
+
const attribute = schema.attributes.find((a) => a.name === attributeName);
|
|
10615
|
+
if (!attribute || attribute.type !== "relation") {
|
|
10616
|
+
return;
|
|
10617
|
+
}
|
|
10618
|
+
const normalized = this.normalizeRelationValue(relationValue);
|
|
10619
|
+
const propertySchema = this.getPropertySchema(attribute);
|
|
10620
|
+
const hasPropsInInput = normalized.some((item) => item.props !== void 0);
|
|
10621
|
+
const hasSchema = Boolean(propertySchema);
|
|
10622
|
+
const canSync = hasSchema || hasPropsInInput;
|
|
10623
|
+
if (!canSync) {
|
|
10624
|
+
return;
|
|
10625
|
+
}
|
|
10626
|
+
if (propertySchema) {
|
|
10627
|
+
for (const item of normalized) {
|
|
10628
|
+
if (item.props && Object.keys(item.props).length > 0) {
|
|
10629
|
+
this.validateProperties(propertySchema, item.props);
|
|
10630
|
+
}
|
|
10631
|
+
}
|
|
10632
|
+
}
|
|
10633
|
+
const shouldStoreAsInverse = _optionalChain([attribute, 'access', _196 => _196.bilateral, 'optionalAccess', _197 => _197.storageOwner]) === false;
|
|
10634
|
+
let storageFromObject = schema.name;
|
|
10635
|
+
let storageFromAttribute = attributeName;
|
|
10636
|
+
if (shouldStoreAsInverse && attribute.bilateral) {
|
|
10637
|
+
storageFromObject = attribute.bilateral.object;
|
|
10638
|
+
storageFromAttribute = attribute.bilateral.attribute;
|
|
10639
|
+
}
|
|
10640
|
+
let existing;
|
|
10641
|
+
if (adapter.relationAttributes) {
|
|
10642
|
+
if (shouldStoreAsInverse) {
|
|
10643
|
+
const results = await Promise.all(
|
|
10644
|
+
normalized.map(
|
|
10645
|
+
(item) => _optionalChain([adapter, 'access', _198 => _198.relationAttributes, 'optionalAccess', _199 => _199.findBySource, 'call', _200 => _200(
|
|
10646
|
+
storageFromObject,
|
|
10647
|
+
item.id,
|
|
10648
|
+
storageFromAttribute
|
|
10649
|
+
)])
|
|
10650
|
+
)
|
|
10651
|
+
);
|
|
10652
|
+
existing = results.filter((r) => r !== void 0).flat().filter((r) => r.toId === recordId);
|
|
10653
|
+
} else {
|
|
10654
|
+
existing = await adapter.relationAttributes.findBySource(
|
|
10655
|
+
schema.name,
|
|
10656
|
+
recordId,
|
|
10657
|
+
attributeName
|
|
10658
|
+
);
|
|
10659
|
+
}
|
|
10660
|
+
}
|
|
10661
|
+
const hasChanges = existing && existing.length > 0;
|
|
10662
|
+
const toUpsert = normalized.filter((item) => {
|
|
10663
|
+
return item.props !== void 0 && Object.keys(item.props).length > 0;
|
|
10664
|
+
});
|
|
10665
|
+
if (!adapter.relationAttributes) {
|
|
10666
|
+
return;
|
|
10667
|
+
}
|
|
10668
|
+
if (hasChanges && existing) {
|
|
10669
|
+
if (shouldStoreAsInverse) {
|
|
10670
|
+
for (const item of normalized) {
|
|
10671
|
+
await adapter.relationAttributes.deleteBySourceAndTarget(
|
|
10672
|
+
storageFromObject,
|
|
10673
|
+
item.id,
|
|
10674
|
+
storageFromAttribute,
|
|
10675
|
+
recordId
|
|
10676
|
+
);
|
|
10677
|
+
}
|
|
10678
|
+
} else {
|
|
10679
|
+
await adapter.relationAttributes.deleteBySource(schema.name, recordId, attributeName);
|
|
10680
|
+
}
|
|
10681
|
+
}
|
|
10682
|
+
if (toUpsert.length > 0) {
|
|
10683
|
+
const inputs = toUpsert.map((item) => {
|
|
10684
|
+
if (shouldStoreAsInverse) {
|
|
10685
|
+
return {
|
|
10686
|
+
fromObject: storageFromObject,
|
|
10687
|
+
fromId: item.id,
|
|
10688
|
+
fromAttribute: storageFromAttribute,
|
|
10689
|
+
toId: recordId,
|
|
10690
|
+
properties: _nullishCoalesce(item.props, () => ( {})),
|
|
10691
|
+
updatedBy: _nullishCoalesce(this.userId, () => ( void 0)),
|
|
10692
|
+
createdBy: _nullishCoalesce(this.userId, () => ( void 0))
|
|
10693
|
+
};
|
|
10694
|
+
}
|
|
10695
|
+
return {
|
|
10696
|
+
fromObject: schema.name,
|
|
10697
|
+
fromId: recordId,
|
|
10698
|
+
fromAttribute: attributeName,
|
|
10699
|
+
toId: item.id,
|
|
10700
|
+
properties: _nullishCoalesce(item.props, () => ( {})),
|
|
10701
|
+
updatedBy: _nullishCoalesce(this.userId, () => ( void 0)),
|
|
10702
|
+
createdBy: _nullishCoalesce(this.userId, () => ( void 0))
|
|
10703
|
+
};
|
|
10704
|
+
});
|
|
10705
|
+
await adapter.relationAttributes.upsertBatch(inputs);
|
|
10706
|
+
}
|
|
10707
|
+
}
|
|
10708
|
+
/**
|
|
10709
|
+
* Validate relation properties against PropertySchema.
|
|
10710
|
+
*
|
|
10711
|
+
* Uses Zod for runtime validation based on PropertyAttribute types.
|
|
10712
|
+
*
|
|
10713
|
+
* @param propertySchema - Schema defining allowed properties
|
|
10714
|
+
* @param properties - Properties to validate
|
|
10715
|
+
* @throws {z.ZodError} if validation fails
|
|
10716
|
+
*/
|
|
10717
|
+
validateProperties(propertySchema, properties) {
|
|
10718
|
+
const schema = this.buildZodSchema(propertySchema);
|
|
10719
|
+
schema.parse(properties);
|
|
10720
|
+
}
|
|
10721
|
+
// ============================================================================
|
|
10722
|
+
// PRIVATE HELPERS
|
|
10723
|
+
// ============================================================================
|
|
10724
|
+
/**
|
|
10725
|
+
* Get PropertySchema for a relation attribute.
|
|
10726
|
+
*
|
|
10727
|
+
* For bilateral relations without .qualifyWith(), returns undefined.
|
|
10728
|
+
* Properties will be stored/retrieved but not validated on the inverse side.
|
|
10729
|
+
*/
|
|
10730
|
+
getPropertySchema(attribute) {
|
|
10731
|
+
return attribute.properties;
|
|
10732
|
+
}
|
|
10733
|
+
/**
|
|
10734
|
+
* Normalize relation value to unified internal format.
|
|
10735
|
+
*
|
|
10736
|
+
* Converts:
|
|
10737
|
+
* - string[] → Array<{ id, props?: undefined }>
|
|
10738
|
+
* - string → [{ id, props?: undefined }]
|
|
10739
|
+
* - null → []
|
|
10740
|
+
* - Array<{ id, props }> → Array<{ id, props }> (passthrough)
|
|
10741
|
+
* - { id, props } → [{ id, props }] (single to array)
|
|
10742
|
+
*/
|
|
10743
|
+
normalizeRelationValue(value) {
|
|
10744
|
+
if (value === null || value === void 0) {
|
|
10745
|
+
return [];
|
|
10746
|
+
}
|
|
10747
|
+
if (typeof value === "string") {
|
|
10748
|
+
return [{ id: value }];
|
|
10749
|
+
}
|
|
10750
|
+
if (!Array.isArray(value) && typeof value === "object" && "id" in value) {
|
|
10751
|
+
return [value];
|
|
10752
|
+
}
|
|
10753
|
+
if (Array.isArray(value)) {
|
|
10754
|
+
return value.map((item) => {
|
|
10755
|
+
if (typeof item === "string") {
|
|
10756
|
+
return { id: item };
|
|
10757
|
+
}
|
|
10758
|
+
return item;
|
|
10759
|
+
});
|
|
10302
10760
|
}
|
|
10303
|
-
|
|
10761
|
+
return [];
|
|
10762
|
+
}
|
|
10763
|
+
/**
|
|
10764
|
+
* Build Zod schema from PropertySchema definition.
|
|
10765
|
+
*
|
|
10766
|
+
* Reuses createFormAttributeValidator() to avoid code duplication with validators.ts.
|
|
10767
|
+
* This validator handles null/undefined values correctly for optional fields.
|
|
10768
|
+
*/
|
|
10769
|
+
buildZodSchema(propertySchema) {
|
|
10770
|
+
const shape = {};
|
|
10771
|
+
for (const def of propertySchema.definitions) {
|
|
10772
|
+
shape[def.name] = _chunkU4AB53AMjs.createFormAttributeValidator.call(void 0, def);
|
|
10773
|
+
}
|
|
10774
|
+
return _zod.z.object(shape);
|
|
10775
|
+
}
|
|
10776
|
+
};
|
|
10777
|
+
|
|
10778
|
+
// src/runtime/services/record/query.service.ts
|
|
10779
|
+
var RecordQueryService = class extends BaseService {
|
|
10780
|
+
constructor(adapter, schemaService, options) {
|
|
10781
|
+
super(adapter);
|
|
10782
|
+
this.schemaService = schemaService;
|
|
10783
|
+
this.options = options;
|
|
10784
|
+
this.policyRegistry = _optionalChain([options, 'optionalAccess', _201 => _201.policyRegistry]) === null ? null : _nullishCoalesce(_optionalChain([options, 'optionalAccess', _202 => _202.policyRegistry]), () => ( defaultPolicyRegistry));
|
|
10785
|
+
this.relationPropertiesService = new RelationPropertiesService(adapter);
|
|
10786
|
+
}
|
|
10787
|
+
// ============================================================================
|
|
10788
|
+
// LIST
|
|
10789
|
+
// ============================================================================
|
|
10790
|
+
/**
|
|
10791
|
+
* List records for an object with pagination, permissions, and policy filtering.
|
|
10792
|
+
*
|
|
10793
|
+
* @param objectId - Object UUID
|
|
10794
|
+
* @param options - Query options (pagination, filters, etc.)
|
|
10795
|
+
* @returns Records and total count
|
|
10796
|
+
*
|
|
10797
|
+
* @example
|
|
10798
|
+
* ```typescript
|
|
10799
|
+
* const { records, total } = await queryService.listRecords(objectId, {
|
|
10800
|
+
* limit: 20,
|
|
10801
|
+
* offset: 0,
|
|
10802
|
+
* filters: { status: "active" },
|
|
10803
|
+
* });
|
|
10804
|
+
* ```
|
|
10805
|
+
*/
|
|
10806
|
+
async listRecords(objectId, options) {
|
|
10807
|
+
const schema = await this.schemaService.getObjectSchema(objectId);
|
|
10808
|
+
return this.cachedList(
|
|
10809
|
+
"recordList",
|
|
10810
|
+
objectId,
|
|
10811
|
+
{ ...options, _userId: this.userId },
|
|
10812
|
+
() => this.executeListQuery(schema, objectId, options)
|
|
10813
|
+
);
|
|
10814
|
+
}
|
|
10815
|
+
/**
|
|
10816
|
+
* List records using a pre-fetched schema.
|
|
10817
|
+
* Useful when the caller already has the schema to avoid redundant lookups.
|
|
10818
|
+
*/
|
|
10819
|
+
async listRecordsWithSchema(schema, options) {
|
|
10820
|
+
if (!schema.id) {
|
|
10821
|
+
throw new Error("Schema must have an ID to list records");
|
|
10822
|
+
}
|
|
10823
|
+
const objectId = schema.id;
|
|
10824
|
+
return this.cachedList(
|
|
10825
|
+
"recordList",
|
|
10826
|
+
objectId,
|
|
10827
|
+
{ ...options, _userId: this.userId },
|
|
10828
|
+
() => this.executeListQuery(schema, objectId, options)
|
|
10829
|
+
);
|
|
10830
|
+
}
|
|
10831
|
+
/**
|
|
10832
|
+
* Internal list query execution
|
|
10833
|
+
*/
|
|
10834
|
+
async executeListQuery(schema, objectId, options) {
|
|
10835
|
+
if (_optionalChain([this, 'access', _203 => _203.options, 'optionalAccess', _204 => _204.permissionService]) && this.userId) {
|
|
10836
|
+
await checkPermission(this.options.permissionService, this.userId, schema.name, "read");
|
|
10837
|
+
}
|
|
10838
|
+
const policy = _optionalChain([options, 'optionalAccess', _205 => _205.skipPolicyFilter]) ? void 0 : getPolicy(this.policyRegistry, this.userId, schema.name);
|
|
10839
|
+
let effectiveOptions = options;
|
|
10840
|
+
if (_optionalChain([policy, 'optionalAccess', _206 => _206.applyListFilter]) && this.userId) {
|
|
10841
|
+
const ctx = buildPolicyContext(schema.name, this.userId, this.tenantId);
|
|
10842
|
+
effectiveOptions = policy.applyListFilter(ctx, options);
|
|
10843
|
+
}
|
|
10844
|
+
const result = await runWithSchemaContext(
|
|
10845
|
+
[schema],
|
|
10846
|
+
() => this.adapter.objectRecords.list(objectId, effectiveOptions)
|
|
10847
|
+
);
|
|
10848
|
+
let filteredRecords = result.records;
|
|
10849
|
+
let effectiveTotal = result.total;
|
|
10850
|
+
if (_optionalChain([policy, 'optionalAccess', _207 => _207.canAccessRecord]) && this.userId) {
|
|
10851
|
+
const ctx = buildPolicyContext(schema.name, this.userId, this.tenantId);
|
|
10852
|
+
const requestedLimit = _nullishCoalesce(_optionalChain([effectiveOptions, 'optionalAccess', _208 => _208.limit]), () => ( 20));
|
|
10853
|
+
const requestedOffset = _nullishCoalesce(_optionalChain([effectiveOptions, 'optionalAccess', _209 => _209.offset]), () => ( 0));
|
|
10854
|
+
const overfetchMultiplier = 5;
|
|
10855
|
+
const batchSize = requestedLimit * overfetchMultiplier;
|
|
10856
|
+
const maxScanRecords = 1e4;
|
|
10857
|
+
const collected = [];
|
|
10858
|
+
let dbOffset = 0;
|
|
10859
|
+
let totalScanned = 0;
|
|
10860
|
+
let exhausted = false;
|
|
10861
|
+
const target = requestedOffset + requestedLimit;
|
|
10862
|
+
while (collected.length < target && totalScanned < maxScanRecords) {
|
|
10863
|
+
const batch = await runWithSchemaContext(
|
|
10864
|
+
[schema],
|
|
10865
|
+
() => this.adapter.objectRecords.list(objectId, {
|
|
10866
|
+
...effectiveOptions,
|
|
10867
|
+
limit: batchSize,
|
|
10868
|
+
offset: dbOffset
|
|
10869
|
+
})
|
|
10870
|
+
);
|
|
10871
|
+
if (batch.records.length === 0) {
|
|
10872
|
+
exhausted = true;
|
|
10873
|
+
break;
|
|
10874
|
+
}
|
|
10875
|
+
const filtered = batch.records.filter((record) => _optionalChain([policy, 'access', _210 => _210.canAccessRecord, 'optionalCall', _211 => _211(ctx, record)]));
|
|
10876
|
+
collected.push(...filtered);
|
|
10877
|
+
dbOffset += batch.records.length;
|
|
10878
|
+
totalScanned += batch.records.length;
|
|
10879
|
+
if (batch.records.length < batchSize) {
|
|
10880
|
+
exhausted = true;
|
|
10881
|
+
break;
|
|
10882
|
+
}
|
|
10883
|
+
}
|
|
10884
|
+
effectiveTotal = exhausted ? collected.length : Math.max(collected.length, result.total);
|
|
10885
|
+
filteredRecords = collected.slice(requestedOffset, requestedOffset + requestedLimit);
|
|
10886
|
+
}
|
|
10887
|
+
filteredRecords = await this.relationPropertiesService.enrichRecordsBatch(
|
|
10888
|
+
filteredRecords,
|
|
10889
|
+
schema
|
|
10890
|
+
);
|
|
10891
|
+
if (!_optionalChain([options, 'optionalAccess', _212 => _212.skipFormulas])) {
|
|
10304
10892
|
return {
|
|
10305
10893
|
records: enrichRecordsWithFormulas(filteredRecords, schema),
|
|
10306
10894
|
total: effectiveTotal
|
|
@@ -10360,459 +10948,119 @@ var RecordQueryService = class extends BaseService {
|
|
|
10360
10948
|
* Internal search query execution
|
|
10361
10949
|
*/
|
|
10362
10950
|
async executeSearchQuery(schema, objectId, query, options) {
|
|
10363
|
-
if (_optionalChain([this, 'access',
|
|
10951
|
+
if (_optionalChain([this, 'access', _213 => _213.options, 'optionalAccess', _214 => _214.permissionService]) && this.userId) {
|
|
10364
10952
|
await checkPermission(this.options.permissionService, this.userId, schema.name, "read");
|
|
10365
10953
|
}
|
|
10366
10954
|
const result = await runWithSchemaContext(
|
|
10367
10955
|
[schema],
|
|
10368
10956
|
() => this.adapter.objectRecords.search(objectId, query, options)
|
|
10369
10957
|
);
|
|
10370
|
-
|
|
10958
|
+
const enrichedRecords = await this.relationPropertiesService.enrichRecordsBatch(
|
|
10959
|
+
result.records,
|
|
10960
|
+
schema
|
|
10961
|
+
);
|
|
10962
|
+
if (!_optionalChain([options, 'optionalAccess', _215 => _215.skipFormulas])) {
|
|
10371
10963
|
return {
|
|
10372
|
-
records: enrichRecordsWithFormulas(
|
|
10964
|
+
records: enrichRecordsWithFormulas(enrichedRecords, schema),
|
|
10373
10965
|
total: result.total
|
|
10374
10966
|
};
|
|
10375
10967
|
}
|
|
10376
|
-
return
|
|
10377
|
-
|
|
10378
|
-
|
|
10379
|
-
|
|
10380
|
-
|
|
10381
|
-
|
|
10382
|
-
|
|
10383
|
-
|
|
10384
|
-
|
|
10385
|
-
|
|
10386
|
-
|
|
10387
|
-
*
|
|
10388
|
-
* Uses batch loading to avoid N+1 queries.
|
|
10389
|
-
*
|
|
10390
|
-
* @param records - Records to enrich with relation properties
|
|
10391
|
-
* @param schema - Object schema
|
|
10392
|
-
* @param includes - Array of relation attribute names to include
|
|
10393
|
-
* @returns Records enriched with relation properties in hybrid format
|
|
10394
|
-
* @private
|
|
10395
|
-
*/
|
|
10396
|
-
async includeRelationsWithProperties(records, schema, includes) {
|
|
10397
|
-
if (records.length === 0 || includes.length === 0) {
|
|
10398
|
-
return records;
|
|
10399
|
-
}
|
|
10400
|
-
for (const includeName of includes) {
|
|
10401
|
-
const attr = schema.attributes.find((a) => a.name === includeName);
|
|
10402
|
-
if (!attr || attr.type !== "relation") {
|
|
10403
|
-
continue;
|
|
10404
|
-
}
|
|
10405
|
-
if (attr.properties && this.adapter.relationAttributes) {
|
|
10406
|
-
const recordIds = records.map((r) => r.id);
|
|
10407
|
-
const relationAttributesRepo = this.adapter.relationAttributes;
|
|
10408
|
-
const allRelationProps = await Promise.all(
|
|
10409
|
-
recordIds.map(
|
|
10410
|
-
(recordId) => relationAttributesRepo.findBySource(schema.name, recordId, includeName)
|
|
10411
|
-
)
|
|
10412
|
-
);
|
|
10413
|
-
const propsByRecord = /* @__PURE__ */ new Map();
|
|
10414
|
-
allRelationProps.forEach((props, index) => {
|
|
10415
|
-
const recordId = recordIds[index];
|
|
10416
|
-
const propsMap = /* @__PURE__ */ new Map();
|
|
10417
|
-
for (const prop of props) {
|
|
10418
|
-
propsMap.set(prop.toId, prop.properties);
|
|
10419
|
-
}
|
|
10420
|
-
propsByRecord.set(recordId, propsMap);
|
|
10421
|
-
});
|
|
10422
|
-
for (const record of records) {
|
|
10423
|
-
const currentValue = record.values[includeName];
|
|
10424
|
-
const propsMap = propsByRecord.get(record.id);
|
|
10425
|
-
if (!currentValue) {
|
|
10426
|
-
continue;
|
|
10427
|
-
}
|
|
10428
|
-
if (!propsMap) {
|
|
10429
|
-
continue;
|
|
10430
|
-
}
|
|
10431
|
-
if (attr.cardinality === "many" && Array.isArray(currentValue)) {
|
|
10432
|
-
record.values[includeName] = currentValue.map((id) => {
|
|
10433
|
-
if (typeof id === "string") {
|
|
10434
|
-
const props = propsMap.get(id);
|
|
10435
|
-
return props ? { id, props } : { id };
|
|
10436
|
-
}
|
|
10437
|
-
return id;
|
|
10438
|
-
});
|
|
10439
|
-
} else if (attr.cardinality === "one") {
|
|
10440
|
-
const id = typeof currentValue === "string" ? currentValue : null;
|
|
10441
|
-
if (id) {
|
|
10442
|
-
const props = propsMap.get(id);
|
|
10443
|
-
record.values[includeName] = props ? { id, props } : { id };
|
|
10444
|
-
}
|
|
10445
|
-
}
|
|
10446
|
-
}
|
|
10447
|
-
}
|
|
10448
|
-
}
|
|
10449
|
-
return records;
|
|
10450
|
-
}
|
|
10451
|
-
};
|
|
10452
|
-
|
|
10453
|
-
// src/runtime/services/record/record-resolver.service.ts
|
|
10454
|
-
var RecordResolverService = class extends BaseService {
|
|
10455
|
-
constructor(adapter) {
|
|
10456
|
-
super(adapter);
|
|
10457
|
-
}
|
|
10458
|
-
// ============================================================================
|
|
10459
|
-
// CACHED RECORD ACCESS
|
|
10460
|
-
// ============================================================================
|
|
10461
|
-
/**
|
|
10462
|
-
* Find a record by ID with caching.
|
|
10463
|
-
*
|
|
10464
|
-
* Uses the shared record cache for optimal performance.
|
|
10465
|
-
* Delegates to findByIds for consistent cache handling.
|
|
10466
|
-
*
|
|
10467
|
-
* @param id - Record ID
|
|
10468
|
-
* @returns Record or null if not found
|
|
10469
|
-
*/
|
|
10470
|
-
async findById(id) {
|
|
10471
|
-
if (!id) return null;
|
|
10472
|
-
const results = await this.findByIds([id]);
|
|
10473
|
-
return _nullishCoalesce(results[0], () => ( null));
|
|
10474
|
-
}
|
|
10475
|
-
/**
|
|
10476
|
-
* Find multiple records by IDs with caching.
|
|
10477
|
-
*
|
|
10478
|
-
* Each record is cached individually for reuse across services.
|
|
10479
|
-
* Only fetches records not already in cache.
|
|
10480
|
-
*
|
|
10481
|
-
* @param ids - Record IDs to fetch
|
|
10482
|
-
* @returns Array of found records (missing IDs are not included)
|
|
10483
|
-
*/
|
|
10484
|
-
async findByIds(ids) {
|
|
10485
|
-
if (!ids || ids.length === 0) {
|
|
10486
|
-
return [];
|
|
10487
|
-
}
|
|
10488
|
-
const uniqueIds = [...new Set(ids)];
|
|
10489
|
-
return this.cachedByMany(
|
|
10490
|
-
"record",
|
|
10491
|
-
uniqueIds,
|
|
10492
|
-
(missingIds) => this.adapter.objectRecords.findByIds(missingIds),
|
|
10493
|
-
(record) => record.id,
|
|
10494
|
-
cacheTtl.records
|
|
10495
|
-
);
|
|
10496
|
-
}
|
|
10497
|
-
// ============================================================================
|
|
10498
|
-
// FACTORY METHODS
|
|
10499
|
-
// ============================================================================
|
|
10500
|
-
/**
|
|
10501
|
-
* Create a RelationLabelResolver callback for computeLabelWithRelations.
|
|
10502
|
-
*
|
|
10503
|
-
* Used by RelationService.resolveLabel() and ObjectSchemaService.
|
|
10504
|
-
*
|
|
10505
|
-
* @returns Callback that resolves record IDs to their labels (cached)
|
|
10506
|
-
*/
|
|
10507
|
-
createRelationLabelResolver() {
|
|
10508
|
-
return async (ids) => {
|
|
10509
|
-
const records = await this.findByIds(ids);
|
|
10510
|
-
return new Map(records.map((r) => [r.id, r.label]));
|
|
10511
|
-
};
|
|
10512
|
-
}
|
|
10513
|
-
/**
|
|
10514
|
-
* Create a LabelResolver interface for label computation helpers.
|
|
10515
|
-
*
|
|
10516
|
-
* Used by RecordService for computing record labels.
|
|
10517
|
-
*
|
|
10518
|
-
* @param relationService - RelationService for resolving relation display labels
|
|
10519
|
-
* @returns LabelResolver interface with cached record fetching
|
|
10520
|
-
*/
|
|
10521
|
-
createLabelResolver(relationService) {
|
|
10522
|
-
return {
|
|
10523
|
-
resolveRelationIds: (ids, attrId) => relationService.resolveIds(ids, attrId),
|
|
10524
|
-
findRecordLabels: (ids) => this.findByIds(ids)
|
|
10525
|
-
};
|
|
10526
|
-
}
|
|
10527
|
-
/**
|
|
10528
|
-
* Create a RollupCascadeContext for rollup recalculation.
|
|
10529
|
-
*
|
|
10530
|
-
* Used by RecordService after create/update/delete operations.
|
|
10531
|
-
*
|
|
10532
|
-
* @param rollupService - RollupService for recalculating rollups
|
|
10533
|
-
* @param schemaService - ObjectSchemaService for fetching schemas
|
|
10534
|
-
* @returns Context with cached record fetching
|
|
10535
|
-
*/
|
|
10536
|
-
createRollupContext(rollupService, schemaService) {
|
|
10537
|
-
return {
|
|
10538
|
-
rollupService,
|
|
10539
|
-
schemaService,
|
|
10540
|
-
findRecordsByIds: (ids) => this.findByIds(ids)
|
|
10541
|
-
};
|
|
10542
|
-
}
|
|
10543
|
-
};
|
|
10544
|
-
|
|
10545
|
-
// src/runtime/services/record/relation-properties.service.ts
|
|
10546
|
-
|
|
10547
|
-
var RelationPropertiesService = class extends BaseService {
|
|
10548
|
-
constructor(adapter) {
|
|
10549
|
-
super(adapter);
|
|
10550
|
-
}
|
|
10551
|
-
// ============================================================================
|
|
10552
|
-
// PUBLIC API
|
|
10553
|
-
// ============================================================================
|
|
10554
|
-
/**
|
|
10555
|
-
* Normalize relation values for storage in object_records table.
|
|
10556
|
-
*
|
|
10557
|
-
* Extracts IDs from hybrid format ({ id, props }) and returns legacy format (string[] or string).
|
|
10558
|
-
* This ensures object_records.values only contains IDs, while properties are in relation_attributes.
|
|
10559
|
-
*
|
|
10560
|
-
* @param schema - Object schema
|
|
10561
|
-
* @param data - Record data with hybrid relation values
|
|
10562
|
-
* @returns Data with relation values normalized to ID-only format
|
|
10563
|
-
*/
|
|
10564
|
-
normalizeRelationValuesForStorage(schema, data) {
|
|
10565
|
-
const normalized = { ...data };
|
|
10566
|
-
for (const attr of schema.attributes) {
|
|
10567
|
-
if (attr.type !== "relation" || !attr.properties) {
|
|
10568
|
-
continue;
|
|
10569
|
-
}
|
|
10570
|
-
const value = data[attr.name];
|
|
10571
|
-
if (value === null || value === void 0) {
|
|
10572
|
-
continue;
|
|
10573
|
-
}
|
|
10574
|
-
if (attr.cardinality === "many" && Array.isArray(value)) {
|
|
10575
|
-
normalized[attr.name] = value.map((item) => {
|
|
10576
|
-
if (typeof item === "string") return item;
|
|
10577
|
-
if (typeof item === "object" && item !== null && "id" in item) {
|
|
10578
|
-
return item.id;
|
|
10579
|
-
}
|
|
10580
|
-
return item;
|
|
10581
|
-
});
|
|
10582
|
-
} else if (typeof value === "object" && value !== null && "id" in value) {
|
|
10583
|
-
normalized[attr.name] = value.id;
|
|
10584
|
-
}
|
|
10585
|
-
}
|
|
10586
|
-
return normalized;
|
|
10968
|
+
return {
|
|
10969
|
+
records: enrichedRecords,
|
|
10970
|
+
total: result.total
|
|
10971
|
+
};
|
|
10972
|
+
}
|
|
10973
|
+
};
|
|
10974
|
+
|
|
10975
|
+
// src/runtime/services/record/record-resolver.service.ts
|
|
10976
|
+
var RecordResolverService = class extends BaseService {
|
|
10977
|
+
constructor(adapter) {
|
|
10978
|
+
super(adapter);
|
|
10587
10979
|
}
|
|
10980
|
+
// ============================================================================
|
|
10981
|
+
// CACHED RECORD ACCESS
|
|
10982
|
+
// ============================================================================
|
|
10588
10983
|
/**
|
|
10589
|
-
*
|
|
10984
|
+
* Find a record by ID with caching.
|
|
10590
10985
|
*
|
|
10591
|
-
*
|
|
10592
|
-
*
|
|
10593
|
-
* - Validation of properties
|
|
10594
|
-
* - Upsert for present IDs
|
|
10595
|
-
* - Delete for absent IDs
|
|
10986
|
+
* Uses the shared record cache for optimal performance.
|
|
10987
|
+
* Delegates to findByIds for consistent cache handling.
|
|
10596
10988
|
*
|
|
10597
|
-
* @param
|
|
10598
|
-
* @
|
|
10599
|
-
* @param attributeName - Relation attribute name
|
|
10600
|
-
* @param relationValue - Relation value (hybrid format)
|
|
10601
|
-
* @param adapter - Database adapter
|
|
10989
|
+
* @param id - Record ID
|
|
10990
|
+
* @returns Record or null if not found
|
|
10602
10991
|
*/
|
|
10603
|
-
async
|
|
10604
|
-
|
|
10605
|
-
|
|
10606
|
-
|
|
10607
|
-
}
|
|
10608
|
-
if (!attribute.properties) {
|
|
10609
|
-
return;
|
|
10610
|
-
}
|
|
10611
|
-
const normalized = this.normalizeRelationValue(relationValue);
|
|
10612
|
-
for (const item of normalized) {
|
|
10613
|
-
if (item.props) {
|
|
10614
|
-
this.validateProperties(attribute.properties, item.props);
|
|
10615
|
-
}
|
|
10616
|
-
}
|
|
10617
|
-
const existing = await _optionalChain([adapter, 'access', _208 => _208.relationAttributes, 'optionalAccess', _209 => _209.findBySource, 'call', _210 => _210(
|
|
10618
|
-
schema.name,
|
|
10619
|
-
recordId,
|
|
10620
|
-
attributeName
|
|
10621
|
-
)]);
|
|
10622
|
-
const existingIds = new Set((_nullishCoalesce(existing, () => ( []))).map((r) => r.toId));
|
|
10623
|
-
const newIds = new Set(normalized.map((item) => item.id));
|
|
10624
|
-
const toUpsert = normalized.filter((item) => item.props !== void 0);
|
|
10625
|
-
const toDelete = Array.from(existingIds).filter((id) => !newIds.has(id));
|
|
10626
|
-
if (toUpsert.length > 0 && adapter.relationAttributes) {
|
|
10627
|
-
const inputs = toUpsert.map((item) => ({
|
|
10628
|
-
fromObject: schema.name,
|
|
10629
|
-
fromId: recordId,
|
|
10630
|
-
fromAttribute: attributeName,
|
|
10631
|
-
toId: item.id,
|
|
10632
|
-
properties: _nullishCoalesce(item.props, () => ( {})),
|
|
10633
|
-
updatedBy: _nullishCoalesce(this.userId, () => ( void 0)),
|
|
10634
|
-
createdBy: _nullishCoalesce(this.userId, () => ( void 0))
|
|
10635
|
-
}));
|
|
10636
|
-
await adapter.relationAttributes.upsertBatch(inputs);
|
|
10637
|
-
}
|
|
10638
|
-
if (toDelete.length > 0 && adapter.relationAttributes && existing) {
|
|
10639
|
-
for (const toId of toDelete) {
|
|
10640
|
-
const relation2 = existing.find((r) => r.toId === toId);
|
|
10641
|
-
if (relation2) {
|
|
10642
|
-
}
|
|
10643
|
-
}
|
|
10644
|
-
await adapter.relationAttributes.deleteBySource(schema.name, recordId, attributeName);
|
|
10645
|
-
if (toUpsert.length > 0) {
|
|
10646
|
-
const inputs = toUpsert.map((item) => ({
|
|
10647
|
-
fromObject: schema.name,
|
|
10648
|
-
fromId: recordId,
|
|
10649
|
-
fromAttribute: attributeName,
|
|
10650
|
-
toId: item.id,
|
|
10651
|
-
properties: _nullishCoalesce(item.props, () => ( {})),
|
|
10652
|
-
updatedBy: _nullishCoalesce(this.userId, () => ( void 0)),
|
|
10653
|
-
createdBy: _nullishCoalesce(this.userId, () => ( void 0))
|
|
10654
|
-
}));
|
|
10655
|
-
await adapter.relationAttributes.upsertBatch(inputs);
|
|
10656
|
-
}
|
|
10657
|
-
}
|
|
10992
|
+
async findById(id) {
|
|
10993
|
+
if (!id) return null;
|
|
10994
|
+
const results = await this.findByIds([id]);
|
|
10995
|
+
return _nullishCoalesce(results[0], () => ( null));
|
|
10658
10996
|
}
|
|
10659
10997
|
/**
|
|
10660
|
-
*
|
|
10998
|
+
* Find multiple records by IDs with caching.
|
|
10661
10999
|
*
|
|
10662
|
-
*
|
|
11000
|
+
* Each record is cached individually for reuse across services.
|
|
11001
|
+
* Only fetches records not already in cache.
|
|
10663
11002
|
*
|
|
10664
|
-
* @param
|
|
10665
|
-
* @
|
|
10666
|
-
* @throws {z.ZodError} if validation fails
|
|
11003
|
+
* @param ids - Record IDs to fetch
|
|
11004
|
+
* @returns Array of found records (missing IDs are not included)
|
|
10667
11005
|
*/
|
|
10668
|
-
|
|
10669
|
-
|
|
10670
|
-
|
|
11006
|
+
async findByIds(ids) {
|
|
11007
|
+
if (!ids || ids.length === 0) {
|
|
11008
|
+
return [];
|
|
11009
|
+
}
|
|
11010
|
+
const uniqueIds = [...new Set(ids)];
|
|
11011
|
+
return this.cachedByMany(
|
|
11012
|
+
"record",
|
|
11013
|
+
uniqueIds,
|
|
11014
|
+
(missingIds) => this.adapter.objectRecords.findByIds(missingIds),
|
|
11015
|
+
(record) => record.id,
|
|
11016
|
+
cacheTtl.records
|
|
11017
|
+
);
|
|
10671
11018
|
}
|
|
10672
11019
|
// ============================================================================
|
|
10673
|
-
//
|
|
11020
|
+
// FACTORY METHODS
|
|
10674
11021
|
// ============================================================================
|
|
10675
11022
|
/**
|
|
10676
|
-
*
|
|
11023
|
+
* Create a RelationLabelResolver callback for computeLabelWithRelations.
|
|
10677
11024
|
*
|
|
10678
|
-
*
|
|
10679
|
-
* - string[] → Array<{ id, props?: undefined }>
|
|
10680
|
-
* - string → [{ id, props?: undefined }]
|
|
10681
|
-
* - null → []
|
|
10682
|
-
* - Array<{ id, props }> → Array<{ id, props }> (passthrough)
|
|
10683
|
-
* - { id, props } → [{ id, props }] (single to array)
|
|
11025
|
+
* Used by RelationService.resolveLabel() and ObjectSchemaService.
|
|
10684
11026
|
*
|
|
10685
|
-
* @
|
|
10686
|
-
* @returns Normalized array of relation items
|
|
10687
|
-
* @private
|
|
11027
|
+
* @returns Callback that resolves record IDs to their labels (cached)
|
|
10688
11028
|
*/
|
|
10689
|
-
|
|
10690
|
-
|
|
10691
|
-
|
|
10692
|
-
|
|
10693
|
-
|
|
10694
|
-
return [{ id: value }];
|
|
10695
|
-
}
|
|
10696
|
-
if (!Array.isArray(value) && typeof value === "object" && "id" in value) {
|
|
10697
|
-
return [value];
|
|
10698
|
-
}
|
|
10699
|
-
if (Array.isArray(value)) {
|
|
10700
|
-
return value.map((item) => {
|
|
10701
|
-
if (typeof item === "string") {
|
|
10702
|
-
return { id: item };
|
|
10703
|
-
}
|
|
10704
|
-
return item;
|
|
10705
|
-
});
|
|
10706
|
-
}
|
|
10707
|
-
return [];
|
|
11029
|
+
createRelationLabelResolver() {
|
|
11030
|
+
return async (ids) => {
|
|
11031
|
+
const records = await this.findByIds(ids);
|
|
11032
|
+
return new Map(records.map((r) => [r.id, r.label]));
|
|
11033
|
+
};
|
|
10708
11034
|
}
|
|
10709
11035
|
/**
|
|
10710
|
-
*
|
|
11036
|
+
* Create a LabelResolver interface for label computation helpers.
|
|
10711
11037
|
*
|
|
10712
|
-
*
|
|
11038
|
+
* Used by RecordService for computing record labels.
|
|
10713
11039
|
*
|
|
10714
|
-
* @param
|
|
10715
|
-
* @returns
|
|
10716
|
-
* @private
|
|
11040
|
+
* @param relationService - RelationService for resolving relation display labels
|
|
11041
|
+
* @returns LabelResolver interface with cached record fetching
|
|
10717
11042
|
*/
|
|
10718
|
-
|
|
10719
|
-
|
|
10720
|
-
|
|
10721
|
-
|
|
10722
|
-
|
|
10723
|
-
fieldSchema = fieldSchema.optional();
|
|
10724
|
-
}
|
|
10725
|
-
shape[def.name] = fieldSchema;
|
|
10726
|
-
}
|
|
10727
|
-
return _zod.z.object(shape);
|
|
11043
|
+
createLabelResolver(relationService) {
|
|
11044
|
+
return {
|
|
11045
|
+
resolveRelationIds: (ids, attrId) => relationService.resolveIds(ids, attrId),
|
|
11046
|
+
findRecordLabels: (ids) => this.findByIds(ids)
|
|
11047
|
+
};
|
|
10728
11048
|
}
|
|
10729
11049
|
/**
|
|
10730
|
-
*
|
|
11050
|
+
* Create a RollupCascadeContext for rollup recalculation.
|
|
10731
11051
|
*
|
|
10732
|
-
*
|
|
10733
|
-
*
|
|
10734
|
-
* @
|
|
11052
|
+
* Used by RecordService after create/update/delete operations.
|
|
11053
|
+
*
|
|
11054
|
+
* @param rollupService - RollupService for recalculating rollups
|
|
11055
|
+
* @param schemaService - ObjectSchemaService for fetching schemas
|
|
11056
|
+
* @returns Context with cached record fetching
|
|
10735
11057
|
*/
|
|
10736
|
-
|
|
10737
|
-
|
|
10738
|
-
|
|
10739
|
-
|
|
10740
|
-
|
|
10741
|
-
|
|
10742
|
-
schema = schema.min(def.minLength);
|
|
10743
|
-
}
|
|
10744
|
-
if (def.maxLength !== void 0) {
|
|
10745
|
-
schema = schema.max(def.maxLength);
|
|
10746
|
-
}
|
|
10747
|
-
if (def.type === "text" && def.pattern) {
|
|
10748
|
-
schema = schema.regex(new RegExp(def.pattern));
|
|
10749
|
-
}
|
|
10750
|
-
return schema;
|
|
10751
|
-
}
|
|
10752
|
-
case "number": {
|
|
10753
|
-
let schema = _zod.z.number();
|
|
10754
|
-
if (def.min !== void 0) {
|
|
10755
|
-
schema = schema.min(def.min);
|
|
10756
|
-
}
|
|
10757
|
-
if (def.max !== void 0) {
|
|
10758
|
-
schema = schema.max(def.max);
|
|
10759
|
-
}
|
|
10760
|
-
if (def.integer) {
|
|
10761
|
-
schema = schema.int();
|
|
10762
|
-
}
|
|
10763
|
-
return schema;
|
|
10764
|
-
}
|
|
10765
|
-
case "checkbox": {
|
|
10766
|
-
return _zod.z.boolean();
|
|
10767
|
-
}
|
|
10768
|
-
case "date": {
|
|
10769
|
-
const schema = _zod.z.string().datetime();
|
|
10770
|
-
return schema;
|
|
10771
|
-
}
|
|
10772
|
-
case "phone": {
|
|
10773
|
-
return _zod.z.string();
|
|
10774
|
-
}
|
|
10775
|
-
case "currency": {
|
|
10776
|
-
let schema = _zod.z.number();
|
|
10777
|
-
if (def.min !== void 0) {
|
|
10778
|
-
schema = schema.min(def.min);
|
|
10779
|
-
}
|
|
10780
|
-
if (def.max !== void 0) {
|
|
10781
|
-
schema = schema.max(def.max);
|
|
10782
|
-
}
|
|
10783
|
-
return schema;
|
|
10784
|
-
}
|
|
10785
|
-
case "status":
|
|
10786
|
-
case "select": {
|
|
10787
|
-
const validValues = def.options.map((opt) => opt.value);
|
|
10788
|
-
return _zod.z.enum(validValues);
|
|
10789
|
-
}
|
|
10790
|
-
case "multiselect": {
|
|
10791
|
-
const validValues = def.options.map((opt) => opt.value);
|
|
10792
|
-
let schema = _zod.z.array(_zod.z.enum(validValues));
|
|
10793
|
-
if (def.maxSelections !== void 0) {
|
|
10794
|
-
schema = schema.max(def.maxSelections);
|
|
10795
|
-
}
|
|
10796
|
-
return schema;
|
|
10797
|
-
}
|
|
10798
|
-
case "rating": {
|
|
10799
|
-
let schema = _zod.z.number().int();
|
|
10800
|
-
if (def.max !== void 0) {
|
|
10801
|
-
schema = schema.max(def.max);
|
|
10802
|
-
}
|
|
10803
|
-
return schema.min(0);
|
|
10804
|
-
}
|
|
10805
|
-
case "location": {
|
|
10806
|
-
return _zod.z.object({
|
|
10807
|
-
address: _zod.z.string().optional(),
|
|
10808
|
-
lat: _zod.z.number().optional(),
|
|
10809
|
-
lng: _zod.z.number().optional()
|
|
10810
|
-
});
|
|
10811
|
-
}
|
|
10812
|
-
default: {
|
|
10813
|
-
return _zod.z.unknown();
|
|
10814
|
-
}
|
|
10815
|
-
}
|
|
11058
|
+
createRollupContext(rollupService, schemaService) {
|
|
11059
|
+
return {
|
|
11060
|
+
rollupService,
|
|
11061
|
+
schemaService,
|
|
11062
|
+
findRecordsByIds: (ids) => this.findByIds(ids)
|
|
11063
|
+
};
|
|
10816
11064
|
}
|
|
10817
11065
|
};
|
|
10818
11066
|
|
|
@@ -10823,6 +11071,7 @@ var RelationService = class extends BaseService {
|
|
|
10823
11071
|
this.schemaService = new ObjectSchemaService(adapter, nativeRegistry);
|
|
10824
11072
|
this.queryService = options.queryService;
|
|
10825
11073
|
this.recordResolver = options.recordResolver;
|
|
11074
|
+
this.relationPropertiesService = options.relationPropertiesService;
|
|
10826
11075
|
}
|
|
10827
11076
|
/**
|
|
10828
11077
|
* Set the query service after construction.
|
|
@@ -10893,7 +11142,7 @@ var RelationService = class extends BaseService {
|
|
|
10893
11142
|
}
|
|
10894
11143
|
const isUniversal = attr.targets.length === 1 && attr.targets[0].object === RELATION_TARGET_ANY;
|
|
10895
11144
|
const validObjectIds = isUniversal ? null : await this.getValidObjectIds(attr.targets);
|
|
10896
|
-
if (!isUniversal && _optionalChain([validObjectIds, 'optionalAccess',
|
|
11145
|
+
if (!isUniversal && _optionalChain([validObjectIds, 'optionalAccess', _216 => _216.size]) === 0) {
|
|
10897
11146
|
errors.push({
|
|
10898
11147
|
attribute: attr.name,
|
|
10899
11148
|
message: `No valid target objects found for ${attr.label}`
|
|
@@ -10946,10 +11195,10 @@ var RelationService = class extends BaseService {
|
|
|
10946
11195
|
for (const target of targets) {
|
|
10947
11196
|
try {
|
|
10948
11197
|
const objectSchema = await this.schemaService.getObjectSchemaByName(target.object);
|
|
10949
|
-
if (_optionalChain([objectSchema, 'optionalAccess',
|
|
11198
|
+
if (_optionalChain([objectSchema, 'optionalAccess', _217 => _217.id])) {
|
|
10950
11199
|
objectIds.add(objectSchema.id);
|
|
10951
11200
|
}
|
|
10952
|
-
} catch (
|
|
11201
|
+
} catch (e15) {
|
|
10953
11202
|
}
|
|
10954
11203
|
}
|
|
10955
11204
|
return objectIds;
|
|
@@ -11015,7 +11264,7 @@ var RelationService = class extends BaseService {
|
|
|
11015
11264
|
const targetResults = await Promise.all(
|
|
11016
11265
|
filteredTargets.map(async (target) => {
|
|
11017
11266
|
const objectSchema = await this.schemaService.getObjectSchemaByName(target.object);
|
|
11018
|
-
if (!_optionalChain([objectSchema, 'optionalAccess',
|
|
11267
|
+
if (!_optionalChain([objectSchema, 'optionalAccess', _218 => _218.id])) return { options: [], total: 0 };
|
|
11019
11268
|
const objectId = objectSchema.id;
|
|
11020
11269
|
const result = query ? await queryService.searchRecords(objectId, query, queryOptions) : await queryService.listRecords(objectId, queryOptions);
|
|
11021
11270
|
const options = await Promise.all(
|
|
@@ -11172,8 +11421,8 @@ var RelationService = class extends BaseService {
|
|
|
11172
11421
|
continue;
|
|
11173
11422
|
}
|
|
11174
11423
|
const attribute = attributeMap.get(attributeId);
|
|
11175
|
-
const targetConfig = _optionalChain([attribute, 'optionalAccess',
|
|
11176
|
-
const customTemplate = _optionalChain([targetConfig, 'optionalAccess',
|
|
11424
|
+
const targetConfig = _optionalChain([attribute, 'optionalAccess', _219 => _219.targets, 'optionalAccess', _220 => _220.find, 'call', _221 => _221((t) => t.object === objectSchema.name)]);
|
|
11425
|
+
const customTemplate = _optionalChain([targetConfig, 'optionalAccess', _222 => _222.displayTemplate]);
|
|
11177
11426
|
const label = await this.resolveLabel(record, objectSchema, customTemplate);
|
|
11178
11427
|
resolved.push({
|
|
11179
11428
|
_compositeId: compositeId,
|
|
@@ -11190,20 +11439,33 @@ var RelationService = class extends BaseService {
|
|
|
11190
11439
|
/**
|
|
11191
11440
|
* Resolve the display label for a record.
|
|
11192
11441
|
* Uses custom template if provided, otherwise falls back to pre-computed label.
|
|
11442
|
+
*
|
|
11443
|
+
* Preserves `{{ props.X }}` tokens for client-side substitution using a sentinel approach:
|
|
11444
|
+
* tokens are replaced with null-byte sentinels before template rendering, then restored after.
|
|
11445
|
+
* This lets `computeLabelWithRelations` resolve target fields while keeping prop placeholders intact.
|
|
11193
11446
|
*/
|
|
11194
11447
|
async resolveLabel(record, objectSchema, customTemplate) {
|
|
11195
|
-
if (customTemplate)
|
|
11196
|
-
|
|
11197
|
-
|
|
11198
|
-
|
|
11199
|
-
|
|
11200
|
-
|
|
11201
|
-
|
|
11202
|
-
|
|
11203
|
-
|
|
11204
|
-
|
|
11448
|
+
if (!customTemplate) return record.label;
|
|
11449
|
+
const preserved = [];
|
|
11450
|
+
let i = 0;
|
|
11451
|
+
const safeTemplate = customTemplate.replace(/\{\{\s*props\.\w+[^}]*\}\}/g, (match) => {
|
|
11452
|
+
const key = `\0PROP${i++}\0`;
|
|
11453
|
+
preserved.push([key, match]);
|
|
11454
|
+
return key;
|
|
11455
|
+
});
|
|
11456
|
+
let label = await computeLabelWithRelations(
|
|
11457
|
+
safeTemplate,
|
|
11458
|
+
record.values,
|
|
11459
|
+
objectSchema.attributes,
|
|
11460
|
+
async (nestedIds) => {
|
|
11461
|
+
const linkedRecords = await this.recordResolver.findByIds(nestedIds);
|
|
11462
|
+
return new Map(linkedRecords.map((r) => [r.id, r.label]));
|
|
11463
|
+
}
|
|
11464
|
+
);
|
|
11465
|
+
for (const [key, token] of preserved) {
|
|
11466
|
+
label = label.replace(key, token);
|
|
11205
11467
|
}
|
|
11206
|
-
return
|
|
11468
|
+
return label;
|
|
11207
11469
|
}
|
|
11208
11470
|
/**
|
|
11209
11471
|
* Find a relation attribute by ID.
|
|
@@ -11323,14 +11585,14 @@ var RollupService = class extends BaseService {
|
|
|
11323
11585
|
const sourceSchema = getSchemaByNameFromContext(sourceObjectName);
|
|
11324
11586
|
let sourceObjectId;
|
|
11325
11587
|
let reverseRelationAttrName;
|
|
11326
|
-
if (_optionalChain([sourceSchema, 'optionalAccess',
|
|
11588
|
+
if (_optionalChain([sourceSchema, 'optionalAccess', _223 => _223.id])) {
|
|
11327
11589
|
sourceObjectId = sourceSchema.id;
|
|
11328
11590
|
const reverseRelationAttr = sourceSchema.attributes.find((attr) => {
|
|
11329
11591
|
if (attr.type !== "relation") return false;
|
|
11330
11592
|
const relationConfig = attr;
|
|
11331
|
-
return _optionalChain([relationConfig, 'optionalAccess',
|
|
11593
|
+
return _optionalChain([relationConfig, 'optionalAccess', _224 => _224.targets, 'optionalAccess', _225 => _225.some, 'call', _226 => _226((t) => t.object === schema.name)]);
|
|
11332
11594
|
});
|
|
11333
|
-
reverseRelationAttrName = _optionalChain([reverseRelationAttr, 'optionalAccess',
|
|
11595
|
+
reverseRelationAttrName = _optionalChain([reverseRelationAttr, 'optionalAccess', _227 => _227.name]);
|
|
11334
11596
|
} else {
|
|
11335
11597
|
const sourceObject = await this.adapter.objects.findByName(sourceObjectName);
|
|
11336
11598
|
if (!sourceObject) {
|
|
@@ -11341,9 +11603,9 @@ var RollupService = class extends BaseService {
|
|
|
11341
11603
|
const reverseRelationAttr = sourceAttributes.find((attr) => {
|
|
11342
11604
|
if (attr.type !== "relation") return false;
|
|
11343
11605
|
const relationConfig = attr.config;
|
|
11344
|
-
return _optionalChain([relationConfig, 'optionalAccess',
|
|
11606
|
+
return _optionalChain([relationConfig, 'optionalAccess', _228 => _228.targets, 'optionalAccess', _229 => _229.some, 'call', _230 => _230((t) => t.object === schema.name)]);
|
|
11345
11607
|
});
|
|
11346
|
-
reverseRelationAttrName = _optionalChain([reverseRelationAttr, 'optionalAccess',
|
|
11608
|
+
reverseRelationAttrName = _optionalChain([reverseRelationAttr, 'optionalAccess', _231 => _231.name]);
|
|
11347
11609
|
}
|
|
11348
11610
|
if (!reverseRelationAttrName) {
|
|
11349
11611
|
return { value: null, recordCount: 0 };
|
|
@@ -11599,13 +11861,13 @@ var RollupService = class extends BaseService {
|
|
|
11599
11861
|
if (!obj) continue;
|
|
11600
11862
|
for (const rollupDbAttr of rollupAttrs) {
|
|
11601
11863
|
const rollupConfig = rollupDbAttr.config;
|
|
11602
|
-
if (!_optionalChain([rollupConfig, 'optionalAccess',
|
|
11864
|
+
if (!_optionalChain([rollupConfig, 'optionalAccess', _232 => _232.relationAttribute])) continue;
|
|
11603
11865
|
const relationAttr = attributes.find(
|
|
11604
11866
|
(a) => a.type === "relation" && a.name === rollupConfig.relationAttribute
|
|
11605
11867
|
);
|
|
11606
11868
|
if (!relationAttr) continue;
|
|
11607
11869
|
const relationConfig = relationAttr.config;
|
|
11608
|
-
const targetsChangedObject = _optionalChain([relationConfig, 'optionalAccess',
|
|
11870
|
+
const targetsChangedObject = _optionalChain([relationConfig, 'optionalAccess', _233 => _233.targets, 'optionalAccess', _234 => _234.some, 'call', _235 => _235(
|
|
11609
11871
|
(t) => t.object === changedSchema.name
|
|
11610
11872
|
)]);
|
|
11611
11873
|
if (!targetsChangedObject) continue;
|
|
@@ -11630,11 +11892,11 @@ var RecordService = class extends BaseService {
|
|
|
11630
11892
|
constructor(adapter, options) {
|
|
11631
11893
|
super(adapter);
|
|
11632
11894
|
this.schemaService = new ObjectSchemaService(adapter, registry, {
|
|
11633
|
-
auditService: _optionalChain([options, 'optionalAccess',
|
|
11895
|
+
auditService: _optionalChain([options, 'optionalAccess', _236 => _236.auditService])
|
|
11634
11896
|
});
|
|
11635
|
-
this.permissionService = _optionalChain([options, 'optionalAccess',
|
|
11636
|
-
this.auditService = _nullishCoalesce(_optionalChain([options, 'optionalAccess',
|
|
11637
|
-
this.policyRegistry = _optionalChain([options, 'optionalAccess',
|
|
11897
|
+
this.permissionService = _optionalChain([options, 'optionalAccess', _237 => _237.permissionService]);
|
|
11898
|
+
this.auditService = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _238 => _238.auditService]), () => ( (adapter.audit ? new AuditService(adapter) : void 0)));
|
|
11899
|
+
this.policyRegistry = _optionalChain([options, 'optionalAccess', _239 => _239.policyRegistry]) === null ? null : _nullishCoalesce(_optionalChain([options, 'optionalAccess', _240 => _240.policyRegistry]), () => ( defaultPolicyRegistry));
|
|
11638
11900
|
this.recordResolver = new RecordResolverService(adapter);
|
|
11639
11901
|
this.queryService = new RecordQueryService(adapter, this.schemaService, {
|
|
11640
11902
|
permissionService: this.permissionService,
|
|
@@ -11649,7 +11911,12 @@ var RecordService = class extends BaseService {
|
|
|
11649
11911
|
recordResolver: this.recordResolver
|
|
11650
11912
|
});
|
|
11651
11913
|
this.userService = new UserService(adapter);
|
|
11652
|
-
this.hookRegistry = _nullishCoalesce(_optionalChain([options, 'optionalAccess',
|
|
11914
|
+
this.hookRegistry = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _241 => _241.hookRegistry]), () => ( new NoopHookRegistry()));
|
|
11915
|
+
this.bilateralSyncService = new BilateralSyncService(
|
|
11916
|
+
adapter,
|
|
11917
|
+
this.schemaService,
|
|
11918
|
+
this.relationPropertiesService
|
|
11919
|
+
);
|
|
11653
11920
|
this.labelResolver = this.recordResolver.createLabelResolver(this.relationService);
|
|
11654
11921
|
this.rollupContext = this.recordResolver.createRollupContext(
|
|
11655
11922
|
this.rollupService,
|
|
@@ -11684,25 +11951,25 @@ var RecordService = class extends BaseService {
|
|
|
11684
11951
|
schema,
|
|
11685
11952
|
this.tenantId,
|
|
11686
11953
|
dataWithDefaults,
|
|
11687
|
-
_optionalChain([options, 'optionalAccess',
|
|
11954
|
+
_optionalChain([options, 'optionalAccess', _242 => _242.hookMetadata])
|
|
11688
11955
|
);
|
|
11689
|
-
if (!_optionalChain([options, 'optionalAccess',
|
|
11956
|
+
if (!_optionalChain([options, 'optionalAccess', _243 => _243.skipHooks])) {
|
|
11690
11957
|
await this.hookRegistry.execute("beforeCreate", schema.name, hookCtx);
|
|
11691
11958
|
}
|
|
11692
11959
|
const normalizedData = this.relationPropertiesService.normalizeRelationValuesForStorage(
|
|
11693
11960
|
schema,
|
|
11694
11961
|
dataWithDefaults
|
|
11695
11962
|
);
|
|
11696
|
-
if (_optionalChain([options, 'optionalAccess',
|
|
11697
|
-
if (_optionalChain([options, 'optionalAccess',
|
|
11963
|
+
if (_optionalChain([options, 'optionalAccess', _244 => _244.validate]) !== false) {
|
|
11964
|
+
if (_optionalChain([options, 'optionalAccess', _245 => _245.allowDraft])) {
|
|
11698
11965
|
_chunkU4AB53AMjs.validateDraftOrThrow.call(void 0, schema, normalizedData);
|
|
11699
11966
|
} else {
|
|
11700
11967
|
_chunkU4AB53AMjs.validateObjectOrThrow.call(void 0, schema, normalizedData);
|
|
11701
11968
|
}
|
|
11702
|
-
if (!_optionalChain([options, 'optionalAccess',
|
|
11969
|
+
if (!_optionalChain([options, 'optionalAccess', _246 => _246.skipRelationValidation])) {
|
|
11703
11970
|
await this.relationService.validateRelationsOrThrow(schema, normalizedData);
|
|
11704
11971
|
}
|
|
11705
|
-
if (!_optionalChain([options, 'optionalAccess',
|
|
11972
|
+
if (!_optionalChain([options, 'optionalAccess', _247 => _247.skipUserValidation])) {
|
|
11706
11973
|
await this.userService.validateUsersOrThrow(schema, normalizedData);
|
|
11707
11974
|
}
|
|
11708
11975
|
}
|
|
@@ -11713,22 +11980,39 @@ var RecordService = class extends BaseService {
|
|
|
11713
11980
|
data: normalizedData,
|
|
11714
11981
|
label,
|
|
11715
11982
|
completionStatus,
|
|
11716
|
-
metadata: _optionalChain([options, 'optionalAccess',
|
|
11983
|
+
metadata: _optionalChain([options, 'optionalAccess', _248 => _248.metadata]),
|
|
11717
11984
|
createdBy: this.userId
|
|
11718
11985
|
});
|
|
11719
11986
|
for (const [attrName, value] of Object.entries(dataWithDefaults)) {
|
|
11720
11987
|
const attr = schema.attributes.find((a) => a.name === attrName);
|
|
11721
|
-
if (_optionalChain([attr, 'optionalAccess',
|
|
11722
|
-
|
|
11988
|
+
if (_optionalChain([attr, 'optionalAccess', _249 => _249.type]) === "relation") {
|
|
11989
|
+
const hasProperties2 = attr.properties !== void 0;
|
|
11990
|
+
const isBilateral = isBilateralRelation(attr);
|
|
11991
|
+
if (hasProperties2 || isBilateral) {
|
|
11992
|
+
await this.relationPropertiesService.syncRelationProperties(
|
|
11993
|
+
schema,
|
|
11994
|
+
record.id,
|
|
11995
|
+
attrName,
|
|
11996
|
+
value,
|
|
11997
|
+
this.adapter
|
|
11998
|
+
);
|
|
11999
|
+
}
|
|
12000
|
+
}
|
|
12001
|
+
}
|
|
12002
|
+
for (const [attrName, value] of Object.entries(normalizedData)) {
|
|
12003
|
+
const attr = schema.attributes.find((a) => a.name === attrName);
|
|
12004
|
+
if (_optionalChain([attr, 'optionalAccess', _250 => _250.type]) === "relation" && isBilateralRelation(attr)) {
|
|
12005
|
+
await this.bilateralSyncService.syncBilateralRelation(
|
|
11723
12006
|
schema,
|
|
11724
12007
|
record.id,
|
|
11725
12008
|
attrName,
|
|
11726
12009
|
value,
|
|
11727
|
-
|
|
12010
|
+
null
|
|
12011
|
+
// oldValue is null for create
|
|
11728
12012
|
);
|
|
11729
12013
|
}
|
|
11730
12014
|
}
|
|
11731
|
-
if (!_optionalChain([options, 'optionalAccess',
|
|
12015
|
+
if (!_optionalChain([options, 'optionalAccess', _251 => _251.skipHooks])) {
|
|
11732
12016
|
const afterCtx = {
|
|
11733
12017
|
...hookCtx,
|
|
11734
12018
|
recordId: record.id,
|
|
@@ -11746,12 +12030,8 @@ var RecordService = class extends BaseService {
|
|
|
11746
12030
|
objectId: schema.id,
|
|
11747
12031
|
recordId: record.id,
|
|
11748
12032
|
recordLabel: record.label,
|
|
11749
|
-
metadata: _optionalChain([options, 'optionalAccess',
|
|
11750
|
-
}).catch((
|
|
11751
|
-
console.error(
|
|
11752
|
-
"Audit log failed (record.created):",
|
|
11753
|
-
err instanceof Error ? err.message : err
|
|
11754
|
-
);
|
|
12033
|
+
metadata: _optionalChain([options, 'optionalAccess', _252 => _252.hookMetadata])
|
|
12034
|
+
}).catch(() => {
|
|
11755
12035
|
});
|
|
11756
12036
|
}
|
|
11757
12037
|
return record;
|
|
@@ -11772,7 +12052,7 @@ var RecordService = class extends BaseService {
|
|
|
11772
12052
|
return null;
|
|
11773
12053
|
}
|
|
11774
12054
|
const schema = await this.schemaService.getObjectSchema(record.objectId);
|
|
11775
|
-
if (!_optionalChain([options, 'optionalAccess',
|
|
12055
|
+
if (!_optionalChain([options, 'optionalAccess', _253 => _253.skipPolicyCheck])) {
|
|
11776
12056
|
const policy = getPolicy(this.policyRegistry, this.userId, schema.name);
|
|
11777
12057
|
if (policy) {
|
|
11778
12058
|
const ctx = buildPolicyContext(schema.name, this.userId, this.tenantId);
|
|
@@ -11782,10 +12062,11 @@ var RecordService = class extends BaseService {
|
|
|
11782
12062
|
}
|
|
11783
12063
|
}
|
|
11784
12064
|
let enrichedRecord = record;
|
|
11785
|
-
if (!_optionalChain([options, 'optionalAccess',
|
|
12065
|
+
if (!_optionalChain([options, 'optionalAccess', _254 => _254.skipFormulas])) {
|
|
11786
12066
|
enrichedRecord = enrichWithFormulas(record, schema);
|
|
11787
12067
|
}
|
|
11788
|
-
|
|
12068
|
+
enrichedRecord = await this.enrichRelationProperties(enrichedRecord, schema);
|
|
12069
|
+
if (_optionalChain([options, 'optionalAccess', _255 => _255.includeSchema])) {
|
|
11789
12070
|
const recordWithSchema = enrichedRecord;
|
|
11790
12071
|
recordWithSchema.schema = schema;
|
|
11791
12072
|
return recordWithSchema;
|
|
@@ -11835,7 +12116,7 @@ var RecordService = class extends BaseService {
|
|
|
11835
12116
|
if (oldVal !== null && newVal !== null && typeof oldVal === "object" && typeof newVal === "object") {
|
|
11836
12117
|
try {
|
|
11837
12118
|
return JSON.stringify(oldVal) !== JSON.stringify(newVal);
|
|
11838
|
-
} catch (
|
|
12119
|
+
} catch (e16) {
|
|
11839
12120
|
return true;
|
|
11840
12121
|
}
|
|
11841
12122
|
}
|
|
@@ -11847,9 +12128,9 @@ var RecordService = class extends BaseService {
|
|
|
11847
12128
|
existing,
|
|
11848
12129
|
mergedData,
|
|
11849
12130
|
changedAttributes,
|
|
11850
|
-
_optionalChain([options, 'optionalAccess',
|
|
12131
|
+
_optionalChain([options, 'optionalAccess', _256 => _256.hookMetadata])
|
|
11851
12132
|
);
|
|
11852
|
-
if (!_optionalChain([options, 'optionalAccess',
|
|
12133
|
+
if (!_optionalChain([options, 'optionalAccess', _257 => _257.skipHooks])) {
|
|
11853
12134
|
await this.hookRegistry.execute("beforeUpdate", schema.name, hookCtx);
|
|
11854
12135
|
}
|
|
11855
12136
|
const hookModifiedValues = {};
|
|
@@ -11864,16 +12145,16 @@ var RecordService = class extends BaseService {
|
|
|
11864
12145
|
dataToUpdate
|
|
11865
12146
|
);
|
|
11866
12147
|
const normalizedMergedData = { ...existing.values, ...normalizedUpdate };
|
|
11867
|
-
if (_optionalChain([options, 'optionalAccess',
|
|
11868
|
-
if (_optionalChain([options, 'optionalAccess',
|
|
12148
|
+
if (_optionalChain([options, 'optionalAccess', _258 => _258.validate]) !== false) {
|
|
12149
|
+
if (_optionalChain([options, 'optionalAccess', _259 => _259.partial])) {
|
|
11869
12150
|
_chunkU4AB53AMjs.validateDraftOrThrow.call(void 0, schema, normalizedMergedData);
|
|
11870
12151
|
} else {
|
|
11871
12152
|
_chunkU4AB53AMjs.validateObjectOrThrow.call(void 0, schema, normalizedMergedData);
|
|
11872
12153
|
}
|
|
11873
|
-
if (!_optionalChain([options, 'optionalAccess',
|
|
12154
|
+
if (!_optionalChain([options, 'optionalAccess', _260 => _260.skipRelationValidation])) {
|
|
11874
12155
|
await this.relationService.validateRelationsOrThrow(schema, normalizedUpdate);
|
|
11875
12156
|
}
|
|
11876
|
-
if (!_optionalChain([options, 'optionalAccess',
|
|
12157
|
+
if (!_optionalChain([options, 'optionalAccess', _261 => _261.skipUserValidation])) {
|
|
11877
12158
|
await this.userService.validateUsersOrThrow(schema, normalizedUpdate);
|
|
11878
12159
|
}
|
|
11879
12160
|
}
|
|
@@ -11886,7 +12167,7 @@ var RecordService = class extends BaseService {
|
|
|
11886
12167
|
__lastUpdatedBy: this.userId,
|
|
11887
12168
|
__expectedUpdatedAt: existing.updatedAt instanceof Date ? existing.updatedAt.toISOString() : existing.updatedAt
|
|
11888
12169
|
};
|
|
11889
|
-
if (_optionalChain([options, 'optionalAccess',
|
|
12170
|
+
if (_optionalChain([options, 'optionalAccess', _262 => _262.metadata]) !== void 0) {
|
|
11890
12171
|
const existingMetadata = _nullishCoalesce(existing.metadata, () => ( {}));
|
|
11891
12172
|
const mergedMetadata = { ...existingMetadata, ...options.metadata };
|
|
11892
12173
|
const cleanedMetadata = Object.fromEntries(
|
|
@@ -11894,21 +12175,45 @@ var RecordService = class extends BaseService {
|
|
|
11894
12175
|
);
|
|
11895
12176
|
updatePayload.__metadata = cleanedMetadata;
|
|
11896
12177
|
}
|
|
12178
|
+
const bilateralOldValues = {};
|
|
12179
|
+
for (const attrName of Object.keys(normalizedUpdate)) {
|
|
12180
|
+
const attr = schema.attributes.find((a) => a.name === attrName);
|
|
12181
|
+
if (_optionalChain([attr, 'optionalAccess', _263 => _263.type]) === "relation" && isBilateralRelation(attr)) {
|
|
12182
|
+
bilateralOldValues[attrName] = existing.values[attrName];
|
|
12183
|
+
}
|
|
12184
|
+
}
|
|
11897
12185
|
const updated = await this.adapter.objectRecords.update(recordId, updatePayload);
|
|
11898
12186
|
await this.invalidateRecordCaches(recordId, existing.objectId);
|
|
11899
12187
|
for (const [attrName, value] of Object.entries(dataToUpdate)) {
|
|
11900
12188
|
const attr = schema.attributes.find((a) => a.name === attrName);
|
|
11901
|
-
if (_optionalChain([attr, 'optionalAccess',
|
|
11902
|
-
|
|
12189
|
+
if (_optionalChain([attr, 'optionalAccess', _264 => _264.type]) === "relation") {
|
|
12190
|
+
const hasProperties2 = attr.properties !== void 0;
|
|
12191
|
+
const isBilateral = isBilateralRelation(attr);
|
|
12192
|
+
if (hasProperties2 || isBilateral) {
|
|
12193
|
+
await this.relationPropertiesService.syncRelationProperties(
|
|
12194
|
+
schema,
|
|
12195
|
+
recordId,
|
|
12196
|
+
attrName,
|
|
12197
|
+
value,
|
|
12198
|
+
this.adapter
|
|
12199
|
+
);
|
|
12200
|
+
}
|
|
12201
|
+
}
|
|
12202
|
+
}
|
|
12203
|
+
for (const [attrName, value] of Object.entries(normalizedUpdate)) {
|
|
12204
|
+
const attr = schema.attributes.find((a) => a.name === attrName);
|
|
12205
|
+
if (_optionalChain([attr, 'optionalAccess', _265 => _265.type]) === "relation" && isBilateralRelation(attr)) {
|
|
12206
|
+
const oldValue = bilateralOldValues[attrName];
|
|
12207
|
+
await this.bilateralSyncService.syncBilateralRelation(
|
|
11903
12208
|
schema,
|
|
11904
12209
|
recordId,
|
|
11905
12210
|
attrName,
|
|
11906
12211
|
value,
|
|
11907
|
-
|
|
12212
|
+
oldValue
|
|
11908
12213
|
);
|
|
11909
12214
|
}
|
|
11910
12215
|
}
|
|
11911
|
-
if (!_optionalChain([options, 'optionalAccess',
|
|
12216
|
+
if (!_optionalChain([options, 'optionalAccess', _266 => _266.skipHooks])) {
|
|
11912
12217
|
const afterCtx = {
|
|
11913
12218
|
...hookCtx,
|
|
11914
12219
|
record: updated
|
|
@@ -11923,7 +12228,7 @@ var RecordService = class extends BaseService {
|
|
|
11923
12228
|
if (this.auditService && this.userId && allChangedAttributes.length > 0) {
|
|
11924
12229
|
const changes = allChangedAttributes.map((attr) => ({
|
|
11925
12230
|
field: attr,
|
|
11926
|
-
oldValue: _optionalChain([hookCtx, 'access',
|
|
12231
|
+
oldValue: _optionalChain([hookCtx, 'access', _267 => _267.oldValues, 'optionalAccess', _268 => _268[attr]]),
|
|
11927
12232
|
newValue: hookCtx.newValues[attr]
|
|
11928
12233
|
}));
|
|
11929
12234
|
this.auditService.logRecordAction({
|
|
@@ -11934,12 +12239,8 @@ var RecordService = class extends BaseService {
|
|
|
11934
12239
|
recordId: updated.id,
|
|
11935
12240
|
recordLabel: updated.label,
|
|
11936
12241
|
changes,
|
|
11937
|
-
metadata: _optionalChain([options, 'optionalAccess',
|
|
11938
|
-
}).catch((
|
|
11939
|
-
console.error(
|
|
11940
|
-
"Audit log failed (record.updated):",
|
|
11941
|
-
err instanceof Error ? err.message : err
|
|
11942
|
-
);
|
|
12242
|
+
metadata: _optionalChain([options, 'optionalAccess', _269 => _269.hookMetadata])
|
|
12243
|
+
}).catch(() => {
|
|
11943
12244
|
});
|
|
11944
12245
|
}
|
|
11945
12246
|
return updated;
|
|
@@ -11969,22 +12270,35 @@ var RecordService = class extends BaseService {
|
|
|
11969
12270
|
const ctx = buildPolicyContext(schema.name, this.userId, this.tenantId);
|
|
11970
12271
|
checkRecordDeleteOrThrow(policy, record, ctx);
|
|
11971
12272
|
}
|
|
11972
|
-
if (_optionalChain([options, 'optionalAccess',
|
|
12273
|
+
if (_optionalChain([options, 'optionalAccess', _270 => _270.checkSystem]) && schema.system) {
|
|
11973
12274
|
throw new ProtectedResourceError("object", schema.name, "delete");
|
|
11974
12275
|
}
|
|
11975
|
-
if (!_optionalChain([options, 'optionalAccess',
|
|
12276
|
+
if (!_optionalChain([options, 'optionalAccess', _271 => _271.skipReferenceCheck])) {
|
|
11976
12277
|
const references = await this.adapter.objectRecords.countRecordsReferencingId(recordId);
|
|
11977
12278
|
if (references.length > 0) {
|
|
11978
12279
|
throw new RecordReferencedError(recordId, references);
|
|
11979
12280
|
}
|
|
11980
12281
|
}
|
|
11981
|
-
const hookCtx = createContextForDelete(schema, this.tenantId, record, _optionalChain([options, 'optionalAccess',
|
|
11982
|
-
if (!_optionalChain([options, 'optionalAccess',
|
|
12282
|
+
const hookCtx = createContextForDelete(schema, this.tenantId, record, _optionalChain([options, 'optionalAccess', _272 => _272.hookMetadata]));
|
|
12283
|
+
if (!_optionalChain([options, 'optionalAccess', _273 => _273.skipHooks])) {
|
|
11983
12284
|
await this.hookRegistry.execute("beforeDelete", schema.name, hookCtx);
|
|
11984
12285
|
}
|
|
12286
|
+
for (const attr of schema.attributes) {
|
|
12287
|
+
if (attr.type === "relation" && isBilateralRelation(attr)) {
|
|
12288
|
+
const currentValue = record.values[attr.name];
|
|
12289
|
+
await this.bilateralSyncService.syncBilateralRelation(
|
|
12290
|
+
schema,
|
|
12291
|
+
recordId,
|
|
12292
|
+
attr.name,
|
|
12293
|
+
null,
|
|
12294
|
+
// newValue is null
|
|
12295
|
+
currentValue
|
|
12296
|
+
);
|
|
12297
|
+
}
|
|
12298
|
+
}
|
|
11985
12299
|
await this.adapter.objectRecords.delete(recordId);
|
|
11986
12300
|
await this.invalidateRecordCaches(recordId, record.objectId);
|
|
11987
|
-
if (!_optionalChain([options, 'optionalAccess',
|
|
12301
|
+
if (!_optionalChain([options, 'optionalAccess', _274 => _274.skipHooks])) {
|
|
11988
12302
|
await this.hookRegistry.execute("afterDelete", schema.name, hookCtx);
|
|
11989
12303
|
}
|
|
11990
12304
|
await recalculateParentRollups(record, schema, this.rollupContext);
|
|
@@ -11996,12 +12310,8 @@ var RecordService = class extends BaseService {
|
|
|
11996
12310
|
objectId: schema.id,
|
|
11997
12311
|
recordId: record.id,
|
|
11998
12312
|
recordLabel: record.label,
|
|
11999
|
-
metadata: _optionalChain([options, 'optionalAccess',
|
|
12000
|
-
}).catch((
|
|
12001
|
-
console.error(
|
|
12002
|
-
"Audit log failed (record.deleted):",
|
|
12003
|
-
err instanceof Error ? err.message : err
|
|
12004
|
-
);
|
|
12313
|
+
metadata: _optionalChain([options, 'optionalAccess', _275 => _275.hookMetadata])
|
|
12314
|
+
}).catch(() => {
|
|
12005
12315
|
});
|
|
12006
12316
|
}
|
|
12007
12317
|
}
|
|
@@ -12061,13 +12371,13 @@ var RecordService = class extends BaseService {
|
|
|
12061
12371
|
this.tenantId
|
|
12062
12372
|
);
|
|
12063
12373
|
await checkPermission(this.permissionService, this.userId, schema.name, "update");
|
|
12064
|
-
const hookCtx = createContextForRestore(schema, this.tenantId, record, _optionalChain([options, 'optionalAccess',
|
|
12065
|
-
if (!_optionalChain([options, 'optionalAccess',
|
|
12374
|
+
const hookCtx = createContextForRestore(schema, this.tenantId, record, _optionalChain([options, 'optionalAccess', _276 => _276.hookMetadata]));
|
|
12375
|
+
if (!_optionalChain([options, 'optionalAccess', _277 => _277.skipHooks])) {
|
|
12066
12376
|
await this.hookRegistry.execute("beforeRestore", schema.name, hookCtx);
|
|
12067
12377
|
}
|
|
12068
12378
|
const restored = await this.adapter.objectRecords.restore(recordId);
|
|
12069
12379
|
await this.invalidateRecordCaches(recordId, record.objectId);
|
|
12070
|
-
if (!_optionalChain([options, 'optionalAccess',
|
|
12380
|
+
if (!_optionalChain([options, 'optionalAccess', _278 => _278.skipHooks])) {
|
|
12071
12381
|
const afterCtx = {
|
|
12072
12382
|
...hookCtx,
|
|
12073
12383
|
record: restored
|
|
@@ -12082,12 +12392,8 @@ var RecordService = class extends BaseService {
|
|
|
12082
12392
|
objectId: schema.id,
|
|
12083
12393
|
recordId: restored.id,
|
|
12084
12394
|
recordLabel: restored.label,
|
|
12085
|
-
metadata: _optionalChain([options, 'optionalAccess',
|
|
12086
|
-
}).catch((
|
|
12087
|
-
console.error(
|
|
12088
|
-
"Audit log failed (record.restored):",
|
|
12089
|
-
err instanceof Error ? err.message : err
|
|
12090
|
-
);
|
|
12395
|
+
metadata: _optionalChain([options, 'optionalAccess', _279 => _279.hookMetadata])
|
|
12396
|
+
}).catch(() => {
|
|
12091
12397
|
});
|
|
12092
12398
|
}
|
|
12093
12399
|
return restored;
|
|
@@ -12095,6 +12401,60 @@ var RecordService = class extends BaseService {
|
|
|
12095
12401
|
// ============================================================================
|
|
12096
12402
|
// PRIVATE HELPERS
|
|
12097
12403
|
// ============================================================================
|
|
12404
|
+
/**
|
|
12405
|
+
* Enrich relation attributes with their properties (for qualified relations).
|
|
12406
|
+
*
|
|
12407
|
+
* Transforms simple ID arrays into hybrid format { id, props } when properties exist.
|
|
12408
|
+
*
|
|
12409
|
+
* @param record - Record to enrich
|
|
12410
|
+
* @param schema - Object schema
|
|
12411
|
+
* @returns Enriched record with relation properties loaded
|
|
12412
|
+
* @private
|
|
12413
|
+
*/
|
|
12414
|
+
async enrichRelationProperties(record, schema) {
|
|
12415
|
+
const enrichedValues = { ...record.values };
|
|
12416
|
+
for (const attr of schema.attributes) {
|
|
12417
|
+
if (attr.type !== "relation") {
|
|
12418
|
+
continue;
|
|
12419
|
+
}
|
|
12420
|
+
const hasProperties2 = attr.properties && attr.properties.definitions.length > 0;
|
|
12421
|
+
const isBilateral = isBilateralRelation(attr);
|
|
12422
|
+
const shouldEnrich = hasProperties2 || isBilateral;
|
|
12423
|
+
if (!shouldEnrich) {
|
|
12424
|
+
continue;
|
|
12425
|
+
}
|
|
12426
|
+
const value = record.values[attr.name];
|
|
12427
|
+
if (value === null || value === void 0) {
|
|
12428
|
+
continue;
|
|
12429
|
+
}
|
|
12430
|
+
const isMany = attr.cardinality === "many";
|
|
12431
|
+
const targetIds = isMany ? value : [value];
|
|
12432
|
+
if (!targetIds || targetIds.length === 0) {
|
|
12433
|
+
continue;
|
|
12434
|
+
}
|
|
12435
|
+
const propsMap = await this.relationPropertiesService.getRelationProperties(
|
|
12436
|
+
schema.name,
|
|
12437
|
+
record.id,
|
|
12438
|
+
attr.name,
|
|
12439
|
+
targetIds
|
|
12440
|
+
);
|
|
12441
|
+
if (isMany) {
|
|
12442
|
+
const hybridArray = targetIds.map((id) => {
|
|
12443
|
+
const props = propsMap.get(id);
|
|
12444
|
+
return props ? { id, props } : id;
|
|
12445
|
+
});
|
|
12446
|
+
enrichedValues[attr.name] = hybridArray;
|
|
12447
|
+
} else {
|
|
12448
|
+
const id = targetIds[0];
|
|
12449
|
+
const props = propsMap.get(id);
|
|
12450
|
+
enrichedValues[attr.name] = props ? { id, props } : id;
|
|
12451
|
+
}
|
|
12452
|
+
}
|
|
12453
|
+
return {
|
|
12454
|
+
...record,
|
|
12455
|
+
values: enrichedValues
|
|
12456
|
+
};
|
|
12457
|
+
}
|
|
12098
12458
|
/**
|
|
12099
12459
|
* Invalidate all caches related to a record (record cache + lists + global search)
|
|
12100
12460
|
* @private
|
|
@@ -12463,7 +12823,7 @@ var DocumentRendererService = class {
|
|
|
12463
12823
|
throw new StorageDownloadNotSupportedError();
|
|
12464
12824
|
}
|
|
12465
12825
|
let storagePath = fileId;
|
|
12466
|
-
if (_optionalChain([this, 'access',
|
|
12826
|
+
if (_optionalChain([this, 'access', _280 => _280.options, 'optionalAccess', _281 => _281.filesRepository])) {
|
|
12467
12827
|
const file2 = await this.options.filesRepository.findById(fileId);
|
|
12468
12828
|
if (!file2) {
|
|
12469
12829
|
throw new Error(`Template file not found: ${fileId}`);
|
|
@@ -12481,8 +12841,8 @@ var DocumentRendererService = class {
|
|
|
12481
12841
|
for (const field of fields) {
|
|
12482
12842
|
const rawValue = getContextValue(context, field.contextPath);
|
|
12483
12843
|
const attrInfo = await this.getAttributeInfo(field.contextPath, workflow2);
|
|
12484
|
-
if (_optionalChain([attrInfo, 'optionalAccess',
|
|
12485
|
-
if (attrInfo.attribute.type === "relation" && rawValue && _optionalChain([this, 'access',
|
|
12844
|
+
if (_optionalChain([attrInfo, 'optionalAccess', _282 => _282.attribute])) {
|
|
12845
|
+
if (attrInfo.attribute.type === "relation" && rawValue && _optionalChain([this, 'access', _283 => _283.options, 'optionalAccess', _284 => _284.relationService])) {
|
|
12486
12846
|
const ids = Array.isArray(rawValue) ? rawValue : [rawValue];
|
|
12487
12847
|
const stringIds = ids.filter((id) => typeof id === "string");
|
|
12488
12848
|
if (stringIds.length > 0) {
|
|
@@ -12503,7 +12863,7 @@ var DocumentRendererService = class {
|
|
|
12503
12863
|
resolved.set(field.id, this.formatValueSimple(rawValue, field.fallback));
|
|
12504
12864
|
}
|
|
12505
12865
|
}
|
|
12506
|
-
if (relationBatch.length > 0 && _optionalChain([this, 'access',
|
|
12866
|
+
if (relationBatch.length > 0 && _optionalChain([this, 'access', _285 => _285.options, 'optionalAccess', _286 => _286.relationService])) {
|
|
12507
12867
|
try {
|
|
12508
12868
|
const batchResult = await this.options.relationService.resolveIdsBatch(
|
|
12509
12869
|
relationBatch.map((r) => ({ attributeId: r.attributeId, ids: r.ids }))
|
|
@@ -12512,12 +12872,12 @@ var DocumentRendererService = class {
|
|
|
12512
12872
|
const options = _nullishCoalesce(batchResult[attributeId], () => ( []));
|
|
12513
12873
|
const labels = options.map((o) => o.label);
|
|
12514
12874
|
const field = fields.find((f) => f.id === fieldId);
|
|
12515
|
-
resolved.set(fieldId, labels.join(", ") || _optionalChain([field, 'optionalAccess',
|
|
12875
|
+
resolved.set(fieldId, labels.join(", ") || _optionalChain([field, 'optionalAccess', _287 => _287.fallback]) || "");
|
|
12516
12876
|
}
|
|
12517
|
-
} catch (
|
|
12877
|
+
} catch (e17) {
|
|
12518
12878
|
for (const { fieldId, ids } of relationBatch) {
|
|
12519
12879
|
const field = fields.find((f) => f.id === fieldId);
|
|
12520
|
-
resolved.set(fieldId, ids.join(", ") || _optionalChain([field, 'optionalAccess',
|
|
12880
|
+
resolved.set(fieldId, ids.join(", ") || _optionalChain([field, 'optionalAccess', _288 => _288.fallback]) || "");
|
|
12521
12881
|
}
|
|
12522
12882
|
}
|
|
12523
12883
|
}
|
|
@@ -12528,7 +12888,7 @@ var DocumentRendererService = class {
|
|
|
12528
12888
|
* Parses paths like "slots.client.firstName" to find the attribute definition
|
|
12529
12889
|
*/
|
|
12530
12890
|
async getAttributeInfo(contextPath, workflow2) {
|
|
12531
|
-
const schemaService = _optionalChain([this, 'access',
|
|
12891
|
+
const schemaService = _optionalChain([this, 'access', _289 => _289.options, 'optionalAccess', _290 => _290.schemaService]);
|
|
12532
12892
|
if (!schemaService) {
|
|
12533
12893
|
return null;
|
|
12534
12894
|
}
|
|
@@ -12541,7 +12901,7 @@ var DocumentRendererService = class {
|
|
|
12541
12901
|
}
|
|
12542
12902
|
const slotId = parts[1];
|
|
12543
12903
|
const attributeName = parts[2];
|
|
12544
|
-
const slot = _optionalChain([workflow2, 'access',
|
|
12904
|
+
const slot = _optionalChain([workflow2, 'access', _291 => _291.slots, 'optionalAccess', _292 => _292.find, 'call', _293 => _293((s) => s.id === slotId)]);
|
|
12545
12905
|
if (!slot) {
|
|
12546
12906
|
return null;
|
|
12547
12907
|
}
|
|
@@ -12550,7 +12910,7 @@ var DocumentRendererService = class {
|
|
|
12550
12910
|
try {
|
|
12551
12911
|
schema = await schemaService.getObjectSchemaByName(slot.objectName);
|
|
12552
12912
|
this.schemaCache.set(slot.objectName, schema);
|
|
12553
|
-
} catch (
|
|
12913
|
+
} catch (e18) {
|
|
12554
12914
|
return null;
|
|
12555
12915
|
}
|
|
12556
12916
|
}
|
|
@@ -12740,7 +13100,7 @@ var DocumentProcessingHook = class extends BaseService {
|
|
|
12740
13100
|
const pendingIds = [];
|
|
12741
13101
|
for (const [nodeId, doc] of Object.entries(context.documents)) {
|
|
12742
13102
|
const metadata = doc.metadata;
|
|
12743
|
-
if (_optionalChain([metadata, 'optionalAccess',
|
|
13103
|
+
if (_optionalChain([metadata, 'optionalAccess', _294 => _294.status]) === "pending") {
|
|
12744
13104
|
pendingIds.push(nodeId);
|
|
12745
13105
|
}
|
|
12746
13106
|
}
|
|
@@ -12791,12 +13151,12 @@ var DocumentProcessingHook = class extends BaseService {
|
|
|
12791
13151
|
}
|
|
12792
13152
|
for (const slotId of targetSlotIds) {
|
|
12793
13153
|
try {
|
|
12794
|
-
const recordId = _optionalChain([context, 'access',
|
|
13154
|
+
const recordId = _optionalChain([context, 'access', _295 => _295.createdRecordIds, 'optionalAccess', _296 => _296[slotId]]);
|
|
12795
13155
|
if (!recordId) {
|
|
12796
13156
|
continue;
|
|
12797
13157
|
}
|
|
12798
|
-
const slotDef = _optionalChain([workflow2, 'access',
|
|
12799
|
-
const objectName = _optionalChain([slotDef, 'optionalAccess',
|
|
13158
|
+
const slotDef = _optionalChain([workflow2, 'access', _297 => _297.slots, 'optionalAccess', _298 => _298.find, 'call', _299 => _299((s) => s.id === slotId)]);
|
|
13159
|
+
const objectName = _optionalChain([slotDef, 'optionalAccess', _300 => _300.objectName]);
|
|
12800
13160
|
if (!objectName) {
|
|
12801
13161
|
continue;
|
|
12802
13162
|
}
|
|
@@ -12813,14 +13173,14 @@ var DocumentProcessingHook = class extends BaseService {
|
|
|
12813
13173
|
attachedDocumentIds.push(result.document.id);
|
|
12814
13174
|
const record = await recordService.getRecord(recordId);
|
|
12815
13175
|
if (record) {
|
|
12816
|
-
const attachments = _nullishCoalesce(_optionalChain([record, 'access',
|
|
13176
|
+
const attachments = _nullishCoalesce(_optionalChain([record, 'access', _301 => _301.values, 'optionalAccess', _302 => _302.attachments]), () => ( []));
|
|
12817
13177
|
await recordService.updateRecord(
|
|
12818
13178
|
recordId,
|
|
12819
13179
|
{ attachments: [...attachments, result.document.id] },
|
|
12820
13180
|
{ partial: true }
|
|
12821
13181
|
);
|
|
12822
13182
|
}
|
|
12823
|
-
} catch (
|
|
13183
|
+
} catch (e19) {
|
|
12824
13184
|
}
|
|
12825
13185
|
}
|
|
12826
13186
|
return attachedDocumentIds;
|
|
@@ -13079,7 +13439,7 @@ var WorkflowAccessGrantService = class extends BaseService {
|
|
|
13079
13439
|
* Check if a specific token has been revoked.
|
|
13080
13440
|
*/
|
|
13081
13441
|
isTokenRevoked(dbGrant, jti) {
|
|
13082
|
-
return _nullishCoalesce(_optionalChain([dbGrant, 'access',
|
|
13442
|
+
return _nullishCoalesce(_optionalChain([dbGrant, 'access', _303 => _303.revoked_token_jtis, 'optionalAccess', _304 => _304.includes, 'call', _305 => _305(jti)]), () => ( false));
|
|
13083
13443
|
}
|
|
13084
13444
|
/**
|
|
13085
13445
|
* Validate access token payload against the grant.
|
|
@@ -13131,10 +13491,10 @@ var WorkflowInstanceService = class extends BaseService {
|
|
|
13131
13491
|
constructor(adapter, workflowService, options) {
|
|
13132
13492
|
super(adapter);
|
|
13133
13493
|
this.workflowService = workflowService;
|
|
13134
|
-
this.executorRegistry = _nullishCoalesce(_optionalChain([options, 'optionalAccess',
|
|
13135
|
-
this.schemaService = _optionalChain([options, 'optionalAccess',
|
|
13136
|
-
this.recordService = _optionalChain([options, 'optionalAccess',
|
|
13137
|
-
this.documentProcessingHook = _optionalChain([options, 'optionalAccess',
|
|
13494
|
+
this.executorRegistry = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _306 => _306.executorRegistry]), () => ( getDefaultExecutorRegistry()));
|
|
13495
|
+
this.schemaService = _optionalChain([options, 'optionalAccess', _307 => _307.schemaService]);
|
|
13496
|
+
this.recordService = _optionalChain([options, 'optionalAccess', _308 => _308.recordService]);
|
|
13497
|
+
this.documentProcessingHook = _optionalChain([options, 'optionalAccess', _309 => _309.documentProcessingHook]);
|
|
13138
13498
|
}
|
|
13139
13499
|
/**
|
|
13140
13500
|
* Start a new workflow instance
|
|
@@ -13316,7 +13676,7 @@ var WorkflowInstanceService = class extends BaseService {
|
|
|
13316
13676
|
if (!this.adapter.workflowInstances) {
|
|
13317
13677
|
return { instances: [], total: 0 };
|
|
13318
13678
|
}
|
|
13319
|
-
if (_optionalChain([options, 'optionalAccess',
|
|
13679
|
+
if (_optionalChain([options, 'optionalAccess', _310 => _310.workflowName])) {
|
|
13320
13680
|
const allDbInstances = await this.adapter.workflowInstances.findByWorkflowName(
|
|
13321
13681
|
options.workflowName,
|
|
13322
13682
|
{ status: options.status }
|
|
@@ -13330,11 +13690,11 @@ var WorkflowInstanceService = class extends BaseService {
|
|
|
13330
13690
|
return { instances: instances2, total: total2 };
|
|
13331
13691
|
}
|
|
13332
13692
|
const { instances: dbInstances, total } = await this.adapter.workflowInstances.list({
|
|
13333
|
-
limit: _optionalChain([options, 'optionalAccess',
|
|
13334
|
-
offset: _optionalChain([options, 'optionalAccess',
|
|
13693
|
+
limit: _optionalChain([options, 'optionalAccess', _311 => _311.limit]),
|
|
13694
|
+
offset: _optionalChain([options, 'optionalAccess', _312 => _312.offset])
|
|
13335
13695
|
});
|
|
13336
13696
|
let instances = dbInstances.map((db) => this.convertDBInstanceToInstance(db));
|
|
13337
|
-
if (_optionalChain([options, 'optionalAccess',
|
|
13697
|
+
if (_optionalChain([options, 'optionalAccess', _313 => _313.status])) {
|
|
13338
13698
|
instances = instances.filter((i) => i.status === options.status);
|
|
13339
13699
|
}
|
|
13340
13700
|
instances = await this.markExpiredInstances(instances);
|
|
@@ -13355,9 +13715,9 @@ var WorkflowInstanceService = class extends BaseService {
|
|
|
13355
13715
|
return { instances: [], total: 0 };
|
|
13356
13716
|
}
|
|
13357
13717
|
const { instances: dbInstances, total } = await this.adapter.workflowInstances.findByRecordInSlots(objectName, recordId, {
|
|
13358
|
-
status: _optionalChain([options, 'optionalAccess',
|
|
13359
|
-
limit: _optionalChain([options, 'optionalAccess',
|
|
13360
|
-
offset: _optionalChain([options, 'optionalAccess',
|
|
13718
|
+
status: _optionalChain([options, 'optionalAccess', _314 => _314.status]),
|
|
13719
|
+
limit: _optionalChain([options, 'optionalAccess', _315 => _315.limit]),
|
|
13720
|
+
offset: _optionalChain([options, 'optionalAccess', _316 => _316.offset])
|
|
13361
13721
|
});
|
|
13362
13722
|
const instances = dbInstances.map((db) => this.convertDBInstanceToInstance(db));
|
|
13363
13723
|
return { instances, total };
|
|
@@ -13423,13 +13783,13 @@ var WorkflowInstanceService = class extends BaseService {
|
|
|
13423
13783
|
try {
|
|
13424
13784
|
const schemas = await Promise.all(
|
|
13425
13785
|
current.workflowSnapshot.slots.map(
|
|
13426
|
-
(slot) => _optionalChain([this, 'access',
|
|
13786
|
+
(slot) => _optionalChain([this, 'access', _317 => _317.schemaService, 'optionalAccess', _318 => _318.getObjectSchemaByName, 'call', _319 => _319(slot.objectName)])
|
|
13427
13787
|
)
|
|
13428
13788
|
);
|
|
13429
13789
|
objectDefinitions = schemas.filter(
|
|
13430
13790
|
(s) => s !== void 0
|
|
13431
13791
|
);
|
|
13432
|
-
} catch (
|
|
13792
|
+
} catch (e20) {
|
|
13433
13793
|
}
|
|
13434
13794
|
}
|
|
13435
13795
|
const executorContext = {
|
|
@@ -13688,9 +14048,9 @@ var WorkflowInstanceService = class extends BaseService {
|
|
|
13688
14048
|
*/
|
|
13689
14049
|
async snapshotRecord(recordId) {
|
|
13690
14050
|
try {
|
|
13691
|
-
const record = await _optionalChain([this, 'access',
|
|
13692
|
-
return _optionalChain([record, 'optionalAccess',
|
|
13693
|
-
} catch (
|
|
14051
|
+
const record = await _optionalChain([this, 'access', _320 => _320.recordService, 'optionalAccess', _321 => _321.getRecord, 'call', _322 => _322(recordId, { skipPolicyCheck: true })]);
|
|
14052
|
+
return _optionalChain([record, 'optionalAccess', _323 => _323.values]);
|
|
14053
|
+
} catch (e21) {
|
|
13694
14054
|
return void 0;
|
|
13695
14055
|
}
|
|
13696
14056
|
}
|
|
@@ -13708,18 +14068,18 @@ var WorkflowInstanceService = class extends BaseService {
|
|
|
13708
14068
|
for (const op of [...operations].reverse()) {
|
|
13709
14069
|
try {
|
|
13710
14070
|
if (op.operation === "create") {
|
|
13711
|
-
await _optionalChain([this, 'access',
|
|
14071
|
+
await _optionalChain([this, 'access', _324 => _324.recordService, 'optionalAccess', _325 => _325.deleteRecord, 'call', _326 => _326(op.recordId, {
|
|
13712
14072
|
skipHooks: true,
|
|
13713
14073
|
skipReferenceCheck: true
|
|
13714
14074
|
})]);
|
|
13715
14075
|
rolledBack.push(op.slotId);
|
|
13716
14076
|
} else if (op.operation === "update" && op.previousData) {
|
|
13717
|
-
await _optionalChain([this, 'access',
|
|
14077
|
+
await _optionalChain([this, 'access', _327 => _327.recordService, 'optionalAccess', _328 => _328.updateRecord, 'call', _329 => _329(op.recordId, op.previousData, {
|
|
13718
14078
|
partial: false
|
|
13719
14079
|
})]);
|
|
13720
14080
|
rolledBack.push(op.slotId);
|
|
13721
14081
|
}
|
|
13722
|
-
} catch (
|
|
14082
|
+
} catch (e22) {
|
|
13723
14083
|
}
|
|
13724
14084
|
}
|
|
13725
14085
|
return rolledBack;
|
|
@@ -13838,7 +14198,7 @@ var WorkflowInstanceService = class extends BaseService {
|
|
|
13838
14198
|
if (!this.adapter.workflowInstances) {
|
|
13839
14199
|
return;
|
|
13840
14200
|
}
|
|
13841
|
-
const currentVersion = _nullishCoalesce(_optionalChain([instance, 'access',
|
|
14201
|
+
const currentVersion = _nullishCoalesce(_optionalChain([instance, 'access', _330 => _330.context, 'access', _331 => _331.variables, 'optionalAccess', _332 => _332.__version]), () => ( 0));
|
|
13842
14202
|
const nextVersion = currentVersion + 1;
|
|
13843
14203
|
const instanceWithVersion = {
|
|
13844
14204
|
...instance,
|
|
@@ -14119,7 +14479,7 @@ var WorkflowRelationService = class extends BaseService {
|
|
|
14119
14479
|
if (attr.type !== "relation") continue;
|
|
14120
14480
|
for (const slot of slots) {
|
|
14121
14481
|
const slotData = context.slots[slot.id];
|
|
14122
|
-
const slotRecordId = _optionalChain([slotData, 'optionalAccess',
|
|
14482
|
+
const slotRecordId = _optionalChain([slotData, 'optionalAccess', _333 => _333.id]);
|
|
14123
14483
|
if (!slotRecordId) continue;
|
|
14124
14484
|
const targetsSlotObject = attr.targets.some(
|
|
14125
14485
|
(t) => t.object === slot.objectName
|
|
@@ -14187,7 +14547,7 @@ var WorkflowService = class extends BaseService {
|
|
|
14187
14547
|
if (Array.isArray(options)) {
|
|
14188
14548
|
this.systemWorkflows = new Map(options.map((w) => [w.name, w]));
|
|
14189
14549
|
} else {
|
|
14190
|
-
this.systemWorkflows = new Map((_nullishCoalesce(_optionalChain([options, 'optionalAccess',
|
|
14550
|
+
this.systemWorkflows = new Map((_nullishCoalesce(_optionalChain([options, 'optionalAccess', _334 => _334.systemWorkflows]), () => ( []))).map((w) => [w.name, w]));
|
|
14191
14551
|
}
|
|
14192
14552
|
}
|
|
14193
14553
|
// ============================================================================
|
|
@@ -14485,7 +14845,7 @@ var WorkflowService = class extends BaseService {
|
|
|
14485
14845
|
var UserProfileService = class extends BaseService {
|
|
14486
14846
|
constructor(adapter, options) {
|
|
14487
14847
|
super(adapter);
|
|
14488
|
-
this.auditService = _optionalChain([options, 'optionalAccess',
|
|
14848
|
+
this.auditService = _optionalChain([options, 'optionalAccess', _335 => _335.auditService]);
|
|
14489
14849
|
}
|
|
14490
14850
|
// ============================================================================
|
|
14491
14851
|
// CACHE MANAGEMENT
|
|
@@ -14648,7 +15008,7 @@ var UserProfileService = class extends BaseService {
|
|
|
14648
15008
|
*/
|
|
14649
15009
|
async deleteProfile(profileId, options) {
|
|
14650
15010
|
const profile = await this.getProfileOrThrow(profileId);
|
|
14651
|
-
if (_optionalChain([options, 'optionalAccess',
|
|
15011
|
+
if (_optionalChain([options, 'optionalAccess', _336 => _336.checkAdmin])) {
|
|
14652
15012
|
if (profile.role === "admin") {
|
|
14653
15013
|
const adminCount = await this.adapter.userProfiles.countByRole("admin");
|
|
14654
15014
|
if (adminCount <= 1) {
|
|
@@ -14723,7 +15083,7 @@ var UserProfileService = class extends BaseService {
|
|
|
14723
15083
|
*/
|
|
14724
15084
|
async hasRole(profileId, role) {
|
|
14725
15085
|
const profile = await this.getProfile(profileId);
|
|
14726
|
-
return _optionalChain([profile, 'optionalAccess',
|
|
15086
|
+
return _optionalChain([profile, 'optionalAccess', _337 => _337.role]) === role;
|
|
14727
15087
|
}
|
|
14728
15088
|
/**
|
|
14729
15089
|
* Check if user is admin
|
|
@@ -15157,7 +15517,7 @@ var DocumentTemplateService = class extends BaseService {
|
|
|
15157
15517
|
* Includes both system templates and tenant-specific templates.
|
|
15158
15518
|
*/
|
|
15159
15519
|
async listTemplates(options) {
|
|
15160
|
-
if (_optionalChain([options, 'optionalAccess',
|
|
15520
|
+
if (_optionalChain([options, 'optionalAccess', _338 => _338.systemOnly])) {
|
|
15161
15521
|
return SYSTEM_TEMPLATES;
|
|
15162
15522
|
}
|
|
15163
15523
|
const templates = [...SYSTEM_TEMPLATES];
|
|
@@ -15240,8 +15600,8 @@ var DocumentTemplateService = class extends BaseService {
|
|
|
15240
15600
|
var DocumentService = class extends BaseService {
|
|
15241
15601
|
constructor(adapter, options) {
|
|
15242
15602
|
super(adapter);
|
|
15243
|
-
this.templateService = _nullishCoalesce(_optionalChain([options, 'optionalAccess',
|
|
15244
|
-
this.fileService = _nullishCoalesce(_optionalChain([options, 'optionalAccess',
|
|
15603
|
+
this.templateService = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _339 => _339.templateService]), () => ( new DocumentTemplateService(adapter)));
|
|
15604
|
+
this.fileService = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _340 => _340.fileService]), () => ( null));
|
|
15245
15605
|
}
|
|
15246
15606
|
// ============================================================================
|
|
15247
15607
|
// CREATE
|
|
@@ -15492,7 +15852,7 @@ var DocumentService = class extends BaseService {
|
|
|
15492
15852
|
*/
|
|
15493
15853
|
async isComplete(documentId) {
|
|
15494
15854
|
const document2 = await this.getDocument(documentId);
|
|
15495
|
-
return _optionalChain([document2, 'optionalAccess',
|
|
15855
|
+
return _optionalChain([document2, 'optionalAccess', _341 => _341.status]) !== "draft";
|
|
15496
15856
|
}
|
|
15497
15857
|
/**
|
|
15498
15858
|
* Get document with its template and slots.
|
|
@@ -15750,7 +16110,7 @@ var DocumentProcessingService = class extends BaseService {
|
|
|
15750
16110
|
type: "signature",
|
|
15751
16111
|
provider: this.config.signatureAdapter.name,
|
|
15752
16112
|
input: { signers, ...options },
|
|
15753
|
-
expiresAt: _optionalChain([options, 'optionalAccess',
|
|
16113
|
+
expiresAt: _optionalChain([options, 'optionalAccess', _342 => _342.expiresAt])
|
|
15754
16114
|
});
|
|
15755
16115
|
return job;
|
|
15756
16116
|
}
|
|
@@ -15907,7 +16267,7 @@ var DocumentProcessingService = class extends BaseService {
|
|
|
15907
16267
|
}
|
|
15908
16268
|
const document2 = await this.documentService.getDocumentOrThrow(documentId);
|
|
15909
16269
|
const template = await this.templateService.getTemplateOrThrow(document2.templateId);
|
|
15910
|
-
if (!_optionalChain([template, 'access',
|
|
16270
|
+
if (!_optionalChain([template, 'access', _343 => _343.autoProcessing, 'optionalAccess', _344 => _344.identityVerification, 'optionalAccess', _345 => _345.enabled])) {
|
|
15911
16271
|
throw new Error("Identity verification is not enabled for this document type");
|
|
15912
16272
|
}
|
|
15913
16273
|
const job = await this.adapter.documentJobs.create({
|
|
@@ -15993,13 +16353,13 @@ var DocumentProcessingService = class extends BaseService {
|
|
|
15993
16353
|
const template = await this.templateService.getTemplateOrThrow(document2.templateId);
|
|
15994
16354
|
const slots = await this.documentService.getSlots(documentId);
|
|
15995
16355
|
const jobs = [];
|
|
15996
|
-
if (_optionalChain([template, 'access',
|
|
16356
|
+
if (_optionalChain([template, 'access', _346 => _346.autoProcessing, 'optionalAccess', _347 => _347.ocr, 'optionalAccess', _348 => _348.enabled]) && this.config.ocrAdapter) {
|
|
15997
16357
|
for (const slot of slots) {
|
|
15998
16358
|
const job = await this.processOcr(documentId, slot.slotName);
|
|
15999
16359
|
jobs.push(job);
|
|
16000
16360
|
}
|
|
16001
16361
|
}
|
|
16002
|
-
if (_optionalChain([template, 'access',
|
|
16362
|
+
if (_optionalChain([template, 'access', _349 => _349.autoProcessing, 'optionalAccess', _350 => _350.identityVerification, 'optionalAccess', _351 => _351.enabled]) && this.config.identityAdapter) {
|
|
16003
16363
|
const job = await this.verifyIdentity(documentId);
|
|
16004
16364
|
jobs.push(job);
|
|
16005
16365
|
}
|
|
@@ -16070,15 +16430,15 @@ var DocumentProcessingService = class extends BaseService {
|
|
|
16070
16430
|
return {
|
|
16071
16431
|
ocr: {
|
|
16072
16432
|
available: !!this.config.ocrAdapter,
|
|
16073
|
-
provider: _optionalChain([this, 'access',
|
|
16433
|
+
provider: _optionalChain([this, 'access', _352 => _352.config, 'access', _353 => _353.ocrAdapter, 'optionalAccess', _354 => _354.name])
|
|
16074
16434
|
},
|
|
16075
16435
|
signature: {
|
|
16076
16436
|
available: !!this.config.signatureAdapter,
|
|
16077
|
-
provider: _optionalChain([this, 'access',
|
|
16437
|
+
provider: _optionalChain([this, 'access', _355 => _355.config, 'access', _356 => _356.signatureAdapter, 'optionalAccess', _357 => _357.name])
|
|
16078
16438
|
},
|
|
16079
16439
|
identityVerification: {
|
|
16080
16440
|
available: !!this.config.identityAdapter,
|
|
16081
|
-
provider: _optionalChain([this, 'access',
|
|
16441
|
+
provider: _optionalChain([this, 'access', _358 => _358.config, 'access', _359 => _359.identityAdapter, 'optionalAccess', _360 => _360.name])
|
|
16082
16442
|
}
|
|
16083
16443
|
};
|
|
16084
16444
|
}
|
|
@@ -16088,7 +16448,7 @@ var DocumentProcessingService = class extends BaseService {
|
|
|
16088
16448
|
var FileService = class extends BaseService {
|
|
16089
16449
|
constructor(adapter, options) {
|
|
16090
16450
|
super(adapter);
|
|
16091
|
-
this.auditService = _nullishCoalesce(_optionalChain([options, 'optionalAccess',
|
|
16451
|
+
this.auditService = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _361 => _361.auditService]), () => ( (adapter.audit ? new AuditService(adapter) : void 0)));
|
|
16092
16452
|
}
|
|
16093
16453
|
// ============================================================================
|
|
16094
16454
|
// UPLOAD (requires StorageAdapter)
|
|
@@ -16227,7 +16587,7 @@ var FileService = class extends BaseService {
|
|
|
16227
16587
|
*/
|
|
16228
16588
|
async getFile(fileId) {
|
|
16229
16589
|
const file2 = await this.adapter.files.findById(fileId);
|
|
16230
|
-
if (_optionalChain([file2, 'optionalAccess',
|
|
16590
|
+
if (_optionalChain([file2, 'optionalAccess', _362 => _362.deletedAt])) {
|
|
16231
16591
|
return null;
|
|
16232
16592
|
}
|
|
16233
16593
|
return file2;
|
|
@@ -16289,12 +16649,12 @@ var FileService = class extends BaseService {
|
|
|
16289
16649
|
*/
|
|
16290
16650
|
async deleteFile(fileId, options) {
|
|
16291
16651
|
const file2 = await this.getFileOrThrow(fileId);
|
|
16292
|
-
if (_optionalChain([options, 'optionalAccess',
|
|
16652
|
+
if (_optionalChain([options, 'optionalAccess', _363 => _363.checkOwnership]) && options.userId) {
|
|
16293
16653
|
if (file2.uploadedBy !== options.userId) {
|
|
16294
16654
|
throw new Error("You can only delete files you uploaded");
|
|
16295
16655
|
}
|
|
16296
16656
|
}
|
|
16297
|
-
if (_optionalChain([options, 'optionalAccess',
|
|
16657
|
+
if (_optionalChain([options, 'optionalAccess', _364 => _364.hard])) {
|
|
16298
16658
|
await this.adapter.files.hardDelete(fileId);
|
|
16299
16659
|
} else {
|
|
16300
16660
|
await this.adapter.files.delete(fileId);
|
|
@@ -16325,7 +16685,7 @@ var FileService = class extends BaseService {
|
|
|
16325
16685
|
}
|
|
16326
16686
|
const file2 = await this.getFileOrThrow(fileId);
|
|
16327
16687
|
await this.adapter.storage.delete(file2.storagePath);
|
|
16328
|
-
if (_optionalChain([options, 'optionalAccess',
|
|
16688
|
+
if (_optionalChain([options, 'optionalAccess', _365 => _365.hard])) {
|
|
16329
16689
|
await this.adapter.files.hardDelete(fileId);
|
|
16330
16690
|
} else {
|
|
16331
16691
|
await this.adapter.files.delete(fileId);
|
|
@@ -16351,15 +16711,15 @@ var FileService = class extends BaseService {
|
|
|
16351
16711
|
const fileResults = await Promise.all(fileIds.map((id) => this.getFile(id)));
|
|
16352
16712
|
const files = fileResults.filter((f) => f !== null);
|
|
16353
16713
|
if (files.length === 0) return;
|
|
16354
|
-
if (_optionalChain([options, 'optionalAccess',
|
|
16714
|
+
if (_optionalChain([options, 'optionalAccess', _366 => _366.deleteFromStorage]) && this.adapter.storage) {
|
|
16355
16715
|
const BATCH_SIZE = 10;
|
|
16356
16716
|
for (let i = 0; i < files.length; i += BATCH_SIZE) {
|
|
16357
16717
|
const batch = files.slice(i, i + BATCH_SIZE);
|
|
16358
|
-
await Promise.all(batch.map((file2) => _optionalChain([this, 'access',
|
|
16718
|
+
await Promise.all(batch.map((file2) => _optionalChain([this, 'access', _367 => _367.adapter, 'access', _368 => _368.storage, 'optionalAccess', _369 => _369.delete, 'call', _370 => _370(file2.storagePath)])));
|
|
16359
16719
|
}
|
|
16360
16720
|
}
|
|
16361
16721
|
const idsToDelete = files.map((f) => f.id);
|
|
16362
|
-
if (_optionalChain([options, 'optionalAccess',
|
|
16722
|
+
if (_optionalChain([options, 'optionalAccess', _371 => _371.hard])) {
|
|
16363
16723
|
await Promise.all(idsToDelete.map((id) => this.adapter.files.hardDelete(id)));
|
|
16364
16724
|
} else {
|
|
16365
16725
|
await Promise.all(idsToDelete.map((id) => this.adapter.files.delete(id)));
|
|
@@ -16367,12 +16727,12 @@ var FileService = class extends BaseService {
|
|
|
16367
16727
|
if (this.auditService && this.userId) {
|
|
16368
16728
|
await Promise.all(
|
|
16369
16729
|
files.map(
|
|
16370
|
-
(file2) => _optionalChain([this, 'access',
|
|
16730
|
+
(file2) => _optionalChain([this, 'access', _372 => _372.auditService, 'optionalAccess', _373 => _373.logFileAction, 'call', _374 => _374({
|
|
16371
16731
|
action: "file.deleted",
|
|
16372
16732
|
actorId: _nullishCoalesce(this.userId, () => ( "")),
|
|
16373
16733
|
fileId: file2.id,
|
|
16374
16734
|
fileName: file2.name,
|
|
16375
|
-
metadata: { deletedFromStorage: _nullishCoalesce(_optionalChain([options, 'optionalAccess',
|
|
16735
|
+
metadata: { deletedFromStorage: _nullishCoalesce(_optionalChain([options, 'optionalAccess', _375 => _375.deleteFromStorage]), () => ( false)) }
|
|
16376
16736
|
})])
|
|
16377
16737
|
)
|
|
16378
16738
|
);
|
|
@@ -16450,7 +16810,7 @@ var FileService = class extends BaseService {
|
|
|
16450
16810
|
if (!file2) {
|
|
16451
16811
|
return false;
|
|
16452
16812
|
}
|
|
16453
|
-
if (_optionalChain([options, 'optionalAccess',
|
|
16813
|
+
if (_optionalChain([options, 'optionalAccess', _376 => _376.isAdmin])) {
|
|
16454
16814
|
return true;
|
|
16455
16815
|
}
|
|
16456
16816
|
if (file2.visibility === "public") {
|
|
@@ -16460,7 +16820,7 @@ var FileService = class extends BaseService {
|
|
|
16460
16820
|
return true;
|
|
16461
16821
|
}
|
|
16462
16822
|
if (file2.visibility === "restricted") {
|
|
16463
|
-
return _nullishCoalesce(_optionalChain([file2, 'access',
|
|
16823
|
+
return _nullishCoalesce(_optionalChain([file2, 'access', _377 => _377.allowedUsers, 'optionalAccess', _378 => _378.includes, 'call', _379 => _379(userId)]), () => ( false));
|
|
16464
16824
|
}
|
|
16465
16825
|
return false;
|
|
16466
16826
|
}
|
|
@@ -16555,7 +16915,7 @@ function withTimeout(promise, ms, label) {
|
|
|
16555
16915
|
var GeocodingService = class {
|
|
16556
16916
|
constructor(adapter, options) {
|
|
16557
16917
|
this.adapter = adapter;
|
|
16558
|
-
this.timeoutMs = _nullishCoalesce(_optionalChain([options, 'optionalAccess',
|
|
16918
|
+
this.timeoutMs = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _380 => _380.timeoutMs]), () => ( GEOCODING_TIMEOUT_MS));
|
|
16559
16919
|
}
|
|
16560
16920
|
/**
|
|
16561
16921
|
* Search for address suggestions as the user types
|
|
@@ -16615,9 +16975,9 @@ var GlobalSearchService = class extends BaseService {
|
|
|
16615
16975
|
"search",
|
|
16616
16976
|
{ query: query.trim(), ...options },
|
|
16617
16977
|
() => this.adapter.objectRecords.globalSearch(query.trim(), {
|
|
16618
|
-
limit: _nullishCoalesce(_optionalChain([options, 'optionalAccess',
|
|
16619
|
-
offset: _nullishCoalesce(_optionalChain([options, 'optionalAccess',
|
|
16620
|
-
objectNames: _optionalChain([options, 'optionalAccess',
|
|
16978
|
+
limit: _nullishCoalesce(_optionalChain([options, 'optionalAccess', _381 => _381.limit]), () => ( 20)),
|
|
16979
|
+
offset: _nullishCoalesce(_optionalChain([options, 'optionalAccess', _382 => _382.offset]), () => ( 0)),
|
|
16980
|
+
objectNames: _optionalChain([options, 'optionalAccess', _383 => _383.objectNames])
|
|
16621
16981
|
})
|
|
16622
16982
|
);
|
|
16623
16983
|
}
|
|
@@ -16638,8 +16998,8 @@ var GlobalSearchService = class extends BaseService {
|
|
|
16638
16998
|
"grouped",
|
|
16639
16999
|
{ query: query.trim(), ...options },
|
|
16640
17000
|
() => this.adapter.objectRecords.globalSearchGrouped(query.trim(), {
|
|
16641
|
-
objectNames: _optionalChain([options, 'optionalAccess',
|
|
16642
|
-
limitPerGroup: _nullishCoalesce(_optionalChain([options, 'optionalAccess',
|
|
17001
|
+
objectNames: _optionalChain([options, 'optionalAccess', _384 => _384.objectNames]),
|
|
17002
|
+
limitPerGroup: _nullishCoalesce(_optionalChain([options, 'optionalAccess', _385 => _385.limitPerGroup]), () => ( 5))
|
|
16643
17003
|
})
|
|
16644
17004
|
);
|
|
16645
17005
|
}
|
|
@@ -16656,7 +17016,7 @@ var PermissionService = class extends BaseService {
|
|
|
16656
17016
|
}
|
|
16657
17017
|
this.permissionsRepo = adapter.permissions;
|
|
16658
17018
|
this.permissionCache = _nullishCoalesce(adapter.cache, () => ( new NoopCacheAdapter()));
|
|
16659
|
-
this.auditService = _optionalChain([options, 'optionalAccess',
|
|
17019
|
+
this.auditService = _optionalChain([options, 'optionalAccess', _386 => _386.auditService]);
|
|
16660
17020
|
}
|
|
16661
17021
|
// ============================================================================
|
|
16662
17022
|
// PERMISSION CHECKS
|
|
@@ -16675,11 +17035,11 @@ var PermissionService = class extends BaseService {
|
|
|
16675
17035
|
return true;
|
|
16676
17036
|
}
|
|
16677
17037
|
const wildcardPerms = permissions.objectPermissions["*"];
|
|
16678
|
-
if (_optionalChain([wildcardPerms, 'optionalAccess',
|
|
17038
|
+
if (_optionalChain([wildcardPerms, 'optionalAccess', _387 => _387.includes, 'call', _388 => _388(action)])) {
|
|
16679
17039
|
return true;
|
|
16680
17040
|
}
|
|
16681
17041
|
const objectPerms = permissions.objectPermissions[objectName];
|
|
16682
|
-
return _nullishCoalesce(_optionalChain([objectPerms, 'optionalAccess',
|
|
17042
|
+
return _nullishCoalesce(_optionalChain([objectPerms, 'optionalAccess', _389 => _389.includes, 'call', _390 => _390(action)]), () => ( false));
|
|
16683
17043
|
}
|
|
16684
17044
|
/**
|
|
16685
17045
|
* Check if user can access an object, throw ForbiddenError if not.
|
|
@@ -16734,12 +17094,12 @@ var PermissionService = class extends BaseService {
|
|
|
16734
17094
|
if (permissions.isAdmin) {
|
|
16735
17095
|
return true;
|
|
16736
17096
|
}
|
|
16737
|
-
const wildcardPerms = _optionalChain([permissions, 'access',
|
|
16738
|
-
if (_optionalChain([wildcardPerms, 'optionalAccess',
|
|
17097
|
+
const wildcardPerms = _optionalChain([permissions, 'access', _391 => _391.systemPermissions, 'optionalAccess', _392 => _392["*"]]);
|
|
17098
|
+
if (_optionalChain([wildcardPerms, 'optionalAccess', _393 => _393.includes, 'call', _394 => _394(action)])) {
|
|
16739
17099
|
return true;
|
|
16740
17100
|
}
|
|
16741
|
-
const resourcePerms = _optionalChain([permissions, 'access',
|
|
16742
|
-
return _nullishCoalesce(_optionalChain([resourcePerms, 'optionalAccess',
|
|
17101
|
+
const resourcePerms = _optionalChain([permissions, 'access', _395 => _395.systemPermissions, 'optionalAccess', _396 => _396[resource]]);
|
|
17102
|
+
return _nullishCoalesce(_optionalChain([resourcePerms, 'optionalAccess', _397 => _397.includes, 'call', _398 => _398(action)]), () => ( false));
|
|
16743
17103
|
}
|
|
16744
17104
|
/**
|
|
16745
17105
|
* Check if user can access a system resource, throw ForbiddenError if not.
|
|
@@ -16768,8 +17128,8 @@ var PermissionService = class extends BaseService {
|
|
|
16768
17128
|
if (permissions.isAdmin) {
|
|
16769
17129
|
return { canRead: true, canCreate: true, canUpdate: true, canDelete: true };
|
|
16770
17130
|
}
|
|
16771
|
-
const wildcardPerms = _nullishCoalesce(_optionalChain([permissions, 'access',
|
|
16772
|
-
const resourcePerms = _nullishCoalesce(_optionalChain([permissions, 'access',
|
|
17131
|
+
const wildcardPerms = _nullishCoalesce(_optionalChain([permissions, 'access', _399 => _399.systemPermissions, 'optionalAccess', _400 => _400["*"]]), () => ( []));
|
|
17132
|
+
const resourcePerms = _nullishCoalesce(_optionalChain([permissions, 'access', _401 => _401.systemPermissions, 'optionalAccess', _402 => _402[resource]]), () => ( []));
|
|
16773
17133
|
const allPerms = /* @__PURE__ */ new Set([...wildcardPerms, ...resourcePerms]);
|
|
16774
17134
|
return {
|
|
16775
17135
|
canRead: allPerms.has("read"),
|
|
@@ -16912,7 +17272,7 @@ var PermissionService = class extends BaseService {
|
|
|
16912
17272
|
action: "role.updated",
|
|
16913
17273
|
actorId: this.userId,
|
|
16914
17274
|
roleId,
|
|
16915
|
-
roleLabel: _nullishCoalesce(_optionalChain([role, 'optionalAccess',
|
|
17275
|
+
roleLabel: _nullishCoalesce(_optionalChain([role, 'optionalAccess', _403 => _403.label]), () => ( roleId)),
|
|
16916
17276
|
metadata: { permissionsUpdated: true, permissionCount: permissions.length }
|
|
16917
17277
|
});
|
|
16918
17278
|
}
|
|
@@ -16942,7 +17302,7 @@ var PermissionService = class extends BaseService {
|
|
|
16942
17302
|
action: "role.assigned",
|
|
16943
17303
|
actorId: this.userId,
|
|
16944
17304
|
roleId,
|
|
16945
|
-
roleLabel: _nullishCoalesce(_optionalChain([role, 'optionalAccess',
|
|
17305
|
+
roleLabel: _nullishCoalesce(_optionalChain([role, 'optionalAccess', _404 => _404.label]), () => ( roleId)),
|
|
16946
17306
|
targetUserId: userProfileId
|
|
16947
17307
|
});
|
|
16948
17308
|
}
|
|
@@ -16960,7 +17320,7 @@ var PermissionService = class extends BaseService {
|
|
|
16960
17320
|
action: "role.revoked",
|
|
16961
17321
|
actorId: this.userId,
|
|
16962
17322
|
roleId,
|
|
16963
|
-
roleLabel: _nullishCoalesce(_optionalChain([role, 'optionalAccess',
|
|
17323
|
+
roleLabel: _nullishCoalesce(_optionalChain([role, 'optionalAccess', _405 => _405.label]), () => ( roleId)),
|
|
16964
17324
|
targetUserId: userProfileId
|
|
16965
17325
|
});
|
|
16966
17326
|
}
|
|
@@ -17259,14 +17619,6 @@ var ViewService = class extends BaseService {
|
|
|
17259
17619
|
type: "activity",
|
|
17260
17620
|
order: 1
|
|
17261
17621
|
});
|
|
17262
|
-
tabs.push({
|
|
17263
|
-
id: "notes",
|
|
17264
|
-
name: "notes",
|
|
17265
|
-
label: "Notes",
|
|
17266
|
-
type: "notes",
|
|
17267
|
-
order: 2,
|
|
17268
|
-
allowCreate: true
|
|
17269
|
-
});
|
|
17270
17622
|
const hasDocuments = object2.attributes.some((attr) => attr.type === "document");
|
|
17271
17623
|
if (hasDocuments) {
|
|
17272
17624
|
tabs.push({
|
|
@@ -17443,7 +17795,7 @@ var ViewService = class extends BaseService {
|
|
|
17443
17795
|
dbView.objectName,
|
|
17444
17796
|
dbView.type,
|
|
17445
17797
|
objectDefinition,
|
|
17446
|
-
dbView.type === "detail" ? _nullishCoalesce(_optionalChain([dbView, 'access',
|
|
17798
|
+
dbView.type === "detail" ? _nullishCoalesce(_optionalChain([dbView, 'access', _406 => _406.config, 'optionalAccess', _407 => _407.layout]), () => ( "page")) : void 0
|
|
17447
17799
|
);
|
|
17448
17800
|
const newConfig = generated.config;
|
|
17449
17801
|
const updated = await this.adapter.views.update(viewId, { config: newConfig });
|
|
@@ -18314,18 +18666,4 @@ var NoopGeocodingAdapter = class {
|
|
|
18314
18666
|
|
|
18315
18667
|
|
|
18316
18668
|
|
|
18317
|
-
|
|
18318
|
-
|
|
18319
|
-
|
|
18320
|
-
|
|
18321
|
-
|
|
18322
|
-
|
|
18323
|
-
|
|
18324
|
-
|
|
18325
|
-
|
|
18326
|
-
|
|
18327
|
-
|
|
18328
|
-
|
|
18329
|
-
|
|
18330
|
-
|
|
18331
|
-
exports.IDENTITY_PROPERTIES = IDENTITY_PROPERTIES; exports.BEHAVIOR_PROPERTIES = BEHAVIOR_PROPERTIES; exports.PRESENTATION_PROPERTIES = PRESENTATION_PROPERTIES; exports.isIdentityProperty = isIdentityProperty; exports.isBehaviorProperty = isBehaviorProperty; exports.isPresentationProperty = isPresentationProperty; exports.RELATION_TARGET_ANY = RELATION_TARGET_ANY; exports.isUniversalRelation = isUniversalRelation; exports.RecordReferencedError = RecordReferencedError; exports.AttributeInUseError = AttributeInUseError; exports.ObjectReferencedError = ObjectReferencedError; exports.getErrorMessage = getErrorMessage; exports.NoopGeocodingAdapter = NoopGeocodingAdapter; exports.SYSTEM_FIELD_NAMES = SYSTEM_FIELD_NAMES; exports.RESERVED_ATTRIBUTE_NAMES = RESERVED_ATTRIBUTE_NAMES; exports.PolicyViolationError = PolicyViolationError; exports.FORBIDDEN_PROPERTY_TYPES = FORBIDDEN_PROPERTY_TYPES; exports.SYSTEM_ATTRIBUTES = SYSTEM_ATTRIBUTES; exports.getSystemAttributeList = getSystemAttributeList; exports.isSystemAttribute = isSystemAttribute; exports.isSystemAttributeObject = isSystemAttributeObject; exports.isSimpleFormNode = isSimpleFormNode; exports.isAdvancedFormNode = isAdvancedFormNode; exports.isStartNode = isStartNode; exports.isFormNode = isFormNode; exports.isConditionNode = isConditionNode; exports.isDocumentNode = isDocumentNode; exports.isEndNode = isEndNode; exports.getNodeOutputs = getNodeOutputs; exports.isConditionRule = isConditionRule; exports.isConditionGroup = isConditionGroup; exports.eq = eq; exports.neq = neq; exports.and = and; exports.or = or; exports.inValues = inValues; exports.isWorkflowDefinition = isWorkflowDefinition; exports.isWorkflowPublished = isWorkflowPublished; exports.isSystemWorkflow = isSystemWorkflow; exports.isInstanceTerminal = isInstanceTerminal; exports.isInstanceWaiting = isInstanceWaiting; exports.canResumeInstance = canResumeInstance; exports.createStartTransition = createStartTransition; exports.isInvitationValid = isInvitationValid; exports.isInvitationAccepted = isInvitationAccepted; exports.isInvitationExpired = isInvitationExpired; exports.isGrantValid = isGrantValid; exports.isGrantRevoked = isGrantRevoked; exports.isTokenRevoked = isTokenRevoked; exports.isGrantExpired = isGrantExpired; exports.canAccessNode = canAccessNode; exports.createEmptyContext = createEmptyContext; exports.getContextValue = getContextValue; exports.setContextValue = setContextValue; exports.DEFAULT_THEME = DEFAULT_THEME; exports.mergeWithDefaults = mergeWithDefaults; exports.generateCssVariables = generateCssVariables; exports.isInstanceEvent = isInstanceEvent; exports.isNodeEvent = isNodeEvent; exports.isInvitationOrGrantEvent = isInvitationOrGrantEvent; exports.ConditionOperatorSchema = ConditionOperatorSchema; exports.ConditionRuleSchema = ConditionRuleSchema; exports.ConditionGroupSchema = ConditionGroupSchema; exports.StartNodeSchema = StartNodeSchema; exports.FormFieldRefSchema = FormFieldRefSchema; exports.FlowRowFieldSchema = FlowRowFieldSchema; exports.FlowRowSchema = FlowRowSchema; exports.FormNodeSchema = FormNodeSchema; exports.ConditionNodeSchema = ConditionNodeSchema; exports.DocumentNodeSchema = DocumentNodeSchema; exports.EndNodeSchema = EndNodeSchema; exports.WorkflowNodeSchema = WorkflowNodeSchema; exports.SlotModeSchema = SlotModeSchema; exports.WorkflowSlotSchema = WorkflowSlotSchema; exports.AuthMethodSchema = AuthMethodSchema; exports.ShareStatusSchema = ShareStatusSchema; exports.WorkflowShareSchema = WorkflowShareSchema; exports.CreateShareInputSchema = CreateShareInputSchema; exports.NodePositionSchema = NodePositionSchema; exports.ViewportSchema = ViewportSchema; exports.WorkflowLayoutSchema = WorkflowLayoutSchema; exports.ThemeColorsSchema = ThemeColorsSchema; exports.ThemeLogoSchema = ThemeLogoSchema; exports.WorkflowThemeSchema = WorkflowThemeSchema; exports.WorkflowConfigSchema = WorkflowConfigSchema; exports.WorkflowStatusSchema = WorkflowStatusSchema; exports.WorkflowDefinitionSchema = WorkflowDefinitionSchema; exports.isEmpty = isEmpty; exports.isNotEmpty = isNotEmpty; exports.toUndefinedIfEmpty = toUndefinedIfEmpty; exports.hasProperties = hasProperties; exports.EMPTY_VALUE_PLACEHOLDER = EMPTY_VALUE_PLACEHOLDER; exports.formatAttributeValue = formatAttributeValue; exports.SchemaErrorCode = SchemaErrorCode; exports.SchemaError = SchemaError; exports.NotFoundError = NotFoundError; exports.ObjectNotFoundError = ObjectNotFoundError; exports.AttributeNotFoundError = AttributeNotFoundError; exports.RecordNotFoundError = RecordNotFoundError; exports.UserProfileNotFoundError = UserProfileNotFoundError; exports.FileNotFoundError = FileNotFoundError; exports.ValidationError = ValidationError; exports.ProtectedResourceError = ProtectedResourceError; exports.SyncError = SyncError; exports.NotSystemObjectError = NotSystemObjectError; exports.DuplicateError = DuplicateError; exports.isSchemaError = isSchemaError; exports.isNotFoundError = isNotFoundError; exports.isValidationError = isValidationError; exports.isProtectedResourceError = isProtectedResourceError; exports.ForbiddenError = ForbiddenError; exports.ProtectedRoleError = ProtectedRoleError; exports.RoleNotFoundError = RoleNotFoundError; exports.isForbiddenError = isForbiddenError; exports.ConcurrentModificationError = ConcurrentModificationError; exports.PropertySchemaBuilder = PropertySchemaBuilder; exports.PropertyTypeBuilder = PropertyTypeBuilder; exports.BasePropertyBuilder = BasePropertyBuilder; exports.TextPropertyBuilder = TextPropertyBuilder; exports.TextareaPropertyBuilder = TextareaPropertyBuilder; exports.NumberPropertyBuilder = NumberPropertyBuilder; exports.CheckboxPropertyBuilder = CheckboxPropertyBuilder; exports.DatePropertyBuilder = DatePropertyBuilder; exports.PhonePropertyBuilder = PhonePropertyBuilder; exports.CurrencyPropertyBuilder = CurrencyPropertyBuilder; exports.StatusPropertyBuilder = StatusPropertyBuilder; exports.SelectPropertyBuilder = SelectPropertyBuilder; exports.MultiselectPropertyBuilder = MultiselectPropertyBuilder; exports.RatingPropertyBuilder = RatingPropertyBuilder; exports.LocationPropertyBuilder = LocationPropertyBuilder; exports.validatePropertyType = validatePropertyType; exports.text = text; exports.textarea = textarea; exports.richtext = richtext; exports.number = number; exports.checkbox = checkbox; exports.date = date; exports.phone = phone; exports.currency = currency; exports.status = status; exports.select = select; exports.multiselect = multiselect; exports.location = location; exports.file = file; exports.user = user; exports.relation = relation; exports.rating = rating; exports.formula = formula; exports.rollup = rollup; exports.document = document; exports.ObjectBuilder = ObjectBuilder; exports.object = object; exports.GroupBuilder = GroupBuilder; exports.DirectTableTabConfig = DirectTableTabConfig; exports.InverseTableTabConfig = InverseTableTabConfig; exports.CustomTabConfig = CustomTabConfig; exports.NotesTabConfig = NotesTabConfig; exports.ActivityTabConfig = ActivityTabConfig; exports.FlowsTabConfig = FlowsTabConfig; exports.DocumentsTabConfig = DocumentsTabConfig; exports.TabBuilder = TabBuilder; exports.DetailViewBuilder = DetailViewBuilder; exports.ViewBuilder = ViewBuilder; exports.detailView = detailView; exports.view = view; exports.ListViewBuilder = ListViewBuilder; exports.ListViewTabConfigBuilder = ListViewTabConfigBuilder; exports.listView = listView; exports.group = group; exports.WorkflowFormRowBuilder = WorkflowFormRowBuilder; exports.WorkflowFormBuilder = WorkflowFormBuilder; exports.WorkflowSimpleFormBuilder = WorkflowSimpleFormBuilder; exports.WorkflowConditionBuilder = WorkflowConditionBuilder; exports.WorkflowEndBuilder = WorkflowEndBuilder; exports.WorkflowStartBuilder = WorkflowStartBuilder; exports.WorkflowBuilder = WorkflowBuilder; exports.workflow = workflow; exports.registry = registry; exports.SYSTEM_TEMPLATE_IDS = SYSTEM_TEMPLATE_IDS; exports.FRENCH_ID_CARD = FRENCH_ID_CARD; exports.PASSPORT = PASSPORT; exports.DRIVING_LICENSE = DRIVING_LICENSE; exports.PROOF_OF_ADDRESS = PROOF_OF_ADDRESS; exports.SIGNABLE_CONTRACT = SIGNABLE_CONTRACT; exports.GENERIC_DOCUMENT = GENERIC_DOCUMENT; exports.SYSTEM_TEMPLATES = SYSTEM_TEMPLATES; exports.getSystemTemplate = getSystemTemplate; exports.isSystemTemplate = isSystemTemplate; exports.WorkflowJwtService = WorkflowJwtService; exports.hashOptions = hashOptions; exports.cacheKeys = cacheKeys; exports.cacheTtl = cacheTtl; exports.defaultTtl = defaultTtl; exports.NoopCacheAdapter = NoopCacheAdapter; exports.formatRecord = formatRecord; exports.formatRecords = formatRecords; exports.createDefaultState = createDefaultState; exports.SHORTCUT_TO_FILTER_OPERATOR = SHORTCUT_TO_FILTER_OPERATOR; exports.QueryNoResultError = QueryNoResultError; exports.QueryMultipleResultsError = QueryMultipleResultsError; exports.TenantContextError = TenantContextError; exports.FeatureFlagsContextError = FeatureFlagsContextError; exports.isFeatureEnabled = isFeatureEnabled; exports.getFeatureValue = getFeatureValue; exports.getFeatureFlags = getFeatureFlags; exports.tryGetFeatureValue = tryGetFeatureValue; exports.hasFeatureFlagsContext = hasFeatureFlagsContext; exports.runWithFeatureFlags = runWithFeatureFlags; exports.withFeatureFlags = withFeatureFlags; exports.getSchemaFromContext = getSchemaFromContext; exports.getSchemaByNameFromContext = getSchemaByNameFromContext; exports.hasSchemaContext = hasSchemaContext; exports.getSchemaContext = getSchemaContext; exports.addSchemaToContext = addSchemaToContext; exports.runWithSchemaContext = runWithSchemaContext; exports.runWithMergedSchemaContext = runWithMergedSchemaContext; exports.getContext = getContext2; exports.getTenantId = getTenantId; exports.getUserId = getUserId; exports.hasContext = hasContext; exports.runWithContext = runWithContext; exports.withTenantContext = withTenantContext; exports.QueryBuilder = QueryBuilder; exports.createQueryBuilder = createQueryBuilder; exports.evaluateCondition = evaluateCondition; exports.evaluate = evaluate; exports.evaluateWithTrace = evaluateWithTrace; exports.ExecutorRegistry = ExecutorRegistry; exports.success = success; exports.wait = wait; exports.complete = complete; exports.error = error; exports.ConditionExecutor = ConditionExecutor; exports.DocumentExecutor = DocumentExecutor; exports.EndExecutor = EndExecutor; exports.FormExecutor = FormExecutor; exports.StartExecutor = StartExecutor; exports.createDefaultExecutorRegistry = createDefaultExecutorRegistry; exports.getDefaultExecutorRegistry = getDefaultExecutorRegistry; exports.evaluateFormula = evaluateFormula; exports.evaluateFormulaWithResult = evaluateFormulaWithResult; exports.formatFormulaResult = formatFormulaResult; exports.evaluateFormulaAttribute = evaluateFormulaAttribute; exports.validateFormulaExpression = validateFormulaExpression; exports.extractFormulaVariables = extractFormulaVariables; exports.extractRelationReferences = extractRelationReferences; exports.extractRelationNames = extractRelationNames; exports.hasRelationReferences = hasRelationReferences; exports.flattenRelationsForEval = flattenRelationsForEval; exports.evaluateFormulaWithRelations = evaluateFormulaWithRelations; exports.evaluateFormulaAttributeWithRelations = evaluateFormulaAttributeWithRelations; exports.InvalidPathError = InvalidPathError; exports.MaxDepthExceededError = MaxDepthExceededError; exports.parsePath = parsePath; exports.validatePath = validatePath; exports.pathHasManyCardinality = pathHasManyCardinality; exports.getPathDepth = getPathDepth; exports.getTargetAttributeName = getTargetAttributeName; exports.getRelationPath = getRelationPath; exports.traversePath = traversePath; exports.resolveSingleValue = resolveSingleValue; exports.resolveMultiplePaths = resolveMultiplePaths; exports.NoopHookRegistry = NoopHookRegistry; exports.DEFAULT_LABEL_FALLBACK = DEFAULT_LABEL_FALLBACK; exports.renderLabelExpression = renderLabelExpression; exports.isLabelExpression = isLabelExpression; exports.extractAttributeNames = extractAttributeNames; exports.enrichValuesForDisplay = enrichValuesForDisplay; exports.enrichValuesWithSelectLabels = enrichValuesWithSelectLabels; exports.extractRelationIds = extractRelationIds; exports.computeLabelWithRelations = computeLabelWithRelations; exports.createMockAdapter = createMockAdapter; exports.PolicyRegistry = PolicyRegistry; exports.defaultPolicyRegistry = defaultPolicyRegistry; exports.notesPolicy = notesPolicy; exports.BaseService = BaseService; exports.BaseRepository = BaseRepository; exports.SchemaContextAwareRepository = SchemaContextAwareRepository; exports.buildAuditChanges = buildAuditChanges; exports.ObjectSchemaService = ObjectSchemaService; exports.AuditService = AuditService; exports.UserService = UserService; exports.applyDefaultValues = applyDefaultValues; exports.checkPermission = checkPermission; exports.getPolicy = getPolicy; exports.buildPolicyContext = buildPolicyContext; exports.checkRecordAccess = checkRecordAccess; exports.checkRecordModifyOrThrow = checkRecordModifyOrThrow; exports.checkRecordDeleteOrThrow = checkRecordDeleteOrThrow; exports.checkSharedObjectWriteAccess = checkSharedObjectWriteAccess; exports.computeLabel = computeLabel; exports.enrichWithFormulas = enrichWithFormulas; exports.enrichRecordsWithFormulas = enrichRecordsWithFormulas; exports.createContextForCreate = createContextForCreate; exports.createContextForUpdate = createContextForUpdate; exports.createContextForDelete = createContextForDelete; exports.createContextForRestore = createContextForRestore; exports.recalculateParentRollups = recalculateParentRollups; exports.RecordQueryService = RecordQueryService; exports.RecordResolverService = RecordResolverService; exports.RelationPropertiesService = RelationPropertiesService; exports.RelationService = RelationService; exports.RollupService = RollupService; exports.RecordService = RecordService; exports.FormulaResolverService = FormulaResolverService; exports.RollupScheduler = RollupScheduler; exports.DocumentRenderError = DocumentRenderError; exports.StorageDownloadNotSupportedError = StorageDownloadNotSupportedError; exports.DocumentRendererService = DocumentRendererService; exports.DocumentProcessingHook = DocumentProcessingHook; exports.GrantNotFoundError = GrantNotFoundError; exports.GrantExpiredError = GrantExpiredError; exports.GrantRevokedError = GrantRevokedError; exports.TokenRevokedError = TokenRevokedError; exports.WorkflowAccessGrantService = WorkflowAccessGrantService; exports.WorkflowInstanceService = WorkflowInstanceService; exports.InvitationNotFoundError = InvitationNotFoundError; exports.InvitationExpiredError = InvitationExpiredError; exports.InvitationAlreadyAcceptedError = InvitationAlreadyAcceptedError; exports.InvitationRevokedError = InvitationRevokedError; exports.WorkflowInvitationService = WorkflowInvitationService; exports.WorkflowRelationService = WorkflowRelationService; exports.WorkflowService = WorkflowService; exports.UserProfileService = UserProfileService; exports.DocumentGenerationTemplateNotFoundError = DocumentGenerationTemplateNotFoundError; exports.DocumentGenerationNotConfiguredError = DocumentGenerationNotConfiguredError; exports.DocumentGenerationService = DocumentGenerationService; exports.DocumentTemplateService = DocumentTemplateService; exports.DocumentService = DocumentService; exports.DocumentProcessingService = DocumentProcessingService; exports.FileService = FileService; exports.GeocodingService = GeocodingService; exports.GlobalSearchService = GlobalSearchService; exports.PermissionService = PermissionService; exports.ViewService = ViewService; exports.seedRegistryViews = seedRegistryViews; exports.syncNativeViews = syncNativeViews; exports.verifyRegistryViewsSeeded = verifyRegistryViewsSeeded; exports.verifyNativeViewsSync = verifyNativeViewsSync; exports.getViewSeedPreview = getViewSeedPreview; exports.getViewSyncPreview = getViewSyncPreview; exports.syncNativeObjects = syncNativeObjects; exports.verifyNativeObjectsSync = verifyNativeObjectsSync; exports.getSyncPreview = getSyncPreview; exports.syncAll = syncAll;
|
|
18669
|
+
exports.IDENTITY_PROPERTIES = IDENTITY_PROPERTIES; exports.BEHAVIOR_PROPERTIES = BEHAVIOR_PROPERTIES; exports.PRESENTATION_PROPERTIES = PRESENTATION_PROPERTIES; exports.isIdentityProperty = isIdentityProperty; exports.isBehaviorProperty = isBehaviorProperty; exports.isPresentationProperty = isPresentationProperty; exports.RELATION_TARGET_ANY = RELATION_TARGET_ANY; exports.isUniversalRelation = isUniversalRelation; exports.isBilateralRelation = isBilateralRelation; exports.inferInverseCardinality = inferInverseCardinality; exports.RecordReferencedError = RecordReferencedError; exports.AttributeInUseError = AttributeInUseError; exports.ObjectReferencedError = ObjectReferencedError; exports.getErrorMessage = getErrorMessage; exports.NoopGeocodingAdapter = NoopGeocodingAdapter; exports.SYSTEM_FIELD_NAMES = SYSTEM_FIELD_NAMES; exports.RESERVED_ATTRIBUTE_NAMES = RESERVED_ATTRIBUTE_NAMES; exports.PolicyViolationError = PolicyViolationError; exports.FORBIDDEN_PROPERTY_TYPES = FORBIDDEN_PROPERTY_TYPES; exports.SYSTEM_ATTRIBUTES = SYSTEM_ATTRIBUTES; exports.getSystemAttributeList = getSystemAttributeList; exports.isSystemAttribute = isSystemAttribute; exports.isSystemAttributeObject = isSystemAttributeObject; exports.isSimpleFormNode = isSimpleFormNode; exports.isAdvancedFormNode = isAdvancedFormNode; exports.isStartNode = isStartNode; exports.isFormNode = isFormNode; exports.isConditionNode = isConditionNode; exports.isDocumentNode = isDocumentNode; exports.isEndNode = isEndNode; exports.getNodeOutputs = getNodeOutputs; exports.isConditionRule = isConditionRule; exports.isConditionGroup = isConditionGroup; exports.eq = eq; exports.neq = neq; exports.and = and; exports.or = or; exports.inValues = inValues; exports.isWorkflowDefinition = isWorkflowDefinition; exports.isWorkflowPublished = isWorkflowPublished; exports.isSystemWorkflow = isSystemWorkflow; exports.isInstanceTerminal = isInstanceTerminal; exports.isInstanceWaiting = isInstanceWaiting; exports.canResumeInstance = canResumeInstance; exports.createStartTransition = createStartTransition; exports.isInvitationValid = isInvitationValid; exports.isInvitationAccepted = isInvitationAccepted; exports.isInvitationExpired = isInvitationExpired; exports.isGrantValid = isGrantValid; exports.isGrantRevoked = isGrantRevoked; exports.isTokenRevoked = isTokenRevoked; exports.isGrantExpired = isGrantExpired; exports.canAccessNode = canAccessNode; exports.createEmptyContext = createEmptyContext; exports.getContextValue = getContextValue; exports.setContextValue = setContextValue; exports.DEFAULT_THEME = DEFAULT_THEME; exports.mergeWithDefaults = mergeWithDefaults; exports.generateCssVariables = generateCssVariables; exports.isInstanceEvent = isInstanceEvent; exports.isNodeEvent = isNodeEvent; exports.isInvitationOrGrantEvent = isInvitationOrGrantEvent; exports.ConditionOperatorSchema = ConditionOperatorSchema; exports.ConditionRuleSchema = ConditionRuleSchema; exports.ConditionGroupSchema = ConditionGroupSchema; exports.StartNodeSchema = StartNodeSchema; exports.FormFieldRefSchema = FormFieldRefSchema; exports.FlowRowFieldSchema = FlowRowFieldSchema; exports.FlowRowSchema = FlowRowSchema; exports.FormNodeSchema = FormNodeSchema; exports.ConditionNodeSchema = ConditionNodeSchema; exports.DocumentNodeSchema = DocumentNodeSchema; exports.EndNodeSchema = EndNodeSchema; exports.WorkflowNodeSchema = WorkflowNodeSchema; exports.SlotModeSchema = SlotModeSchema; exports.WorkflowSlotSchema = WorkflowSlotSchema; exports.AuthMethodSchema = AuthMethodSchema; exports.ShareStatusSchema = ShareStatusSchema; exports.WorkflowShareSchema = WorkflowShareSchema; exports.CreateShareInputSchema = CreateShareInputSchema; exports.NodePositionSchema = NodePositionSchema; exports.ViewportSchema = ViewportSchema; exports.WorkflowLayoutSchema = WorkflowLayoutSchema; exports.ThemeColorsSchema = ThemeColorsSchema; exports.ThemeLogoSchema = ThemeLogoSchema; exports.WorkflowThemeSchema = WorkflowThemeSchema; exports.WorkflowConfigSchema = WorkflowConfigSchema; exports.WorkflowStatusSchema = WorkflowStatusSchema; exports.WorkflowDefinitionSchema = WorkflowDefinitionSchema; exports.isEmpty = isEmpty; exports.isNotEmpty = isNotEmpty; exports.toUndefinedIfEmpty = toUndefinedIfEmpty; exports.hasProperties = hasProperties; exports.EMPTY_VALUE_PLACEHOLDER = EMPTY_VALUE_PLACEHOLDER; exports.formatAttributeValue = formatAttributeValue; exports.DEFAULT_LABEL_FALLBACK = DEFAULT_LABEL_FALLBACK; exports.renderLabelExpression = renderLabelExpression; exports.isLabelExpression = isLabelExpression; exports.extractAttributeNames = extractAttributeNames; exports.enrichValuesForDisplay = enrichValuesForDisplay; exports.enrichValuesWithSelectLabels = enrichValuesWithSelectLabels; exports.extractRelationIds = extractRelationIds; exports.computeLabelWithRelations = computeLabelWithRelations; exports.SchemaErrorCode = SchemaErrorCode; exports.SchemaError = SchemaError; exports.NotFoundError = NotFoundError; exports.ObjectNotFoundError = ObjectNotFoundError; exports.AttributeNotFoundError = AttributeNotFoundError; exports.RecordNotFoundError = RecordNotFoundError; exports.UserProfileNotFoundError = UserProfileNotFoundError; exports.FileNotFoundError = FileNotFoundError; exports.ValidationError = ValidationError; exports.ProtectedResourceError = ProtectedResourceError; exports.SyncError = SyncError; exports.NotSystemObjectError = NotSystemObjectError; exports.DuplicateError = DuplicateError; exports.isSchemaError = isSchemaError; exports.isNotFoundError = isNotFoundError; exports.isValidationError = isValidationError; exports.isProtectedResourceError = isProtectedResourceError; exports.ForbiddenError = ForbiddenError; exports.ProtectedRoleError = ProtectedRoleError; exports.RoleNotFoundError = RoleNotFoundError; exports.isForbiddenError = isForbiddenError; exports.ConcurrentModificationError = ConcurrentModificationError; exports.text = text; exports.textarea = textarea; exports.richtext = richtext; exports.number = number; exports.checkbox = checkbox; exports.date = date; exports.phone = phone; exports.currency = currency; exports.status = status; exports.select = select; exports.multiselect = multiselect; exports.location = location; exports.file = file; exports.user = user; exports.relation = relation; exports.rating = rating; exports.formula = formula; exports.rollup = rollup; exports.document = document; exports.ObjectBuilder = ObjectBuilder; exports.object = object; exports.GroupBuilder = GroupBuilder; exports.RelationGroupBuilder = RelationGroupBuilder; exports.TableTabConfig = TableTabConfig; exports.CustomTabConfig = CustomTabConfig; exports.RichtextTabConfig = RichtextTabConfig; exports.ActivityTabConfig = ActivityTabConfig; exports.FlowsTabConfig = FlowsTabConfig; exports.DocumentsTabConfig = DocumentsTabConfig; exports.TabBuilder = TabBuilder; exports.DetailViewBuilder = DetailViewBuilder; exports.ViewBuilder = ViewBuilder; exports.detailView = detailView; exports.view = view; exports.ListViewBuilder = ListViewBuilder; exports.ListViewTabConfigBuilder = ListViewTabConfigBuilder; exports.listView = listView; exports.group = group; exports.relationGroup = relationGroup; exports.WorkflowFormRowBuilder = WorkflowFormRowBuilder; exports.WorkflowFormBuilder = WorkflowFormBuilder; exports.WorkflowSimpleFormBuilder = WorkflowSimpleFormBuilder; exports.WorkflowConditionBuilder = WorkflowConditionBuilder; exports.WorkflowEndBuilder = WorkflowEndBuilder; exports.WorkflowStartBuilder = WorkflowStartBuilder; exports.WorkflowBuilder = WorkflowBuilder; exports.workflow = workflow; exports.registry = registry; exports.SYSTEM_TEMPLATE_IDS = SYSTEM_TEMPLATE_IDS; exports.FRENCH_ID_CARD = FRENCH_ID_CARD; exports.PASSPORT = PASSPORT; exports.DRIVING_LICENSE = DRIVING_LICENSE; exports.PROOF_OF_ADDRESS = PROOF_OF_ADDRESS; exports.SIGNABLE_CONTRACT = SIGNABLE_CONTRACT; exports.GENERIC_DOCUMENT = GENERIC_DOCUMENT; exports.SYSTEM_TEMPLATES = SYSTEM_TEMPLATES; exports.getSystemTemplate = getSystemTemplate; exports.isSystemTemplate = isSystemTemplate; exports.WorkflowJwtService = WorkflowJwtService; exports.hashOptions = hashOptions; exports.cacheKeys = cacheKeys; exports.cacheTtl = cacheTtl; exports.defaultTtl = defaultTtl; exports.NoopCacheAdapter = NoopCacheAdapter; exports.formatRecord = formatRecord; exports.formatRecords = formatRecords; exports.createDefaultState = createDefaultState; exports.SHORTCUT_TO_FILTER_OPERATOR = SHORTCUT_TO_FILTER_OPERATOR; exports.QueryNoResultError = QueryNoResultError; exports.QueryMultipleResultsError = QueryMultipleResultsError; exports.TenantContextError = TenantContextError; exports.FeatureFlagsContextError = FeatureFlagsContextError; exports.isFeatureEnabled = isFeatureEnabled; exports.getFeatureValue = getFeatureValue; exports.getFeatureFlags = getFeatureFlags; exports.tryGetFeatureValue = tryGetFeatureValue; exports.hasFeatureFlagsContext = hasFeatureFlagsContext; exports.runWithFeatureFlags = runWithFeatureFlags; exports.withFeatureFlags = withFeatureFlags; exports.getSchemaFromContext = getSchemaFromContext; exports.getSchemaByNameFromContext = getSchemaByNameFromContext; exports.hasSchemaContext = hasSchemaContext; exports.getSchemaContext = getSchemaContext; exports.addSchemaToContext = addSchemaToContext; exports.runWithSchemaContext = runWithSchemaContext; exports.runWithMergedSchemaContext = runWithMergedSchemaContext; exports.getContext = getContext2; exports.getTenantId = getTenantId; exports.getUserId = getUserId; exports.hasContext = hasContext; exports.runWithContext = runWithContext; exports.withTenantContext = withTenantContext; exports.QueryBuilder = QueryBuilder; exports.createQueryBuilder = createQueryBuilder; exports.evaluateCondition = evaluateCondition; exports.evaluate = evaluate; exports.evaluateWithTrace = evaluateWithTrace; exports.ExecutorRegistry = ExecutorRegistry; exports.success = success; exports.wait = wait; exports.complete = complete; exports.error = error; exports.ConditionExecutor = ConditionExecutor; exports.DocumentExecutor = DocumentExecutor; exports.EndExecutor = EndExecutor; exports.FormExecutor = FormExecutor; exports.StartExecutor = StartExecutor; exports.createDefaultExecutorRegistry = createDefaultExecutorRegistry; exports.getDefaultExecutorRegistry = getDefaultExecutorRegistry; exports.evaluateFormula = evaluateFormula; exports.evaluateFormulaWithResult = evaluateFormulaWithResult; exports.formatFormulaResult = formatFormulaResult; exports.evaluateFormulaAttribute = evaluateFormulaAttribute; exports.validateFormulaExpression = validateFormulaExpression; exports.extractFormulaVariables = extractFormulaVariables; exports.extractRelationReferences = extractRelationReferences; exports.extractRelationNames = extractRelationNames; exports.hasRelationReferences = hasRelationReferences; exports.flattenRelationsForEval = flattenRelationsForEval; exports.evaluateFormulaWithRelations = evaluateFormulaWithRelations; exports.evaluateFormulaAttributeWithRelations = evaluateFormulaAttributeWithRelations; exports.InvalidPathError = InvalidPathError; exports.MaxDepthExceededError = MaxDepthExceededError; exports.parsePath = parsePath; exports.validatePath = validatePath; exports.pathHasManyCardinality = pathHasManyCardinality; exports.getPathDepth = getPathDepth; exports.getTargetAttributeName = getTargetAttributeName; exports.getRelationPath = getRelationPath; exports.traversePath = traversePath; exports.resolveSingleValue = resolveSingleValue; exports.resolveMultiplePaths = resolveMultiplePaths; exports.NoopHookRegistry = NoopHookRegistry; exports.createMockAdapter = createMockAdapter; exports.PolicyRegistry = PolicyRegistry; exports.defaultPolicyRegistry = defaultPolicyRegistry; exports.BaseService = BaseService; exports.BaseRepository = BaseRepository; exports.SchemaContextAwareRepository = SchemaContextAwareRepository; exports.buildAuditChanges = buildAuditChanges; exports.ObjectSchemaService = ObjectSchemaService; exports.AuditService = AuditService; exports.UserService = UserService; exports.applyDefaultValues = applyDefaultValues; exports.checkPermission = checkPermission; exports.getPolicy = getPolicy; exports.buildPolicyContext = buildPolicyContext; exports.checkRecordAccess = checkRecordAccess; exports.checkRecordModifyOrThrow = checkRecordModifyOrThrow; exports.checkRecordDeleteOrThrow = checkRecordDeleteOrThrow; exports.checkSharedObjectWriteAccess = checkSharedObjectWriteAccess; exports.computeLabel = computeLabel; exports.enrichWithFormulas = enrichWithFormulas; exports.enrichRecordsWithFormulas = enrichRecordsWithFormulas; exports.createContextForCreate = createContextForCreate; exports.createContextForUpdate = createContextForUpdate; exports.createContextForDelete = createContextForDelete; exports.createContextForRestore = createContextForRestore; exports.recalculateParentRollups = recalculateParentRollups; exports.RelationPropertiesService = RelationPropertiesService; exports.RecordQueryService = RecordQueryService; exports.RecordResolverService = RecordResolverService; exports.RelationService = RelationService; exports.RollupService = RollupService; exports.RecordService = RecordService; exports.FormulaResolverService = FormulaResolverService; exports.RollupScheduler = RollupScheduler; exports.DocumentRenderError = DocumentRenderError; exports.StorageDownloadNotSupportedError = StorageDownloadNotSupportedError; exports.DocumentRendererService = DocumentRendererService; exports.DocumentProcessingHook = DocumentProcessingHook; exports.GrantNotFoundError = GrantNotFoundError; exports.GrantExpiredError = GrantExpiredError; exports.GrantRevokedError = GrantRevokedError; exports.TokenRevokedError = TokenRevokedError; exports.WorkflowAccessGrantService = WorkflowAccessGrantService; exports.WorkflowInstanceService = WorkflowInstanceService; exports.InvitationNotFoundError = InvitationNotFoundError; exports.InvitationExpiredError = InvitationExpiredError; exports.InvitationAlreadyAcceptedError = InvitationAlreadyAcceptedError; exports.InvitationRevokedError = InvitationRevokedError; exports.WorkflowInvitationService = WorkflowInvitationService; exports.WorkflowRelationService = WorkflowRelationService; exports.WorkflowService = WorkflowService; exports.UserProfileService = UserProfileService; exports.DocumentGenerationTemplateNotFoundError = DocumentGenerationTemplateNotFoundError; exports.DocumentGenerationNotConfiguredError = DocumentGenerationNotConfiguredError; exports.DocumentGenerationService = DocumentGenerationService; exports.DocumentTemplateService = DocumentTemplateService; exports.DocumentService = DocumentService; exports.DocumentProcessingService = DocumentProcessingService; exports.FileService = FileService; exports.GeocodingService = GeocodingService; exports.GlobalSearchService = GlobalSearchService; exports.PermissionService = PermissionService; exports.ViewService = ViewService; exports.seedRegistryViews = seedRegistryViews; exports.syncNativeViews = syncNativeViews; exports.verifyRegistryViewsSeeded = verifyRegistryViewsSeeded; exports.verifyNativeViewsSync = verifyNativeViewsSync; exports.getViewSeedPreview = getViewSeedPreview; exports.getViewSyncPreview = getViewSyncPreview; exports.syncNativeObjects = syncNativeObjects; exports.verifyNativeObjectsSync = verifyNativeObjectsSync; exports.getSyncPreview = getSyncPreview; exports.syncAll = syncAll;
|