@stndrds/schema 0.1.0-alpha.62 → 0.1.0-alpha.64
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-KMAKDHCL.js → chunk-5IU6XTFA.js} +1471 -1219
- package/dist/{chunk-MUJVBSBL.mjs → chunk-IIKZXK57.mjs} +1233 -981
- package/dist/index.d.mts +168 -323
- package/dist/index.d.ts +168 -323
- package/dist/index.js +37 -67
- package/dist/index.mjs +41 -71
- package/dist/{runtime-7G9tZJYC.d.ts → runtime-BzYhhUVf.d.ts} +311 -210
- package/dist/{runtime-C4U2ppAk.d.mts → runtime-D52-pPFI.d.mts} +311 -210
- 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,8 @@ var GroupBuilder = class {
|
|
|
7063
6707
|
return this.data;
|
|
7064
6708
|
}
|
|
7065
6709
|
};
|
|
7066
|
-
var
|
|
6710
|
+
var TableTabConfig = class {
|
|
6711
|
+
/** @internal */
|
|
7067
6712
|
constructor(view2, tabData) {
|
|
7068
6713
|
this.view = view2;
|
|
7069
6714
|
this.tabData = tabData;
|
|
@@ -7141,6 +6786,29 @@ var BaseTableTabConfig = class {
|
|
|
7141
6786
|
this.tabData.sorts.push({ attribute, direction });
|
|
7142
6787
|
return this;
|
|
7143
6788
|
}
|
|
6789
|
+
/**
|
|
6790
|
+
* Traverse a 2nd-level relation to display nested data.
|
|
6791
|
+
* When active, `tab.columns` stores the 2nd-level object's attribute names.
|
|
6792
|
+
*
|
|
6793
|
+
* @param attribute - Relation attribute on the first-level target object
|
|
6794
|
+
* @example .table("members").through("companies").columns(["name", "sector"])
|
|
6795
|
+
*/
|
|
6796
|
+
through(attribute) {
|
|
6797
|
+
this.tabData.through = { attribute };
|
|
6798
|
+
return this;
|
|
6799
|
+
}
|
|
6800
|
+
/**
|
|
6801
|
+
* Show _source and _target columns in flattened (through) view
|
|
6802
|
+
*/
|
|
6803
|
+
showSourceTarget(value = true) {
|
|
6804
|
+
if (!this.tabData.through) {
|
|
6805
|
+
throw new Error(
|
|
6806
|
+
`[TableTabConfig] showSourceTarget() requires through() to be called first for tab "${this.tabData.name}"`
|
|
6807
|
+
);
|
|
6808
|
+
}
|
|
6809
|
+
this.tabData.through.showSourceTarget = value;
|
|
6810
|
+
return this;
|
|
6811
|
+
}
|
|
7144
6812
|
/**
|
|
7145
6813
|
* Continue building with a new tab
|
|
7146
6814
|
*/
|
|
@@ -7169,31 +6837,6 @@ var BaseTableTabConfig = class {
|
|
|
7169
6837
|
this.view._addTab(this.tabData);
|
|
7170
6838
|
}
|
|
7171
6839
|
};
|
|
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
6840
|
var CustomTabConfig = class {
|
|
7198
6841
|
/** @internal */
|
|
7199
6842
|
constructor(view2, base, component) {
|
|
@@ -7229,24 +6872,17 @@ var CustomTabConfig = class {
|
|
|
7229
6872
|
return this.view.build();
|
|
7230
6873
|
}
|
|
7231
6874
|
};
|
|
7232
|
-
var
|
|
6875
|
+
var RichtextTabConfig = class {
|
|
7233
6876
|
/** @internal */
|
|
7234
|
-
constructor(view2, base) {
|
|
6877
|
+
constructor(view2, base, attribute) {
|
|
7235
6878
|
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;
|
|
6879
|
+
this.tabData = { ...base, type: "richtext", attribute };
|
|
7244
6880
|
}
|
|
7245
6881
|
/**
|
|
7246
|
-
*
|
|
6882
|
+
* Set a text attribute to display as an editable title above the editor
|
|
7247
6883
|
*/
|
|
7248
|
-
|
|
7249
|
-
this.tabData.
|
|
6884
|
+
titleAttribute(name) {
|
|
6885
|
+
this.tabData.titleAttribute = name;
|
|
7250
6886
|
return this;
|
|
7251
6887
|
}
|
|
7252
6888
|
/**
|
|
@@ -7485,27 +7121,37 @@ var TabBuilder = class {
|
|
|
7485
7121
|
return this.view._addTab(tab);
|
|
7486
7122
|
}
|
|
7487
7123
|
/**
|
|
7488
|
-
* Create a
|
|
7124
|
+
* Create a table tab for a relation attribute on the current object
|
|
7489
7125
|
*
|
|
7490
7126
|
* Use this when the current object has a relation attribute pointing to another object.
|
|
7491
7127
|
*
|
|
7492
7128
|
* @param relationAttribute - Name of the relation attribute on the current object
|
|
7493
|
-
* @example .table("members").columns("name", "email").crud()
|
|
7129
|
+
* @example .table("members").columns("name", "email").crud()
|
|
7494
7130
|
*/
|
|
7495
7131
|
table(relationAttribute) {
|
|
7496
|
-
return new
|
|
7132
|
+
return new TableTabConfig(this.view, {
|
|
7133
|
+
...this.base,
|
|
7134
|
+
type: "table",
|
|
7135
|
+
source: { type: "relation", attribute: relationAttribute },
|
|
7136
|
+
columns: []
|
|
7137
|
+
});
|
|
7497
7138
|
}
|
|
7498
7139
|
/**
|
|
7499
|
-
* Create
|
|
7140
|
+
* Create a table tab showing records from another object that have a relation to us
|
|
7500
7141
|
*
|
|
7501
7142
|
* Use this when another object has a relation attribute pointing to the current object.
|
|
7502
7143
|
*
|
|
7503
7144
|
* @param sourceObject - Name of the object that has the relation to us
|
|
7504
7145
|
* @param relationAttribute - Name of the relation attribute on the source object
|
|
7505
|
-
* @example .tableFrom("contacts", "company").columns("firstName", "lastName")
|
|
7146
|
+
* @example .tableFrom("contacts", "company").columns("firstName", "lastName")
|
|
7506
7147
|
*/
|
|
7507
7148
|
tableFrom(sourceObject, relationAttribute) {
|
|
7508
|
-
return new
|
|
7149
|
+
return new TableTabConfig(this.view, {
|
|
7150
|
+
...this.base,
|
|
7151
|
+
type: "table",
|
|
7152
|
+
source: { type: "inverse", object: sourceObject, attribute: relationAttribute },
|
|
7153
|
+
columns: []
|
|
7154
|
+
});
|
|
7509
7155
|
}
|
|
7510
7156
|
/**
|
|
7511
7157
|
* Create a custom tab with a component
|
|
@@ -7515,11 +7161,11 @@ var TabBuilder = class {
|
|
|
7515
7161
|
return new CustomTabConfig(this.view, this.base, component);
|
|
7516
7162
|
}
|
|
7517
7163
|
/**
|
|
7518
|
-
* Create a
|
|
7519
|
-
* @example .
|
|
7164
|
+
* Create a richtext tab for a richtext attribute
|
|
7165
|
+
* @example .richtext("content").titleAttribute("title")
|
|
7520
7166
|
*/
|
|
7521
|
-
|
|
7522
|
-
return new
|
|
7167
|
+
richtext(attribute) {
|
|
7168
|
+
return new RichtextTabConfig(this.view, this.base, attribute);
|
|
7523
7169
|
}
|
|
7524
7170
|
/**
|
|
7525
7171
|
* Create an activity tab
|
|
@@ -7606,6 +7252,16 @@ var DetailViewBuilder = class {
|
|
|
7606
7252
|
this.data.metadata = value;
|
|
7607
7253
|
return this;
|
|
7608
7254
|
}
|
|
7255
|
+
/**
|
|
7256
|
+
* Configure a side panel with flat attribute fields displayed alongside tab content.
|
|
7257
|
+
* Not available for modal layout.
|
|
7258
|
+
*
|
|
7259
|
+
* @example .sidePanel({ attributes: ["visibility", "linkedTo"] })
|
|
7260
|
+
*/
|
|
7261
|
+
sidePanel(config) {
|
|
7262
|
+
this.data.sidePanel = config;
|
|
7263
|
+
return this;
|
|
7264
|
+
}
|
|
7609
7265
|
/**
|
|
7610
7266
|
* Start building a new tab
|
|
7611
7267
|
*/
|
|
@@ -7650,10 +7306,14 @@ var DetailViewBuilder = class {
|
|
|
7650
7306
|
if (this.data.tabs[0].type !== "form") {
|
|
7651
7307
|
throw new Error("[DetailViewBuilder] Modal views must have a form tab");
|
|
7652
7308
|
}
|
|
7309
|
+
if (this.data.sidePanel) {
|
|
7310
|
+
throw new Error("[DetailViewBuilder] Modal views cannot have a side panel");
|
|
7311
|
+
}
|
|
7653
7312
|
}
|
|
7654
7313
|
const config = {
|
|
7655
7314
|
layout: this.data.layout,
|
|
7656
|
-
tabs: this.data.tabs
|
|
7315
|
+
tabs: this.data.tabs,
|
|
7316
|
+
sidePanel: this.data.sidePanel
|
|
7657
7317
|
};
|
|
7658
7318
|
return {
|
|
7659
7319
|
name: this.data.name,
|
|
@@ -8012,8 +7672,8 @@ var WorkflowFormRowBuilder = class {
|
|
|
8012
7672
|
id: `${this.rowData.id}-${slotId}-${attribute}`,
|
|
8013
7673
|
slotId,
|
|
8014
7674
|
attribute,
|
|
8015
|
-
label: _optionalChain([options, 'optionalAccess',
|
|
8016
|
-
required: _optionalChain([options, 'optionalAccess',
|
|
7675
|
+
label: _optionalChain([options, 'optionalAccess', _148 => _148.label]),
|
|
7676
|
+
required: _optionalChain([options, 'optionalAccess', _149 => _149.required])
|
|
8017
7677
|
};
|
|
8018
7678
|
this.rowData.fields.push(field);
|
|
8019
7679
|
return this;
|
|
@@ -8304,7 +7964,7 @@ var WorkflowBuilder = class {
|
|
|
8304
7964
|
* @param options - Slot configuration
|
|
8305
7965
|
*/
|
|
8306
7966
|
slot(id, objectName, options) {
|
|
8307
|
-
if (_optionalChain([this, 'access',
|
|
7967
|
+
if (_optionalChain([this, 'access', _150 => _150.data, 'access', _151 => _151.slots, 'optionalAccess', _152 => _152.some, 'call', _153 => _153((s) => s.id === id)])) {
|
|
8308
7968
|
throw new Error(`[WorkflowBuilder] Duplicate slot id: "${id}"`);
|
|
8309
7969
|
}
|
|
8310
7970
|
const slot = {
|
|
@@ -8315,7 +7975,7 @@ var WorkflowBuilder = class {
|
|
|
8315
7975
|
color: options.color,
|
|
8316
7976
|
icon: options.icon
|
|
8317
7977
|
};
|
|
8318
|
-
_optionalChain([this, 'access',
|
|
7978
|
+
_optionalChain([this, 'access', _154 => _154.data, 'access', _155 => _155.slots, 'optionalAccess', _156 => _156.push, 'call', _157 => _157(slot)]);
|
|
8319
7979
|
return this;
|
|
8320
7980
|
}
|
|
8321
7981
|
// ============================================================================
|
|
@@ -8447,7 +8107,7 @@ var WorkflowBuilder = class {
|
|
|
8447
8107
|
}
|
|
8448
8108
|
}
|
|
8449
8109
|
validateSlotReferences() {
|
|
8450
|
-
const slotIds = _nullishCoalesce(_optionalChain([this, 'access',
|
|
8110
|
+
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
8111
|
for (const node of Object.values(_nullishCoalesce(this.data.nodes, () => ( {})))) {
|
|
8452
8112
|
if (node.type === "form") {
|
|
8453
8113
|
const referencedSlots = /* @__PURE__ */ new Set();
|
|
@@ -8648,12 +8308,125 @@ function buildAuditChanges(oldValues, newValues, fieldsToCheck) {
|
|
|
8648
8308
|
return changes;
|
|
8649
8309
|
}
|
|
8650
8310
|
|
|
8311
|
+
// src/runtime/services/bilateral/bilateral-validation.service.ts
|
|
8312
|
+
var BilateralValidationService = class extends BaseService {
|
|
8313
|
+
constructor(adapter, schemaService) {
|
|
8314
|
+
super(adapter);
|
|
8315
|
+
this.schemaService = schemaService;
|
|
8316
|
+
}
|
|
8317
|
+
/**
|
|
8318
|
+
* Validate a bilateral relation configuration.
|
|
8319
|
+
*
|
|
8320
|
+
* Performs comprehensive checks:
|
|
8321
|
+
* 1. Verifies target object exists
|
|
8322
|
+
* 2. Verifies inverse attribute exists on target object
|
|
8323
|
+
* 3. Verifies inverse attribute targets the source object
|
|
8324
|
+
* 4. Detects invalid circular bilateral declarations
|
|
8325
|
+
*
|
|
8326
|
+
* @param sourceSchema - Schema containing the relation attribute
|
|
8327
|
+
* @param sourceAttr - Relation attribute to validate
|
|
8328
|
+
* @returns Validation result with errors if any
|
|
8329
|
+
*/
|
|
8330
|
+
async validateBilateralRelation(sourceSchema, sourceAttr) {
|
|
8331
|
+
const errors = [];
|
|
8332
|
+
if (!(isBilateralRelation(sourceAttr) && sourceAttr.bilateral)) {
|
|
8333
|
+
return { valid: true, errors: [] };
|
|
8334
|
+
}
|
|
8335
|
+
const { object: targetObjectName, attribute: inverseAttrName } = sourceAttr.bilateral;
|
|
8336
|
+
let targetSchema = null;
|
|
8337
|
+
try {
|
|
8338
|
+
targetSchema = await this.schemaService.getObjectSchemaByName(targetObjectName);
|
|
8339
|
+
} catch (e12) {
|
|
8340
|
+
targetSchema = null;
|
|
8341
|
+
}
|
|
8342
|
+
if (!targetSchema) {
|
|
8343
|
+
errors.push({
|
|
8344
|
+
code: "INVERSE_ATTR_NOT_FOUND",
|
|
8345
|
+
message: `Target object "${targetObjectName}" not found`,
|
|
8346
|
+
context: {
|
|
8347
|
+
sourceObject: sourceSchema.name,
|
|
8348
|
+
sourceAttribute: sourceAttr.name,
|
|
8349
|
+
targetObject: targetObjectName,
|
|
8350
|
+
targetAttribute: inverseAttrName
|
|
8351
|
+
}
|
|
8352
|
+
});
|
|
8353
|
+
return { valid: false, errors };
|
|
8354
|
+
}
|
|
8355
|
+
const inverseAttr = targetSchema.attributes.find(
|
|
8356
|
+
(a) => a.name === inverseAttrName && a.type === "relation"
|
|
8357
|
+
);
|
|
8358
|
+
if (!inverseAttr) {
|
|
8359
|
+
errors.push({
|
|
8360
|
+
code: "INVERSE_ATTR_NOT_FOUND",
|
|
8361
|
+
message: `Inverse attribute "${inverseAttrName}" not found on "${targetObjectName}"`,
|
|
8362
|
+
context: {
|
|
8363
|
+
sourceObject: sourceSchema.name,
|
|
8364
|
+
sourceAttribute: sourceAttr.name,
|
|
8365
|
+
targetObject: targetObjectName,
|
|
8366
|
+
targetAttribute: inverseAttrName
|
|
8367
|
+
}
|
|
8368
|
+
});
|
|
8369
|
+
return { valid: false, errors };
|
|
8370
|
+
}
|
|
8371
|
+
const inverseTargetsSource = inverseAttr.targets.some(
|
|
8372
|
+
(target) => target.object === sourceSchema.name
|
|
8373
|
+
);
|
|
8374
|
+
if (!inverseTargetsSource) {
|
|
8375
|
+
errors.push({
|
|
8376
|
+
code: "INVERSE_TARGET_MISMATCH",
|
|
8377
|
+
message: `Inverse attribute doesn't target source object`,
|
|
8378
|
+
context: {
|
|
8379
|
+
sourceObject: sourceSchema.name,
|
|
8380
|
+
sourceAttribute: sourceAttr.name,
|
|
8381
|
+
targetObject: targetObjectName,
|
|
8382
|
+
targetAttribute: inverseAttrName
|
|
8383
|
+
}
|
|
8384
|
+
});
|
|
8385
|
+
}
|
|
8386
|
+
if (isBilateralRelation(inverseAttr)) {
|
|
8387
|
+
const inverseBilateral = inverseAttr.bilateral;
|
|
8388
|
+
if (inverseBilateral.object === sourceSchema.name && inverseBilateral.attribute !== sourceAttr.name) {
|
|
8389
|
+
errors.push({
|
|
8390
|
+
code: "CIRCULAR_BILATERAL",
|
|
8391
|
+
message: "Both sides declare bilateral but point to different attributes",
|
|
8392
|
+
context: {
|
|
8393
|
+
sourceObject: sourceSchema.name,
|
|
8394
|
+
sourceAttribute: sourceAttr.name,
|
|
8395
|
+
targetObject: targetObjectName,
|
|
8396
|
+
targetAttribute: inverseAttrName
|
|
8397
|
+
}
|
|
8398
|
+
});
|
|
8399
|
+
}
|
|
8400
|
+
}
|
|
8401
|
+
return { valid: errors.length === 0, errors };
|
|
8402
|
+
}
|
|
8403
|
+
/**
|
|
8404
|
+
* Validate all bilateral relations in a schema.
|
|
8405
|
+
*
|
|
8406
|
+
* Iterates through all relation attributes and validates each bilateral configuration.
|
|
8407
|
+
*
|
|
8408
|
+
* @param schema - Object schema to validate
|
|
8409
|
+
* @returns Combined validation result with all errors
|
|
8410
|
+
*/
|
|
8411
|
+
async validateAllBilateralRelations(schema) {
|
|
8412
|
+
const allErrors = [];
|
|
8413
|
+
for (const attr of schema.attributes) {
|
|
8414
|
+
if (attr.type === "relation" && isBilateralRelation(attr)) {
|
|
8415
|
+
const result = await this.validateBilateralRelation(schema, attr);
|
|
8416
|
+
allErrors.push(...result.errors);
|
|
8417
|
+
}
|
|
8418
|
+
}
|
|
8419
|
+
return { valid: allErrors.length === 0, errors: allErrors };
|
|
8420
|
+
}
|
|
8421
|
+
};
|
|
8422
|
+
|
|
8651
8423
|
// src/runtime/services/schema/object-schema.service.ts
|
|
8652
8424
|
var ObjectSchemaService = class extends BaseService {
|
|
8653
8425
|
constructor(adapter, nativeRegistry, options) {
|
|
8654
8426
|
super(adapter);
|
|
8655
8427
|
this.nativeRegistry = nativeRegistry;
|
|
8656
|
-
this.auditService = _optionalChain([options, 'optionalAccess',
|
|
8428
|
+
this.auditService = _optionalChain([options, 'optionalAccess', _162 => _162.auditService]);
|
|
8429
|
+
this.bilateralValidationService = new BilateralValidationService(adapter, this);
|
|
8657
8430
|
}
|
|
8658
8431
|
/**
|
|
8659
8432
|
* Create a new custom object.
|
|
@@ -8677,6 +8450,15 @@ var ObjectSchemaService = class extends BaseService {
|
|
|
8677
8450
|
builder.attributes(definition.attributes);
|
|
8678
8451
|
}
|
|
8679
8452
|
const objectDef = builder.build();
|
|
8453
|
+
const bilateralValidation = await this.bilateralValidationService.validateAllBilateralRelations(objectDef);
|
|
8454
|
+
if (!bilateralValidation.valid) {
|
|
8455
|
+
const errorMessages = bilateralValidation.errors.map((e) => `${e.code}: ${e.message}`).join("; ");
|
|
8456
|
+
throw new SchemaError(
|
|
8457
|
+
`Bilateral relation validation failed: ${errorMessages}`,
|
|
8458
|
+
SchemaErrorCode.VALIDATION_FAILED,
|
|
8459
|
+
{ errors: bilateralValidation.errors }
|
|
8460
|
+
);
|
|
8461
|
+
}
|
|
8680
8462
|
const existing = await this.adapter.objects.findByName(objectDef.name);
|
|
8681
8463
|
if (existing) {
|
|
8682
8464
|
throw new Error(`Object with name "${objectDef.name}" already exists`);
|
|
@@ -8766,6 +8548,28 @@ var ObjectSchemaService = class extends BaseService {
|
|
|
8766
8548
|
);
|
|
8767
8549
|
}
|
|
8768
8550
|
const config = await this.validateAttributeInput(attribute);
|
|
8551
|
+
if (attribute.type === "relation" && attribute.bilateral) {
|
|
8552
|
+
const tempSchema = await this.getObjectSchema(objectId);
|
|
8553
|
+
const tempAttr = {
|
|
8554
|
+
...attribute,
|
|
8555
|
+
id: "temp-id",
|
|
8556
|
+
// Temporary ID for validation
|
|
8557
|
+
system: false,
|
|
8558
|
+
config
|
|
8559
|
+
};
|
|
8560
|
+
const validation = await this.bilateralValidationService.validateBilateralRelation(
|
|
8561
|
+
tempSchema,
|
|
8562
|
+
tempAttr
|
|
8563
|
+
);
|
|
8564
|
+
if (!validation.valid) {
|
|
8565
|
+
const errorMessages = validation.errors.map((e) => `${e.code}: ${e.message}`).join("; ");
|
|
8566
|
+
throw new SchemaError(
|
|
8567
|
+
`Bilateral relation validation failed: ${errorMessages}`,
|
|
8568
|
+
SchemaErrorCode.VALIDATION_FAILED,
|
|
8569
|
+
{ errors: validation.errors }
|
|
8570
|
+
);
|
|
8571
|
+
}
|
|
8572
|
+
}
|
|
8769
8573
|
const dbAttr = await this.adapter.attributes.create({
|
|
8770
8574
|
objectId,
|
|
8771
8575
|
name: attribute.name,
|
|
@@ -8866,7 +8670,7 @@ var ObjectSchemaService = class extends BaseService {
|
|
|
8866
8670
|
resourceType: "attribute",
|
|
8867
8671
|
resourceId: attributeId,
|
|
8868
8672
|
resourceLabel: updatedDbAttr.label,
|
|
8869
|
-
objectName: _optionalChain([dbObject, 'optionalAccess',
|
|
8673
|
+
objectName: _optionalChain([dbObject, 'optionalAccess', _163 => _163.name]),
|
|
8870
8674
|
objectId: dbAttr.objectId,
|
|
8871
8675
|
changes
|
|
8872
8676
|
});
|
|
@@ -8899,7 +8703,7 @@ var ObjectSchemaService = class extends BaseService {
|
|
|
8899
8703
|
);
|
|
8900
8704
|
}
|
|
8901
8705
|
const dbObject = await this.adapter.objects.findById(dbAttr.objectId);
|
|
8902
|
-
if (_optionalChain([dbObject, 'optionalAccess',
|
|
8706
|
+
if (_optionalChain([dbObject, 'optionalAccess', _164 => _164.labelExpression])) {
|
|
8903
8707
|
const usedAttributes = extractAttributeNames(dbObject.labelExpression);
|
|
8904
8708
|
if (usedAttributes.includes(dbAttr.name)) {
|
|
8905
8709
|
throw new AttributeInUseError(dbAttr.name, "labelExpression");
|
|
@@ -8915,7 +8719,7 @@ var ObjectSchemaService = class extends BaseService {
|
|
|
8915
8719
|
resourceType: "attribute",
|
|
8916
8720
|
resourceId: attributeId,
|
|
8917
8721
|
resourceLabel: dbAttr.label,
|
|
8918
|
-
objectName: _optionalChain([dbObject, 'optionalAccess',
|
|
8722
|
+
objectName: _optionalChain([dbObject, 'optionalAccess', _165 => _165.name]),
|
|
8919
8723
|
objectId: dbAttr.objectId
|
|
8920
8724
|
});
|
|
8921
8725
|
}
|
|
@@ -8930,9 +8734,9 @@ var ObjectSchemaService = class extends BaseService {
|
|
|
8930
8734
|
async listAttributes(objectId, options) {
|
|
8931
8735
|
const dbAttributes = await this.adapter.attributes.findByObjectId(objectId);
|
|
8932
8736
|
let filtered = dbAttributes;
|
|
8933
|
-
if (_optionalChain([options, 'optionalAccess',
|
|
8737
|
+
if (_optionalChain([options, 'optionalAccess', _166 => _166.systemOnly])) {
|
|
8934
8738
|
filtered = dbAttributes.filter((attr) => attr.system);
|
|
8935
|
-
} else if (_optionalChain([options, 'optionalAccess',
|
|
8739
|
+
} else if (_optionalChain([options, 'optionalAccess', _167 => _167.customOnly])) {
|
|
8936
8740
|
filtered = dbAttributes.filter((attr) => !attr.system);
|
|
8937
8741
|
}
|
|
8938
8742
|
return filtered.map((attr) => this.convertDBAttributeToAttribute(attr));
|
|
@@ -8968,14 +8772,14 @@ var ObjectSchemaService = class extends BaseService {
|
|
|
8968
8772
|
pluralLabel: dbObject.pluralLabel,
|
|
8969
8773
|
description: dbObject.description,
|
|
8970
8774
|
labelExpression: dbObject.labelExpression,
|
|
8971
|
-
icon: _optionalChain([dbObject, 'access',
|
|
8775
|
+
icon: _optionalChain([dbObject, 'access', _168 => _168.metadata, 'optionalAccess', _169 => _169.icon])
|
|
8972
8776
|
};
|
|
8973
8777
|
let metadata = dbObject.metadata;
|
|
8974
8778
|
if (updates.icon !== void 0 || updates.metadata !== void 0) {
|
|
8975
8779
|
metadata = {
|
|
8976
8780
|
...dbObject.metadata,
|
|
8977
8781
|
...updates.metadata,
|
|
8978
|
-
icon: _nullishCoalesce(updates.icon, () => ( _optionalChain([dbObject, 'access',
|
|
8782
|
+
icon: _nullishCoalesce(updates.icon, () => ( _optionalChain([dbObject, 'access', _170 => _170.metadata, 'optionalAccess', _171 => _171.icon])))
|
|
8979
8783
|
};
|
|
8980
8784
|
}
|
|
8981
8785
|
const updatedDbObject = await this.adapter.objects.update(objectId, {
|
|
@@ -9190,7 +8994,59 @@ Reserved names: ${RESERVED_ATTRIBUTE_NAMES.join(", ")}`
|
|
|
9190
8994
|
async buildObjectDefinition(dbObject) {
|
|
9191
8995
|
const dbAttributes = await this.adapter.attributes.findByObjectId(dbObject.id);
|
|
9192
8996
|
const baseDef = dbObject.system ? this.mergeNativeObject(dbObject, dbAttributes) : this.convertDBObjectToDefinition(dbObject, dbAttributes);
|
|
9193
|
-
|
|
8997
|
+
const enriched = await this.enrichBilateralProperties(baseDef);
|
|
8998
|
+
return this.withSystemAttributes(enriched);
|
|
8999
|
+
}
|
|
9000
|
+
/**
|
|
9001
|
+
* Enrich bilateral relation attributes that don't own property definitions.
|
|
9002
|
+
* Copies `properties` from the canonical side (the one with `.qualifyWith()`)
|
|
9003
|
+
* and sets `storageOwner: false` so the storage layer knows direction.
|
|
9004
|
+
*
|
|
9005
|
+
* Uses direct DB lookups to avoid circular recursion through `getObjectSchema`.
|
|
9006
|
+
* @internal
|
|
9007
|
+
*/
|
|
9008
|
+
async enrichBilateralProperties(def) {
|
|
9009
|
+
const toEnrich = def.attributes.filter(
|
|
9010
|
+
(attr) => attr.type === "relation" && !!attr.bilateral && !attr.properties
|
|
9011
|
+
);
|
|
9012
|
+
if (toEnrich.length === 0) return def;
|
|
9013
|
+
const enrichedMap = /* @__PURE__ */ new Map();
|
|
9014
|
+
for (const attr of toEnrich) {
|
|
9015
|
+
const { bilateral } = attr;
|
|
9016
|
+
if (!bilateral) continue;
|
|
9017
|
+
const inverseObject = await this.adapter.objects.findByName(bilateral.object);
|
|
9018
|
+
if (!inverseObject) continue;
|
|
9019
|
+
const inverseDbAttrs = await this.adapter.attributes.findByObjectId(inverseObject.id);
|
|
9020
|
+
const inverseDbAttr = inverseDbAttrs.find((a) => a.name === bilateral.attribute);
|
|
9021
|
+
if (!inverseDbAttr) continue;
|
|
9022
|
+
let properties = inverseDbAttr.config.properties;
|
|
9023
|
+
if (!properties) {
|
|
9024
|
+
const nativeObj = this.nativeRegistry.getByName(bilateral.object);
|
|
9025
|
+
const nativeAttr = _optionalChain([nativeObj, 'optionalAccess', _172 => _172.attributes, 'access', _173 => _173.find, 'call', _174 => _174((a) => a.name === bilateral.attribute)]);
|
|
9026
|
+
if (nativeAttr && "properties" in nativeAttr) {
|
|
9027
|
+
properties = nativeAttr.properties;
|
|
9028
|
+
}
|
|
9029
|
+
}
|
|
9030
|
+
if (properties) {
|
|
9031
|
+
enrichedMap.set(attr.name, {
|
|
9032
|
+
properties,
|
|
9033
|
+
bilateral: { ...bilateral, storageOwner: false }
|
|
9034
|
+
});
|
|
9035
|
+
}
|
|
9036
|
+
}
|
|
9037
|
+
if (enrichedMap.size === 0) return def;
|
|
9038
|
+
return {
|
|
9039
|
+
...def,
|
|
9040
|
+
attributes: def.attributes.map((attr) => {
|
|
9041
|
+
const enrichment = enrichedMap.get(attr.name);
|
|
9042
|
+
if (!enrichment) return attr;
|
|
9043
|
+
return {
|
|
9044
|
+
...attr,
|
|
9045
|
+
properties: enrichment.properties,
|
|
9046
|
+
bilateral: enrichment.bilateral
|
|
9047
|
+
};
|
|
9048
|
+
})
|
|
9049
|
+
};
|
|
9194
9050
|
}
|
|
9195
9051
|
/**
|
|
9196
9052
|
* Append system attributes to an ObjectDefinition
|
|
@@ -9255,7 +9111,7 @@ Reserved names: ${RESERVED_ATTRIBUTE_NAMES.join(", ")}`
|
|
|
9255
9111
|
label: dbObject.label,
|
|
9256
9112
|
pluralLabel: dbObject.pluralLabel,
|
|
9257
9113
|
description: dbObject.description,
|
|
9258
|
-
icon: _optionalChain([dbObject, 'access',
|
|
9114
|
+
icon: _optionalChain([dbObject, 'access', _175 => _175.metadata, 'optionalAccess', _176 => _176.icon]),
|
|
9259
9115
|
labelExpression: dbObject.labelExpression,
|
|
9260
9116
|
attributes,
|
|
9261
9117
|
system: dbObject.system,
|
|
@@ -9355,7 +9211,7 @@ Reserved names: ${RESERVED_ATTRIBUTE_NAMES.join(", ")}`
|
|
|
9355
9211
|
const hasRelationToTarget = attrs.some((attr) => {
|
|
9356
9212
|
if (attr.type !== "relation") return false;
|
|
9357
9213
|
const config = attr.config;
|
|
9358
|
-
return _nullishCoalesce(_optionalChain([config, 'optionalAccess',
|
|
9214
|
+
return _nullishCoalesce(_optionalChain([config, 'optionalAccess', _177 => _177.targets, 'optionalAccess', _178 => _178.some, 'call', _179 => _179((t) => t.object === targetObjectName)]), () => ( false));
|
|
9359
9215
|
});
|
|
9360
9216
|
if (hasRelationToTarget) {
|
|
9361
9217
|
referencing.push(obj.name);
|
|
@@ -9433,7 +9289,7 @@ Native objects must have system=true. Did you forget to call .system() in your b
|
|
|
9433
9289
|
const existing = this.objects.get(object2.name);
|
|
9434
9290
|
throw new Error(
|
|
9435
9291
|
`[NativeObjectRegistry] Duplicate object name "${object2.name}":
|
|
9436
|
-
- Existing: "${_optionalChain([existing, 'optionalAccess',
|
|
9292
|
+
- Existing: "${_optionalChain([existing, 'optionalAccess', _180 => _180.label])}" (id: ${_optionalChain([existing, 'optionalAccess', _181 => _181.id])})
|
|
9437
9293
|
- New: "${object2.label}" (id: ${object2.id})
|
|
9438
9294
|
Please use unique names for each native object.`
|
|
9439
9295
|
);
|
|
@@ -9550,7 +9406,7 @@ var AuditService = class extends BaseService {
|
|
|
9550
9406
|
this.isFlushing = false;
|
|
9551
9407
|
/** Pending flush promise to allow waiting on concurrent flush */
|
|
9552
9408
|
this.flushPromise = null;
|
|
9553
|
-
if (_optionalChain([options, 'optionalAccess',
|
|
9409
|
+
if (_optionalChain([options, 'optionalAccess', _182 => _182.async]) && options.flushIntervalMs) {
|
|
9554
9410
|
this.startFlushTimer();
|
|
9555
9411
|
}
|
|
9556
9412
|
}
|
|
@@ -9747,7 +9603,7 @@ var AuditService = class extends BaseService {
|
|
|
9747
9603
|
if (!this.adapter.audit) {
|
|
9748
9604
|
return;
|
|
9749
9605
|
}
|
|
9750
|
-
if (_optionalChain([this, 'access',
|
|
9606
|
+
if (_optionalChain([this, 'access', _183 => _183.options, 'optionalAccess', _184 => _184.async])) {
|
|
9751
9607
|
this.buffer.push(entry);
|
|
9752
9608
|
const batchSize = _nullishCoalesce(this.options.batchSize, () => ( 10));
|
|
9753
9609
|
if (this.buffer.length >= batchSize) {
|
|
@@ -9761,7 +9617,7 @@ var AuditService = class extends BaseService {
|
|
|
9761
9617
|
* Start the flush timer for async mode
|
|
9762
9618
|
*/
|
|
9763
9619
|
startFlushTimer() {
|
|
9764
|
-
const intervalMs = _nullishCoalesce(_optionalChain([this, 'access',
|
|
9620
|
+
const intervalMs = _nullishCoalesce(_optionalChain([this, 'access', _185 => _185.options, 'optionalAccess', _186 => _186.flushIntervalMs]), () => ( 1e3));
|
|
9765
9621
|
this.flushTimer = setInterval(() => {
|
|
9766
9622
|
this.flush().catch(() => {
|
|
9767
9623
|
});
|
|
@@ -9785,40 +9641,337 @@ var AuditService = class extends BaseService {
|
|
|
9785
9641
|
}
|
|
9786
9642
|
};
|
|
9787
9643
|
|
|
9788
|
-
// src/runtime/services/
|
|
9789
|
-
var
|
|
9790
|
-
|
|
9644
|
+
// src/runtime/services/bilateral/bilateral-sync.service.ts
|
|
9645
|
+
var browserStub4 = {
|
|
9646
|
+
getStore: () => void 0,
|
|
9647
|
+
run: (_store, callback) => callback()
|
|
9648
|
+
};
|
|
9649
|
+
var AsyncLocalStorageClass4 = null;
|
|
9650
|
+
if (typeof process !== "undefined" && _optionalChain([process, 'access', _187 => _187.versions, 'optionalAccess', _188 => _188.node])) {
|
|
9651
|
+
try {
|
|
9652
|
+
if (typeof _chunk3RG5ZIWIjs.__require !== "undefined") {
|
|
9653
|
+
const asyncHooks = _chunk3RG5ZIWIjs.__require.call(void 0, "async_hooks");
|
|
9654
|
+
AsyncLocalStorageClass4 = asyncHooks.AsyncLocalStorage;
|
|
9655
|
+
}
|
|
9656
|
+
} catch (e13) {
|
|
9657
|
+
try {
|
|
9658
|
+
const dynamicRequire = new Function(
|
|
9659
|
+
"m",
|
|
9660
|
+
'return typeof require!=="undefined"?require(m):null'
|
|
9661
|
+
);
|
|
9662
|
+
const asyncHooks = dynamicRequire("node:async_hooks");
|
|
9663
|
+
if (asyncHooks) {
|
|
9664
|
+
AsyncLocalStorageClass4 = asyncHooks.AsyncLocalStorage;
|
|
9665
|
+
}
|
|
9666
|
+
} catch (e14) {
|
|
9667
|
+
}
|
|
9668
|
+
}
|
|
9669
|
+
}
|
|
9670
|
+
var bilateralSyncContext = null;
|
|
9671
|
+
function getSyncContext() {
|
|
9672
|
+
if (bilateralSyncContext !== null) {
|
|
9673
|
+
return bilateralSyncContext;
|
|
9674
|
+
}
|
|
9675
|
+
if (AsyncLocalStorageClass4) {
|
|
9676
|
+
bilateralSyncContext = new AsyncLocalStorageClass4();
|
|
9677
|
+
return bilateralSyncContext;
|
|
9678
|
+
}
|
|
9679
|
+
bilateralSyncContext = browserStub4;
|
|
9680
|
+
return bilateralSyncContext;
|
|
9681
|
+
}
|
|
9682
|
+
var BilateralSyncService = class extends BaseService {
|
|
9683
|
+
constructor(adapter, schemaService, relationPropertiesService) {
|
|
9791
9684
|
super(adapter);
|
|
9685
|
+
this.schemaService = schemaService;
|
|
9686
|
+
this.relationPropertiesService = relationPropertiesService;
|
|
9792
9687
|
}
|
|
9688
|
+
// ============================================================================
|
|
9689
|
+
// PUBLIC API
|
|
9690
|
+
// ============================================================================
|
|
9793
9691
|
/**
|
|
9794
|
-
*
|
|
9795
|
-
*
|
|
9796
|
-
* Uses batch fetching (findByIds) to avoid N+1 query pattern.
|
|
9797
|
-
*
|
|
9798
|
-
* @param schema - Object schema containing attribute definitions
|
|
9799
|
-
* @param data - Record data to validate
|
|
9800
|
-
* @returns Validation result with errors if any
|
|
9801
|
-
*
|
|
9802
|
-
* @example
|
|
9803
|
-
* ```typescript
|
|
9804
|
-
* const result = await userService.validateUsers(schema, {
|
|
9805
|
-
* assignee: "user-123",
|
|
9806
|
-
* watchers: ["user-456", "user-789"]
|
|
9807
|
-
* });
|
|
9692
|
+
* Synchronize a bilateral relation after modification.
|
|
9808
9693
|
*
|
|
9809
|
-
*
|
|
9810
|
-
*
|
|
9811
|
-
*
|
|
9812
|
-
*
|
|
9813
|
-
*
|
|
9694
|
+
* @param sourceSchema - Schema of the object containing the relation
|
|
9695
|
+
* @param sourceRecordId - ID of the record being modified
|
|
9696
|
+
* @param attributeName - Name of the relation attribute
|
|
9697
|
+
* @param newValue - New value (ID, array of IDs, or hybrid format with properties)
|
|
9698
|
+
* @param oldValue - Old value (ID, array of IDs, or hybrid format with properties)
|
|
9814
9699
|
*/
|
|
9815
|
-
async
|
|
9816
|
-
const
|
|
9817
|
-
|
|
9818
|
-
(attr) => attr.type === "user"
|
|
9700
|
+
async syncBilateralRelation(sourceSchema, sourceRecordId, attributeName, newValue, oldValue) {
|
|
9701
|
+
const attribute = sourceSchema.attributes.find(
|
|
9702
|
+
(a) => a.name === attributeName && a.type === "relation"
|
|
9819
9703
|
);
|
|
9820
|
-
if (
|
|
9821
|
-
return
|
|
9704
|
+
if (!(attribute && isBilateralRelation(attribute))) {
|
|
9705
|
+
return;
|
|
9706
|
+
}
|
|
9707
|
+
const ctx = getSyncContext().getStore();
|
|
9708
|
+
const syncKey = `${sourceSchema.name}:${sourceRecordId}:${attributeName}`;
|
|
9709
|
+
if (_optionalChain([ctx, 'optionalAccess', _189 => _189.syncing, 'access', _190 => _190.has, 'call', _191 => _191(syncKey)])) {
|
|
9710
|
+
return;
|
|
9711
|
+
}
|
|
9712
|
+
await this.runWithSyncContext(syncKey, async () => {
|
|
9713
|
+
await this.performBilateralSync(sourceSchema, sourceRecordId, attribute, newValue, oldValue);
|
|
9714
|
+
});
|
|
9715
|
+
}
|
|
9716
|
+
// ============================================================================
|
|
9717
|
+
// PRIVATE METHODS
|
|
9718
|
+
// ============================================================================
|
|
9719
|
+
/**
|
|
9720
|
+
* Perform the bidirectional synchronization.
|
|
9721
|
+
* @private
|
|
9722
|
+
*/
|
|
9723
|
+
async performBilateralSync(sourceSchema, sourceRecordId, sourceAttr, newValue, oldValue) {
|
|
9724
|
+
const bilateral = sourceAttr.bilateral;
|
|
9725
|
+
const targetSchema = await this.schemaService.getObjectSchemaByName(bilateral.object);
|
|
9726
|
+
if (!targetSchema) {
|
|
9727
|
+
throw new Error(`Target object "${bilateral.object}" not found`);
|
|
9728
|
+
}
|
|
9729
|
+
const inverseAttr = targetSchema.attributes.find(
|
|
9730
|
+
(a) => a.name === bilateral.attribute && a.type === "relation"
|
|
9731
|
+
);
|
|
9732
|
+
if (!inverseAttr) {
|
|
9733
|
+
throw new Error(
|
|
9734
|
+
`Inverse attribute "${bilateral.attribute}" not found on "${bilateral.object}"`
|
|
9735
|
+
);
|
|
9736
|
+
}
|
|
9737
|
+
const newData = this.extractRelationData(newValue);
|
|
9738
|
+
const oldData = this.extractRelationData(oldValue);
|
|
9739
|
+
const addedIds = newData.ids.filter((id) => !oldData.ids.includes(id));
|
|
9740
|
+
const removedIds = oldData.ids.filter((id) => !newData.ids.includes(id));
|
|
9741
|
+
const commonIds = newData.ids.filter((id) => oldData.ids.includes(id));
|
|
9742
|
+
await Promise.all([
|
|
9743
|
+
// Add new relations
|
|
9744
|
+
...addedIds.map(
|
|
9745
|
+
(targetId) => this.addInverseRelation(
|
|
9746
|
+
targetId,
|
|
9747
|
+
inverseAttr,
|
|
9748
|
+
sourceRecordId,
|
|
9749
|
+
sourceSchema.name,
|
|
9750
|
+
sourceAttr.name,
|
|
9751
|
+
newData.properties.get(targetId)
|
|
9752
|
+
)
|
|
9753
|
+
),
|
|
9754
|
+
// Remove deleted relations
|
|
9755
|
+
...removedIds.map(
|
|
9756
|
+
(targetId) => this.removeInverseRelation(targetId, inverseAttr, sourceRecordId)
|
|
9757
|
+
),
|
|
9758
|
+
// Update properties for common IDs
|
|
9759
|
+
...commonIds.map(
|
|
9760
|
+
(targetId) => this.updateInverseRelationProperties(
|
|
9761
|
+
targetId,
|
|
9762
|
+
inverseAttr,
|
|
9763
|
+
sourceRecordId,
|
|
9764
|
+
sourceSchema.name,
|
|
9765
|
+
sourceAttr.name,
|
|
9766
|
+
newData.properties.get(targetId),
|
|
9767
|
+
oldData.properties.get(targetId)
|
|
9768
|
+
)
|
|
9769
|
+
)
|
|
9770
|
+
]);
|
|
9771
|
+
}
|
|
9772
|
+
/**
|
|
9773
|
+
* Extract IDs and properties from hybrid relation value.
|
|
9774
|
+
* @private
|
|
9775
|
+
*/
|
|
9776
|
+
extractRelationData(value) {
|
|
9777
|
+
const ids = [];
|
|
9778
|
+
const properties = /* @__PURE__ */ new Map();
|
|
9779
|
+
if (value === null || value === void 0) {
|
|
9780
|
+
return { ids, properties };
|
|
9781
|
+
}
|
|
9782
|
+
if (typeof value === "string") {
|
|
9783
|
+
ids.push(value);
|
|
9784
|
+
return { ids, properties };
|
|
9785
|
+
}
|
|
9786
|
+
if (!Array.isArray(value) && typeof value === "object" && "id" in value) {
|
|
9787
|
+
ids.push(value.id);
|
|
9788
|
+
if (value.props) {
|
|
9789
|
+
properties.set(value.id, value.props);
|
|
9790
|
+
}
|
|
9791
|
+
return { ids, properties };
|
|
9792
|
+
}
|
|
9793
|
+
if (Array.isArray(value)) {
|
|
9794
|
+
for (const item of value) {
|
|
9795
|
+
if (typeof item === "string") {
|
|
9796
|
+
ids.push(item);
|
|
9797
|
+
} else if (typeof item === "object" && item !== null && "id" in item) {
|
|
9798
|
+
ids.push(item.id);
|
|
9799
|
+
if (item.props) {
|
|
9800
|
+
properties.set(item.id, item.props);
|
|
9801
|
+
}
|
|
9802
|
+
}
|
|
9803
|
+
}
|
|
9804
|
+
}
|
|
9805
|
+
return { ids, properties };
|
|
9806
|
+
}
|
|
9807
|
+
/**
|
|
9808
|
+
* Add an ID to an inverse relation (with properties).
|
|
9809
|
+
* @private
|
|
9810
|
+
*/
|
|
9811
|
+
async addInverseRelation(targetRecordId, inverseAttr, sourceRecordId, sourceObject, sourceAttribute, properties) {
|
|
9812
|
+
const targetRecord = await this.adapter.objectRecords.findById(targetRecordId);
|
|
9813
|
+
if (!targetRecord) {
|
|
9814
|
+
return;
|
|
9815
|
+
}
|
|
9816
|
+
const currentValue = targetRecord.values[inverseAttr.name];
|
|
9817
|
+
let newValue;
|
|
9818
|
+
if (inverseAttr.cardinality === "one") {
|
|
9819
|
+
newValue = sourceRecordId;
|
|
9820
|
+
} else {
|
|
9821
|
+
const currentArray = this.normalizeToArray(currentValue);
|
|
9822
|
+
if (currentArray.includes(sourceRecordId)) {
|
|
9823
|
+
return;
|
|
9824
|
+
}
|
|
9825
|
+
newValue = [...currentArray, sourceRecordId];
|
|
9826
|
+
}
|
|
9827
|
+
await this.adapter.objectRecords.update(targetRecordId, {
|
|
9828
|
+
[inverseAttr.name]: newValue
|
|
9829
|
+
});
|
|
9830
|
+
await this.invalidateTargetRecordCaches(targetRecordId, targetRecord.objectId);
|
|
9831
|
+
if (properties && Object.keys(properties).length > 0 && this.adapter.relationAttributes) {
|
|
9832
|
+
const sourceSchema = await this.schemaService.getObjectSchemaByName(sourceObject);
|
|
9833
|
+
if (sourceSchema) {
|
|
9834
|
+
await this.relationPropertiesService.syncRelationProperties(
|
|
9835
|
+
sourceSchema,
|
|
9836
|
+
sourceRecordId,
|
|
9837
|
+
sourceAttribute,
|
|
9838
|
+
[{ id: targetRecordId, props: properties }],
|
|
9839
|
+
this.adapter
|
|
9840
|
+
);
|
|
9841
|
+
}
|
|
9842
|
+
}
|
|
9843
|
+
}
|
|
9844
|
+
/**
|
|
9845
|
+
* Update properties of an existing inverse relation.
|
|
9846
|
+
* @private
|
|
9847
|
+
*/
|
|
9848
|
+
async updateInverseRelationProperties(targetRecordId, _inverseAttr, sourceRecordId, sourceObject, sourceAttribute, newProperties, oldProperties) {
|
|
9849
|
+
if (JSON.stringify(newProperties) === JSON.stringify(oldProperties)) {
|
|
9850
|
+
return;
|
|
9851
|
+
}
|
|
9852
|
+
if (!this.adapter.relationAttributes) {
|
|
9853
|
+
return;
|
|
9854
|
+
}
|
|
9855
|
+
const sourceSchema = await this.schemaService.getObjectSchemaByName(sourceObject);
|
|
9856
|
+
if (!sourceSchema) {
|
|
9857
|
+
return;
|
|
9858
|
+
}
|
|
9859
|
+
if (newProperties && Object.keys(newProperties).length > 0) {
|
|
9860
|
+
await this.relationPropertiesService.syncRelationProperties(
|
|
9861
|
+
sourceSchema,
|
|
9862
|
+
sourceRecordId,
|
|
9863
|
+
sourceAttribute,
|
|
9864
|
+
[{ id: targetRecordId, props: newProperties }],
|
|
9865
|
+
this.adapter
|
|
9866
|
+
);
|
|
9867
|
+
} else {
|
|
9868
|
+
await this.adapter.relationAttributes.deleteBySource(
|
|
9869
|
+
sourceObject,
|
|
9870
|
+
sourceRecordId,
|
|
9871
|
+
sourceAttribute
|
|
9872
|
+
);
|
|
9873
|
+
}
|
|
9874
|
+
}
|
|
9875
|
+
/**
|
|
9876
|
+
* Remove an ID from an inverse relation.
|
|
9877
|
+
* @private
|
|
9878
|
+
*/
|
|
9879
|
+
async removeInverseRelation(targetRecordId, inverseAttr, sourceRecordId) {
|
|
9880
|
+
const targetRecord = await this.adapter.objectRecords.findById(targetRecordId);
|
|
9881
|
+
if (!targetRecord) {
|
|
9882
|
+
return;
|
|
9883
|
+
}
|
|
9884
|
+
const currentValue = targetRecord.values[inverseAttr.name];
|
|
9885
|
+
let newValue;
|
|
9886
|
+
if (inverseAttr.cardinality === "one") {
|
|
9887
|
+
if (currentValue === sourceRecordId) {
|
|
9888
|
+
newValue = null;
|
|
9889
|
+
} else {
|
|
9890
|
+
return;
|
|
9891
|
+
}
|
|
9892
|
+
} else {
|
|
9893
|
+
const currentArray = this.normalizeToArray(currentValue);
|
|
9894
|
+
newValue = currentArray.filter((id) => id !== sourceRecordId);
|
|
9895
|
+
if (newValue.length === currentArray.length) {
|
|
9896
|
+
return;
|
|
9897
|
+
}
|
|
9898
|
+
}
|
|
9899
|
+
await this.adapter.objectRecords.update(targetRecordId, {
|
|
9900
|
+
[inverseAttr.name]: newValue
|
|
9901
|
+
});
|
|
9902
|
+
await this.invalidateTargetRecordCaches(targetRecordId, targetRecord.objectId);
|
|
9903
|
+
}
|
|
9904
|
+
/**
|
|
9905
|
+
* Normalize a relation value to an array of IDs.
|
|
9906
|
+
* @private
|
|
9907
|
+
*/
|
|
9908
|
+
normalizeToArray(value) {
|
|
9909
|
+
if (value === null || value === void 0) return [];
|
|
9910
|
+
if (typeof value === "string") return [value];
|
|
9911
|
+
if (Array.isArray(value)) return value;
|
|
9912
|
+
return [];
|
|
9913
|
+
}
|
|
9914
|
+
/**
|
|
9915
|
+
* Invalidate caches for a target record after bilateral update.
|
|
9916
|
+
* Mirrors RecordService.invalidateRecordCaches to ensure consistency.
|
|
9917
|
+
* @private
|
|
9918
|
+
*/
|
|
9919
|
+
async invalidateTargetRecordCaches(recordId, objectId) {
|
|
9920
|
+
await this.invalidateCache(cacheKeys.record(this.tenantId, recordId));
|
|
9921
|
+
await this.invalidateLists("allRecordLists", objectId);
|
|
9922
|
+
await this.invalidateLists("allSearchResults", objectId);
|
|
9923
|
+
await this.invalidateCachePattern(cacheKeys.allGlobalSearch(this.tenantId));
|
|
9924
|
+
await this.invalidateCachePattern(cacheKeys.resolvedRelationsByRecord(this.tenantId, recordId));
|
|
9925
|
+
}
|
|
9926
|
+
/**
|
|
9927
|
+
* Execute a function with sync context.
|
|
9928
|
+
* @private
|
|
9929
|
+
*/
|
|
9930
|
+
async runWithSyncContext(syncKey, fn) {
|
|
9931
|
+
const storage = getSyncContext();
|
|
9932
|
+
const existingCtx = storage.getStore();
|
|
9933
|
+
const ctx = {
|
|
9934
|
+
syncing: new Set(_nullishCoalesce(_optionalChain([existingCtx, 'optionalAccess', _192 => _192.syncing]), () => ( [])))
|
|
9935
|
+
};
|
|
9936
|
+
ctx.syncing.add(syncKey);
|
|
9937
|
+
return await storage.run(ctx, fn);
|
|
9938
|
+
}
|
|
9939
|
+
};
|
|
9940
|
+
|
|
9941
|
+
// src/runtime/services/user/user.service.ts
|
|
9942
|
+
var UserService = class extends BaseService {
|
|
9943
|
+
constructor(adapter) {
|
|
9944
|
+
super(adapter);
|
|
9945
|
+
}
|
|
9946
|
+
/**
|
|
9947
|
+
* Validate all user attributes in the data.
|
|
9948
|
+
*
|
|
9949
|
+
* Uses batch fetching (findByIds) to avoid N+1 query pattern.
|
|
9950
|
+
*
|
|
9951
|
+
* @param schema - Object schema containing attribute definitions
|
|
9952
|
+
* @param data - Record data to validate
|
|
9953
|
+
* @returns Validation result with errors if any
|
|
9954
|
+
*
|
|
9955
|
+
* @example
|
|
9956
|
+
* ```typescript
|
|
9957
|
+
* const result = await userService.validateUsers(schema, {
|
|
9958
|
+
* assignee: "user-123",
|
|
9959
|
+
* watchers: ["user-456", "user-789"]
|
|
9960
|
+
* });
|
|
9961
|
+
*
|
|
9962
|
+
* if (!result.valid) {
|
|
9963
|
+
* console.log(result.errors);
|
|
9964
|
+
* // [{ attribute: "assignee", message: "User not found", invalidIds: ["user-123"] }]
|
|
9965
|
+
* }
|
|
9966
|
+
* ```
|
|
9967
|
+
*/
|
|
9968
|
+
async validateUsers(schema, data) {
|
|
9969
|
+
const errors = [];
|
|
9970
|
+
const userAttrs = schema.attributes.filter(
|
|
9971
|
+
(attr) => attr.type === "user"
|
|
9972
|
+
);
|
|
9973
|
+
if (userAttrs.length === 0) {
|
|
9974
|
+
return { valid: true, errors: [] };
|
|
9822
9975
|
}
|
|
9823
9976
|
const allIds = /* @__PURE__ */ new Set();
|
|
9824
9977
|
const attrIdMap = /* @__PURE__ */ new Map();
|
|
@@ -9869,7 +10022,7 @@ var UserService = class extends BaseService {
|
|
|
9869
10022
|
if (roleErrors.length > 0) {
|
|
9870
10023
|
errors.push({
|
|
9871
10024
|
attribute: attrName,
|
|
9872
|
-
message: `Users do not have required role for ${attr.label}. Allowed roles: ${_optionalChain([attr, 'access',
|
|
10025
|
+
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
10026
|
invalidIds: roleErrors
|
|
9874
10027
|
});
|
|
9875
10028
|
}
|
|
@@ -10185,13 +10338,367 @@ async function recalculateParentRollups(record, schema, ctx) {
|
|
|
10185
10338
|
}
|
|
10186
10339
|
}
|
|
10187
10340
|
|
|
10341
|
+
// src/runtime/services/record/relation-properties.service.ts
|
|
10342
|
+
|
|
10343
|
+
var RelationPropertiesService = class extends BaseService {
|
|
10344
|
+
constructor(adapter) {
|
|
10345
|
+
super(adapter);
|
|
10346
|
+
}
|
|
10347
|
+
// ============================================================================
|
|
10348
|
+
// PUBLIC API
|
|
10349
|
+
// ============================================================================
|
|
10350
|
+
/**
|
|
10351
|
+
* Get relation properties for a given attribute.
|
|
10352
|
+
*
|
|
10353
|
+
* Supports bidirectional relations: searches for properties in both directions
|
|
10354
|
+
* (forward: from_object/from_id → to_id, and inverse: to_id → from_id).
|
|
10355
|
+
*
|
|
10356
|
+
* This ensures that qualified properties are SHARED between both directions
|
|
10357
|
+
* of a bilateral relation, as they are stored in a single row in relation_attributes.
|
|
10358
|
+
*
|
|
10359
|
+
* @param objectName - Source object name
|
|
10360
|
+
* @param recordId - Source record ID
|
|
10361
|
+
* @param attributeName - Relation attribute name
|
|
10362
|
+
* @param targetIds - Array of target record IDs
|
|
10363
|
+
* @returns Map of target ID → properties
|
|
10364
|
+
*
|
|
10365
|
+
* @example
|
|
10366
|
+
* ```typescript
|
|
10367
|
+
* // Properties stored as: contacts/A/companies → X with { role: "CEO" }
|
|
10368
|
+
*
|
|
10369
|
+
* // Read from Contact A → Company X
|
|
10370
|
+
* const propsFromContact = await service.getRelationProperties(
|
|
10371
|
+
* "contacts", "A", "companies", ["X"]
|
|
10372
|
+
* );
|
|
10373
|
+
* // → Map { "X" => { role: "CEO" } }
|
|
10374
|
+
*
|
|
10375
|
+
* // Read from Company X → Contact A (inverse)
|
|
10376
|
+
* const propsFromCompany = await service.getRelationProperties(
|
|
10377
|
+
* "companies", "X", "contacts", ["A"]
|
|
10378
|
+
* );
|
|
10379
|
+
* // → Map { "A" => { role: "CEO" } } (same properties!)
|
|
10380
|
+
* ```
|
|
10381
|
+
*/
|
|
10382
|
+
async getRelationProperties(objectName, recordId, attributeName, targetIds) {
|
|
10383
|
+
const properties = /* @__PURE__ */ new Map();
|
|
10384
|
+
if (!this.adapter.relationAttributes) {
|
|
10385
|
+
return properties;
|
|
10386
|
+
}
|
|
10387
|
+
const forwardProps = await this.adapter.relationAttributes.findBySource(
|
|
10388
|
+
objectName,
|
|
10389
|
+
recordId,
|
|
10390
|
+
attributeName
|
|
10391
|
+
);
|
|
10392
|
+
for (const prop of forwardProps) {
|
|
10393
|
+
if (targetIds.includes(prop.toId)) {
|
|
10394
|
+
properties.set(prop.toId, prop.properties);
|
|
10395
|
+
}
|
|
10396
|
+
}
|
|
10397
|
+
const inverseProps = await this.adapter.relationAttributes.findByTarget(recordId);
|
|
10398
|
+
for (const prop of inverseProps) {
|
|
10399
|
+
if (targetIds.includes(prop.fromId) && !properties.has(prop.fromId)) {
|
|
10400
|
+
properties.set(prop.fromId, prop.properties);
|
|
10401
|
+
}
|
|
10402
|
+
}
|
|
10403
|
+
return properties;
|
|
10404
|
+
}
|
|
10405
|
+
/**
|
|
10406
|
+
* Batch enrich records with qualified relation properties.
|
|
10407
|
+
*
|
|
10408
|
+
* Detects qualified attributes in the schema and fetches their properties
|
|
10409
|
+
* using batch queries (1 query per qualified attribute, not per record).
|
|
10410
|
+
* Returns records with values in hybrid format `{ id, props }`.
|
|
10411
|
+
*
|
|
10412
|
+
* For bilateral relations, also checks the inverse direction.
|
|
10413
|
+
*
|
|
10414
|
+
* @param records - Records to enrich
|
|
10415
|
+
* @param schema - Object schema
|
|
10416
|
+
* @returns Records with relation values enriched with properties
|
|
10417
|
+
*/
|
|
10418
|
+
async enrichRecordsBatch(records, schema) {
|
|
10419
|
+
if (!this.adapter.relationAttributes) return records;
|
|
10420
|
+
if (records.length === 0) return records;
|
|
10421
|
+
const qualifiedAttrs = schema.attributes.filter(
|
|
10422
|
+
(a) => a.type === "relation" && (!!a.properties || !!a.bilateral)
|
|
10423
|
+
);
|
|
10424
|
+
if (qualifiedAttrs.length === 0) return records;
|
|
10425
|
+
const recordIds = records.map((r) => r.id);
|
|
10426
|
+
const relationAttrsRepo = this.adapter.relationAttributes;
|
|
10427
|
+
await Promise.all(
|
|
10428
|
+
qualifiedAttrs.map(async (attr) => {
|
|
10429
|
+
const forwardRows = await relationAttrsRepo.findBySourceBatch(
|
|
10430
|
+
schema.name,
|
|
10431
|
+
recordIds,
|
|
10432
|
+
attr.name
|
|
10433
|
+
);
|
|
10434
|
+
const inverseRows = attr.bilateral ? await relationAttrsRepo.findByTargetBatch(recordIds) : [];
|
|
10435
|
+
const byRecord = /* @__PURE__ */ new Map();
|
|
10436
|
+
for (const row of forwardRows) {
|
|
10437
|
+
let recordMap = byRecord.get(row.fromId);
|
|
10438
|
+
if (!recordMap) {
|
|
10439
|
+
recordMap = /* @__PURE__ */ new Map();
|
|
10440
|
+
byRecord.set(row.fromId, recordMap);
|
|
10441
|
+
}
|
|
10442
|
+
recordMap.set(row.toId, row.properties);
|
|
10443
|
+
}
|
|
10444
|
+
for (const row of inverseRows) {
|
|
10445
|
+
let recordMap = byRecord.get(row.toId);
|
|
10446
|
+
if (!recordMap) {
|
|
10447
|
+
recordMap = /* @__PURE__ */ new Map();
|
|
10448
|
+
byRecord.set(row.toId, recordMap);
|
|
10449
|
+
}
|
|
10450
|
+
if (!recordMap.has(row.fromId)) {
|
|
10451
|
+
recordMap.set(row.fromId, row.properties);
|
|
10452
|
+
}
|
|
10453
|
+
}
|
|
10454
|
+
for (const record of records) {
|
|
10455
|
+
const propsForRecord = byRecord.get(record.id);
|
|
10456
|
+
if (!propsForRecord) continue;
|
|
10457
|
+
const value = record.values[attr.name];
|
|
10458
|
+
if (Array.isArray(value)) {
|
|
10459
|
+
record.values = {
|
|
10460
|
+
...record.values,
|
|
10461
|
+
[attr.name]: value.map((id) => {
|
|
10462
|
+
const props = propsForRecord.get(id);
|
|
10463
|
+
return props ? { id, props } : id;
|
|
10464
|
+
})
|
|
10465
|
+
};
|
|
10466
|
+
} else if (typeof value === "string") {
|
|
10467
|
+
const props = propsForRecord.get(value);
|
|
10468
|
+
if (props) {
|
|
10469
|
+
record.values = {
|
|
10470
|
+
...record.values,
|
|
10471
|
+
[attr.name]: { id: value, props }
|
|
10472
|
+
};
|
|
10473
|
+
}
|
|
10474
|
+
}
|
|
10475
|
+
}
|
|
10476
|
+
})
|
|
10477
|
+
);
|
|
10478
|
+
return records;
|
|
10479
|
+
}
|
|
10480
|
+
/**
|
|
10481
|
+
* Normalize relation values for storage in object_records table.
|
|
10482
|
+
*
|
|
10483
|
+
* Extracts IDs from hybrid format ({ id, props }) and returns legacy format (string[] or string).
|
|
10484
|
+
* This ensures object_records.values only contains IDs, while properties are in relation_attributes.
|
|
10485
|
+
*
|
|
10486
|
+
* @param schema - Object schema
|
|
10487
|
+
* @param data - Record data with hybrid relation values
|
|
10488
|
+
* @returns Data with relation values normalized to ID-only format
|
|
10489
|
+
*/
|
|
10490
|
+
normalizeRelationValuesForStorage(schema, data) {
|
|
10491
|
+
const normalized = { ...data };
|
|
10492
|
+
for (const attr of schema.attributes) {
|
|
10493
|
+
if (attr.type !== "relation") {
|
|
10494
|
+
continue;
|
|
10495
|
+
}
|
|
10496
|
+
const value = data[attr.name];
|
|
10497
|
+
if (value === null || value === void 0) {
|
|
10498
|
+
continue;
|
|
10499
|
+
}
|
|
10500
|
+
if (attr.cardinality === "many" && Array.isArray(value)) {
|
|
10501
|
+
normalized[attr.name] = value.map((item) => {
|
|
10502
|
+
if (typeof item === "string") return item;
|
|
10503
|
+
if (typeof item === "object" && item !== null && "id" in item) {
|
|
10504
|
+
return item.id;
|
|
10505
|
+
}
|
|
10506
|
+
return item;
|
|
10507
|
+
});
|
|
10508
|
+
} else if (typeof value === "object" && value !== null && "id" in value) {
|
|
10509
|
+
normalized[attr.name] = value.id;
|
|
10510
|
+
}
|
|
10511
|
+
}
|
|
10512
|
+
return normalized;
|
|
10513
|
+
}
|
|
10514
|
+
/**
|
|
10515
|
+
* Synchronize relation properties for a given attribute.
|
|
10516
|
+
*
|
|
10517
|
+
* Handles:
|
|
10518
|
+
* - Format normalization (legacy → new)
|
|
10519
|
+
* - Validation of properties
|
|
10520
|
+
* - Upsert for present IDs
|
|
10521
|
+
* - Delete for absent IDs
|
|
10522
|
+
*
|
|
10523
|
+
* @param schema - Object schema
|
|
10524
|
+
* @param recordId - Source record ID
|
|
10525
|
+
* @param attributeName - Relation attribute name
|
|
10526
|
+
* @param relationValue - Relation value (hybrid format)
|
|
10527
|
+
* @param adapter - Database adapter
|
|
10528
|
+
*/
|
|
10529
|
+
async syncRelationProperties(schema, recordId, attributeName, relationValue, adapter) {
|
|
10530
|
+
const attribute = schema.attributes.find((a) => a.name === attributeName);
|
|
10531
|
+
if (!attribute || attribute.type !== "relation") {
|
|
10532
|
+
return;
|
|
10533
|
+
}
|
|
10534
|
+
const normalized = this.normalizeRelationValue(relationValue);
|
|
10535
|
+
const propertySchema = this.getPropertySchema(attribute);
|
|
10536
|
+
const hasPropsInInput = normalized.some((item) => item.props !== void 0);
|
|
10537
|
+
const hasSchema = Boolean(propertySchema);
|
|
10538
|
+
const canSync = hasSchema || hasPropsInInput;
|
|
10539
|
+
if (!canSync) {
|
|
10540
|
+
return;
|
|
10541
|
+
}
|
|
10542
|
+
if (propertySchema) {
|
|
10543
|
+
for (const item of normalized) {
|
|
10544
|
+
if (item.props && Object.keys(item.props).length > 0) {
|
|
10545
|
+
this.validateProperties(propertySchema, item.props);
|
|
10546
|
+
}
|
|
10547
|
+
}
|
|
10548
|
+
}
|
|
10549
|
+
const shouldStoreAsInverse = _optionalChain([attribute, 'access', _196 => _196.bilateral, 'optionalAccess', _197 => _197.storageOwner]) === false;
|
|
10550
|
+
let storageFromObject = schema.name;
|
|
10551
|
+
let storageFromAttribute = attributeName;
|
|
10552
|
+
if (shouldStoreAsInverse && attribute.bilateral) {
|
|
10553
|
+
storageFromObject = attribute.bilateral.object;
|
|
10554
|
+
storageFromAttribute = attribute.bilateral.attribute;
|
|
10555
|
+
}
|
|
10556
|
+
let existing;
|
|
10557
|
+
if (adapter.relationAttributes) {
|
|
10558
|
+
if (shouldStoreAsInverse) {
|
|
10559
|
+
const results = await Promise.all(
|
|
10560
|
+
normalized.map(
|
|
10561
|
+
(item) => _optionalChain([adapter, 'access', _198 => _198.relationAttributes, 'optionalAccess', _199 => _199.findBySource, 'call', _200 => _200(
|
|
10562
|
+
storageFromObject,
|
|
10563
|
+
item.id,
|
|
10564
|
+
storageFromAttribute
|
|
10565
|
+
)])
|
|
10566
|
+
)
|
|
10567
|
+
);
|
|
10568
|
+
existing = results.filter((r) => r !== void 0).flat().filter((r) => r.toId === recordId);
|
|
10569
|
+
} else {
|
|
10570
|
+
existing = await adapter.relationAttributes.findBySource(
|
|
10571
|
+
schema.name,
|
|
10572
|
+
recordId,
|
|
10573
|
+
attributeName
|
|
10574
|
+
);
|
|
10575
|
+
}
|
|
10576
|
+
}
|
|
10577
|
+
const hasChanges = existing && existing.length > 0;
|
|
10578
|
+
const toUpsert = normalized.filter((item) => {
|
|
10579
|
+
return item.props !== void 0 && Object.keys(item.props).length > 0;
|
|
10580
|
+
});
|
|
10581
|
+
if (!adapter.relationAttributes) {
|
|
10582
|
+
return;
|
|
10583
|
+
}
|
|
10584
|
+
if (hasChanges && existing) {
|
|
10585
|
+
if (shouldStoreAsInverse) {
|
|
10586
|
+
for (const item of normalized) {
|
|
10587
|
+
await adapter.relationAttributes.deleteBySourceAndTarget(
|
|
10588
|
+
storageFromObject,
|
|
10589
|
+
item.id,
|
|
10590
|
+
storageFromAttribute,
|
|
10591
|
+
recordId
|
|
10592
|
+
);
|
|
10593
|
+
}
|
|
10594
|
+
} else {
|
|
10595
|
+
await adapter.relationAttributes.deleteBySource(schema.name, recordId, attributeName);
|
|
10596
|
+
}
|
|
10597
|
+
}
|
|
10598
|
+
if (toUpsert.length > 0) {
|
|
10599
|
+
const inputs = toUpsert.map((item) => {
|
|
10600
|
+
if (shouldStoreAsInverse) {
|
|
10601
|
+
return {
|
|
10602
|
+
fromObject: storageFromObject,
|
|
10603
|
+
fromId: item.id,
|
|
10604
|
+
fromAttribute: storageFromAttribute,
|
|
10605
|
+
toId: recordId,
|
|
10606
|
+
properties: _nullishCoalesce(item.props, () => ( {})),
|
|
10607
|
+
updatedBy: _nullishCoalesce(this.userId, () => ( void 0)),
|
|
10608
|
+
createdBy: _nullishCoalesce(this.userId, () => ( void 0))
|
|
10609
|
+
};
|
|
10610
|
+
}
|
|
10611
|
+
return {
|
|
10612
|
+
fromObject: schema.name,
|
|
10613
|
+
fromId: recordId,
|
|
10614
|
+
fromAttribute: attributeName,
|
|
10615
|
+
toId: item.id,
|
|
10616
|
+
properties: _nullishCoalesce(item.props, () => ( {})),
|
|
10617
|
+
updatedBy: _nullishCoalesce(this.userId, () => ( void 0)),
|
|
10618
|
+
createdBy: _nullishCoalesce(this.userId, () => ( void 0))
|
|
10619
|
+
};
|
|
10620
|
+
});
|
|
10621
|
+
await adapter.relationAttributes.upsertBatch(inputs);
|
|
10622
|
+
}
|
|
10623
|
+
}
|
|
10624
|
+
/**
|
|
10625
|
+
* Validate relation properties against PropertySchema.
|
|
10626
|
+
*
|
|
10627
|
+
* Uses Zod for runtime validation based on PropertyAttribute types.
|
|
10628
|
+
*
|
|
10629
|
+
* @param propertySchema - Schema defining allowed properties
|
|
10630
|
+
* @param properties - Properties to validate
|
|
10631
|
+
* @throws {z.ZodError} if validation fails
|
|
10632
|
+
*/
|
|
10633
|
+
validateProperties(propertySchema, properties) {
|
|
10634
|
+
const schema = this.buildZodSchema(propertySchema);
|
|
10635
|
+
schema.parse(properties);
|
|
10636
|
+
}
|
|
10637
|
+
// ============================================================================
|
|
10638
|
+
// PRIVATE HELPERS
|
|
10639
|
+
// ============================================================================
|
|
10640
|
+
/**
|
|
10641
|
+
* Get PropertySchema for a relation attribute.
|
|
10642
|
+
*
|
|
10643
|
+
* For bilateral relations without .qualifyWith(), returns undefined.
|
|
10644
|
+
* Properties will be stored/retrieved but not validated on the inverse side.
|
|
10645
|
+
*/
|
|
10646
|
+
getPropertySchema(attribute) {
|
|
10647
|
+
return attribute.properties;
|
|
10648
|
+
}
|
|
10649
|
+
/**
|
|
10650
|
+
* Normalize relation value to unified internal format.
|
|
10651
|
+
*
|
|
10652
|
+
* Converts:
|
|
10653
|
+
* - string[] → Array<{ id, props?: undefined }>
|
|
10654
|
+
* - string → [{ id, props?: undefined }]
|
|
10655
|
+
* - null → []
|
|
10656
|
+
* - Array<{ id, props }> → Array<{ id, props }> (passthrough)
|
|
10657
|
+
* - { id, props } → [{ id, props }] (single to array)
|
|
10658
|
+
*/
|
|
10659
|
+
normalizeRelationValue(value) {
|
|
10660
|
+
if (value === null || value === void 0) {
|
|
10661
|
+
return [];
|
|
10662
|
+
}
|
|
10663
|
+
if (typeof value === "string") {
|
|
10664
|
+
return [{ id: value }];
|
|
10665
|
+
}
|
|
10666
|
+
if (!Array.isArray(value) && typeof value === "object" && "id" in value) {
|
|
10667
|
+
return [value];
|
|
10668
|
+
}
|
|
10669
|
+
if (Array.isArray(value)) {
|
|
10670
|
+
return value.map((item) => {
|
|
10671
|
+
if (typeof item === "string") {
|
|
10672
|
+
return { id: item };
|
|
10673
|
+
}
|
|
10674
|
+
return item;
|
|
10675
|
+
});
|
|
10676
|
+
}
|
|
10677
|
+
return [];
|
|
10678
|
+
}
|
|
10679
|
+
/**
|
|
10680
|
+
* Build Zod schema from PropertySchema definition.
|
|
10681
|
+
*
|
|
10682
|
+
* Reuses createFormAttributeValidator() to avoid code duplication with validators.ts.
|
|
10683
|
+
* This validator handles null/undefined values correctly for optional fields.
|
|
10684
|
+
*/
|
|
10685
|
+
buildZodSchema(propertySchema) {
|
|
10686
|
+
const shape = {};
|
|
10687
|
+
for (const def of propertySchema.definitions) {
|
|
10688
|
+
shape[def.name] = _chunkU4AB53AMjs.createFormAttributeValidator.call(void 0, def);
|
|
10689
|
+
}
|
|
10690
|
+
return _zod.z.object(shape);
|
|
10691
|
+
}
|
|
10692
|
+
};
|
|
10693
|
+
|
|
10188
10694
|
// src/runtime/services/record/query.service.ts
|
|
10189
10695
|
var RecordQueryService = class extends BaseService {
|
|
10190
10696
|
constructor(adapter, schemaService, options) {
|
|
10191
10697
|
super(adapter);
|
|
10192
10698
|
this.schemaService = schemaService;
|
|
10193
10699
|
this.options = options;
|
|
10194
|
-
this.policyRegistry = _optionalChain([options, 'optionalAccess',
|
|
10700
|
+
this.policyRegistry = _optionalChain([options, 'optionalAccess', _201 => _201.policyRegistry]) === null ? null : _nullishCoalesce(_optionalChain([options, 'optionalAccess', _202 => _202.policyRegistry]), () => ( defaultPolicyRegistry));
|
|
10701
|
+
this.relationPropertiesService = new RelationPropertiesService(adapter);
|
|
10195
10702
|
}
|
|
10196
10703
|
// ============================================================================
|
|
10197
10704
|
// LIST
|
|
@@ -10241,12 +10748,12 @@ var RecordQueryService = class extends BaseService {
|
|
|
10241
10748
|
* Internal list query execution
|
|
10242
10749
|
*/
|
|
10243
10750
|
async executeListQuery(schema, objectId, options) {
|
|
10244
|
-
if (_optionalChain([this, 'access',
|
|
10751
|
+
if (_optionalChain([this, 'access', _203 => _203.options, 'optionalAccess', _204 => _204.permissionService]) && this.userId) {
|
|
10245
10752
|
await checkPermission(this.options.permissionService, this.userId, schema.name, "read");
|
|
10246
10753
|
}
|
|
10247
|
-
const policy = _optionalChain([options, 'optionalAccess',
|
|
10754
|
+
const policy = _optionalChain([options, 'optionalAccess', _205 => _205.skipPolicyFilter]) ? void 0 : getPolicy(this.policyRegistry, this.userId, schema.name);
|
|
10248
10755
|
let effectiveOptions = options;
|
|
10249
|
-
if (_optionalChain([policy, 'optionalAccess',
|
|
10756
|
+
if (_optionalChain([policy, 'optionalAccess', _206 => _206.applyListFilter]) && this.userId) {
|
|
10250
10757
|
const ctx = buildPolicyContext(schema.name, this.userId, this.tenantId);
|
|
10251
10758
|
effectiveOptions = policy.applyListFilter(ctx, options);
|
|
10252
10759
|
}
|
|
@@ -10256,10 +10763,10 @@ var RecordQueryService = class extends BaseService {
|
|
|
10256
10763
|
);
|
|
10257
10764
|
let filteredRecords = result.records;
|
|
10258
10765
|
let effectiveTotal = result.total;
|
|
10259
|
-
if (_optionalChain([policy, 'optionalAccess',
|
|
10766
|
+
if (_optionalChain([policy, 'optionalAccess', _207 => _207.canAccessRecord]) && this.userId) {
|
|
10260
10767
|
const ctx = buildPolicyContext(schema.name, this.userId, this.tenantId);
|
|
10261
|
-
const requestedLimit = _nullishCoalesce(_optionalChain([effectiveOptions, 'optionalAccess',
|
|
10262
|
-
const requestedOffset = _nullishCoalesce(_optionalChain([effectiveOptions, 'optionalAccess',
|
|
10768
|
+
const requestedLimit = _nullishCoalesce(_optionalChain([effectiveOptions, 'optionalAccess', _208 => _208.limit]), () => ( 20));
|
|
10769
|
+
const requestedOffset = _nullishCoalesce(_optionalChain([effectiveOptions, 'optionalAccess', _209 => _209.offset]), () => ( 0));
|
|
10263
10770
|
const overfetchMultiplier = 5;
|
|
10264
10771
|
const batchSize = requestedLimit * overfetchMultiplier;
|
|
10265
10772
|
const maxScanRecords = 1e4;
|
|
@@ -10281,7 +10788,7 @@ var RecordQueryService = class extends BaseService {
|
|
|
10281
10788
|
exhausted = true;
|
|
10282
10789
|
break;
|
|
10283
10790
|
}
|
|
10284
|
-
const filtered = batch.records.filter((record) => _optionalChain([policy, 'access',
|
|
10791
|
+
const filtered = batch.records.filter((record) => _optionalChain([policy, 'access', _210 => _210.canAccessRecord, 'optionalCall', _211 => _211(ctx, record)]));
|
|
10285
10792
|
collected.push(...filtered);
|
|
10286
10793
|
dbOffset += batch.records.length;
|
|
10287
10794
|
totalScanned += batch.records.length;
|
|
@@ -10293,14 +10800,11 @@ var RecordQueryService = class extends BaseService {
|
|
|
10293
10800
|
effectiveTotal = exhausted ? collected.length : Math.max(collected.length, result.total);
|
|
10294
10801
|
filteredRecords = collected.slice(requestedOffset, requestedOffset + requestedLimit);
|
|
10295
10802
|
}
|
|
10296
|
-
|
|
10297
|
-
filteredRecords
|
|
10298
|
-
|
|
10299
|
-
|
|
10300
|
-
|
|
10301
|
-
);
|
|
10302
|
-
}
|
|
10303
|
-
if (!_optionalChain([options, 'optionalAccess', _204 => _204.skipFormulas])) {
|
|
10803
|
+
filteredRecords = await this.relationPropertiesService.enrichRecordsBatch(
|
|
10804
|
+
filteredRecords,
|
|
10805
|
+
schema
|
|
10806
|
+
);
|
|
10807
|
+
if (!_optionalChain([options, 'optionalAccess', _212 => _212.skipFormulas])) {
|
|
10304
10808
|
return {
|
|
10305
10809
|
records: enrichRecordsWithFormulas(filteredRecords, schema),
|
|
10306
10810
|
total: effectiveTotal
|
|
@@ -10360,459 +10864,119 @@ var RecordQueryService = class extends BaseService {
|
|
|
10360
10864
|
* Internal search query execution
|
|
10361
10865
|
*/
|
|
10362
10866
|
async executeSearchQuery(schema, objectId, query, options) {
|
|
10363
|
-
if (_optionalChain([this, 'access',
|
|
10867
|
+
if (_optionalChain([this, 'access', _213 => _213.options, 'optionalAccess', _214 => _214.permissionService]) && this.userId) {
|
|
10364
10868
|
await checkPermission(this.options.permissionService, this.userId, schema.name, "read");
|
|
10365
10869
|
}
|
|
10366
10870
|
const result = await runWithSchemaContext(
|
|
10367
10871
|
[schema],
|
|
10368
10872
|
() => this.adapter.objectRecords.search(objectId, query, options)
|
|
10369
10873
|
);
|
|
10370
|
-
|
|
10874
|
+
const enrichedRecords = await this.relationPropertiesService.enrichRecordsBatch(
|
|
10875
|
+
result.records,
|
|
10876
|
+
schema
|
|
10877
|
+
);
|
|
10878
|
+
if (!_optionalChain([options, 'optionalAccess', _215 => _215.skipFormulas])) {
|
|
10371
10879
|
return {
|
|
10372
|
-
records: enrichRecordsWithFormulas(
|
|
10880
|
+
records: enrichRecordsWithFormulas(enrichedRecords, schema),
|
|
10373
10881
|
total: result.total
|
|
10374
10882
|
};
|
|
10375
10883
|
}
|
|
10376
|
-
return result;
|
|
10377
|
-
}
|
|
10378
|
-
// ============================================================================
|
|
10379
|
-
// INCLUDE RELATIONS WITH PROPERTIES
|
|
10380
|
-
// ============================================================================
|
|
10381
|
-
/**
|
|
10382
|
-
* Include relation properties in records.
|
|
10383
|
-
*
|
|
10384
|
-
* For each requested relation attribute:
|
|
10385
|
-
* - If attribute has properties → Fetch from relation_attributes and return hybrid format
|
|
10386
|
-
* - If attribute has NO properties → Return legacy format (string[] or string)
|
|
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
10884
|
return {
|
|
10523
|
-
|
|
10524
|
-
|
|
10525
|
-
};
|
|
10526
|
-
}
|
|
10527
|
-
|
|
10528
|
-
|
|
10529
|
-
|
|
10530
|
-
|
|
10531
|
-
|
|
10532
|
-
|
|
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;
|
|
10885
|
+
records: enrichedRecords,
|
|
10886
|
+
total: result.total
|
|
10887
|
+
};
|
|
10888
|
+
}
|
|
10889
|
+
};
|
|
10890
|
+
|
|
10891
|
+
// src/runtime/services/record/record-resolver.service.ts
|
|
10892
|
+
var RecordResolverService = class extends BaseService {
|
|
10893
|
+
constructor(adapter) {
|
|
10894
|
+
super(adapter);
|
|
10587
10895
|
}
|
|
10896
|
+
// ============================================================================
|
|
10897
|
+
// CACHED RECORD ACCESS
|
|
10898
|
+
// ============================================================================
|
|
10588
10899
|
/**
|
|
10589
|
-
*
|
|
10900
|
+
* Find a record by ID with caching.
|
|
10590
10901
|
*
|
|
10591
|
-
*
|
|
10592
|
-
*
|
|
10593
|
-
* - Validation of properties
|
|
10594
|
-
* - Upsert for present IDs
|
|
10595
|
-
* - Delete for absent IDs
|
|
10902
|
+
* Uses the shared record cache for optimal performance.
|
|
10903
|
+
* Delegates to findByIds for consistent cache handling.
|
|
10596
10904
|
*
|
|
10597
|
-
* @param
|
|
10598
|
-
* @
|
|
10599
|
-
* @param attributeName - Relation attribute name
|
|
10600
|
-
* @param relationValue - Relation value (hybrid format)
|
|
10601
|
-
* @param adapter - Database adapter
|
|
10905
|
+
* @param id - Record ID
|
|
10906
|
+
* @returns Record or null if not found
|
|
10602
10907
|
*/
|
|
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
|
-
}
|
|
10908
|
+
async findById(id) {
|
|
10909
|
+
if (!id) return null;
|
|
10910
|
+
const results = await this.findByIds([id]);
|
|
10911
|
+
return _nullishCoalesce(results[0], () => ( null));
|
|
10658
10912
|
}
|
|
10659
10913
|
/**
|
|
10660
|
-
*
|
|
10914
|
+
* Find multiple records by IDs with caching.
|
|
10661
10915
|
*
|
|
10662
|
-
*
|
|
10916
|
+
* Each record is cached individually for reuse across services.
|
|
10917
|
+
* Only fetches records not already in cache.
|
|
10663
10918
|
*
|
|
10664
|
-
* @param
|
|
10665
|
-
* @
|
|
10666
|
-
* @throws {z.ZodError} if validation fails
|
|
10919
|
+
* @param ids - Record IDs to fetch
|
|
10920
|
+
* @returns Array of found records (missing IDs are not included)
|
|
10667
10921
|
*/
|
|
10668
|
-
|
|
10669
|
-
|
|
10670
|
-
|
|
10922
|
+
async findByIds(ids) {
|
|
10923
|
+
if (!ids || ids.length === 0) {
|
|
10924
|
+
return [];
|
|
10925
|
+
}
|
|
10926
|
+
const uniqueIds = [...new Set(ids)];
|
|
10927
|
+
return this.cachedByMany(
|
|
10928
|
+
"record",
|
|
10929
|
+
uniqueIds,
|
|
10930
|
+
(missingIds) => this.adapter.objectRecords.findByIds(missingIds),
|
|
10931
|
+
(record) => record.id,
|
|
10932
|
+
cacheTtl.records
|
|
10933
|
+
);
|
|
10671
10934
|
}
|
|
10672
10935
|
// ============================================================================
|
|
10673
|
-
//
|
|
10936
|
+
// FACTORY METHODS
|
|
10674
10937
|
// ============================================================================
|
|
10675
10938
|
/**
|
|
10676
|
-
*
|
|
10939
|
+
* Create a RelationLabelResolver callback for computeLabelWithRelations.
|
|
10677
10940
|
*
|
|
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)
|
|
10941
|
+
* Used by RelationService.resolveLabel() and ObjectSchemaService.
|
|
10684
10942
|
*
|
|
10685
|
-
* @
|
|
10686
|
-
* @returns Normalized array of relation items
|
|
10687
|
-
* @private
|
|
10943
|
+
* @returns Callback that resolves record IDs to their labels (cached)
|
|
10688
10944
|
*/
|
|
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 [];
|
|
10945
|
+
createRelationLabelResolver() {
|
|
10946
|
+
return async (ids) => {
|
|
10947
|
+
const records = await this.findByIds(ids);
|
|
10948
|
+
return new Map(records.map((r) => [r.id, r.label]));
|
|
10949
|
+
};
|
|
10708
10950
|
}
|
|
10709
10951
|
/**
|
|
10710
|
-
*
|
|
10952
|
+
* Create a LabelResolver interface for label computation helpers.
|
|
10711
10953
|
*
|
|
10712
|
-
*
|
|
10954
|
+
* Used by RecordService for computing record labels.
|
|
10713
10955
|
*
|
|
10714
|
-
* @param
|
|
10715
|
-
* @returns
|
|
10716
|
-
* @private
|
|
10956
|
+
* @param relationService - RelationService for resolving relation display labels
|
|
10957
|
+
* @returns LabelResolver interface with cached record fetching
|
|
10717
10958
|
*/
|
|
10718
|
-
|
|
10719
|
-
|
|
10720
|
-
|
|
10721
|
-
|
|
10722
|
-
|
|
10723
|
-
fieldSchema = fieldSchema.optional();
|
|
10724
|
-
}
|
|
10725
|
-
shape[def.name] = fieldSchema;
|
|
10726
|
-
}
|
|
10727
|
-
return _zod.z.object(shape);
|
|
10959
|
+
createLabelResolver(relationService) {
|
|
10960
|
+
return {
|
|
10961
|
+
resolveRelationIds: (ids, attrId) => relationService.resolveIds(ids, attrId),
|
|
10962
|
+
findRecordLabels: (ids) => this.findByIds(ids)
|
|
10963
|
+
};
|
|
10728
10964
|
}
|
|
10729
10965
|
/**
|
|
10730
|
-
*
|
|
10966
|
+
* Create a RollupCascadeContext for rollup recalculation.
|
|
10731
10967
|
*
|
|
10732
|
-
*
|
|
10733
|
-
*
|
|
10734
|
-
* @
|
|
10968
|
+
* Used by RecordService after create/update/delete operations.
|
|
10969
|
+
*
|
|
10970
|
+
* @param rollupService - RollupService for recalculating rollups
|
|
10971
|
+
* @param schemaService - ObjectSchemaService for fetching schemas
|
|
10972
|
+
* @returns Context with cached record fetching
|
|
10735
10973
|
*/
|
|
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
|
-
}
|
|
10974
|
+
createRollupContext(rollupService, schemaService) {
|
|
10975
|
+
return {
|
|
10976
|
+
rollupService,
|
|
10977
|
+
schemaService,
|
|
10978
|
+
findRecordsByIds: (ids) => this.findByIds(ids)
|
|
10979
|
+
};
|
|
10816
10980
|
}
|
|
10817
10981
|
};
|
|
10818
10982
|
|
|
@@ -10823,6 +10987,7 @@ var RelationService = class extends BaseService {
|
|
|
10823
10987
|
this.schemaService = new ObjectSchemaService(adapter, nativeRegistry);
|
|
10824
10988
|
this.queryService = options.queryService;
|
|
10825
10989
|
this.recordResolver = options.recordResolver;
|
|
10990
|
+
this.relationPropertiesService = options.relationPropertiesService;
|
|
10826
10991
|
}
|
|
10827
10992
|
/**
|
|
10828
10993
|
* Set the query service after construction.
|
|
@@ -10893,7 +11058,7 @@ var RelationService = class extends BaseService {
|
|
|
10893
11058
|
}
|
|
10894
11059
|
const isUniversal = attr.targets.length === 1 && attr.targets[0].object === RELATION_TARGET_ANY;
|
|
10895
11060
|
const validObjectIds = isUniversal ? null : await this.getValidObjectIds(attr.targets);
|
|
10896
|
-
if (!isUniversal && _optionalChain([validObjectIds, 'optionalAccess',
|
|
11061
|
+
if (!isUniversal && _optionalChain([validObjectIds, 'optionalAccess', _216 => _216.size]) === 0) {
|
|
10897
11062
|
errors.push({
|
|
10898
11063
|
attribute: attr.name,
|
|
10899
11064
|
message: `No valid target objects found for ${attr.label}`
|
|
@@ -10946,10 +11111,10 @@ var RelationService = class extends BaseService {
|
|
|
10946
11111
|
for (const target of targets) {
|
|
10947
11112
|
try {
|
|
10948
11113
|
const objectSchema = await this.schemaService.getObjectSchemaByName(target.object);
|
|
10949
|
-
if (_optionalChain([objectSchema, 'optionalAccess',
|
|
11114
|
+
if (_optionalChain([objectSchema, 'optionalAccess', _217 => _217.id])) {
|
|
10950
11115
|
objectIds.add(objectSchema.id);
|
|
10951
11116
|
}
|
|
10952
|
-
} catch (
|
|
11117
|
+
} catch (e15) {
|
|
10953
11118
|
}
|
|
10954
11119
|
}
|
|
10955
11120
|
return objectIds;
|
|
@@ -11015,7 +11180,7 @@ var RelationService = class extends BaseService {
|
|
|
11015
11180
|
const targetResults = await Promise.all(
|
|
11016
11181
|
filteredTargets.map(async (target) => {
|
|
11017
11182
|
const objectSchema = await this.schemaService.getObjectSchemaByName(target.object);
|
|
11018
|
-
if (!_optionalChain([objectSchema, 'optionalAccess',
|
|
11183
|
+
if (!_optionalChain([objectSchema, 'optionalAccess', _218 => _218.id])) return { options: [], total: 0 };
|
|
11019
11184
|
const objectId = objectSchema.id;
|
|
11020
11185
|
const result = query ? await queryService.searchRecords(objectId, query, queryOptions) : await queryService.listRecords(objectId, queryOptions);
|
|
11021
11186
|
const options = await Promise.all(
|
|
@@ -11172,8 +11337,8 @@ var RelationService = class extends BaseService {
|
|
|
11172
11337
|
continue;
|
|
11173
11338
|
}
|
|
11174
11339
|
const attribute = attributeMap.get(attributeId);
|
|
11175
|
-
const targetConfig = _optionalChain([attribute, 'optionalAccess',
|
|
11176
|
-
const customTemplate = _optionalChain([targetConfig, 'optionalAccess',
|
|
11340
|
+
const targetConfig = _optionalChain([attribute, 'optionalAccess', _219 => _219.targets, 'optionalAccess', _220 => _220.find, 'call', _221 => _221((t) => t.object === objectSchema.name)]);
|
|
11341
|
+
const customTemplate = _optionalChain([targetConfig, 'optionalAccess', _222 => _222.displayTemplate]);
|
|
11177
11342
|
const label = await this.resolveLabel(record, objectSchema, customTemplate);
|
|
11178
11343
|
resolved.push({
|
|
11179
11344
|
_compositeId: compositeId,
|
|
@@ -11190,20 +11355,33 @@ var RelationService = class extends BaseService {
|
|
|
11190
11355
|
/**
|
|
11191
11356
|
* Resolve the display label for a record.
|
|
11192
11357
|
* Uses custom template if provided, otherwise falls back to pre-computed label.
|
|
11358
|
+
*
|
|
11359
|
+
* Preserves `{{ props.X }}` tokens for client-side substitution using a sentinel approach:
|
|
11360
|
+
* tokens are replaced with null-byte sentinels before template rendering, then restored after.
|
|
11361
|
+
* This lets `computeLabelWithRelations` resolve target fields while keeping prop placeholders intact.
|
|
11193
11362
|
*/
|
|
11194
11363
|
async resolveLabel(record, objectSchema, customTemplate) {
|
|
11195
|
-
if (customTemplate)
|
|
11196
|
-
|
|
11197
|
-
|
|
11198
|
-
|
|
11199
|
-
|
|
11200
|
-
|
|
11201
|
-
|
|
11202
|
-
|
|
11203
|
-
|
|
11204
|
-
|
|
11364
|
+
if (!customTemplate) return record.label;
|
|
11365
|
+
const preserved = [];
|
|
11366
|
+
let i = 0;
|
|
11367
|
+
const safeTemplate = customTemplate.replace(/\{\{\s*props\.\w+[^}]*\}\}/g, (match) => {
|
|
11368
|
+
const key = `\0PROP${i++}\0`;
|
|
11369
|
+
preserved.push([key, match]);
|
|
11370
|
+
return key;
|
|
11371
|
+
});
|
|
11372
|
+
let label = await computeLabelWithRelations(
|
|
11373
|
+
safeTemplate,
|
|
11374
|
+
record.values,
|
|
11375
|
+
objectSchema.attributes,
|
|
11376
|
+
async (nestedIds) => {
|
|
11377
|
+
const linkedRecords = await this.recordResolver.findByIds(nestedIds);
|
|
11378
|
+
return new Map(linkedRecords.map((r) => [r.id, r.label]));
|
|
11379
|
+
}
|
|
11380
|
+
);
|
|
11381
|
+
for (const [key, token] of preserved) {
|
|
11382
|
+
label = label.replace(key, token);
|
|
11205
11383
|
}
|
|
11206
|
-
return
|
|
11384
|
+
return label;
|
|
11207
11385
|
}
|
|
11208
11386
|
/**
|
|
11209
11387
|
* Find a relation attribute by ID.
|
|
@@ -11323,14 +11501,14 @@ var RollupService = class extends BaseService {
|
|
|
11323
11501
|
const sourceSchema = getSchemaByNameFromContext(sourceObjectName);
|
|
11324
11502
|
let sourceObjectId;
|
|
11325
11503
|
let reverseRelationAttrName;
|
|
11326
|
-
if (_optionalChain([sourceSchema, 'optionalAccess',
|
|
11504
|
+
if (_optionalChain([sourceSchema, 'optionalAccess', _223 => _223.id])) {
|
|
11327
11505
|
sourceObjectId = sourceSchema.id;
|
|
11328
11506
|
const reverseRelationAttr = sourceSchema.attributes.find((attr) => {
|
|
11329
11507
|
if (attr.type !== "relation") return false;
|
|
11330
11508
|
const relationConfig = attr;
|
|
11331
|
-
return _optionalChain([relationConfig, 'optionalAccess',
|
|
11509
|
+
return _optionalChain([relationConfig, 'optionalAccess', _224 => _224.targets, 'optionalAccess', _225 => _225.some, 'call', _226 => _226((t) => t.object === schema.name)]);
|
|
11332
11510
|
});
|
|
11333
|
-
reverseRelationAttrName = _optionalChain([reverseRelationAttr, 'optionalAccess',
|
|
11511
|
+
reverseRelationAttrName = _optionalChain([reverseRelationAttr, 'optionalAccess', _227 => _227.name]);
|
|
11334
11512
|
} else {
|
|
11335
11513
|
const sourceObject = await this.adapter.objects.findByName(sourceObjectName);
|
|
11336
11514
|
if (!sourceObject) {
|
|
@@ -11341,9 +11519,9 @@ var RollupService = class extends BaseService {
|
|
|
11341
11519
|
const reverseRelationAttr = sourceAttributes.find((attr) => {
|
|
11342
11520
|
if (attr.type !== "relation") return false;
|
|
11343
11521
|
const relationConfig = attr.config;
|
|
11344
|
-
return _optionalChain([relationConfig, 'optionalAccess',
|
|
11522
|
+
return _optionalChain([relationConfig, 'optionalAccess', _228 => _228.targets, 'optionalAccess', _229 => _229.some, 'call', _230 => _230((t) => t.object === schema.name)]);
|
|
11345
11523
|
});
|
|
11346
|
-
reverseRelationAttrName = _optionalChain([reverseRelationAttr, 'optionalAccess',
|
|
11524
|
+
reverseRelationAttrName = _optionalChain([reverseRelationAttr, 'optionalAccess', _231 => _231.name]);
|
|
11347
11525
|
}
|
|
11348
11526
|
if (!reverseRelationAttrName) {
|
|
11349
11527
|
return { value: null, recordCount: 0 };
|
|
@@ -11599,13 +11777,13 @@ var RollupService = class extends BaseService {
|
|
|
11599
11777
|
if (!obj) continue;
|
|
11600
11778
|
for (const rollupDbAttr of rollupAttrs) {
|
|
11601
11779
|
const rollupConfig = rollupDbAttr.config;
|
|
11602
|
-
if (!_optionalChain([rollupConfig, 'optionalAccess',
|
|
11780
|
+
if (!_optionalChain([rollupConfig, 'optionalAccess', _232 => _232.relationAttribute])) continue;
|
|
11603
11781
|
const relationAttr = attributes.find(
|
|
11604
11782
|
(a) => a.type === "relation" && a.name === rollupConfig.relationAttribute
|
|
11605
11783
|
);
|
|
11606
11784
|
if (!relationAttr) continue;
|
|
11607
11785
|
const relationConfig = relationAttr.config;
|
|
11608
|
-
const targetsChangedObject = _optionalChain([relationConfig, 'optionalAccess',
|
|
11786
|
+
const targetsChangedObject = _optionalChain([relationConfig, 'optionalAccess', _233 => _233.targets, 'optionalAccess', _234 => _234.some, 'call', _235 => _235(
|
|
11609
11787
|
(t) => t.object === changedSchema.name
|
|
11610
11788
|
)]);
|
|
11611
11789
|
if (!targetsChangedObject) continue;
|
|
@@ -11630,11 +11808,11 @@ var RecordService = class extends BaseService {
|
|
|
11630
11808
|
constructor(adapter, options) {
|
|
11631
11809
|
super(adapter);
|
|
11632
11810
|
this.schemaService = new ObjectSchemaService(adapter, registry, {
|
|
11633
|
-
auditService: _optionalChain([options, 'optionalAccess',
|
|
11811
|
+
auditService: _optionalChain([options, 'optionalAccess', _236 => _236.auditService])
|
|
11634
11812
|
});
|
|
11635
|
-
this.permissionService = _optionalChain([options, 'optionalAccess',
|
|
11636
|
-
this.auditService = _nullishCoalesce(_optionalChain([options, 'optionalAccess',
|
|
11637
|
-
this.policyRegistry = _optionalChain([options, 'optionalAccess',
|
|
11813
|
+
this.permissionService = _optionalChain([options, 'optionalAccess', _237 => _237.permissionService]);
|
|
11814
|
+
this.auditService = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _238 => _238.auditService]), () => ( (adapter.audit ? new AuditService(adapter) : void 0)));
|
|
11815
|
+
this.policyRegistry = _optionalChain([options, 'optionalAccess', _239 => _239.policyRegistry]) === null ? null : _nullishCoalesce(_optionalChain([options, 'optionalAccess', _240 => _240.policyRegistry]), () => ( defaultPolicyRegistry));
|
|
11638
11816
|
this.recordResolver = new RecordResolverService(adapter);
|
|
11639
11817
|
this.queryService = new RecordQueryService(adapter, this.schemaService, {
|
|
11640
11818
|
permissionService: this.permissionService,
|
|
@@ -11649,7 +11827,12 @@ var RecordService = class extends BaseService {
|
|
|
11649
11827
|
recordResolver: this.recordResolver
|
|
11650
11828
|
});
|
|
11651
11829
|
this.userService = new UserService(adapter);
|
|
11652
|
-
this.hookRegistry = _nullishCoalesce(_optionalChain([options, 'optionalAccess',
|
|
11830
|
+
this.hookRegistry = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _241 => _241.hookRegistry]), () => ( new NoopHookRegistry()));
|
|
11831
|
+
this.bilateralSyncService = new BilateralSyncService(
|
|
11832
|
+
adapter,
|
|
11833
|
+
this.schemaService,
|
|
11834
|
+
this.relationPropertiesService
|
|
11835
|
+
);
|
|
11653
11836
|
this.labelResolver = this.recordResolver.createLabelResolver(this.relationService);
|
|
11654
11837
|
this.rollupContext = this.recordResolver.createRollupContext(
|
|
11655
11838
|
this.rollupService,
|
|
@@ -11684,25 +11867,25 @@ var RecordService = class extends BaseService {
|
|
|
11684
11867
|
schema,
|
|
11685
11868
|
this.tenantId,
|
|
11686
11869
|
dataWithDefaults,
|
|
11687
|
-
_optionalChain([options, 'optionalAccess',
|
|
11870
|
+
_optionalChain([options, 'optionalAccess', _242 => _242.hookMetadata])
|
|
11688
11871
|
);
|
|
11689
|
-
if (!_optionalChain([options, 'optionalAccess',
|
|
11872
|
+
if (!_optionalChain([options, 'optionalAccess', _243 => _243.skipHooks])) {
|
|
11690
11873
|
await this.hookRegistry.execute("beforeCreate", schema.name, hookCtx);
|
|
11691
11874
|
}
|
|
11692
11875
|
const normalizedData = this.relationPropertiesService.normalizeRelationValuesForStorage(
|
|
11693
11876
|
schema,
|
|
11694
11877
|
dataWithDefaults
|
|
11695
11878
|
);
|
|
11696
|
-
if (_optionalChain([options, 'optionalAccess',
|
|
11697
|
-
if (_optionalChain([options, 'optionalAccess',
|
|
11879
|
+
if (_optionalChain([options, 'optionalAccess', _244 => _244.validate]) !== false) {
|
|
11880
|
+
if (_optionalChain([options, 'optionalAccess', _245 => _245.allowDraft])) {
|
|
11698
11881
|
_chunkU4AB53AMjs.validateDraftOrThrow.call(void 0, schema, normalizedData);
|
|
11699
11882
|
} else {
|
|
11700
11883
|
_chunkU4AB53AMjs.validateObjectOrThrow.call(void 0, schema, normalizedData);
|
|
11701
11884
|
}
|
|
11702
|
-
if (!_optionalChain([options, 'optionalAccess',
|
|
11885
|
+
if (!_optionalChain([options, 'optionalAccess', _246 => _246.skipRelationValidation])) {
|
|
11703
11886
|
await this.relationService.validateRelationsOrThrow(schema, normalizedData);
|
|
11704
11887
|
}
|
|
11705
|
-
if (!_optionalChain([options, 'optionalAccess',
|
|
11888
|
+
if (!_optionalChain([options, 'optionalAccess', _247 => _247.skipUserValidation])) {
|
|
11706
11889
|
await this.userService.validateUsersOrThrow(schema, normalizedData);
|
|
11707
11890
|
}
|
|
11708
11891
|
}
|
|
@@ -11713,22 +11896,39 @@ var RecordService = class extends BaseService {
|
|
|
11713
11896
|
data: normalizedData,
|
|
11714
11897
|
label,
|
|
11715
11898
|
completionStatus,
|
|
11716
|
-
metadata: _optionalChain([options, 'optionalAccess',
|
|
11899
|
+
metadata: _optionalChain([options, 'optionalAccess', _248 => _248.metadata]),
|
|
11717
11900
|
createdBy: this.userId
|
|
11718
11901
|
});
|
|
11719
11902
|
for (const [attrName, value] of Object.entries(dataWithDefaults)) {
|
|
11720
11903
|
const attr = schema.attributes.find((a) => a.name === attrName);
|
|
11721
|
-
if (_optionalChain([attr, 'optionalAccess',
|
|
11722
|
-
|
|
11904
|
+
if (_optionalChain([attr, 'optionalAccess', _249 => _249.type]) === "relation") {
|
|
11905
|
+
const hasProperties2 = attr.properties !== void 0;
|
|
11906
|
+
const isBilateral = isBilateralRelation(attr);
|
|
11907
|
+
if (hasProperties2 || isBilateral) {
|
|
11908
|
+
await this.relationPropertiesService.syncRelationProperties(
|
|
11909
|
+
schema,
|
|
11910
|
+
record.id,
|
|
11911
|
+
attrName,
|
|
11912
|
+
value,
|
|
11913
|
+
this.adapter
|
|
11914
|
+
);
|
|
11915
|
+
}
|
|
11916
|
+
}
|
|
11917
|
+
}
|
|
11918
|
+
for (const [attrName, value] of Object.entries(normalizedData)) {
|
|
11919
|
+
const attr = schema.attributes.find((a) => a.name === attrName);
|
|
11920
|
+
if (_optionalChain([attr, 'optionalAccess', _250 => _250.type]) === "relation" && isBilateralRelation(attr)) {
|
|
11921
|
+
await this.bilateralSyncService.syncBilateralRelation(
|
|
11723
11922
|
schema,
|
|
11724
11923
|
record.id,
|
|
11725
11924
|
attrName,
|
|
11726
11925
|
value,
|
|
11727
|
-
|
|
11926
|
+
null
|
|
11927
|
+
// oldValue is null for create
|
|
11728
11928
|
);
|
|
11729
11929
|
}
|
|
11730
11930
|
}
|
|
11731
|
-
if (!_optionalChain([options, 'optionalAccess',
|
|
11931
|
+
if (!_optionalChain([options, 'optionalAccess', _251 => _251.skipHooks])) {
|
|
11732
11932
|
const afterCtx = {
|
|
11733
11933
|
...hookCtx,
|
|
11734
11934
|
recordId: record.id,
|
|
@@ -11746,12 +11946,8 @@ var RecordService = class extends BaseService {
|
|
|
11746
11946
|
objectId: schema.id,
|
|
11747
11947
|
recordId: record.id,
|
|
11748
11948
|
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
|
-
);
|
|
11949
|
+
metadata: _optionalChain([options, 'optionalAccess', _252 => _252.hookMetadata])
|
|
11950
|
+
}).catch(() => {
|
|
11755
11951
|
});
|
|
11756
11952
|
}
|
|
11757
11953
|
return record;
|
|
@@ -11772,7 +11968,7 @@ var RecordService = class extends BaseService {
|
|
|
11772
11968
|
return null;
|
|
11773
11969
|
}
|
|
11774
11970
|
const schema = await this.schemaService.getObjectSchema(record.objectId);
|
|
11775
|
-
if (!_optionalChain([options, 'optionalAccess',
|
|
11971
|
+
if (!_optionalChain([options, 'optionalAccess', _253 => _253.skipPolicyCheck])) {
|
|
11776
11972
|
const policy = getPolicy(this.policyRegistry, this.userId, schema.name);
|
|
11777
11973
|
if (policy) {
|
|
11778
11974
|
const ctx = buildPolicyContext(schema.name, this.userId, this.tenantId);
|
|
@@ -11782,10 +11978,11 @@ var RecordService = class extends BaseService {
|
|
|
11782
11978
|
}
|
|
11783
11979
|
}
|
|
11784
11980
|
let enrichedRecord = record;
|
|
11785
|
-
if (!_optionalChain([options, 'optionalAccess',
|
|
11981
|
+
if (!_optionalChain([options, 'optionalAccess', _254 => _254.skipFormulas])) {
|
|
11786
11982
|
enrichedRecord = enrichWithFormulas(record, schema);
|
|
11787
11983
|
}
|
|
11788
|
-
|
|
11984
|
+
enrichedRecord = await this.enrichRelationProperties(enrichedRecord, schema);
|
|
11985
|
+
if (_optionalChain([options, 'optionalAccess', _255 => _255.includeSchema])) {
|
|
11789
11986
|
const recordWithSchema = enrichedRecord;
|
|
11790
11987
|
recordWithSchema.schema = schema;
|
|
11791
11988
|
return recordWithSchema;
|
|
@@ -11835,7 +12032,7 @@ var RecordService = class extends BaseService {
|
|
|
11835
12032
|
if (oldVal !== null && newVal !== null && typeof oldVal === "object" && typeof newVal === "object") {
|
|
11836
12033
|
try {
|
|
11837
12034
|
return JSON.stringify(oldVal) !== JSON.stringify(newVal);
|
|
11838
|
-
} catch (
|
|
12035
|
+
} catch (e16) {
|
|
11839
12036
|
return true;
|
|
11840
12037
|
}
|
|
11841
12038
|
}
|
|
@@ -11847,9 +12044,9 @@ var RecordService = class extends BaseService {
|
|
|
11847
12044
|
existing,
|
|
11848
12045
|
mergedData,
|
|
11849
12046
|
changedAttributes,
|
|
11850
|
-
_optionalChain([options, 'optionalAccess',
|
|
12047
|
+
_optionalChain([options, 'optionalAccess', _256 => _256.hookMetadata])
|
|
11851
12048
|
);
|
|
11852
|
-
if (!_optionalChain([options, 'optionalAccess',
|
|
12049
|
+
if (!_optionalChain([options, 'optionalAccess', _257 => _257.skipHooks])) {
|
|
11853
12050
|
await this.hookRegistry.execute("beforeUpdate", schema.name, hookCtx);
|
|
11854
12051
|
}
|
|
11855
12052
|
const hookModifiedValues = {};
|
|
@@ -11864,16 +12061,16 @@ var RecordService = class extends BaseService {
|
|
|
11864
12061
|
dataToUpdate
|
|
11865
12062
|
);
|
|
11866
12063
|
const normalizedMergedData = { ...existing.values, ...normalizedUpdate };
|
|
11867
|
-
if (_optionalChain([options, 'optionalAccess',
|
|
11868
|
-
if (_optionalChain([options, 'optionalAccess',
|
|
12064
|
+
if (_optionalChain([options, 'optionalAccess', _258 => _258.validate]) !== false) {
|
|
12065
|
+
if (_optionalChain([options, 'optionalAccess', _259 => _259.partial])) {
|
|
11869
12066
|
_chunkU4AB53AMjs.validateDraftOrThrow.call(void 0, schema, normalizedMergedData);
|
|
11870
12067
|
} else {
|
|
11871
12068
|
_chunkU4AB53AMjs.validateObjectOrThrow.call(void 0, schema, normalizedMergedData);
|
|
11872
12069
|
}
|
|
11873
|
-
if (!_optionalChain([options, 'optionalAccess',
|
|
12070
|
+
if (!_optionalChain([options, 'optionalAccess', _260 => _260.skipRelationValidation])) {
|
|
11874
12071
|
await this.relationService.validateRelationsOrThrow(schema, normalizedUpdate);
|
|
11875
12072
|
}
|
|
11876
|
-
if (!_optionalChain([options, 'optionalAccess',
|
|
12073
|
+
if (!_optionalChain([options, 'optionalAccess', _261 => _261.skipUserValidation])) {
|
|
11877
12074
|
await this.userService.validateUsersOrThrow(schema, normalizedUpdate);
|
|
11878
12075
|
}
|
|
11879
12076
|
}
|
|
@@ -11886,7 +12083,7 @@ var RecordService = class extends BaseService {
|
|
|
11886
12083
|
__lastUpdatedBy: this.userId,
|
|
11887
12084
|
__expectedUpdatedAt: existing.updatedAt instanceof Date ? existing.updatedAt.toISOString() : existing.updatedAt
|
|
11888
12085
|
};
|
|
11889
|
-
if (_optionalChain([options, 'optionalAccess',
|
|
12086
|
+
if (_optionalChain([options, 'optionalAccess', _262 => _262.metadata]) !== void 0) {
|
|
11890
12087
|
const existingMetadata = _nullishCoalesce(existing.metadata, () => ( {}));
|
|
11891
12088
|
const mergedMetadata = { ...existingMetadata, ...options.metadata };
|
|
11892
12089
|
const cleanedMetadata = Object.fromEntries(
|
|
@@ -11894,21 +12091,45 @@ var RecordService = class extends BaseService {
|
|
|
11894
12091
|
);
|
|
11895
12092
|
updatePayload.__metadata = cleanedMetadata;
|
|
11896
12093
|
}
|
|
12094
|
+
const bilateralOldValues = {};
|
|
12095
|
+
for (const attrName of Object.keys(normalizedUpdate)) {
|
|
12096
|
+
const attr = schema.attributes.find((a) => a.name === attrName);
|
|
12097
|
+
if (_optionalChain([attr, 'optionalAccess', _263 => _263.type]) === "relation" && isBilateralRelation(attr)) {
|
|
12098
|
+
bilateralOldValues[attrName] = existing.values[attrName];
|
|
12099
|
+
}
|
|
12100
|
+
}
|
|
11897
12101
|
const updated = await this.adapter.objectRecords.update(recordId, updatePayload);
|
|
11898
12102
|
await this.invalidateRecordCaches(recordId, existing.objectId);
|
|
11899
12103
|
for (const [attrName, value] of Object.entries(dataToUpdate)) {
|
|
11900
12104
|
const attr = schema.attributes.find((a) => a.name === attrName);
|
|
11901
|
-
if (_optionalChain([attr, 'optionalAccess',
|
|
11902
|
-
|
|
12105
|
+
if (_optionalChain([attr, 'optionalAccess', _264 => _264.type]) === "relation") {
|
|
12106
|
+
const hasProperties2 = attr.properties !== void 0;
|
|
12107
|
+
const isBilateral = isBilateralRelation(attr);
|
|
12108
|
+
if (hasProperties2 || isBilateral) {
|
|
12109
|
+
await this.relationPropertiesService.syncRelationProperties(
|
|
12110
|
+
schema,
|
|
12111
|
+
recordId,
|
|
12112
|
+
attrName,
|
|
12113
|
+
value,
|
|
12114
|
+
this.adapter
|
|
12115
|
+
);
|
|
12116
|
+
}
|
|
12117
|
+
}
|
|
12118
|
+
}
|
|
12119
|
+
for (const [attrName, value] of Object.entries(normalizedUpdate)) {
|
|
12120
|
+
const attr = schema.attributes.find((a) => a.name === attrName);
|
|
12121
|
+
if (_optionalChain([attr, 'optionalAccess', _265 => _265.type]) === "relation" && isBilateralRelation(attr)) {
|
|
12122
|
+
const oldValue = bilateralOldValues[attrName];
|
|
12123
|
+
await this.bilateralSyncService.syncBilateralRelation(
|
|
11903
12124
|
schema,
|
|
11904
12125
|
recordId,
|
|
11905
12126
|
attrName,
|
|
11906
12127
|
value,
|
|
11907
|
-
|
|
12128
|
+
oldValue
|
|
11908
12129
|
);
|
|
11909
12130
|
}
|
|
11910
12131
|
}
|
|
11911
|
-
if (!_optionalChain([options, 'optionalAccess',
|
|
12132
|
+
if (!_optionalChain([options, 'optionalAccess', _266 => _266.skipHooks])) {
|
|
11912
12133
|
const afterCtx = {
|
|
11913
12134
|
...hookCtx,
|
|
11914
12135
|
record: updated
|
|
@@ -11923,7 +12144,7 @@ var RecordService = class extends BaseService {
|
|
|
11923
12144
|
if (this.auditService && this.userId && allChangedAttributes.length > 0) {
|
|
11924
12145
|
const changes = allChangedAttributes.map((attr) => ({
|
|
11925
12146
|
field: attr,
|
|
11926
|
-
oldValue: _optionalChain([hookCtx, 'access',
|
|
12147
|
+
oldValue: _optionalChain([hookCtx, 'access', _267 => _267.oldValues, 'optionalAccess', _268 => _268[attr]]),
|
|
11927
12148
|
newValue: hookCtx.newValues[attr]
|
|
11928
12149
|
}));
|
|
11929
12150
|
this.auditService.logRecordAction({
|
|
@@ -11934,12 +12155,8 @@ var RecordService = class extends BaseService {
|
|
|
11934
12155
|
recordId: updated.id,
|
|
11935
12156
|
recordLabel: updated.label,
|
|
11936
12157
|
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
|
-
);
|
|
12158
|
+
metadata: _optionalChain([options, 'optionalAccess', _269 => _269.hookMetadata])
|
|
12159
|
+
}).catch(() => {
|
|
11943
12160
|
});
|
|
11944
12161
|
}
|
|
11945
12162
|
return updated;
|
|
@@ -11969,22 +12186,35 @@ var RecordService = class extends BaseService {
|
|
|
11969
12186
|
const ctx = buildPolicyContext(schema.name, this.userId, this.tenantId);
|
|
11970
12187
|
checkRecordDeleteOrThrow(policy, record, ctx);
|
|
11971
12188
|
}
|
|
11972
|
-
if (_optionalChain([options, 'optionalAccess',
|
|
12189
|
+
if (_optionalChain([options, 'optionalAccess', _270 => _270.checkSystem]) && schema.system) {
|
|
11973
12190
|
throw new ProtectedResourceError("object", schema.name, "delete");
|
|
11974
12191
|
}
|
|
11975
|
-
if (!_optionalChain([options, 'optionalAccess',
|
|
12192
|
+
if (!_optionalChain([options, 'optionalAccess', _271 => _271.skipReferenceCheck])) {
|
|
11976
12193
|
const references = await this.adapter.objectRecords.countRecordsReferencingId(recordId);
|
|
11977
12194
|
if (references.length > 0) {
|
|
11978
12195
|
throw new RecordReferencedError(recordId, references);
|
|
11979
12196
|
}
|
|
11980
12197
|
}
|
|
11981
|
-
const hookCtx = createContextForDelete(schema, this.tenantId, record, _optionalChain([options, 'optionalAccess',
|
|
11982
|
-
if (!_optionalChain([options, 'optionalAccess',
|
|
12198
|
+
const hookCtx = createContextForDelete(schema, this.tenantId, record, _optionalChain([options, 'optionalAccess', _272 => _272.hookMetadata]));
|
|
12199
|
+
if (!_optionalChain([options, 'optionalAccess', _273 => _273.skipHooks])) {
|
|
11983
12200
|
await this.hookRegistry.execute("beforeDelete", schema.name, hookCtx);
|
|
11984
12201
|
}
|
|
12202
|
+
for (const attr of schema.attributes) {
|
|
12203
|
+
if (attr.type === "relation" && isBilateralRelation(attr)) {
|
|
12204
|
+
const currentValue = record.values[attr.name];
|
|
12205
|
+
await this.bilateralSyncService.syncBilateralRelation(
|
|
12206
|
+
schema,
|
|
12207
|
+
recordId,
|
|
12208
|
+
attr.name,
|
|
12209
|
+
null,
|
|
12210
|
+
// newValue is null
|
|
12211
|
+
currentValue
|
|
12212
|
+
);
|
|
12213
|
+
}
|
|
12214
|
+
}
|
|
11985
12215
|
await this.adapter.objectRecords.delete(recordId);
|
|
11986
12216
|
await this.invalidateRecordCaches(recordId, record.objectId);
|
|
11987
|
-
if (!_optionalChain([options, 'optionalAccess',
|
|
12217
|
+
if (!_optionalChain([options, 'optionalAccess', _274 => _274.skipHooks])) {
|
|
11988
12218
|
await this.hookRegistry.execute("afterDelete", schema.name, hookCtx);
|
|
11989
12219
|
}
|
|
11990
12220
|
await recalculateParentRollups(record, schema, this.rollupContext);
|
|
@@ -11996,12 +12226,8 @@ var RecordService = class extends BaseService {
|
|
|
11996
12226
|
objectId: schema.id,
|
|
11997
12227
|
recordId: record.id,
|
|
11998
12228
|
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
|
-
);
|
|
12229
|
+
metadata: _optionalChain([options, 'optionalAccess', _275 => _275.hookMetadata])
|
|
12230
|
+
}).catch(() => {
|
|
12005
12231
|
});
|
|
12006
12232
|
}
|
|
12007
12233
|
}
|
|
@@ -12061,13 +12287,13 @@ var RecordService = class extends BaseService {
|
|
|
12061
12287
|
this.tenantId
|
|
12062
12288
|
);
|
|
12063
12289
|
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',
|
|
12290
|
+
const hookCtx = createContextForRestore(schema, this.tenantId, record, _optionalChain([options, 'optionalAccess', _276 => _276.hookMetadata]));
|
|
12291
|
+
if (!_optionalChain([options, 'optionalAccess', _277 => _277.skipHooks])) {
|
|
12066
12292
|
await this.hookRegistry.execute("beforeRestore", schema.name, hookCtx);
|
|
12067
12293
|
}
|
|
12068
12294
|
const restored = await this.adapter.objectRecords.restore(recordId);
|
|
12069
12295
|
await this.invalidateRecordCaches(recordId, record.objectId);
|
|
12070
|
-
if (!_optionalChain([options, 'optionalAccess',
|
|
12296
|
+
if (!_optionalChain([options, 'optionalAccess', _278 => _278.skipHooks])) {
|
|
12071
12297
|
const afterCtx = {
|
|
12072
12298
|
...hookCtx,
|
|
12073
12299
|
record: restored
|
|
@@ -12082,12 +12308,8 @@ var RecordService = class extends BaseService {
|
|
|
12082
12308
|
objectId: schema.id,
|
|
12083
12309
|
recordId: restored.id,
|
|
12084
12310
|
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
|
-
);
|
|
12311
|
+
metadata: _optionalChain([options, 'optionalAccess', _279 => _279.hookMetadata])
|
|
12312
|
+
}).catch(() => {
|
|
12091
12313
|
});
|
|
12092
12314
|
}
|
|
12093
12315
|
return restored;
|
|
@@ -12095,6 +12317,60 @@ var RecordService = class extends BaseService {
|
|
|
12095
12317
|
// ============================================================================
|
|
12096
12318
|
// PRIVATE HELPERS
|
|
12097
12319
|
// ============================================================================
|
|
12320
|
+
/**
|
|
12321
|
+
* Enrich relation attributes with their properties (for qualified relations).
|
|
12322
|
+
*
|
|
12323
|
+
* Transforms simple ID arrays into hybrid format { id, props } when properties exist.
|
|
12324
|
+
*
|
|
12325
|
+
* @param record - Record to enrich
|
|
12326
|
+
* @param schema - Object schema
|
|
12327
|
+
* @returns Enriched record with relation properties loaded
|
|
12328
|
+
* @private
|
|
12329
|
+
*/
|
|
12330
|
+
async enrichRelationProperties(record, schema) {
|
|
12331
|
+
const enrichedValues = { ...record.values };
|
|
12332
|
+
for (const attr of schema.attributes) {
|
|
12333
|
+
if (attr.type !== "relation") {
|
|
12334
|
+
continue;
|
|
12335
|
+
}
|
|
12336
|
+
const hasProperties2 = attr.properties && attr.properties.definitions.length > 0;
|
|
12337
|
+
const isBilateral = isBilateralRelation(attr);
|
|
12338
|
+
const shouldEnrich = hasProperties2 || isBilateral;
|
|
12339
|
+
if (!shouldEnrich) {
|
|
12340
|
+
continue;
|
|
12341
|
+
}
|
|
12342
|
+
const value = record.values[attr.name];
|
|
12343
|
+
if (value === null || value === void 0) {
|
|
12344
|
+
continue;
|
|
12345
|
+
}
|
|
12346
|
+
const isMany = attr.cardinality === "many";
|
|
12347
|
+
const targetIds = isMany ? value : [value];
|
|
12348
|
+
if (!targetIds || targetIds.length === 0) {
|
|
12349
|
+
continue;
|
|
12350
|
+
}
|
|
12351
|
+
const propsMap = await this.relationPropertiesService.getRelationProperties(
|
|
12352
|
+
schema.name,
|
|
12353
|
+
record.id,
|
|
12354
|
+
attr.name,
|
|
12355
|
+
targetIds
|
|
12356
|
+
);
|
|
12357
|
+
if (isMany) {
|
|
12358
|
+
const hybridArray = targetIds.map((id) => {
|
|
12359
|
+
const props = propsMap.get(id);
|
|
12360
|
+
return props ? { id, props } : id;
|
|
12361
|
+
});
|
|
12362
|
+
enrichedValues[attr.name] = hybridArray;
|
|
12363
|
+
} else {
|
|
12364
|
+
const id = targetIds[0];
|
|
12365
|
+
const props = propsMap.get(id);
|
|
12366
|
+
enrichedValues[attr.name] = props ? { id, props } : id;
|
|
12367
|
+
}
|
|
12368
|
+
}
|
|
12369
|
+
return {
|
|
12370
|
+
...record,
|
|
12371
|
+
values: enrichedValues
|
|
12372
|
+
};
|
|
12373
|
+
}
|
|
12098
12374
|
/**
|
|
12099
12375
|
* Invalidate all caches related to a record (record cache + lists + global search)
|
|
12100
12376
|
* @private
|
|
@@ -12463,7 +12739,7 @@ var DocumentRendererService = class {
|
|
|
12463
12739
|
throw new StorageDownloadNotSupportedError();
|
|
12464
12740
|
}
|
|
12465
12741
|
let storagePath = fileId;
|
|
12466
|
-
if (_optionalChain([this, 'access',
|
|
12742
|
+
if (_optionalChain([this, 'access', _280 => _280.options, 'optionalAccess', _281 => _281.filesRepository])) {
|
|
12467
12743
|
const file2 = await this.options.filesRepository.findById(fileId);
|
|
12468
12744
|
if (!file2) {
|
|
12469
12745
|
throw new Error(`Template file not found: ${fileId}`);
|
|
@@ -12481,8 +12757,8 @@ var DocumentRendererService = class {
|
|
|
12481
12757
|
for (const field of fields) {
|
|
12482
12758
|
const rawValue = getContextValue(context, field.contextPath);
|
|
12483
12759
|
const attrInfo = await this.getAttributeInfo(field.contextPath, workflow2);
|
|
12484
|
-
if (_optionalChain([attrInfo, 'optionalAccess',
|
|
12485
|
-
if (attrInfo.attribute.type === "relation" && rawValue && _optionalChain([this, 'access',
|
|
12760
|
+
if (_optionalChain([attrInfo, 'optionalAccess', _282 => _282.attribute])) {
|
|
12761
|
+
if (attrInfo.attribute.type === "relation" && rawValue && _optionalChain([this, 'access', _283 => _283.options, 'optionalAccess', _284 => _284.relationService])) {
|
|
12486
12762
|
const ids = Array.isArray(rawValue) ? rawValue : [rawValue];
|
|
12487
12763
|
const stringIds = ids.filter((id) => typeof id === "string");
|
|
12488
12764
|
if (stringIds.length > 0) {
|
|
@@ -12503,7 +12779,7 @@ var DocumentRendererService = class {
|
|
|
12503
12779
|
resolved.set(field.id, this.formatValueSimple(rawValue, field.fallback));
|
|
12504
12780
|
}
|
|
12505
12781
|
}
|
|
12506
|
-
if (relationBatch.length > 0 && _optionalChain([this, 'access',
|
|
12782
|
+
if (relationBatch.length > 0 && _optionalChain([this, 'access', _285 => _285.options, 'optionalAccess', _286 => _286.relationService])) {
|
|
12507
12783
|
try {
|
|
12508
12784
|
const batchResult = await this.options.relationService.resolveIdsBatch(
|
|
12509
12785
|
relationBatch.map((r) => ({ attributeId: r.attributeId, ids: r.ids }))
|
|
@@ -12512,12 +12788,12 @@ var DocumentRendererService = class {
|
|
|
12512
12788
|
const options = _nullishCoalesce(batchResult[attributeId], () => ( []));
|
|
12513
12789
|
const labels = options.map((o) => o.label);
|
|
12514
12790
|
const field = fields.find((f) => f.id === fieldId);
|
|
12515
|
-
resolved.set(fieldId, labels.join(", ") || _optionalChain([field, 'optionalAccess',
|
|
12791
|
+
resolved.set(fieldId, labels.join(", ") || _optionalChain([field, 'optionalAccess', _287 => _287.fallback]) || "");
|
|
12516
12792
|
}
|
|
12517
|
-
} catch (
|
|
12793
|
+
} catch (e17) {
|
|
12518
12794
|
for (const { fieldId, ids } of relationBatch) {
|
|
12519
12795
|
const field = fields.find((f) => f.id === fieldId);
|
|
12520
|
-
resolved.set(fieldId, ids.join(", ") || _optionalChain([field, 'optionalAccess',
|
|
12796
|
+
resolved.set(fieldId, ids.join(", ") || _optionalChain([field, 'optionalAccess', _288 => _288.fallback]) || "");
|
|
12521
12797
|
}
|
|
12522
12798
|
}
|
|
12523
12799
|
}
|
|
@@ -12528,7 +12804,7 @@ var DocumentRendererService = class {
|
|
|
12528
12804
|
* Parses paths like "slots.client.firstName" to find the attribute definition
|
|
12529
12805
|
*/
|
|
12530
12806
|
async getAttributeInfo(contextPath, workflow2) {
|
|
12531
|
-
const schemaService = _optionalChain([this, 'access',
|
|
12807
|
+
const schemaService = _optionalChain([this, 'access', _289 => _289.options, 'optionalAccess', _290 => _290.schemaService]);
|
|
12532
12808
|
if (!schemaService) {
|
|
12533
12809
|
return null;
|
|
12534
12810
|
}
|
|
@@ -12541,7 +12817,7 @@ var DocumentRendererService = class {
|
|
|
12541
12817
|
}
|
|
12542
12818
|
const slotId = parts[1];
|
|
12543
12819
|
const attributeName = parts[2];
|
|
12544
|
-
const slot = _optionalChain([workflow2, 'access',
|
|
12820
|
+
const slot = _optionalChain([workflow2, 'access', _291 => _291.slots, 'optionalAccess', _292 => _292.find, 'call', _293 => _293((s) => s.id === slotId)]);
|
|
12545
12821
|
if (!slot) {
|
|
12546
12822
|
return null;
|
|
12547
12823
|
}
|
|
@@ -12550,7 +12826,7 @@ var DocumentRendererService = class {
|
|
|
12550
12826
|
try {
|
|
12551
12827
|
schema = await schemaService.getObjectSchemaByName(slot.objectName);
|
|
12552
12828
|
this.schemaCache.set(slot.objectName, schema);
|
|
12553
|
-
} catch (
|
|
12829
|
+
} catch (e18) {
|
|
12554
12830
|
return null;
|
|
12555
12831
|
}
|
|
12556
12832
|
}
|
|
@@ -12740,7 +13016,7 @@ var DocumentProcessingHook = class extends BaseService {
|
|
|
12740
13016
|
const pendingIds = [];
|
|
12741
13017
|
for (const [nodeId, doc] of Object.entries(context.documents)) {
|
|
12742
13018
|
const metadata = doc.metadata;
|
|
12743
|
-
if (_optionalChain([metadata, 'optionalAccess',
|
|
13019
|
+
if (_optionalChain([metadata, 'optionalAccess', _294 => _294.status]) === "pending") {
|
|
12744
13020
|
pendingIds.push(nodeId);
|
|
12745
13021
|
}
|
|
12746
13022
|
}
|
|
@@ -12791,12 +13067,12 @@ var DocumentProcessingHook = class extends BaseService {
|
|
|
12791
13067
|
}
|
|
12792
13068
|
for (const slotId of targetSlotIds) {
|
|
12793
13069
|
try {
|
|
12794
|
-
const recordId = _optionalChain([context, 'access',
|
|
13070
|
+
const recordId = _optionalChain([context, 'access', _295 => _295.createdRecordIds, 'optionalAccess', _296 => _296[slotId]]);
|
|
12795
13071
|
if (!recordId) {
|
|
12796
13072
|
continue;
|
|
12797
13073
|
}
|
|
12798
|
-
const slotDef = _optionalChain([workflow2, 'access',
|
|
12799
|
-
const objectName = _optionalChain([slotDef, 'optionalAccess',
|
|
13074
|
+
const slotDef = _optionalChain([workflow2, 'access', _297 => _297.slots, 'optionalAccess', _298 => _298.find, 'call', _299 => _299((s) => s.id === slotId)]);
|
|
13075
|
+
const objectName = _optionalChain([slotDef, 'optionalAccess', _300 => _300.objectName]);
|
|
12800
13076
|
if (!objectName) {
|
|
12801
13077
|
continue;
|
|
12802
13078
|
}
|
|
@@ -12813,14 +13089,14 @@ var DocumentProcessingHook = class extends BaseService {
|
|
|
12813
13089
|
attachedDocumentIds.push(result.document.id);
|
|
12814
13090
|
const record = await recordService.getRecord(recordId);
|
|
12815
13091
|
if (record) {
|
|
12816
|
-
const attachments = _nullishCoalesce(_optionalChain([record, 'access',
|
|
13092
|
+
const attachments = _nullishCoalesce(_optionalChain([record, 'access', _301 => _301.values, 'optionalAccess', _302 => _302.attachments]), () => ( []));
|
|
12817
13093
|
await recordService.updateRecord(
|
|
12818
13094
|
recordId,
|
|
12819
13095
|
{ attachments: [...attachments, result.document.id] },
|
|
12820
13096
|
{ partial: true }
|
|
12821
13097
|
);
|
|
12822
13098
|
}
|
|
12823
|
-
} catch (
|
|
13099
|
+
} catch (e19) {
|
|
12824
13100
|
}
|
|
12825
13101
|
}
|
|
12826
13102
|
return attachedDocumentIds;
|
|
@@ -13079,7 +13355,7 @@ var WorkflowAccessGrantService = class extends BaseService {
|
|
|
13079
13355
|
* Check if a specific token has been revoked.
|
|
13080
13356
|
*/
|
|
13081
13357
|
isTokenRevoked(dbGrant, jti) {
|
|
13082
|
-
return _nullishCoalesce(_optionalChain([dbGrant, 'access',
|
|
13358
|
+
return _nullishCoalesce(_optionalChain([dbGrant, 'access', _303 => _303.revoked_token_jtis, 'optionalAccess', _304 => _304.includes, 'call', _305 => _305(jti)]), () => ( false));
|
|
13083
13359
|
}
|
|
13084
13360
|
/**
|
|
13085
13361
|
* Validate access token payload against the grant.
|
|
@@ -13131,10 +13407,10 @@ var WorkflowInstanceService = class extends BaseService {
|
|
|
13131
13407
|
constructor(adapter, workflowService, options) {
|
|
13132
13408
|
super(adapter);
|
|
13133
13409
|
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',
|
|
13410
|
+
this.executorRegistry = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _306 => _306.executorRegistry]), () => ( getDefaultExecutorRegistry()));
|
|
13411
|
+
this.schemaService = _optionalChain([options, 'optionalAccess', _307 => _307.schemaService]);
|
|
13412
|
+
this.recordService = _optionalChain([options, 'optionalAccess', _308 => _308.recordService]);
|
|
13413
|
+
this.documentProcessingHook = _optionalChain([options, 'optionalAccess', _309 => _309.documentProcessingHook]);
|
|
13138
13414
|
}
|
|
13139
13415
|
/**
|
|
13140
13416
|
* Start a new workflow instance
|
|
@@ -13316,7 +13592,7 @@ var WorkflowInstanceService = class extends BaseService {
|
|
|
13316
13592
|
if (!this.adapter.workflowInstances) {
|
|
13317
13593
|
return { instances: [], total: 0 };
|
|
13318
13594
|
}
|
|
13319
|
-
if (_optionalChain([options, 'optionalAccess',
|
|
13595
|
+
if (_optionalChain([options, 'optionalAccess', _310 => _310.workflowName])) {
|
|
13320
13596
|
const allDbInstances = await this.adapter.workflowInstances.findByWorkflowName(
|
|
13321
13597
|
options.workflowName,
|
|
13322
13598
|
{ status: options.status }
|
|
@@ -13330,11 +13606,11 @@ var WorkflowInstanceService = class extends BaseService {
|
|
|
13330
13606
|
return { instances: instances2, total: total2 };
|
|
13331
13607
|
}
|
|
13332
13608
|
const { instances: dbInstances, total } = await this.adapter.workflowInstances.list({
|
|
13333
|
-
limit: _optionalChain([options, 'optionalAccess',
|
|
13334
|
-
offset: _optionalChain([options, 'optionalAccess',
|
|
13609
|
+
limit: _optionalChain([options, 'optionalAccess', _311 => _311.limit]),
|
|
13610
|
+
offset: _optionalChain([options, 'optionalAccess', _312 => _312.offset])
|
|
13335
13611
|
});
|
|
13336
13612
|
let instances = dbInstances.map((db) => this.convertDBInstanceToInstance(db));
|
|
13337
|
-
if (_optionalChain([options, 'optionalAccess',
|
|
13613
|
+
if (_optionalChain([options, 'optionalAccess', _313 => _313.status])) {
|
|
13338
13614
|
instances = instances.filter((i) => i.status === options.status);
|
|
13339
13615
|
}
|
|
13340
13616
|
instances = await this.markExpiredInstances(instances);
|
|
@@ -13355,9 +13631,9 @@ var WorkflowInstanceService = class extends BaseService {
|
|
|
13355
13631
|
return { instances: [], total: 0 };
|
|
13356
13632
|
}
|
|
13357
13633
|
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',
|
|
13634
|
+
status: _optionalChain([options, 'optionalAccess', _314 => _314.status]),
|
|
13635
|
+
limit: _optionalChain([options, 'optionalAccess', _315 => _315.limit]),
|
|
13636
|
+
offset: _optionalChain([options, 'optionalAccess', _316 => _316.offset])
|
|
13361
13637
|
});
|
|
13362
13638
|
const instances = dbInstances.map((db) => this.convertDBInstanceToInstance(db));
|
|
13363
13639
|
return { instances, total };
|
|
@@ -13423,13 +13699,13 @@ var WorkflowInstanceService = class extends BaseService {
|
|
|
13423
13699
|
try {
|
|
13424
13700
|
const schemas = await Promise.all(
|
|
13425
13701
|
current.workflowSnapshot.slots.map(
|
|
13426
|
-
(slot) => _optionalChain([this, 'access',
|
|
13702
|
+
(slot) => _optionalChain([this, 'access', _317 => _317.schemaService, 'optionalAccess', _318 => _318.getObjectSchemaByName, 'call', _319 => _319(slot.objectName)])
|
|
13427
13703
|
)
|
|
13428
13704
|
);
|
|
13429
13705
|
objectDefinitions = schemas.filter(
|
|
13430
13706
|
(s) => s !== void 0
|
|
13431
13707
|
);
|
|
13432
|
-
} catch (
|
|
13708
|
+
} catch (e20) {
|
|
13433
13709
|
}
|
|
13434
13710
|
}
|
|
13435
13711
|
const executorContext = {
|
|
@@ -13688,9 +13964,9 @@ var WorkflowInstanceService = class extends BaseService {
|
|
|
13688
13964
|
*/
|
|
13689
13965
|
async snapshotRecord(recordId) {
|
|
13690
13966
|
try {
|
|
13691
|
-
const record = await _optionalChain([this, 'access',
|
|
13692
|
-
return _optionalChain([record, 'optionalAccess',
|
|
13693
|
-
} catch (
|
|
13967
|
+
const record = await _optionalChain([this, 'access', _320 => _320.recordService, 'optionalAccess', _321 => _321.getRecord, 'call', _322 => _322(recordId, { skipPolicyCheck: true })]);
|
|
13968
|
+
return _optionalChain([record, 'optionalAccess', _323 => _323.values]);
|
|
13969
|
+
} catch (e21) {
|
|
13694
13970
|
return void 0;
|
|
13695
13971
|
}
|
|
13696
13972
|
}
|
|
@@ -13708,18 +13984,18 @@ var WorkflowInstanceService = class extends BaseService {
|
|
|
13708
13984
|
for (const op of [...operations].reverse()) {
|
|
13709
13985
|
try {
|
|
13710
13986
|
if (op.operation === "create") {
|
|
13711
|
-
await _optionalChain([this, 'access',
|
|
13987
|
+
await _optionalChain([this, 'access', _324 => _324.recordService, 'optionalAccess', _325 => _325.deleteRecord, 'call', _326 => _326(op.recordId, {
|
|
13712
13988
|
skipHooks: true,
|
|
13713
13989
|
skipReferenceCheck: true
|
|
13714
13990
|
})]);
|
|
13715
13991
|
rolledBack.push(op.slotId);
|
|
13716
13992
|
} else if (op.operation === "update" && op.previousData) {
|
|
13717
|
-
await _optionalChain([this, 'access',
|
|
13993
|
+
await _optionalChain([this, 'access', _327 => _327.recordService, 'optionalAccess', _328 => _328.updateRecord, 'call', _329 => _329(op.recordId, op.previousData, {
|
|
13718
13994
|
partial: false
|
|
13719
13995
|
})]);
|
|
13720
13996
|
rolledBack.push(op.slotId);
|
|
13721
13997
|
}
|
|
13722
|
-
} catch (
|
|
13998
|
+
} catch (e22) {
|
|
13723
13999
|
}
|
|
13724
14000
|
}
|
|
13725
14001
|
return rolledBack;
|
|
@@ -13838,7 +14114,7 @@ var WorkflowInstanceService = class extends BaseService {
|
|
|
13838
14114
|
if (!this.adapter.workflowInstances) {
|
|
13839
14115
|
return;
|
|
13840
14116
|
}
|
|
13841
|
-
const currentVersion = _nullishCoalesce(_optionalChain([instance, 'access',
|
|
14117
|
+
const currentVersion = _nullishCoalesce(_optionalChain([instance, 'access', _330 => _330.context, 'access', _331 => _331.variables, 'optionalAccess', _332 => _332.__version]), () => ( 0));
|
|
13842
14118
|
const nextVersion = currentVersion + 1;
|
|
13843
14119
|
const instanceWithVersion = {
|
|
13844
14120
|
...instance,
|
|
@@ -14119,7 +14395,7 @@ var WorkflowRelationService = class extends BaseService {
|
|
|
14119
14395
|
if (attr.type !== "relation") continue;
|
|
14120
14396
|
for (const slot of slots) {
|
|
14121
14397
|
const slotData = context.slots[slot.id];
|
|
14122
|
-
const slotRecordId = _optionalChain([slotData, 'optionalAccess',
|
|
14398
|
+
const slotRecordId = _optionalChain([slotData, 'optionalAccess', _333 => _333.id]);
|
|
14123
14399
|
if (!slotRecordId) continue;
|
|
14124
14400
|
const targetsSlotObject = attr.targets.some(
|
|
14125
14401
|
(t) => t.object === slot.objectName
|
|
@@ -14187,7 +14463,7 @@ var WorkflowService = class extends BaseService {
|
|
|
14187
14463
|
if (Array.isArray(options)) {
|
|
14188
14464
|
this.systemWorkflows = new Map(options.map((w) => [w.name, w]));
|
|
14189
14465
|
} else {
|
|
14190
|
-
this.systemWorkflows = new Map((_nullishCoalesce(_optionalChain([options, 'optionalAccess',
|
|
14466
|
+
this.systemWorkflows = new Map((_nullishCoalesce(_optionalChain([options, 'optionalAccess', _334 => _334.systemWorkflows]), () => ( []))).map((w) => [w.name, w]));
|
|
14191
14467
|
}
|
|
14192
14468
|
}
|
|
14193
14469
|
// ============================================================================
|
|
@@ -14485,7 +14761,7 @@ var WorkflowService = class extends BaseService {
|
|
|
14485
14761
|
var UserProfileService = class extends BaseService {
|
|
14486
14762
|
constructor(adapter, options) {
|
|
14487
14763
|
super(adapter);
|
|
14488
|
-
this.auditService = _optionalChain([options, 'optionalAccess',
|
|
14764
|
+
this.auditService = _optionalChain([options, 'optionalAccess', _335 => _335.auditService]);
|
|
14489
14765
|
}
|
|
14490
14766
|
// ============================================================================
|
|
14491
14767
|
// CACHE MANAGEMENT
|
|
@@ -14648,7 +14924,7 @@ var UserProfileService = class extends BaseService {
|
|
|
14648
14924
|
*/
|
|
14649
14925
|
async deleteProfile(profileId, options) {
|
|
14650
14926
|
const profile = await this.getProfileOrThrow(profileId);
|
|
14651
|
-
if (_optionalChain([options, 'optionalAccess',
|
|
14927
|
+
if (_optionalChain([options, 'optionalAccess', _336 => _336.checkAdmin])) {
|
|
14652
14928
|
if (profile.role === "admin") {
|
|
14653
14929
|
const adminCount = await this.adapter.userProfiles.countByRole("admin");
|
|
14654
14930
|
if (adminCount <= 1) {
|
|
@@ -14723,7 +14999,7 @@ var UserProfileService = class extends BaseService {
|
|
|
14723
14999
|
*/
|
|
14724
15000
|
async hasRole(profileId, role) {
|
|
14725
15001
|
const profile = await this.getProfile(profileId);
|
|
14726
|
-
return _optionalChain([profile, 'optionalAccess',
|
|
15002
|
+
return _optionalChain([profile, 'optionalAccess', _337 => _337.role]) === role;
|
|
14727
15003
|
}
|
|
14728
15004
|
/**
|
|
14729
15005
|
* Check if user is admin
|
|
@@ -15157,7 +15433,7 @@ var DocumentTemplateService = class extends BaseService {
|
|
|
15157
15433
|
* Includes both system templates and tenant-specific templates.
|
|
15158
15434
|
*/
|
|
15159
15435
|
async listTemplates(options) {
|
|
15160
|
-
if (_optionalChain([options, 'optionalAccess',
|
|
15436
|
+
if (_optionalChain([options, 'optionalAccess', _338 => _338.systemOnly])) {
|
|
15161
15437
|
return SYSTEM_TEMPLATES;
|
|
15162
15438
|
}
|
|
15163
15439
|
const templates = [...SYSTEM_TEMPLATES];
|
|
@@ -15240,8 +15516,8 @@ var DocumentTemplateService = class extends BaseService {
|
|
|
15240
15516
|
var DocumentService = class extends BaseService {
|
|
15241
15517
|
constructor(adapter, options) {
|
|
15242
15518
|
super(adapter);
|
|
15243
|
-
this.templateService = _nullishCoalesce(_optionalChain([options, 'optionalAccess',
|
|
15244
|
-
this.fileService = _nullishCoalesce(_optionalChain([options, 'optionalAccess',
|
|
15519
|
+
this.templateService = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _339 => _339.templateService]), () => ( new DocumentTemplateService(adapter)));
|
|
15520
|
+
this.fileService = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _340 => _340.fileService]), () => ( null));
|
|
15245
15521
|
}
|
|
15246
15522
|
// ============================================================================
|
|
15247
15523
|
// CREATE
|
|
@@ -15492,7 +15768,7 @@ var DocumentService = class extends BaseService {
|
|
|
15492
15768
|
*/
|
|
15493
15769
|
async isComplete(documentId) {
|
|
15494
15770
|
const document2 = await this.getDocument(documentId);
|
|
15495
|
-
return _optionalChain([document2, 'optionalAccess',
|
|
15771
|
+
return _optionalChain([document2, 'optionalAccess', _341 => _341.status]) !== "draft";
|
|
15496
15772
|
}
|
|
15497
15773
|
/**
|
|
15498
15774
|
* Get document with its template and slots.
|
|
@@ -15750,7 +16026,7 @@ var DocumentProcessingService = class extends BaseService {
|
|
|
15750
16026
|
type: "signature",
|
|
15751
16027
|
provider: this.config.signatureAdapter.name,
|
|
15752
16028
|
input: { signers, ...options },
|
|
15753
|
-
expiresAt: _optionalChain([options, 'optionalAccess',
|
|
16029
|
+
expiresAt: _optionalChain([options, 'optionalAccess', _342 => _342.expiresAt])
|
|
15754
16030
|
});
|
|
15755
16031
|
return job;
|
|
15756
16032
|
}
|
|
@@ -15907,7 +16183,7 @@ var DocumentProcessingService = class extends BaseService {
|
|
|
15907
16183
|
}
|
|
15908
16184
|
const document2 = await this.documentService.getDocumentOrThrow(documentId);
|
|
15909
16185
|
const template = await this.templateService.getTemplateOrThrow(document2.templateId);
|
|
15910
|
-
if (!_optionalChain([template, 'access',
|
|
16186
|
+
if (!_optionalChain([template, 'access', _343 => _343.autoProcessing, 'optionalAccess', _344 => _344.identityVerification, 'optionalAccess', _345 => _345.enabled])) {
|
|
15911
16187
|
throw new Error("Identity verification is not enabled for this document type");
|
|
15912
16188
|
}
|
|
15913
16189
|
const job = await this.adapter.documentJobs.create({
|
|
@@ -15993,13 +16269,13 @@ var DocumentProcessingService = class extends BaseService {
|
|
|
15993
16269
|
const template = await this.templateService.getTemplateOrThrow(document2.templateId);
|
|
15994
16270
|
const slots = await this.documentService.getSlots(documentId);
|
|
15995
16271
|
const jobs = [];
|
|
15996
|
-
if (_optionalChain([template, 'access',
|
|
16272
|
+
if (_optionalChain([template, 'access', _346 => _346.autoProcessing, 'optionalAccess', _347 => _347.ocr, 'optionalAccess', _348 => _348.enabled]) && this.config.ocrAdapter) {
|
|
15997
16273
|
for (const slot of slots) {
|
|
15998
16274
|
const job = await this.processOcr(documentId, slot.slotName);
|
|
15999
16275
|
jobs.push(job);
|
|
16000
16276
|
}
|
|
16001
16277
|
}
|
|
16002
|
-
if (_optionalChain([template, 'access',
|
|
16278
|
+
if (_optionalChain([template, 'access', _349 => _349.autoProcessing, 'optionalAccess', _350 => _350.identityVerification, 'optionalAccess', _351 => _351.enabled]) && this.config.identityAdapter) {
|
|
16003
16279
|
const job = await this.verifyIdentity(documentId);
|
|
16004
16280
|
jobs.push(job);
|
|
16005
16281
|
}
|
|
@@ -16070,15 +16346,15 @@ var DocumentProcessingService = class extends BaseService {
|
|
|
16070
16346
|
return {
|
|
16071
16347
|
ocr: {
|
|
16072
16348
|
available: !!this.config.ocrAdapter,
|
|
16073
|
-
provider: _optionalChain([this, 'access',
|
|
16349
|
+
provider: _optionalChain([this, 'access', _352 => _352.config, 'access', _353 => _353.ocrAdapter, 'optionalAccess', _354 => _354.name])
|
|
16074
16350
|
},
|
|
16075
16351
|
signature: {
|
|
16076
16352
|
available: !!this.config.signatureAdapter,
|
|
16077
|
-
provider: _optionalChain([this, 'access',
|
|
16353
|
+
provider: _optionalChain([this, 'access', _355 => _355.config, 'access', _356 => _356.signatureAdapter, 'optionalAccess', _357 => _357.name])
|
|
16078
16354
|
},
|
|
16079
16355
|
identityVerification: {
|
|
16080
16356
|
available: !!this.config.identityAdapter,
|
|
16081
|
-
provider: _optionalChain([this, 'access',
|
|
16357
|
+
provider: _optionalChain([this, 'access', _358 => _358.config, 'access', _359 => _359.identityAdapter, 'optionalAccess', _360 => _360.name])
|
|
16082
16358
|
}
|
|
16083
16359
|
};
|
|
16084
16360
|
}
|
|
@@ -16088,7 +16364,7 @@ var DocumentProcessingService = class extends BaseService {
|
|
|
16088
16364
|
var FileService = class extends BaseService {
|
|
16089
16365
|
constructor(adapter, options) {
|
|
16090
16366
|
super(adapter);
|
|
16091
|
-
this.auditService = _nullishCoalesce(_optionalChain([options, 'optionalAccess',
|
|
16367
|
+
this.auditService = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _361 => _361.auditService]), () => ( (adapter.audit ? new AuditService(adapter) : void 0)));
|
|
16092
16368
|
}
|
|
16093
16369
|
// ============================================================================
|
|
16094
16370
|
// UPLOAD (requires StorageAdapter)
|
|
@@ -16227,7 +16503,7 @@ var FileService = class extends BaseService {
|
|
|
16227
16503
|
*/
|
|
16228
16504
|
async getFile(fileId) {
|
|
16229
16505
|
const file2 = await this.adapter.files.findById(fileId);
|
|
16230
|
-
if (_optionalChain([file2, 'optionalAccess',
|
|
16506
|
+
if (_optionalChain([file2, 'optionalAccess', _362 => _362.deletedAt])) {
|
|
16231
16507
|
return null;
|
|
16232
16508
|
}
|
|
16233
16509
|
return file2;
|
|
@@ -16289,12 +16565,12 @@ var FileService = class extends BaseService {
|
|
|
16289
16565
|
*/
|
|
16290
16566
|
async deleteFile(fileId, options) {
|
|
16291
16567
|
const file2 = await this.getFileOrThrow(fileId);
|
|
16292
|
-
if (_optionalChain([options, 'optionalAccess',
|
|
16568
|
+
if (_optionalChain([options, 'optionalAccess', _363 => _363.checkOwnership]) && options.userId) {
|
|
16293
16569
|
if (file2.uploadedBy !== options.userId) {
|
|
16294
16570
|
throw new Error("You can only delete files you uploaded");
|
|
16295
16571
|
}
|
|
16296
16572
|
}
|
|
16297
|
-
if (_optionalChain([options, 'optionalAccess',
|
|
16573
|
+
if (_optionalChain([options, 'optionalAccess', _364 => _364.hard])) {
|
|
16298
16574
|
await this.adapter.files.hardDelete(fileId);
|
|
16299
16575
|
} else {
|
|
16300
16576
|
await this.adapter.files.delete(fileId);
|
|
@@ -16325,7 +16601,7 @@ var FileService = class extends BaseService {
|
|
|
16325
16601
|
}
|
|
16326
16602
|
const file2 = await this.getFileOrThrow(fileId);
|
|
16327
16603
|
await this.adapter.storage.delete(file2.storagePath);
|
|
16328
|
-
if (_optionalChain([options, 'optionalAccess',
|
|
16604
|
+
if (_optionalChain([options, 'optionalAccess', _365 => _365.hard])) {
|
|
16329
16605
|
await this.adapter.files.hardDelete(fileId);
|
|
16330
16606
|
} else {
|
|
16331
16607
|
await this.adapter.files.delete(fileId);
|
|
@@ -16351,15 +16627,15 @@ var FileService = class extends BaseService {
|
|
|
16351
16627
|
const fileResults = await Promise.all(fileIds.map((id) => this.getFile(id)));
|
|
16352
16628
|
const files = fileResults.filter((f) => f !== null);
|
|
16353
16629
|
if (files.length === 0) return;
|
|
16354
|
-
if (_optionalChain([options, 'optionalAccess',
|
|
16630
|
+
if (_optionalChain([options, 'optionalAccess', _366 => _366.deleteFromStorage]) && this.adapter.storage) {
|
|
16355
16631
|
const BATCH_SIZE = 10;
|
|
16356
16632
|
for (let i = 0; i < files.length; i += BATCH_SIZE) {
|
|
16357
16633
|
const batch = files.slice(i, i + BATCH_SIZE);
|
|
16358
|
-
await Promise.all(batch.map((file2) => _optionalChain([this, 'access',
|
|
16634
|
+
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
16635
|
}
|
|
16360
16636
|
}
|
|
16361
16637
|
const idsToDelete = files.map((f) => f.id);
|
|
16362
|
-
if (_optionalChain([options, 'optionalAccess',
|
|
16638
|
+
if (_optionalChain([options, 'optionalAccess', _371 => _371.hard])) {
|
|
16363
16639
|
await Promise.all(idsToDelete.map((id) => this.adapter.files.hardDelete(id)));
|
|
16364
16640
|
} else {
|
|
16365
16641
|
await Promise.all(idsToDelete.map((id) => this.adapter.files.delete(id)));
|
|
@@ -16367,12 +16643,12 @@ var FileService = class extends BaseService {
|
|
|
16367
16643
|
if (this.auditService && this.userId) {
|
|
16368
16644
|
await Promise.all(
|
|
16369
16645
|
files.map(
|
|
16370
|
-
(file2) => _optionalChain([this, 'access',
|
|
16646
|
+
(file2) => _optionalChain([this, 'access', _372 => _372.auditService, 'optionalAccess', _373 => _373.logFileAction, 'call', _374 => _374({
|
|
16371
16647
|
action: "file.deleted",
|
|
16372
16648
|
actorId: _nullishCoalesce(this.userId, () => ( "")),
|
|
16373
16649
|
fileId: file2.id,
|
|
16374
16650
|
fileName: file2.name,
|
|
16375
|
-
metadata: { deletedFromStorage: _nullishCoalesce(_optionalChain([options, 'optionalAccess',
|
|
16651
|
+
metadata: { deletedFromStorage: _nullishCoalesce(_optionalChain([options, 'optionalAccess', _375 => _375.deleteFromStorage]), () => ( false)) }
|
|
16376
16652
|
})])
|
|
16377
16653
|
)
|
|
16378
16654
|
);
|
|
@@ -16450,7 +16726,7 @@ var FileService = class extends BaseService {
|
|
|
16450
16726
|
if (!file2) {
|
|
16451
16727
|
return false;
|
|
16452
16728
|
}
|
|
16453
|
-
if (_optionalChain([options, 'optionalAccess',
|
|
16729
|
+
if (_optionalChain([options, 'optionalAccess', _376 => _376.isAdmin])) {
|
|
16454
16730
|
return true;
|
|
16455
16731
|
}
|
|
16456
16732
|
if (file2.visibility === "public") {
|
|
@@ -16460,7 +16736,7 @@ var FileService = class extends BaseService {
|
|
|
16460
16736
|
return true;
|
|
16461
16737
|
}
|
|
16462
16738
|
if (file2.visibility === "restricted") {
|
|
16463
|
-
return _nullishCoalesce(_optionalChain([file2, 'access',
|
|
16739
|
+
return _nullishCoalesce(_optionalChain([file2, 'access', _377 => _377.allowedUsers, 'optionalAccess', _378 => _378.includes, 'call', _379 => _379(userId)]), () => ( false));
|
|
16464
16740
|
}
|
|
16465
16741
|
return false;
|
|
16466
16742
|
}
|
|
@@ -16555,7 +16831,7 @@ function withTimeout(promise, ms, label) {
|
|
|
16555
16831
|
var GeocodingService = class {
|
|
16556
16832
|
constructor(adapter, options) {
|
|
16557
16833
|
this.adapter = adapter;
|
|
16558
|
-
this.timeoutMs = _nullishCoalesce(_optionalChain([options, 'optionalAccess',
|
|
16834
|
+
this.timeoutMs = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _380 => _380.timeoutMs]), () => ( GEOCODING_TIMEOUT_MS));
|
|
16559
16835
|
}
|
|
16560
16836
|
/**
|
|
16561
16837
|
* Search for address suggestions as the user types
|
|
@@ -16615,9 +16891,9 @@ var GlobalSearchService = class extends BaseService {
|
|
|
16615
16891
|
"search",
|
|
16616
16892
|
{ query: query.trim(), ...options },
|
|
16617
16893
|
() => this.adapter.objectRecords.globalSearch(query.trim(), {
|
|
16618
|
-
limit: _nullishCoalesce(_optionalChain([options, 'optionalAccess',
|
|
16619
|
-
offset: _nullishCoalesce(_optionalChain([options, 'optionalAccess',
|
|
16620
|
-
objectNames: _optionalChain([options, 'optionalAccess',
|
|
16894
|
+
limit: _nullishCoalesce(_optionalChain([options, 'optionalAccess', _381 => _381.limit]), () => ( 20)),
|
|
16895
|
+
offset: _nullishCoalesce(_optionalChain([options, 'optionalAccess', _382 => _382.offset]), () => ( 0)),
|
|
16896
|
+
objectNames: _optionalChain([options, 'optionalAccess', _383 => _383.objectNames])
|
|
16621
16897
|
})
|
|
16622
16898
|
);
|
|
16623
16899
|
}
|
|
@@ -16638,8 +16914,8 @@ var GlobalSearchService = class extends BaseService {
|
|
|
16638
16914
|
"grouped",
|
|
16639
16915
|
{ query: query.trim(), ...options },
|
|
16640
16916
|
() => this.adapter.objectRecords.globalSearchGrouped(query.trim(), {
|
|
16641
|
-
objectNames: _optionalChain([options, 'optionalAccess',
|
|
16642
|
-
limitPerGroup: _nullishCoalesce(_optionalChain([options, 'optionalAccess',
|
|
16917
|
+
objectNames: _optionalChain([options, 'optionalAccess', _384 => _384.objectNames]),
|
|
16918
|
+
limitPerGroup: _nullishCoalesce(_optionalChain([options, 'optionalAccess', _385 => _385.limitPerGroup]), () => ( 5))
|
|
16643
16919
|
})
|
|
16644
16920
|
);
|
|
16645
16921
|
}
|
|
@@ -16656,7 +16932,7 @@ var PermissionService = class extends BaseService {
|
|
|
16656
16932
|
}
|
|
16657
16933
|
this.permissionsRepo = adapter.permissions;
|
|
16658
16934
|
this.permissionCache = _nullishCoalesce(adapter.cache, () => ( new NoopCacheAdapter()));
|
|
16659
|
-
this.auditService = _optionalChain([options, 'optionalAccess',
|
|
16935
|
+
this.auditService = _optionalChain([options, 'optionalAccess', _386 => _386.auditService]);
|
|
16660
16936
|
}
|
|
16661
16937
|
// ============================================================================
|
|
16662
16938
|
// PERMISSION CHECKS
|
|
@@ -16675,11 +16951,11 @@ var PermissionService = class extends BaseService {
|
|
|
16675
16951
|
return true;
|
|
16676
16952
|
}
|
|
16677
16953
|
const wildcardPerms = permissions.objectPermissions["*"];
|
|
16678
|
-
if (_optionalChain([wildcardPerms, 'optionalAccess',
|
|
16954
|
+
if (_optionalChain([wildcardPerms, 'optionalAccess', _387 => _387.includes, 'call', _388 => _388(action)])) {
|
|
16679
16955
|
return true;
|
|
16680
16956
|
}
|
|
16681
16957
|
const objectPerms = permissions.objectPermissions[objectName];
|
|
16682
|
-
return _nullishCoalesce(_optionalChain([objectPerms, 'optionalAccess',
|
|
16958
|
+
return _nullishCoalesce(_optionalChain([objectPerms, 'optionalAccess', _389 => _389.includes, 'call', _390 => _390(action)]), () => ( false));
|
|
16683
16959
|
}
|
|
16684
16960
|
/**
|
|
16685
16961
|
* Check if user can access an object, throw ForbiddenError if not.
|
|
@@ -16734,12 +17010,12 @@ var PermissionService = class extends BaseService {
|
|
|
16734
17010
|
if (permissions.isAdmin) {
|
|
16735
17011
|
return true;
|
|
16736
17012
|
}
|
|
16737
|
-
const wildcardPerms = _optionalChain([permissions, 'access',
|
|
16738
|
-
if (_optionalChain([wildcardPerms, 'optionalAccess',
|
|
17013
|
+
const wildcardPerms = _optionalChain([permissions, 'access', _391 => _391.systemPermissions, 'optionalAccess', _392 => _392["*"]]);
|
|
17014
|
+
if (_optionalChain([wildcardPerms, 'optionalAccess', _393 => _393.includes, 'call', _394 => _394(action)])) {
|
|
16739
17015
|
return true;
|
|
16740
17016
|
}
|
|
16741
|
-
const resourcePerms = _optionalChain([permissions, 'access',
|
|
16742
|
-
return _nullishCoalesce(_optionalChain([resourcePerms, 'optionalAccess',
|
|
17017
|
+
const resourcePerms = _optionalChain([permissions, 'access', _395 => _395.systemPermissions, 'optionalAccess', _396 => _396[resource]]);
|
|
17018
|
+
return _nullishCoalesce(_optionalChain([resourcePerms, 'optionalAccess', _397 => _397.includes, 'call', _398 => _398(action)]), () => ( false));
|
|
16743
17019
|
}
|
|
16744
17020
|
/**
|
|
16745
17021
|
* Check if user can access a system resource, throw ForbiddenError if not.
|
|
@@ -16768,8 +17044,8 @@ var PermissionService = class extends BaseService {
|
|
|
16768
17044
|
if (permissions.isAdmin) {
|
|
16769
17045
|
return { canRead: true, canCreate: true, canUpdate: true, canDelete: true };
|
|
16770
17046
|
}
|
|
16771
|
-
const wildcardPerms = _nullishCoalesce(_optionalChain([permissions, 'access',
|
|
16772
|
-
const resourcePerms = _nullishCoalesce(_optionalChain([permissions, 'access',
|
|
17047
|
+
const wildcardPerms = _nullishCoalesce(_optionalChain([permissions, 'access', _399 => _399.systemPermissions, 'optionalAccess', _400 => _400["*"]]), () => ( []));
|
|
17048
|
+
const resourcePerms = _nullishCoalesce(_optionalChain([permissions, 'access', _401 => _401.systemPermissions, 'optionalAccess', _402 => _402[resource]]), () => ( []));
|
|
16773
17049
|
const allPerms = /* @__PURE__ */ new Set([...wildcardPerms, ...resourcePerms]);
|
|
16774
17050
|
return {
|
|
16775
17051
|
canRead: allPerms.has("read"),
|
|
@@ -16912,7 +17188,7 @@ var PermissionService = class extends BaseService {
|
|
|
16912
17188
|
action: "role.updated",
|
|
16913
17189
|
actorId: this.userId,
|
|
16914
17190
|
roleId,
|
|
16915
|
-
roleLabel: _nullishCoalesce(_optionalChain([role, 'optionalAccess',
|
|
17191
|
+
roleLabel: _nullishCoalesce(_optionalChain([role, 'optionalAccess', _403 => _403.label]), () => ( roleId)),
|
|
16916
17192
|
metadata: { permissionsUpdated: true, permissionCount: permissions.length }
|
|
16917
17193
|
});
|
|
16918
17194
|
}
|
|
@@ -16942,7 +17218,7 @@ var PermissionService = class extends BaseService {
|
|
|
16942
17218
|
action: "role.assigned",
|
|
16943
17219
|
actorId: this.userId,
|
|
16944
17220
|
roleId,
|
|
16945
|
-
roleLabel: _nullishCoalesce(_optionalChain([role, 'optionalAccess',
|
|
17221
|
+
roleLabel: _nullishCoalesce(_optionalChain([role, 'optionalAccess', _404 => _404.label]), () => ( roleId)),
|
|
16946
17222
|
targetUserId: userProfileId
|
|
16947
17223
|
});
|
|
16948
17224
|
}
|
|
@@ -16960,7 +17236,7 @@ var PermissionService = class extends BaseService {
|
|
|
16960
17236
|
action: "role.revoked",
|
|
16961
17237
|
actorId: this.userId,
|
|
16962
17238
|
roleId,
|
|
16963
|
-
roleLabel: _nullishCoalesce(_optionalChain([role, 'optionalAccess',
|
|
17239
|
+
roleLabel: _nullishCoalesce(_optionalChain([role, 'optionalAccess', _405 => _405.label]), () => ( roleId)),
|
|
16964
17240
|
targetUserId: userProfileId
|
|
16965
17241
|
});
|
|
16966
17242
|
}
|
|
@@ -17259,14 +17535,6 @@ var ViewService = class extends BaseService {
|
|
|
17259
17535
|
type: "activity",
|
|
17260
17536
|
order: 1
|
|
17261
17537
|
});
|
|
17262
|
-
tabs.push({
|
|
17263
|
-
id: "notes",
|
|
17264
|
-
name: "notes",
|
|
17265
|
-
label: "Notes",
|
|
17266
|
-
type: "notes",
|
|
17267
|
-
order: 2,
|
|
17268
|
-
allowCreate: true
|
|
17269
|
-
});
|
|
17270
17538
|
const hasDocuments = object2.attributes.some((attr) => attr.type === "document");
|
|
17271
17539
|
if (hasDocuments) {
|
|
17272
17540
|
tabs.push({
|
|
@@ -17443,7 +17711,7 @@ var ViewService = class extends BaseService {
|
|
|
17443
17711
|
dbView.objectName,
|
|
17444
17712
|
dbView.type,
|
|
17445
17713
|
objectDefinition,
|
|
17446
|
-
dbView.type === "detail" ? _nullishCoalesce(_optionalChain([dbView, 'access',
|
|
17714
|
+
dbView.type === "detail" ? _nullishCoalesce(_optionalChain([dbView, 'access', _406 => _406.config, 'optionalAccess', _407 => _407.layout]), () => ( "page")) : void 0
|
|
17447
17715
|
);
|
|
17448
17716
|
const newConfig = generated.config;
|
|
17449
17717
|
const updated = await this.adapter.views.update(viewId, { config: newConfig });
|
|
@@ -18312,20 +18580,4 @@ var NoopGeocodingAdapter = class {
|
|
|
18312
18580
|
|
|
18313
18581
|
|
|
18314
18582
|
|
|
18315
|
-
|
|
18316
|
-
|
|
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;
|
|
18583
|
+
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.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.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;
|