@stndrds/schema 0.1.0-alpha.35 → 0.1.0-alpha.37

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.
@@ -2,6 +2,93 @@
2
2
 
3
3
  var _chunk3RG5ZIWIjs = require('./chunk-3RG5ZIWI.js');
4
4
 
5
+ // src/runtime/cache.ts
6
+ var cacheKeys = {
7
+ // -------------------------------------------------------------------------
8
+ // Schemas - TTL: 1 hour (rarely change)
9
+ // -------------------------------------------------------------------------
10
+ /** Object schema by ID */
11
+ objectSchema: (tenantId, objectId) => `schema:${tenantId}:obj:${objectId}`,
12
+ /** Object schema by name */
13
+ objectSchemaByName: (tenantId, name) => `schema:${tenantId}:name:${name}`,
14
+ /** List of all object schemas */
15
+ objectSchemaList: (tenantId) => `schema:${tenantId}:list`,
16
+ // -------------------------------------------------------------------------
17
+ // Attributes - TTL: 1 hour (rarely change)
18
+ // -------------------------------------------------------------------------
19
+ /** Attributes for an object */
20
+ objectAttributes: (tenantId, objectId) => `attrs:${tenantId}:${objectId}`,
21
+ // -------------------------------------------------------------------------
22
+ // Permissions - TTL: 15 minutes (medium volatility)
23
+ // -------------------------------------------------------------------------
24
+ /** Effective permissions for a user */
25
+ userPermissions: (tenantId, userId) => `perms:${tenantId}:user:${userId}`,
26
+ // -------------------------------------------------------------------------
27
+ // Relations - TTL: 5 minutes (medium volatility)
28
+ // -------------------------------------------------------------------------
29
+ /** Relation options for an attribute */
30
+ relationOptions: (tenantId, attrId, hash) => `rel:${tenantId}:${attrId}:${hash}`,
31
+ // -------------------------------------------------------------------------
32
+ // Rollups - TTL: 2 minutes (high volatility)
33
+ // -------------------------------------------------------------------------
34
+ /** Computed rollup value for a record */
35
+ rollupValue: (tenantId, recordId, attrName) => `rollup:${tenantId}:${recordId}:${attrName}`,
36
+ // -------------------------------------------------------------------------
37
+ // Invalidation Patterns
38
+ // -------------------------------------------------------------------------
39
+ /** All schema cache for a tenant */
40
+ allSchemas: (tenantId) => `schema:${tenantId}:*`,
41
+ /** All attribute cache for a tenant */
42
+ allAttributes: (tenantId) => `attrs:${tenantId}:*`,
43
+ /** All permission cache for a tenant */
44
+ allPermissions: (tenantId) => `perms:${tenantId}:*`,
45
+ /** All relation cache for a tenant */
46
+ allRelations: (tenantId) => `rel:${tenantId}:*`,
47
+ /** All rollup cache for a tenant */
48
+ allRollups: (tenantId) => `rollup:${tenantId}:*`,
49
+ /** All rollups for a specific record */
50
+ rollupsByRecord: (tenantId, recordId) => `rollup:${tenantId}:${recordId}:*`,
51
+ /** All cache for a tenant (nuclear option) */
52
+ allForTenant: (tenantId) => `*:${tenantId}:*`
53
+ };
54
+ var cacheTtl = {
55
+ /** Object schemas - rarely change (1 hour) */
56
+ schema: 60 * 60 * 1e3,
57
+ /** Schema list - new objects more frequent (5 minutes) */
58
+ schemaList: 5 * 60 * 1e3,
59
+ /** Object attributes - rarely change (1 hour) */
60
+ attributes: 60 * 60 * 1e3,
61
+ /** User permissions - medium volatility (15 minutes) */
62
+ permissions: 15 * 60 * 1e3,
63
+ /** Relation options - medium volatility (5 minutes) */
64
+ relations: 5 * 60 * 1e3,
65
+ /** Rollup values - high volatility (2 minutes) */
66
+ rollup: 2 * 60 * 1e3
67
+ };
68
+ var NoopCacheAdapter = class {
69
+ get() {
70
+ return Promise.resolve(null);
71
+ }
72
+ set() {
73
+ return Promise.resolve();
74
+ }
75
+ delete() {
76
+ return Promise.resolve();
77
+ }
78
+ deletePattern() {
79
+ return Promise.resolve();
80
+ }
81
+ has() {
82
+ return Promise.resolve(false);
83
+ }
84
+ clear() {
85
+ return Promise.resolve();
86
+ }
87
+ getOrSet(_key, fetcher) {
88
+ return fetcher();
89
+ }
90
+ };
91
+
5
92
  // src/runtime/client/types.ts
6
93
  function formatRecord(record) {
7
94
  return {
@@ -6284,6 +6371,7 @@ var ObjectSchemaService = class extends TenantAwareService {
6284
6371
  this.adapter = adapter;
6285
6372
  this.nativeRegistry = nativeRegistry;
6286
6373
  this.auditService = _optionalChain([options, 'optionalAccess', _147 => _147.auditService]);
6374
+ this.cache = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _148 => _148.cache]), () => ( adapter.cache));
6287
6375
  }
6288
6376
  /**
6289
6377
  * Create a new custom object.
@@ -6359,6 +6447,7 @@ var ObjectSchemaService = class extends TenantAwareService {
6359
6447
  attributes: createdAttributes,
6360
6448
  system: false
6361
6449
  };
6450
+ await this.invalidateSchemaCache();
6362
6451
  if (this.auditService && this.userId) {
6363
6452
  await this.auditService.logSchemaAction({
6364
6453
  action: "object.created",
@@ -6406,6 +6495,7 @@ var ObjectSchemaService = class extends TenantAwareService {
6406
6495
  // Always false for attributes added via API
6407
6496
  config
6408
6497
  });
6498
+ await this.invalidateSchemaCache();
6409
6499
  if (this.auditService && this.userId) {
6410
6500
  await this.auditService.logSchemaAction({
6411
6501
  action: "attribute.created",
@@ -6479,12 +6569,13 @@ var ObjectSchemaService = class extends TenantAwareService {
6479
6569
  resourceType: "attribute",
6480
6570
  resourceId: attributeId,
6481
6571
  resourceLabel: updatedDbAttr.label,
6482
- objectName: _optionalChain([dbObject, 'optionalAccess', _148 => _148.name]),
6572
+ objectName: _optionalChain([dbObject, 'optionalAccess', _149 => _149.name]),
6483
6573
  objectId: dbAttr.objectId,
6484
6574
  changes
6485
6575
  });
6486
6576
  }
6487
6577
  }
6578
+ await this.invalidateSchemaCache();
6488
6579
  if (updates.required !== void 0 && updates.required !== oldValues.required) {
6489
6580
  const schema = await this.getObjectSchema(dbAttr.objectId);
6490
6581
  await this.adapter.objectRecords.batchRefreshStatus(
@@ -6511,7 +6602,7 @@ var ObjectSchemaService = class extends TenantAwareService {
6511
6602
  );
6512
6603
  }
6513
6604
  const dbObject = await this.adapter.objects.findById(dbAttr.objectId);
6514
- if (_optionalChain([dbObject, 'optionalAccess', _149 => _149.labelExpression])) {
6605
+ if (_optionalChain([dbObject, 'optionalAccess', _150 => _150.labelExpression])) {
6515
6606
  const usedAttributes = extractAttributeNames(dbObject.labelExpression);
6516
6607
  if (usedAttributes.includes(dbAttr.name)) {
6517
6608
  throw new AttributeInUseError(dbAttr.name, "labelExpression");
@@ -6519,6 +6610,7 @@ var ObjectSchemaService = class extends TenantAwareService {
6519
6610
  }
6520
6611
  await this.adapter.attributes.delete(attributeId);
6521
6612
  await this.adapter.objectRecords.removeAttributeData(dbAttr.objectId, dbAttr.name);
6613
+ await this.invalidateSchemaCache();
6522
6614
  if (this.auditService && this.userId) {
6523
6615
  await this.auditService.logSchemaAction({
6524
6616
  action: "attribute.deleted",
@@ -6526,7 +6618,7 @@ var ObjectSchemaService = class extends TenantAwareService {
6526
6618
  resourceType: "attribute",
6527
6619
  resourceId: attributeId,
6528
6620
  resourceLabel: dbAttr.label,
6529
- objectName: _optionalChain([dbObject, 'optionalAccess', _150 => _150.name]),
6621
+ objectName: _optionalChain([dbObject, 'optionalAccess', _151 => _151.name]),
6530
6622
  objectId: dbAttr.objectId
6531
6623
  });
6532
6624
  }
@@ -6541,9 +6633,9 @@ var ObjectSchemaService = class extends TenantAwareService {
6541
6633
  async listAttributes(objectId, options) {
6542
6634
  const dbAttributes = await this.adapter.attributes.findByObjectId(objectId);
6543
6635
  let filtered = dbAttributes;
6544
- if (_optionalChain([options, 'optionalAccess', _151 => _151.systemOnly])) {
6636
+ if (_optionalChain([options, 'optionalAccess', _152 => _152.systemOnly])) {
6545
6637
  filtered = dbAttributes.filter((attr) => attr.system);
6546
- } else if (_optionalChain([options, 'optionalAccess', _152 => _152.customOnly])) {
6638
+ } else if (_optionalChain([options, 'optionalAccess', _153 => _153.customOnly])) {
6547
6639
  filtered = dbAttributes.filter((attr) => !attr.system);
6548
6640
  }
6549
6641
  return filtered.map((attr) => this.convertDBAttributeToAttribute(attr));
@@ -6579,14 +6671,14 @@ var ObjectSchemaService = class extends TenantAwareService {
6579
6671
  pluralLabel: dbObject.pluralLabel,
6580
6672
  description: dbObject.description,
6581
6673
  labelExpression: dbObject.labelExpression,
6582
- icon: _optionalChain([dbObject, 'access', _153 => _153.metadata, 'optionalAccess', _154 => _154.icon])
6674
+ icon: _optionalChain([dbObject, 'access', _154 => _154.metadata, 'optionalAccess', _155 => _155.icon])
6583
6675
  };
6584
6676
  let metadata = dbObject.metadata;
6585
6677
  if (updates.icon !== void 0 || updates.metadata !== void 0) {
6586
6678
  metadata = {
6587
6679
  ...dbObject.metadata,
6588
6680
  ...updates.metadata,
6589
- icon: _nullishCoalesce(updates.icon, () => ( _optionalChain([dbObject, 'access', _155 => _155.metadata, 'optionalAccess', _156 => _156.icon])))
6681
+ icon: _nullishCoalesce(updates.icon, () => ( _optionalChain([dbObject, 'access', _156 => _156.metadata, 'optionalAccess', _157 => _157.icon])))
6590
6682
  };
6591
6683
  }
6592
6684
  const updatedDbObject = await this.adapter.objects.update(objectId, {
@@ -6619,6 +6711,7 @@ var ObjectSchemaService = class extends TenantAwareService {
6619
6711
  }
6620
6712
  const dbAttributes = await this.adapter.attributes.findByObjectId(objectId);
6621
6713
  const attributes = dbAttributes.map((attr) => this.convertDBAttributeToAttribute(attr));
6714
+ await this.invalidateSchemaCache();
6622
6715
  if (updates.labelExpression !== void 0 && updates.labelExpression !== oldValues.labelExpression) {
6623
6716
  const newExpression = updates.labelExpression;
6624
6717
  await this.adapter.objectRecords.batchRefreshLabels(objectId, (values) => {
@@ -6656,6 +6749,7 @@ var ObjectSchemaService = class extends TenantAwareService {
6656
6749
  throw new ObjectReferencedError(dbObject.name, referencingObjects);
6657
6750
  }
6658
6751
  await this.adapter.objects.delete(objectId);
6752
+ await this.invalidateSchemaCache();
6659
6753
  if (this.auditService && this.userId) {
6660
6754
  await this.auditService.logSchemaAction({
6661
6755
  action: "object.deleted",
@@ -6699,10 +6793,26 @@ Reserved names: ${RESERVED_ATTRIBUTE_NAMES.join(", ")}`
6699
6793
  * Get complete object schema (object attributes + system attributes)
6700
6794
  * Includes system attributes (createdAt, updatedAt, createdBy, lastUpdatedBy)
6701
6795
  *
6796
+ * Results are cached if a CacheAdapter is configured.
6797
+ *
6702
6798
  * @param objectId - Object UUID from database
6703
6799
  * @returns Complete ObjectDefinition with all attributes including system attributes
6704
6800
  */
6705
6801
  async getObjectSchema(objectId) {
6802
+ if (this.cache) {
6803
+ const cacheKey = cacheKeys.objectSchema(this.tenantId, objectId);
6804
+ return this.cache.getOrSet(
6805
+ cacheKey,
6806
+ () => this.fetchObjectSchemaById(objectId),
6807
+ cacheTtl.schema
6808
+ );
6809
+ }
6810
+ return this.fetchObjectSchemaById(objectId);
6811
+ }
6812
+ /**
6813
+ * Internal method to fetch object schema by ID (no caching)
6814
+ */
6815
+ async fetchObjectSchemaById(objectId) {
6706
6816
  const dbObject = await this.adapter.objects.findById(objectId);
6707
6817
  if (!dbObject) {
6708
6818
  throw new Error(`Object with id "${objectId}" not found`);
@@ -6723,8 +6833,24 @@ Reserved names: ${RESERVED_ATTRIBUTE_NAMES.join(", ")}`
6723
6833
  /**
6724
6834
  * Get object schema by name (supports both native and custom objects).
6725
6835
  * Automatically uses tenant context from AsyncLocalStorage.
6836
+ *
6837
+ * Results are cached if a CacheAdapter is configured.
6726
6838
  */
6727
6839
  async getObjectSchemaByNameForTenant(name) {
6840
+ if (this.cache) {
6841
+ const cacheKey = cacheKeys.objectSchemaByName(this.tenantId, name);
6842
+ return this.cache.getOrSet(
6843
+ cacheKey,
6844
+ () => this.fetchObjectSchemaByName(name),
6845
+ cacheTtl.schema
6846
+ );
6847
+ }
6848
+ return this.fetchObjectSchemaByName(name);
6849
+ }
6850
+ /**
6851
+ * Internal method to fetch object schema by name (no caching)
6852
+ */
6853
+ async fetchObjectSchemaByName(name) {
6728
6854
  let dbObject = await this.adapter.objects.findByName(name);
6729
6855
  if (!dbObject) {
6730
6856
  dbObject = await this.adapter.objects.findSystemByName(name);
@@ -6737,11 +6863,32 @@ Reserved names: ${RESERVED_ATTRIBUTE_NAMES.join(", ")}`
6737
6863
  /**
6738
6864
  * List all object schemas.
6739
6865
  * Automatically uses tenant context from AsyncLocalStorage.
6866
+ *
6867
+ * Results are cached if a CacheAdapter is configured.
6740
6868
  */
6741
6869
  async listObjectSchemas() {
6870
+ if (this.cache) {
6871
+ const cacheKey = cacheKeys.objectSchemaList(this.tenantId);
6872
+ return this.cache.getOrSet(cacheKey, () => this.fetchObjectSchemaList(), cacheTtl.schemaList);
6873
+ }
6874
+ return this.fetchObjectSchemaList();
6875
+ }
6876
+ /**
6877
+ * Internal method to fetch all object schemas (no caching)
6878
+ */
6879
+ async fetchObjectSchemaList() {
6742
6880
  const dbObjects = await this.adapter.objects.list();
6743
6881
  return Promise.all(dbObjects.map((dbObject) => this.buildObjectDefinition(dbObject)));
6744
6882
  }
6883
+ /**
6884
+ * Invalidate all schema-related cache for the current tenant.
6885
+ * Called automatically after schema mutations.
6886
+ */
6887
+ async invalidateSchemaCache() {
6888
+ if (!this.cache) return;
6889
+ await this.cache.deletePattern(cacheKeys.allSchemas(this.tenantId));
6890
+ await this.cache.deletePattern(cacheKeys.allAttributes(this.tenantId));
6891
+ }
6745
6892
  // ============================================================================
6746
6893
  // PRIVATE HELPERS - SCHEMA BUILDING
6747
6894
  // ============================================================================
@@ -6819,7 +6966,7 @@ Reserved names: ${RESERVED_ATTRIBUTE_NAMES.join(", ")}`
6819
6966
  label: dbObject.label,
6820
6967
  pluralLabel: dbObject.pluralLabel,
6821
6968
  description: dbObject.description,
6822
- icon: _optionalChain([dbObject, 'access', _157 => _157.metadata, 'optionalAccess', _158 => _158.icon]),
6969
+ icon: _optionalChain([dbObject, 'access', _158 => _158.metadata, 'optionalAccess', _159 => _159.icon]),
6823
6970
  labelExpression: dbObject.labelExpression,
6824
6971
  attributes,
6825
6972
  system: dbObject.system,
@@ -6919,7 +7066,7 @@ Reserved names: ${RESERVED_ATTRIBUTE_NAMES.join(", ")}`
6919
7066
  const hasRelationToTarget = attrs.some((attr) => {
6920
7067
  if (attr.type !== "relation") return false;
6921
7068
  const config = attr.config;
6922
- return _nullishCoalesce(_optionalChain([config, 'optionalAccess', _159 => _159.targets, 'optionalAccess', _160 => _160.some, 'call', _161 => _161((t) => t.object === targetObjectName)]), () => ( false));
7069
+ return _nullishCoalesce(_optionalChain([config, 'optionalAccess', _160 => _160.targets, 'optionalAccess', _161 => _161.some, 'call', _162 => _162((t) => t.object === targetObjectName)]), () => ( false));
6923
7070
  });
6924
7071
  if (hasRelationToTarget) {
6925
7072
  referencing.push(obj.name);
@@ -6951,17 +7098,13 @@ var PermissionService = class extends TenantAwareService {
6951
7098
  constructor(adapter, options) {
6952
7099
  super();
6953
7100
  this.adapter = adapter;
6954
- this.cache = /* @__PURE__ */ new Map();
6955
- /** Track pending permission fetches to prevent duplicate concurrent requests */
6956
- this.pendingFetches = /* @__PURE__ */ new Map();
6957
7101
  if (!adapter.permissions) {
6958
7102
  throw new Error(
6959
7103
  "PermissionService requires a DatabaseAdapter with permissions repository. Make sure your adapter implements the permissions property."
6960
7104
  );
6961
7105
  }
6962
7106
  this.permissionsRepo = adapter.permissions;
6963
- this.cacheTtlMs = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _162 => _162.cacheTtlMs]), () => ( 6e4));
6964
- this.maxCacheSize = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _163 => _163.maxCacheSize]), () => ( 1e4));
7107
+ this.cache = _nullishCoalesce(_nullishCoalesce(_optionalChain([options, 'optionalAccess', _163 => _163.cache]), () => ( adapter.cache)), () => ( new NoopCacheAdapter()));
6965
7108
  this.auditService = _optionalChain([options, 'optionalAccess', _164 => _164.auditService]);
6966
7109
  }
6967
7110
  // ============================================================================
@@ -7089,46 +7232,18 @@ var PermissionService = class extends TenantAwareService {
7089
7232
  // ============================================================================
7090
7233
  /**
7091
7234
  * Get effective permissions for a user.
7092
- * Results are cached with TTL and size limit.
7235
+ * Results are cached using CacheAdapter with TTL.
7093
7236
  *
7094
7237
  * @param userProfileId - User profile ID
7095
7238
  * @returns Merged permissions from all user's roles
7096
7239
  */
7097
7240
  async getEffectivePermissions(userProfileId) {
7098
- const cacheKey = this.getCacheKey(userProfileId);
7099
- const cached = this.cache.get(cacheKey);
7100
- if (cached && cached.expiresAt > Date.now()) {
7101
- return cached.permissions;
7102
- }
7103
- const pendingFetch = this.pendingFetches.get(cacheKey);
7104
- if (pendingFetch) {
7105
- return pendingFetch;
7106
- }
7107
- const fetchPromise = this.fetchAndCachePermissions(userProfileId, cacheKey);
7108
- this.pendingFetches.set(cacheKey, fetchPromise);
7109
- try {
7110
- return await fetchPromise;
7111
- } finally {
7112
- this.pendingFetches.delete(cacheKey);
7113
- }
7114
- }
7115
- /**
7116
- * Fetch permissions from database and cache the result
7117
- * @internal
7118
- */
7119
- async fetchAndCachePermissions(userProfileId, cacheKey) {
7120
- const permissions = await this.permissionsRepo.getEffectivePermissions(userProfileId);
7121
- if (this.cache.size >= this.maxCacheSize) {
7122
- const firstKey = this.cache.keys().next().value;
7123
- if (firstKey) {
7124
- this.cache.delete(firstKey);
7125
- }
7126
- }
7127
- this.cache.set(cacheKey, {
7128
- permissions,
7129
- expiresAt: Date.now() + this.cacheTtlMs
7130
- });
7131
- return permissions;
7241
+ const cacheKey = cacheKeys.userPermissions(this.tenantId, userProfileId);
7242
+ return this.cache.getOrSet(
7243
+ cacheKey,
7244
+ () => this.permissionsRepo.getEffectivePermissions(userProfileId),
7245
+ cacheTtl.permissions
7246
+ );
7132
7247
  }
7133
7248
  // ============================================================================
7134
7249
  // CACHE MANAGEMENT
@@ -7137,24 +7252,15 @@ var PermissionService = class extends TenantAwareService {
7137
7252
  * Invalidate cached permissions for a specific user.
7138
7253
  * Call this after role/permission changes.
7139
7254
  */
7140
- invalidateCache(userProfileId) {
7141
- this.cache.delete(this.getCacheKey(userProfileId));
7255
+ async invalidateCache(userProfileId) {
7256
+ await this.cache.delete(cacheKeys.userPermissions(this.tenantId, userProfileId));
7142
7257
  }
7143
7258
  /**
7144
- * Invalidate all cached permissions.
7259
+ * Invalidate all cached permissions for the current tenant.
7145
7260
  * Call this after bulk role/permission changes.
7146
7261
  */
7147
- invalidateAllCache() {
7148
- this.cache.clear();
7149
- }
7150
- /**
7151
- * Get current cache size (for monitoring).
7152
- */
7153
- getCacheSize() {
7154
- return this.cache.size;
7155
- }
7156
- getCacheKey(userProfileId) {
7157
- return `${this.tenantId}:${userProfileId}`;
7262
+ async invalidateAllCache() {
7263
+ await this.cache.deletePattern(cacheKeys.allPermissions(this.tenantId));
7158
7264
  }
7159
7265
  // ============================================================================
7160
7266
  // ROLE MANAGEMENT
@@ -7516,10 +7622,11 @@ var registry = new NativeObjectRegistryClass();
7516
7622
 
7517
7623
  // src/runtime/services/relation.service.ts
7518
7624
  var RelationService = class extends TenantAwareService {
7519
- constructor(adapter, nativeRegistry) {
7625
+ constructor(adapter, nativeRegistry, options) {
7520
7626
  super();
7521
7627
  this.adapter = adapter;
7522
- this.schemaService = new ObjectSchemaService(adapter, nativeRegistry);
7628
+ this.cache = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _186 => _186.cache]), () => ( adapter.cache));
7629
+ this.schemaService = new ObjectSchemaService(adapter, nativeRegistry, { cache: this.cache });
7523
7630
  }
7524
7631
  /**
7525
7632
  * Validate all relation attributes in the data
@@ -7570,7 +7677,7 @@ var RelationService = class extends TenantAwareService {
7570
7677
  }
7571
7678
  const isUniversal = attr.targets.length === 1 && attr.targets[0].object === RELATION_TARGET_ANY;
7572
7679
  const validObjectIds = isUniversal ? null : await this.getValidObjectIds(attr.targets);
7573
- if (!isUniversal && _optionalChain([validObjectIds, 'optionalAccess', _186 => _186.size]) === 0) {
7680
+ if (!isUniversal && _optionalChain([validObjectIds, 'optionalAccess', _187 => _187.size]) === 0) {
7574
7681
  errors.push({
7575
7682
  attribute: attr.name,
7576
7683
  message: `No valid target objects found for ${attr.label}`
@@ -7621,7 +7728,7 @@ var RelationService = class extends TenantAwareService {
7621
7728
  for (const target of targets) {
7622
7729
  try {
7623
7730
  const objectSchema = await this.schemaService.getObjectSchemaByName(target.object);
7624
- if (_optionalChain([objectSchema, 'optionalAccess', _187 => _187.id])) {
7731
+ if (_optionalChain([objectSchema, 'optionalAccess', _188 => _188.id])) {
7625
7732
  objectIds.add(objectSchema.id);
7626
7733
  }
7627
7734
  } catch (e7) {
@@ -7674,7 +7781,7 @@ var RelationService = class extends TenantAwareService {
7674
7781
  const recordService = new RecordService(this.adapter);
7675
7782
  for (const target of filteredTargets) {
7676
7783
  const objectSchema = await this.schemaService.getObjectSchemaByName(target.object);
7677
- if (!_optionalChain([objectSchema, 'optionalAccess', _188 => _188.id])) {
7784
+ if (!_optionalChain([objectSchema, 'optionalAccess', _189 => _189.id])) {
7678
7785
  continue;
7679
7786
  }
7680
7787
  const result = query ? await recordService.searchRecords(objectSchema.id, query, {
@@ -7744,9 +7851,9 @@ var RelationService = class extends TenantAwareService {
7744
7851
  continue;
7745
7852
  }
7746
7853
  let template = objectSchema.labelExpression;
7747
- if (_optionalChain([attribute, 'optionalAccess', _189 => _189.targets])) {
7854
+ if (_optionalChain([attribute, 'optionalAccess', _190 => _190.targets])) {
7748
7855
  const targetConfig = attribute.targets.find((t) => t.object === objectSchema.name);
7749
- if (_optionalChain([targetConfig, 'optionalAccess', _190 => _190.displayTemplate])) {
7856
+ if (_optionalChain([targetConfig, 'optionalAccess', _191 => _191.displayTemplate])) {
7750
7857
  template = targetConfig.displayTemplate;
7751
7858
  }
7752
7859
  }
@@ -7786,12 +7893,15 @@ var RelationService = class extends TenantAwareService {
7786
7893
 
7787
7894
  // src/runtime/services/rollup.service.ts
7788
7895
  var RollupService = class {
7789
- constructor(adapter) {
7896
+ constructor(adapter, options) {
7790
7897
  this.adapter = adapter;
7898
+ this.cache = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _192 => _192.cache]), () => ( adapter.cache));
7791
7899
  }
7792
7900
  /**
7793
7901
  * Calculate a rollup value for a record
7794
7902
  *
7903
+ * Results are cached if a CacheAdapter is configured.
7904
+ *
7795
7905
  * @param recordId - ID of the parent record
7796
7906
  * @param rollupAttr - Rollup attribute definition
7797
7907
  * @param schema - Schema of the parent object
@@ -7815,6 +7925,21 @@ var RollupService = class {
7815
7925
  * ```
7816
7926
  */
7817
7927
  async calculate(recordId, rollupAttr, schema) {
7928
+ if (this.cache) {
7929
+ const tenantId = getTenantId();
7930
+ const cacheKey = cacheKeys.rollupValue(tenantId, recordId, rollupAttr.name);
7931
+ return this.cache.getOrSet(
7932
+ cacheKey,
7933
+ () => this.computeRollup(recordId, rollupAttr, schema),
7934
+ cacheTtl.rollup
7935
+ );
7936
+ }
7937
+ return this.computeRollup(recordId, rollupAttr, schema);
7938
+ }
7939
+ /**
7940
+ * Internal method to compute rollup value (no caching)
7941
+ */
7942
+ async computeRollup(recordId, rollupAttr, schema) {
7818
7943
  const relationAttr = schema.attributes.find(
7819
7944
  (a) => a.type === "relation" && a.name === rollupAttr.relationAttribute
7820
7945
  );
@@ -7866,7 +7991,7 @@ var RollupService = class {
7866
7991
  const reverseRelationAttr = sourceAttributes.find((attr) => {
7867
7992
  if (attr.type !== "relation") return false;
7868
7993
  const relationConfig = attr.config;
7869
- return _optionalChain([relationConfig, 'optionalAccess', _191 => _191.targets, 'optionalAccess', _192 => _192.some, 'call', _193 => _193((t) => t.object === schema.name)]);
7994
+ return _optionalChain([relationConfig, 'optionalAccess', _193 => _193.targets, 'optionalAccess', _194 => _194.some, 'call', _195 => _195((t) => t.object === schema.name)]);
7870
7995
  });
7871
7996
  if (!reverseRelationAttr) {
7872
7997
  return { value: null, recordCount: 0 };
@@ -8017,9 +8142,14 @@ var RollupService = class {
8017
8142
  return record;
8018
8143
  }
8019
8144
  const updates = {};
8020
- for (const attr of rollupAttrs) {
8021
- const result = await this.calculate(record.id, attr, schema);
8022
- updates[attr.name] = result.value;
8145
+ const results = await Promise.all(
8146
+ rollupAttrs.map(async (attr) => {
8147
+ const result = await this.calculate(record.id, attr, schema);
8148
+ return { name: attr.name, value: result.value };
8149
+ })
8150
+ );
8151
+ for (const { name, value } of results) {
8152
+ updates[name] = value;
8023
8153
  }
8024
8154
  return await this.adapter.objectRecords.update(record.id, updates);
8025
8155
  }
@@ -8048,6 +8178,31 @@ var RollupService = class {
8048
8178
  }
8049
8179
  return [...new Set(affectedIds)];
8050
8180
  }
8181
+ /**
8182
+ * Invalidate cached rollups for affected parent records.
8183
+ * Call this after a child record is created, updated, or deleted.
8184
+ *
8185
+ * @param affectedParentIds - Array of parent record IDs whose rollups need invalidation
8186
+ */
8187
+ async invalidateAffectedRollups(affectedParentIds) {
8188
+ if (!this.cache || affectedParentIds.length === 0) return;
8189
+ const tenantId = getTenantId();
8190
+ const cache = this.cache;
8191
+ await Promise.all(
8192
+ affectedParentIds.map(
8193
+ (parentId) => cache.deletePattern(cacheKeys.rollupsByRecord(tenantId, parentId))
8194
+ )
8195
+ );
8196
+ }
8197
+ /**
8198
+ * Invalidate all cached rollups for the current tenant.
8199
+ * Use sparingly - prefer targeted invalidation.
8200
+ */
8201
+ async invalidateAllRollups() {
8202
+ if (!this.cache) return;
8203
+ const tenantId = getTenantId();
8204
+ await this.cache.deletePattern(cacheKeys.allRollups(tenantId));
8205
+ }
8051
8206
  /**
8052
8207
  * Find records that have forward rollups pointing to the modified record.
8053
8208
  *
@@ -8077,7 +8232,7 @@ var RollupService = class {
8077
8232
  }
8078
8233
  for (const rollupDbAttr of rollupAttrs) {
8079
8234
  const rollupConfig = rollupDbAttr.config;
8080
- if (!_optionalChain([rollupConfig, 'optionalAccess', _194 => _194.relationAttribute])) {
8235
+ if (!_optionalChain([rollupConfig, 'optionalAccess', _196 => _196.relationAttribute])) {
8081
8236
  continue;
8082
8237
  }
8083
8238
  const relationAttr = attributes.find(
@@ -8087,7 +8242,7 @@ var RollupService = class {
8087
8242
  continue;
8088
8243
  }
8089
8244
  const relationConfig = relationAttr.config;
8090
- const targetsChangedObject = _optionalChain([relationConfig, 'optionalAccess', _195 => _195.targets, 'optionalAccess', _196 => _196.some, 'call', _197 => _197(
8245
+ const targetsChangedObject = _optionalChain([relationConfig, 'optionalAccess', _197 => _197.targets, 'optionalAccess', _198 => _198.some, 'call', _199 => _199(
8091
8246
  (t) => t.object === changedSchema.name
8092
8247
  )]);
8093
8248
  if (!targetsChangedObject) {
@@ -8190,7 +8345,7 @@ var UserService = class extends TenantAwareService {
8190
8345
  if (roleErrors.length > 0) {
8191
8346
  errors.push({
8192
8347
  attribute: attr.name,
8193
- message: `Users do not have required role for ${attr.label}. Allowed roles: ${_optionalChain([attr, 'access', _198 => _198.allowedRoles, 'optionalAccess', _199 => _199.join, 'call', _200 => _200(", ")])}`,
8348
+ message: `Users do not have required role for ${attr.label}. Allowed roles: ${_optionalChain([attr, 'access', _200 => _200.allowedRoles, 'optionalAccess', _201 => _201.join, 'call', _202 => _202(", ")])}`,
8194
8349
  invalidIds: roleErrors
8195
8350
  });
8196
8351
  }
@@ -8244,15 +8399,15 @@ var RecordService = class extends TenantAwareService {
8244
8399
  super();
8245
8400
  this.adapter = adapter;
8246
8401
  this.schemaService = new ObjectSchemaService(adapter, registry, {
8247
- auditService: _optionalChain([options, 'optionalAccess', _201 => _201.auditService])
8402
+ auditService: _optionalChain([options, 'optionalAccess', _203 => _203.auditService])
8248
8403
  });
8249
8404
  this.relationService = new RelationService(adapter, registry);
8250
8405
  this.userService = new UserService(adapter);
8251
8406
  this.rollupService = new RollupService(adapter);
8252
- this.hookRegistry = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _202 => _202.hookRegistry]), () => ( new NoopHookRegistry()));
8253
- this.permissionService = _optionalChain([options, 'optionalAccess', _203 => _203.permissionService]);
8254
- this.auditService = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _204 => _204.auditService]), () => ( (adapter.audit ? new AuditService(adapter) : void 0)));
8255
- this.policyRegistry = _optionalChain([options, 'optionalAccess', _205 => _205.policyRegistry]) === null ? null : _nullishCoalesce(_optionalChain([options, 'optionalAccess', _206 => _206.policyRegistry]), () => ( defaultPolicyRegistry));
8407
+ this.hookRegistry = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _204 => _204.hookRegistry]), () => ( new NoopHookRegistry()));
8408
+ this.permissionService = _optionalChain([options, 'optionalAccess', _205 => _205.permissionService]);
8409
+ this.auditService = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _206 => _206.auditService]), () => ( (adapter.audit ? new AuditService(adapter) : void 0)));
8410
+ this.policyRegistry = _optionalChain([options, 'optionalAccess', _207 => _207.policyRegistry]) === null ? null : _nullishCoalesce(_optionalChain([options, 'optionalAccess', _208 => _208.policyRegistry]), () => ( defaultPolicyRegistry));
8256
8411
  }
8257
8412
  /**
8258
8413
  * Check permission for an action on an object.
@@ -8436,20 +8591,20 @@ var RecordService = class extends TenantAwareService {
8436
8591
  const schema = await this.schemaService.getObjectSchema(objectId);
8437
8592
  const dataWithDefaults = applyDefaultValues(schema, data);
8438
8593
  await this.checkPermission(schema.name, "create");
8439
- const hookCtx = this.buildCreateHookContext(schema, dataWithDefaults, _optionalChain([options, 'optionalAccess', _207 => _207.hookMetadata]));
8440
- if (!_optionalChain([options, 'optionalAccess', _208 => _208.skipHooks])) {
8594
+ const hookCtx = this.buildCreateHookContext(schema, dataWithDefaults, _optionalChain([options, 'optionalAccess', _209 => _209.hookMetadata]));
8595
+ if (!_optionalChain([options, 'optionalAccess', _210 => _210.skipHooks])) {
8441
8596
  await this.hookRegistry.execute("beforeCreate", schema.name, hookCtx);
8442
8597
  }
8443
- if (_optionalChain([options, 'optionalAccess', _209 => _209.validate]) !== false) {
8444
- if (_optionalChain([options, 'optionalAccess', _210 => _210.allowDraft])) {
8598
+ if (_optionalChain([options, 'optionalAccess', _211 => _211.validate]) !== false) {
8599
+ if (_optionalChain([options, 'optionalAccess', _212 => _212.allowDraft])) {
8445
8600
  validateDraftOrThrow(schema, dataWithDefaults);
8446
8601
  } else {
8447
8602
  validateObjectOrThrow(schema, dataWithDefaults);
8448
8603
  }
8449
- if (!_optionalChain([options, 'optionalAccess', _211 => _211.skipRelationValidation])) {
8604
+ if (!_optionalChain([options, 'optionalAccess', _213 => _213.skipRelationValidation])) {
8450
8605
  await this.relationService.validateRelationsOrThrow(schema, dataWithDefaults);
8451
8606
  }
8452
- if (!_optionalChain([options, 'optionalAccess', _212 => _212.skipUserValidation])) {
8607
+ if (!_optionalChain([options, 'optionalAccess', _214 => _214.skipUserValidation])) {
8453
8608
  await this.userService.validateUsersOrThrow(schema, dataWithDefaults);
8454
8609
  }
8455
8610
  }
@@ -8460,10 +8615,10 @@ var RecordService = class extends TenantAwareService {
8460
8615
  data: dataWithDefaults,
8461
8616
  label,
8462
8617
  completionStatus,
8463
- metadata: _optionalChain([options, 'optionalAccess', _213 => _213.metadata]),
8618
+ metadata: _optionalChain([options, 'optionalAccess', _215 => _215.metadata]),
8464
8619
  createdBy: this.userId
8465
8620
  });
8466
- if (!_optionalChain([options, 'optionalAccess', _214 => _214.skipHooks])) {
8621
+ if (!_optionalChain([options, 'optionalAccess', _216 => _216.skipHooks])) {
8467
8622
  const afterCtx = {
8468
8623
  ...hookCtx,
8469
8624
  recordId: record.id,
@@ -8480,7 +8635,7 @@ var RecordService = class extends TenantAwareService {
8480
8635
  objectId: schema.id,
8481
8636
  recordId: record.id,
8482
8637
  recordLabel: record.label,
8483
- metadata: _optionalChain([options, 'optionalAccess', _215 => _215.hookMetadata])
8638
+ metadata: _optionalChain([options, 'optionalAccess', _217 => _217.hookMetadata])
8484
8639
  });
8485
8640
  }
8486
8641
  return record;
@@ -8498,17 +8653,17 @@ var RecordService = class extends TenantAwareService {
8498
8653
  return null;
8499
8654
  }
8500
8655
  const schema = await this.schemaService.getObjectSchema(record.objectId);
8501
- if (!_optionalChain([options, 'optionalAccess', _216 => _216.skipPolicyCheck])) {
8656
+ if (!_optionalChain([options, 'optionalAccess', _218 => _218.skipPolicyCheck])) {
8502
8657
  const policy = this.getPolicy(schema.name);
8503
8658
  if (policy && !this.checkRecordAccess(policy, record)) {
8504
8659
  return null;
8505
8660
  }
8506
8661
  }
8507
8662
  let enrichedRecord = record;
8508
- if (!_optionalChain([options, 'optionalAccess', _217 => _217.skipFormulas])) {
8663
+ if (!_optionalChain([options, 'optionalAccess', _219 => _219.skipFormulas])) {
8509
8664
  enrichedRecord = this.enrichWithFormulas(record, schema);
8510
8665
  }
8511
- if (_optionalChain([options, 'optionalAccess', _218 => _218.includeSchema])) {
8666
+ if (_optionalChain([options, 'optionalAccess', _220 => _220.includeSchema])) {
8512
8667
  const recordWithSchema = enrichedRecord;
8513
8668
  recordWithSchema.schema = schema;
8514
8669
  return recordWithSchema;
@@ -8567,9 +8722,9 @@ var RecordService = class extends TenantAwareService {
8567
8722
  data,
8568
8723
  mergedData,
8569
8724
  changedAttributes,
8570
- _optionalChain([options, 'optionalAccess', _219 => _219.hookMetadata])
8725
+ _optionalChain([options, 'optionalAccess', _221 => _221.hookMetadata])
8571
8726
  );
8572
- if (!_optionalChain([options, 'optionalAccess', _220 => _220.skipHooks])) {
8727
+ if (!_optionalChain([options, 'optionalAccess', _222 => _222.skipHooks])) {
8573
8728
  await this.hookRegistry.execute("beforeUpdate", schema.name, hookCtx);
8574
8729
  }
8575
8730
  const hookModifiedValues = {};
@@ -8578,19 +8733,19 @@ var RecordService = class extends TenantAwareService {
8578
8733
  hookModifiedValues[key] = hookCtx.newValues[key];
8579
8734
  }
8580
8735
  }
8581
- if (_optionalChain([options, 'optionalAccess', _221 => _221.validate]) !== false) {
8582
- if (_optionalChain([options, 'optionalAccess', _222 => _222.partial])) {
8736
+ if (_optionalChain([options, 'optionalAccess', _223 => _223.validate]) !== false) {
8737
+ if (_optionalChain([options, 'optionalAccess', _224 => _224.partial])) {
8583
8738
  validateDraftOrThrow(schema, mergedData);
8584
8739
  } else {
8585
8740
  validateObjectOrThrow(schema, mergedData);
8586
8741
  }
8587
- if (!_optionalChain([options, 'optionalAccess', _223 => _223.skipRelationValidation])) {
8742
+ if (!_optionalChain([options, 'optionalAccess', _225 => _225.skipRelationValidation])) {
8588
8743
  await this.relationService.validateRelationsOrThrow(schema, {
8589
8744
  ...data,
8590
8745
  ...hookModifiedValues
8591
8746
  });
8592
8747
  }
8593
- if (!_optionalChain([options, 'optionalAccess', _224 => _224.skipUserValidation])) {
8748
+ if (!_optionalChain([options, 'optionalAccess', _226 => _226.skipUserValidation])) {
8594
8749
  await this.userService.validateUsersOrThrow(schema, {
8595
8750
  ...data,
8596
8751
  ...hookModifiedValues
@@ -8606,7 +8761,7 @@ var RecordService = class extends TenantAwareService {
8606
8761
  __label: label,
8607
8762
  __lastUpdatedBy: this.userId
8608
8763
  };
8609
- if (_optionalChain([options, 'optionalAccess', _225 => _225.metadata]) !== void 0) {
8764
+ if (_optionalChain([options, 'optionalAccess', _227 => _227.metadata]) !== void 0) {
8610
8765
  const existingMetadata = _nullishCoalesce(existing.metadata, () => ( {}));
8611
8766
  const mergedMetadata = { ...existingMetadata, ...options.metadata };
8612
8767
  const cleanedMetadata = Object.fromEntries(
@@ -8615,7 +8770,7 @@ var RecordService = class extends TenantAwareService {
8615
8770
  updatePayload.__metadata = cleanedMetadata;
8616
8771
  }
8617
8772
  const updated = await this.adapter.objectRecords.update(recordId, updatePayload);
8618
- if (!_optionalChain([options, 'optionalAccess', _226 => _226.skipHooks])) {
8773
+ if (!_optionalChain([options, 'optionalAccess', _228 => _228.skipHooks])) {
8619
8774
  const afterCtx = {
8620
8775
  ...hookCtx,
8621
8776
  record: updated
@@ -8630,7 +8785,7 @@ var RecordService = class extends TenantAwareService {
8630
8785
  if (this.auditService && this.userId && allChangedAttributes.length > 0) {
8631
8786
  const changes = allChangedAttributes.map((attr) => ({
8632
8787
  field: attr,
8633
- oldValue: _optionalChain([hookCtx, 'access', _227 => _227.oldValues, 'optionalAccess', _228 => _228[attr]]),
8788
+ oldValue: _optionalChain([hookCtx, 'access', _229 => _229.oldValues, 'optionalAccess', _230 => _230[attr]]),
8634
8789
  newValue: hookCtx.newValues[attr]
8635
8790
  }));
8636
8791
  await this.auditService.logRecordAction({
@@ -8641,7 +8796,7 @@ var RecordService = class extends TenantAwareService {
8641
8796
  recordId: updated.id,
8642
8797
  recordLabel: updated.label,
8643
8798
  changes,
8644
- metadata: _optionalChain([options, 'optionalAccess', _229 => _229.hookMetadata])
8799
+ metadata: _optionalChain([options, 'optionalAccess', _231 => _231.hookMetadata])
8645
8800
  });
8646
8801
  }
8647
8802
  return updated;
@@ -8741,23 +8896,23 @@ var RecordService = class extends TenantAwareService {
8741
8896
  if (policy) {
8742
8897
  this.checkRecordDelete(policy, record);
8743
8898
  }
8744
- if (_optionalChain([options, 'optionalAccess', _230 => _230.checkSystem])) {
8899
+ if (_optionalChain([options, 'optionalAccess', _232 => _232.checkSystem])) {
8745
8900
  if (schema.system) {
8746
8901
  throw new ProtectedResourceError("object", schema.name, "delete");
8747
8902
  }
8748
8903
  }
8749
- if (!_optionalChain([options, 'optionalAccess', _231 => _231.skipReferenceCheck])) {
8904
+ if (!_optionalChain([options, 'optionalAccess', _233 => _233.skipReferenceCheck])) {
8750
8905
  const references = await this.adapter.objectRecords.countRecordsReferencingId(recordId);
8751
8906
  if (references.length > 0) {
8752
8907
  throw new RecordReferencedError(recordId, references);
8753
8908
  }
8754
8909
  }
8755
- const hookCtx = this.buildDeleteHookContext(schema, record, _optionalChain([options, 'optionalAccess', _232 => _232.hookMetadata]));
8756
- if (!_optionalChain([options, 'optionalAccess', _233 => _233.skipHooks])) {
8910
+ const hookCtx = this.buildDeleteHookContext(schema, record, _optionalChain([options, 'optionalAccess', _234 => _234.hookMetadata]));
8911
+ if (!_optionalChain([options, 'optionalAccess', _235 => _235.skipHooks])) {
8757
8912
  await this.hookRegistry.execute("beforeDelete", schema.name, hookCtx);
8758
8913
  }
8759
8914
  await this.adapter.objectRecords.delete(recordId);
8760
- if (!_optionalChain([options, 'optionalAccess', _234 => _234.skipHooks])) {
8915
+ if (!_optionalChain([options, 'optionalAccess', _236 => _236.skipHooks])) {
8761
8916
  await this.hookRegistry.execute("afterDelete", schema.name, hookCtx);
8762
8917
  }
8763
8918
  await this.recalculateParentRollups(record, schema);
@@ -8769,7 +8924,7 @@ var RecordService = class extends TenantAwareService {
8769
8924
  objectId: schema.id,
8770
8925
  recordId: record.id,
8771
8926
  recordLabel: record.label,
8772
- metadata: _optionalChain([options, 'optionalAccess', _235 => _235.hookMetadata])
8927
+ metadata: _optionalChain([options, 'optionalAccess', _237 => _237.hookMetadata])
8773
8928
  });
8774
8929
  }
8775
8930
  }
@@ -8800,12 +8955,12 @@ var RecordService = class extends TenantAwareService {
8800
8955
  }
8801
8956
  const schema = await this.schemaService.getObjectSchema(record.objectId);
8802
8957
  await this.checkPermission(schema.name, "update");
8803
- const hookCtx = this.buildRestoreHookContext(schema, record, _optionalChain([options, 'optionalAccess', _236 => _236.hookMetadata]));
8804
- if (!_optionalChain([options, 'optionalAccess', _237 => _237.skipHooks])) {
8958
+ const hookCtx = this.buildRestoreHookContext(schema, record, _optionalChain([options, 'optionalAccess', _238 => _238.hookMetadata]));
8959
+ if (!_optionalChain([options, 'optionalAccess', _239 => _239.skipHooks])) {
8805
8960
  await this.hookRegistry.execute("beforeRestore", schema.name, hookCtx);
8806
8961
  }
8807
8962
  const restored = await this.adapter.objectRecords.restore(recordId);
8808
- if (!_optionalChain([options, 'optionalAccess', _238 => _238.skipHooks])) {
8963
+ if (!_optionalChain([options, 'optionalAccess', _240 => _240.skipHooks])) {
8809
8964
  const afterCtx = {
8810
8965
  ...hookCtx,
8811
8966
  record: restored
@@ -8820,7 +8975,7 @@ var RecordService = class extends TenantAwareService {
8820
8975
  objectId: schema.id,
8821
8976
  recordId: restored.id,
8822
8977
  recordLabel: restored.label,
8823
- metadata: _optionalChain([options, 'optionalAccess', _239 => _239.hookMetadata])
8978
+ metadata: _optionalChain([options, 'optionalAccess', _241 => _241.hookMetadata])
8824
8979
  });
8825
8980
  }
8826
8981
  return restored;
@@ -8910,24 +9065,28 @@ var RecordService = class extends TenantAwareService {
8910
9065
  const affectedParentIds = await this.rollupService.findAffectedParentRecords(record, schema);
8911
9066
  if (affectedParentIds.length > 0) {
8912
9067
  const parentRecords = await this.adapter.objectRecords.findByIds(affectedParentIds);
8913
- for (const parentRecord of parentRecords) {
8914
- const parentSchema = await this.schemaService.getObjectSchema(parentRecord.objectId);
8915
- const rollupAttrs = parentSchema.attributes.filter(
8916
- (a) => a.type === "rollup"
8917
- );
8918
- if (rollupAttrs.length > 0) {
8919
- await this.rollupService.recalculateAndUpdate(parentRecord, parentSchema);
8920
- }
8921
- }
9068
+ await Promise.all(
9069
+ parentRecords.map(async (parentRecord) => {
9070
+ const parentSchema = await this.schemaService.getObjectSchema(parentRecord.objectId);
9071
+ const rollupAttrs = parentSchema.attributes.filter(
9072
+ (a) => a.type === "rollup"
9073
+ );
9074
+ if (rollupAttrs.length > 0) {
9075
+ await this.rollupService.recalculateAndUpdate(parentRecord, parentSchema);
9076
+ }
9077
+ })
9078
+ );
8922
9079
  }
8923
9080
  const affectedForwardRecords = await this.rollupService.findRecordsWithForwardRollup(
8924
9081
  record,
8925
9082
  schema
8926
9083
  );
8927
- for (const forwardRecord of affectedForwardRecords) {
8928
- const forwardSchema = await this.schemaService.getObjectSchema(forwardRecord.objectId);
8929
- await this.rollupService.recalculateAndUpdate(forwardRecord, forwardSchema);
8930
- }
9084
+ await Promise.all(
9085
+ affectedForwardRecords.map(async (forwardRecord) => {
9086
+ const forwardSchema = await this.schemaService.getObjectSchema(forwardRecord.objectId);
9087
+ await this.rollupService.recalculateAndUpdate(forwardRecord, forwardSchema);
9088
+ })
9089
+ );
8931
9090
  }
8932
9091
  /**
8933
9092
  * Permanently delete a record (hard delete)
@@ -8961,20 +9120,20 @@ var RecordService = class extends TenantAwareService {
8961
9120
  if (this.permissionService && this.userId) {
8962
9121
  await this.checkPermission(schema.name, "read");
8963
9122
  }
8964
- const policy = _optionalChain([options, 'optionalAccess', _240 => _240.skipPolicyFilter]) ? void 0 : this.getPolicy(schema.name);
9123
+ const policy = _optionalChain([options, 'optionalAccess', _242 => _242.skipPolicyFilter]) ? void 0 : this.getPolicy(schema.name);
8965
9124
  let effectiveOptions = options;
8966
- if (_optionalChain([policy, 'optionalAccess', _241 => _241.applyListFilter])) {
9125
+ if (_optionalChain([policy, 'optionalAccess', _243 => _243.applyListFilter])) {
8967
9126
  effectiveOptions = policy.applyListFilter(this.buildPolicyContext(schema.name), options);
8968
9127
  }
8969
9128
  const result = await this.adapter.objectRecords.list(objectId, effectiveOptions);
8970
9129
  let filteredRecords = result.records;
8971
9130
  let effectiveTotal = result.total;
8972
- if (_optionalChain([policy, 'optionalAccess', _242 => _242.canAccessRecord])) {
9131
+ if (_optionalChain([policy, 'optionalAccess', _244 => _244.canAccessRecord])) {
8973
9132
  const ctx = this.buildPolicyContext(schema.name);
8974
- filteredRecords = result.records.filter((record) => _optionalChain([policy, 'access', _243 => _243.canAccessRecord, 'optionalCall', _244 => _244(ctx, record)]));
9133
+ filteredRecords = result.records.filter((record) => _optionalChain([policy, 'access', _245 => _245.canAccessRecord, 'optionalCall', _246 => _246(ctx, record)]));
8975
9134
  effectiveTotal = filteredRecords.length;
8976
9135
  }
8977
- if (!_optionalChain([options, 'optionalAccess', _245 => _245.skipFormulas])) {
9136
+ if (!_optionalChain([options, 'optionalAccess', _247 => _247.skipFormulas])) {
8978
9137
  return {
8979
9138
  records: this.enrichRecordsWithFormulas(filteredRecords, schema),
8980
9139
  total: effectiveTotal
@@ -8999,7 +9158,7 @@ var RecordService = class extends TenantAwareService {
8999
9158
  await this.checkPermission(schema.name, "read");
9000
9159
  }
9001
9160
  const result = await this.adapter.objectRecords.search(objectId, query, options);
9002
- if (!_optionalChain([options, 'optionalAccess', _246 => _246.skipFormulas])) {
9161
+ if (!_optionalChain([options, 'optionalAccess', _248 => _248.skipFormulas])) {
9003
9162
  return {
9004
9163
  records: this.enrichRecordsWithFormulas(result.records, schema),
9005
9164
  total: result.total
@@ -9197,8 +9356,8 @@ var RollupScheduler = class {
9197
9356
  this.getSchemaById = getSchemaById;
9198
9357
  this.pending = /* @__PURE__ */ new Map();
9199
9358
  this.rollupService = new RollupService(adapter);
9200
- this.debounceMs = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _247 => _247.debounceMs]), () => ( 100));
9201
- this.maxPending = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _248 => _248.maxPending]), () => ( 100));
9359
+ this.debounceMs = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _249 => _249.debounceMs]), () => ( 100));
9360
+ this.maxPending = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _250 => _250.maxPending]), () => ( 100));
9202
9361
  }
9203
9362
  /**
9204
9363
  * Schedule a rollup recalculation for a parent record.
@@ -9274,7 +9433,7 @@ var UserProfileService = class extends TenantAwareService {
9274
9433
  constructor(adapter, options) {
9275
9434
  super();
9276
9435
  this.adapter = adapter;
9277
- this.auditService = _optionalChain([options, 'optionalAccess', _249 => _249.auditService]);
9436
+ this.auditService = _optionalChain([options, 'optionalAccess', _251 => _251.auditService]);
9278
9437
  }
9279
9438
  /**
9280
9439
  * Create a new user profile (typically after first auth).
@@ -9407,7 +9566,7 @@ var UserProfileService = class extends TenantAwareService {
9407
9566
  */
9408
9567
  async deleteProfile(profileId, options) {
9409
9568
  const profile = await this.getProfileOrThrow(profileId);
9410
- if (_optionalChain([options, 'optionalAccess', _250 => _250.checkAdmin])) {
9569
+ if (_optionalChain([options, 'optionalAccess', _252 => _252.checkAdmin])) {
9411
9570
  if (profile.role === "admin") {
9412
9571
  const adminCount = await this.adapter.userProfiles.countByRole("admin");
9413
9572
  if (adminCount <= 1) {
@@ -9476,7 +9635,7 @@ var UserProfileService = class extends TenantAwareService {
9476
9635
  */
9477
9636
  async hasRole(profileId, role) {
9478
9637
  const profile = await this.getProfile(profileId);
9479
- return _optionalChain([profile, 'optionalAccess', _251 => _251.role]) === role;
9638
+ return _optionalChain([profile, 'optionalAccess', _253 => _253.role]) === role;
9480
9639
  }
9481
9640
  /**
9482
9641
  * Check if user is admin
@@ -10310,4 +10469,7 @@ var NoopGeocodingAdapter = class {
10310
10469
 
10311
10470
 
10312
10471
 
10313
- exports.RELATION_TARGET_ANY = RELATION_TARGET_ANY; exports.isUniversalRelation = isUniversalRelation; exports.RecordReferencedError = RecordReferencedError; exports.AttributeInUseError = AttributeInUseError; exports.ObjectReferencedError = ObjectReferencedError; exports.NoopGeocodingAdapter = NoopGeocodingAdapter; exports.SYSTEM_FIELD_NAMES = SYSTEM_FIELD_NAMES; exports.RESERVED_ATTRIBUTE_NAMES = RESERVED_ATTRIBUTE_NAMES; exports.PolicyViolationError = PolicyViolationError; exports.SYSTEM_ATTRIBUTES = SYSTEM_ATTRIBUTES; exports.getSystemAttributeList = getSystemAttributeList; exports.isSystemAttribute = isSystemAttribute; exports.isSystemAttributeObject = isSystemAttributeObject; exports.asTenantId = asTenantId; exports.asUserId = asUserId; exports.generateId = generateId; exports.generatePrefixedId = generatePrefixedId; 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.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.FlowRowBuilder = FlowRowBuilder; exports.FlowPageBuilder = FlowPageBuilder; exports.FlowBuilder = FlowBuilder; exports.flow = flow; 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.TabBuilder = TabBuilder; exports.ViewBuilder = ViewBuilder; exports.view = view; exports.group = group; exports.registry = registry; exports.DEFAULT_VALIDATION_MESSAGES = DEFAULT_VALIDATION_MESSAGES; exports.textConfigSchema = textConfigSchema; exports.textareaConfigSchema = textareaConfigSchema; exports.richtextConfigSchema = richtextConfigSchema; exports.numberConfigSchema = numberConfigSchema; exports.checkboxConfigSchema = checkboxConfigSchema; exports.dateConfigSchema = dateConfigSchema; exports.phoneConfigSchema = phoneConfigSchema; exports.currencyConfigSchema = currencyConfigSchema; exports.statusConfigSchema = statusConfigSchema; exports.locationConfigSchema = locationConfigSchema; exports.selectConfigSchema = selectConfigSchema; exports.multiselectConfigSchema = multiselectConfigSchema; exports.fileConfigSchema = fileConfigSchema; exports.userConfigSchema = userConfigSchema; exports.relationConfigSchema = relationConfigSchema; exports.ratingConfigSchema = ratingConfigSchema; exports.formulaConfigSchema = formulaConfigSchema; exports.rollupConfigSchema = rollupConfigSchema; exports.attributeConfigSchemas = attributeConfigSchemas; exports.getAttributeConfigSchema = getAttributeConfigSchema; exports.validateAttributeConfig = validateAttributeConfig; exports.parseAttributeConfig = parseAttributeConfig; exports.safeParseAttributeConfig = safeParseAttributeConfig; exports.createTextValidator = createTextValidator; exports.createNumberValidator = createNumberValidator; exports.createCheckboxValidator = createCheckboxValidator; exports.createDateValidator = createDateValidator; exports.createPhoneValidator = createPhoneValidator; exports.createCurrencyValidator = createCurrencyValidator; exports.createStatusValidator = createStatusValidator; exports.createSelectValidator = createSelectValidator; exports.createMultiselectValidator = createMultiselectValidator; exports.createLocationValidator = createLocationValidator; exports.createFileValidator = createFileValidator; exports.createUserValidator = createUserValidator; exports.createSingleRelationValidator = createSingleRelationValidator; exports.createMultiRelationValidator = createMultiRelationValidator; exports.createRelationValidator = createRelationValidator; exports.createRatingValidator = createRatingValidator; exports.createFormulaValidator = createFormulaValidator; exports.createRollupValidator = createRollupValidator; exports.createTextAreaValidator = createTextAreaValidator; exports.createRichtextValidator = createRichtextValidator; exports.createAttributeValidator = createAttributeValidator; exports.createFormAttributeValidator = createFormAttributeValidator; exports.createObjectValidator = createObjectValidator; exports.validateAttribute = validateAttribute; exports.validateObject = validateObject; exports.validateObjectOrThrow = validateObjectOrThrow; exports.createDraftValidator = createDraftValidator; exports.validateDraft = validateDraft; exports.validateDraftOrThrow = validateDraftOrThrow; exports.getMissingRequiredAttributes = getMissingRequiredAttributes; exports.isRecordComplete = isRecordComplete; exports.computeRecordStatus = computeRecordStatus; 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.getContext = getContext; exports.getTenantId = getTenantId; exports.getUserId = getUserId; exports.hasContext = hasContext; exports.runWithContext = runWithContext; exports.withTenantContext = withTenantContext; exports.QueryBuilder = QueryBuilder; exports.createQueryBuilder = createQueryBuilder; 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.enrichValuesWithSelectLabels = enrichValuesWithSelectLabels; exports.createMockAdapter = createMockAdapter; exports.PolicyRegistry = PolicyRegistry; exports.defaultPolicyRegistry = defaultPolicyRegistry; exports.notesPolicy = notesPolicy; exports.buildAuditChanges = buildAuditChanges; exports.TenantAwareService = TenantAwareService; exports.TenantAwareRepository = TenantAwareRepository; exports.AuditService = AuditService; exports.FileService = FileService; exports.FlowService = FlowService; exports.GeocodingService = GeocodingService; exports.GlobalSearchService = GlobalSearchService; exports.ObjectSchemaService = ObjectSchemaService; exports.PermissionService = PermissionService; exports.RelationService = RelationService; exports.RollupService = RollupService; exports.UserService = UserService; exports.RecordService = RecordService; exports.RelationResolverService = RelationResolverService; exports.RollupScheduler = RollupScheduler; exports.UserProfileService = UserProfileService; exports.ViewService = ViewService; exports.syncNativeViews = syncNativeViews; exports.verifyNativeViewsSync = verifyNativeViewsSync; exports.getViewSyncPreview = getViewSyncPreview; exports.syncNativeObjects = syncNativeObjects; exports.verifyNativeObjectsSync = verifyNativeObjectsSync; exports.getSyncPreview = getSyncPreview; exports.syncAll = syncAll;
10472
+
10473
+
10474
+
10475
+ exports.RELATION_TARGET_ANY = RELATION_TARGET_ANY; exports.isUniversalRelation = isUniversalRelation; exports.RecordReferencedError = RecordReferencedError; exports.AttributeInUseError = AttributeInUseError; exports.ObjectReferencedError = ObjectReferencedError; exports.NoopGeocodingAdapter = NoopGeocodingAdapter; exports.SYSTEM_FIELD_NAMES = SYSTEM_FIELD_NAMES; exports.RESERVED_ATTRIBUTE_NAMES = RESERVED_ATTRIBUTE_NAMES; exports.PolicyViolationError = PolicyViolationError; exports.SYSTEM_ATTRIBUTES = SYSTEM_ATTRIBUTES; exports.getSystemAttributeList = getSystemAttributeList; exports.isSystemAttribute = isSystemAttribute; exports.isSystemAttributeObject = isSystemAttributeObject; exports.asTenantId = asTenantId; exports.asUserId = asUserId; exports.generateId = generateId; exports.generatePrefixedId = generatePrefixedId; 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.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.FlowRowBuilder = FlowRowBuilder; exports.FlowPageBuilder = FlowPageBuilder; exports.FlowBuilder = FlowBuilder; exports.flow = flow; 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.TabBuilder = TabBuilder; exports.ViewBuilder = ViewBuilder; exports.view = view; exports.group = group; exports.registry = registry; exports.DEFAULT_VALIDATION_MESSAGES = DEFAULT_VALIDATION_MESSAGES; exports.textConfigSchema = textConfigSchema; exports.textareaConfigSchema = textareaConfigSchema; exports.richtextConfigSchema = richtextConfigSchema; exports.numberConfigSchema = numberConfigSchema; exports.checkboxConfigSchema = checkboxConfigSchema; exports.dateConfigSchema = dateConfigSchema; exports.phoneConfigSchema = phoneConfigSchema; exports.currencyConfigSchema = currencyConfigSchema; exports.statusConfigSchema = statusConfigSchema; exports.locationConfigSchema = locationConfigSchema; exports.selectConfigSchema = selectConfigSchema; exports.multiselectConfigSchema = multiselectConfigSchema; exports.fileConfigSchema = fileConfigSchema; exports.userConfigSchema = userConfigSchema; exports.relationConfigSchema = relationConfigSchema; exports.ratingConfigSchema = ratingConfigSchema; exports.formulaConfigSchema = formulaConfigSchema; exports.rollupConfigSchema = rollupConfigSchema; exports.attributeConfigSchemas = attributeConfigSchemas; exports.getAttributeConfigSchema = getAttributeConfigSchema; exports.validateAttributeConfig = validateAttributeConfig; exports.parseAttributeConfig = parseAttributeConfig; exports.safeParseAttributeConfig = safeParseAttributeConfig; exports.createTextValidator = createTextValidator; exports.createNumberValidator = createNumberValidator; exports.createCheckboxValidator = createCheckboxValidator; exports.createDateValidator = createDateValidator; exports.createPhoneValidator = createPhoneValidator; exports.createCurrencyValidator = createCurrencyValidator; exports.createStatusValidator = createStatusValidator; exports.createSelectValidator = createSelectValidator; exports.createMultiselectValidator = createMultiselectValidator; exports.createLocationValidator = createLocationValidator; exports.createFileValidator = createFileValidator; exports.createUserValidator = createUserValidator; exports.createSingleRelationValidator = createSingleRelationValidator; exports.createMultiRelationValidator = createMultiRelationValidator; exports.createRelationValidator = createRelationValidator; exports.createRatingValidator = createRatingValidator; exports.createFormulaValidator = createFormulaValidator; exports.createRollupValidator = createRollupValidator; exports.createTextAreaValidator = createTextAreaValidator; exports.createRichtextValidator = createRichtextValidator; exports.createAttributeValidator = createAttributeValidator; exports.createFormAttributeValidator = createFormAttributeValidator; exports.createObjectValidator = createObjectValidator; exports.validateAttribute = validateAttribute; exports.validateObject = validateObject; exports.validateObjectOrThrow = validateObjectOrThrow; exports.createDraftValidator = createDraftValidator; exports.validateDraft = validateDraft; exports.validateDraftOrThrow = validateDraftOrThrow; exports.getMissingRequiredAttributes = getMissingRequiredAttributes; exports.isRecordComplete = isRecordComplete; exports.computeRecordStatus = computeRecordStatus; exports.cacheKeys = cacheKeys; exports.cacheTtl = cacheTtl; 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.getContext = getContext; exports.getTenantId = getTenantId; exports.getUserId = getUserId; exports.hasContext = hasContext; exports.runWithContext = runWithContext; exports.withTenantContext = withTenantContext; exports.QueryBuilder = QueryBuilder; exports.createQueryBuilder = createQueryBuilder; 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.enrichValuesWithSelectLabels = enrichValuesWithSelectLabels; exports.createMockAdapter = createMockAdapter; exports.PolicyRegistry = PolicyRegistry; exports.defaultPolicyRegistry = defaultPolicyRegistry; exports.notesPolicy = notesPolicy; exports.buildAuditChanges = buildAuditChanges; exports.TenantAwareService = TenantAwareService; exports.TenantAwareRepository = TenantAwareRepository; exports.AuditService = AuditService; exports.FileService = FileService; exports.FlowService = FlowService; exports.GeocodingService = GeocodingService; exports.GlobalSearchService = GlobalSearchService; exports.ObjectSchemaService = ObjectSchemaService; exports.PermissionService = PermissionService; exports.RelationService = RelationService; exports.RollupService = RollupService; exports.UserService = UserService; exports.RecordService = RecordService; exports.RelationResolverService = RelationResolverService; exports.RollupScheduler = RollupScheduler; exports.UserProfileService = UserProfileService; exports.ViewService = ViewService; exports.syncNativeViews = syncNativeViews; exports.verifyNativeViewsSync = verifyNativeViewsSync; exports.getViewSyncPreview = getViewSyncPreview; exports.syncNativeObjects = syncNativeObjects; exports.verifyNativeObjectsSync = verifyNativeObjectsSync; exports.getSyncPreview = getSyncPreview; exports.syncAll = syncAll;