@stndrds/schema 0.1.0-alpha.31 → 0.1.0-alpha.32

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.
@@ -1512,6 +1512,23 @@ function createMockUserProfilesRepository(stores) {
1512
1512
  stores.userProfiles.set(id, profile);
1513
1513
  }
1514
1514
  return Promise.resolve();
1515
+ },
1516
+ invite(data) {
1517
+ const tenantId = getTenantId();
1518
+ const profile = {
1519
+ id: generateId(),
1520
+ tenantId,
1521
+ authId: `invited-${generateId()}`,
1522
+ email: data.email,
1523
+ firstName: data.firstName,
1524
+ lastName: data.lastName,
1525
+ role: _nullishCoalesce(data.role, () => ( "member")),
1526
+ status: "pending",
1527
+ createdAt: /* @__PURE__ */ new Date(),
1528
+ updatedAt: /* @__PURE__ */ new Date()
1529
+ };
1530
+ stores.userProfiles.set(profile.id, profile);
1531
+ return Promise.resolve(profile);
1515
1532
  }
1516
1533
  };
1517
1534
  }
@@ -5151,11 +5168,10 @@ var GroupBuilder = class {
5151
5168
  return this.data;
5152
5169
  }
5153
5170
  };
5154
- var TableTabConfig = class {
5155
- /** @internal */
5156
- constructor(view2, base, relation2) {
5171
+ var BaseTableTabConfig = class {
5172
+ constructor(view2, tabData) {
5157
5173
  this.view = view2;
5158
- this.tabData = { ...base, type: "table", relation: relation2, columns: [] };
5174
+ this.tabData = tabData;
5159
5175
  }
5160
5176
  /**
5161
5177
  * Set columns to display
@@ -5203,11 +5219,22 @@ var TableTabConfig = class {
5203
5219
  return this;
5204
5220
  }
5205
5221
  /**
5206
- * Set default sort
5222
+ * Set default sort rules
5223
+ * @example .sorts([{ attribute: "lastName", direction: "asc" }])
5224
+ */
5225
+ sorts(value) {
5226
+ this.tabData.sorts = value;
5227
+ return this;
5228
+ }
5229
+ /**
5230
+ * Add a single sort rule (convenience method)
5207
5231
  * @example .sort("lastName") or .sort("createdAt", "desc")
5208
5232
  */
5209
- sort(field, order = "asc") {
5210
- this.tabData.sort = { field, order };
5233
+ sort(attribute, direction = "asc") {
5234
+ if (!this.tabData.sorts) {
5235
+ this.tabData.sorts = [];
5236
+ }
5237
+ this.tabData.sorts.push({ attribute, direction });
5211
5238
  return this;
5212
5239
  }
5213
5240
  /**
@@ -5238,6 +5265,31 @@ var TableTabConfig = class {
5238
5265
  this.view._addTab(this.tabData);
5239
5266
  }
5240
5267
  };
5268
+ var DirectTableTabConfig = class extends BaseTableTabConfig {
5269
+ /** @internal */
5270
+ constructor(view2, base, relationAttribute) {
5271
+ super(view2, {
5272
+ ...base,
5273
+ type: "table",
5274
+ relationMode: "direct",
5275
+ relationAttribute,
5276
+ columns: []
5277
+ });
5278
+ }
5279
+ };
5280
+ var InverseTableTabConfig = class extends BaseTableTabConfig {
5281
+ /** @internal */
5282
+ constructor(view2, base, sourceObject, relationAttribute) {
5283
+ super(view2, {
5284
+ ...base,
5285
+ type: "table",
5286
+ relationMode: "inverse",
5287
+ sourceObject,
5288
+ relationAttribute,
5289
+ columns: []
5290
+ });
5291
+ }
5292
+ };
5241
5293
  var CustomTabConfig = class {
5242
5294
  /** @internal */
5243
5295
  constructor(view2, base, component) {
@@ -5402,11 +5454,27 @@ var TabBuilder = class {
5402
5454
  return this.view._addTab(tab);
5403
5455
  }
5404
5456
  /**
5405
- * Create a table tab for a relation
5406
- * @example .table("contacts").columns("name", "email").crud()
5457
+ * Create a direct table tab for a relation attribute on the current object
5458
+ *
5459
+ * Use this when the current object has a relation attribute pointing to another object.
5460
+ *
5461
+ * @param relationAttribute - Name of the relation attribute on the current object
5462
+ * @example .table("members").columns("name", "email").crud() // Show users from Project.members
5407
5463
  */
5408
- table(relation2) {
5409
- return new TableTabConfig(this.view, this.base, relation2);
5464
+ table(relationAttribute) {
5465
+ return new DirectTableTabConfig(this.view, this.base, relationAttribute);
5466
+ }
5467
+ /**
5468
+ * Create an inverse table tab showing records from another object that have a relation to us
5469
+ *
5470
+ * Use this when another object has a relation attribute pointing to the current object.
5471
+ *
5472
+ * @param sourceObject - Name of the object that has the relation to us
5473
+ * @param relationAttribute - Name of the relation attribute on the source object
5474
+ * @example .tableFrom("contacts", "company").columns("firstName", "lastName") // Show contacts where Contact.company = this
5475
+ */
5476
+ tableFrom(sourceObject, relationAttribute) {
5477
+ return new InverseTableTabConfig(this.view, this.base, sourceObject, relationAttribute);
5410
5478
  }
5411
5479
  /**
5412
5480
  * Create a custom tab with a component
@@ -9339,6 +9407,48 @@ var UserProfileService = class extends TenantAwareService {
9339
9407
  async isAdmin(profileId) {
9340
9408
  return await this.hasRole(profileId, "admin");
9341
9409
  }
9410
+ /**
9411
+ * Invite a new user by email.
9412
+ *
9413
+ * This method:
9414
+ * 1. Sends an invitation email via the auth provider (e.g., Supabase Auth)
9415
+ * 2. Creates a user profile with status "pending"
9416
+ * 3. Returns the created profile
9417
+ *
9418
+ * The user will receive an email with a link to accept the invitation.
9419
+ * When they click the link, their auth account is activated.
9420
+ *
9421
+ * @param data - Invitation data
9422
+ * @returns Created pending user profile
9423
+ *
9424
+ * @example
9425
+ * ```typescript
9426
+ * const profile = await service.inviteUser({
9427
+ * email: "john@example.com",
9428
+ * firstName: "John",
9429
+ * lastName: "Doe",
9430
+ * role: "member",
9431
+ * redirectTo: "https://app.example.com/welcome",
9432
+ * });
9433
+ * // Email sent automatically, profile.status === "pending"
9434
+ * ```
9435
+ */
9436
+ async inviteUser(data) {
9437
+ const existingEmail = await this.adapter.userProfiles.findByEmail(data.email);
9438
+ if (existingEmail) {
9439
+ throw new Error(`User with email "${data.email}" already exists in this tenant`);
9440
+ }
9441
+ const profile = await this.adapter.userProfiles.invite(data);
9442
+ if (this.auditService && this.userId) {
9443
+ await this.auditService.logUserAction({
9444
+ action: "user.invited",
9445
+ actorId: this.userId,
9446
+ targetUserId: profile.id,
9447
+ targetUserEmail: profile.email
9448
+ });
9449
+ }
9450
+ return profile;
9451
+ }
9342
9452
  };
9343
9453
 
9344
9454
  // src/runtime/services/view.service.ts
@@ -10086,4 +10196,5 @@ var NoopGeocodingAdapter = class {
10086
10196
 
10087
10197
 
10088
10198
 
10089
- 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.TableTabConfig = TableTabConfig; 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.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.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;
10199
+
10200
+ 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.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.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;
@@ -1512,6 +1512,23 @@ function createMockUserProfilesRepository(stores) {
1512
1512
  stores.userProfiles.set(id, profile);
1513
1513
  }
1514
1514
  return Promise.resolve();
1515
+ },
1516
+ invite(data) {
1517
+ const tenantId = getTenantId();
1518
+ const profile = {
1519
+ id: generateId(),
1520
+ tenantId,
1521
+ authId: `invited-${generateId()}`,
1522
+ email: data.email,
1523
+ firstName: data.firstName,
1524
+ lastName: data.lastName,
1525
+ role: data.role ?? "member",
1526
+ status: "pending",
1527
+ createdAt: /* @__PURE__ */ new Date(),
1528
+ updatedAt: /* @__PURE__ */ new Date()
1529
+ };
1530
+ stores.userProfiles.set(profile.id, profile);
1531
+ return Promise.resolve(profile);
1515
1532
  }
1516
1533
  };
1517
1534
  }
@@ -5151,11 +5168,10 @@ var GroupBuilder = class {
5151
5168
  return this.data;
5152
5169
  }
5153
5170
  };
5154
- var TableTabConfig = class {
5155
- /** @internal */
5156
- constructor(view2, base, relation2) {
5171
+ var BaseTableTabConfig = class {
5172
+ constructor(view2, tabData) {
5157
5173
  this.view = view2;
5158
- this.tabData = { ...base, type: "table", relation: relation2, columns: [] };
5174
+ this.tabData = tabData;
5159
5175
  }
5160
5176
  /**
5161
5177
  * Set columns to display
@@ -5203,11 +5219,22 @@ var TableTabConfig = class {
5203
5219
  return this;
5204
5220
  }
5205
5221
  /**
5206
- * Set default sort
5222
+ * Set default sort rules
5223
+ * @example .sorts([{ attribute: "lastName", direction: "asc" }])
5224
+ */
5225
+ sorts(value) {
5226
+ this.tabData.sorts = value;
5227
+ return this;
5228
+ }
5229
+ /**
5230
+ * Add a single sort rule (convenience method)
5207
5231
  * @example .sort("lastName") or .sort("createdAt", "desc")
5208
5232
  */
5209
- sort(field, order = "asc") {
5210
- this.tabData.sort = { field, order };
5233
+ sort(attribute, direction = "asc") {
5234
+ if (!this.tabData.sorts) {
5235
+ this.tabData.sorts = [];
5236
+ }
5237
+ this.tabData.sorts.push({ attribute, direction });
5211
5238
  return this;
5212
5239
  }
5213
5240
  /**
@@ -5238,6 +5265,31 @@ var TableTabConfig = class {
5238
5265
  this.view._addTab(this.tabData);
5239
5266
  }
5240
5267
  };
5268
+ var DirectTableTabConfig = class extends BaseTableTabConfig {
5269
+ /** @internal */
5270
+ constructor(view2, base, relationAttribute) {
5271
+ super(view2, {
5272
+ ...base,
5273
+ type: "table",
5274
+ relationMode: "direct",
5275
+ relationAttribute,
5276
+ columns: []
5277
+ });
5278
+ }
5279
+ };
5280
+ var InverseTableTabConfig = class extends BaseTableTabConfig {
5281
+ /** @internal */
5282
+ constructor(view2, base, sourceObject, relationAttribute) {
5283
+ super(view2, {
5284
+ ...base,
5285
+ type: "table",
5286
+ relationMode: "inverse",
5287
+ sourceObject,
5288
+ relationAttribute,
5289
+ columns: []
5290
+ });
5291
+ }
5292
+ };
5241
5293
  var CustomTabConfig = class {
5242
5294
  /** @internal */
5243
5295
  constructor(view2, base, component) {
@@ -5402,11 +5454,27 @@ var TabBuilder = class {
5402
5454
  return this.view._addTab(tab);
5403
5455
  }
5404
5456
  /**
5405
- * Create a table tab for a relation
5406
- * @example .table("contacts").columns("name", "email").crud()
5457
+ * Create a direct table tab for a relation attribute on the current object
5458
+ *
5459
+ * Use this when the current object has a relation attribute pointing to another object.
5460
+ *
5461
+ * @param relationAttribute - Name of the relation attribute on the current object
5462
+ * @example .table("members").columns("name", "email").crud() // Show users from Project.members
5463
+ */
5464
+ table(relationAttribute) {
5465
+ return new DirectTableTabConfig(this.view, this.base, relationAttribute);
5466
+ }
5467
+ /**
5468
+ * Create an inverse table tab showing records from another object that have a relation to us
5469
+ *
5470
+ * Use this when another object has a relation attribute pointing to the current object.
5471
+ *
5472
+ * @param sourceObject - Name of the object that has the relation to us
5473
+ * @param relationAttribute - Name of the relation attribute on the source object
5474
+ * @example .tableFrom("contacts", "company").columns("firstName", "lastName") // Show contacts where Contact.company = this
5407
5475
  */
5408
- table(relation2) {
5409
- return new TableTabConfig(this.view, this.base, relation2);
5476
+ tableFrom(sourceObject, relationAttribute) {
5477
+ return new InverseTableTabConfig(this.view, this.base, sourceObject, relationAttribute);
5410
5478
  }
5411
5479
  /**
5412
5480
  * Create a custom tab with a component
@@ -9339,6 +9407,48 @@ var UserProfileService = class extends TenantAwareService {
9339
9407
  async isAdmin(profileId) {
9340
9408
  return await this.hasRole(profileId, "admin");
9341
9409
  }
9410
+ /**
9411
+ * Invite a new user by email.
9412
+ *
9413
+ * This method:
9414
+ * 1. Sends an invitation email via the auth provider (e.g., Supabase Auth)
9415
+ * 2. Creates a user profile with status "pending"
9416
+ * 3. Returns the created profile
9417
+ *
9418
+ * The user will receive an email with a link to accept the invitation.
9419
+ * When they click the link, their auth account is activated.
9420
+ *
9421
+ * @param data - Invitation data
9422
+ * @returns Created pending user profile
9423
+ *
9424
+ * @example
9425
+ * ```typescript
9426
+ * const profile = await service.inviteUser({
9427
+ * email: "john@example.com",
9428
+ * firstName: "John",
9429
+ * lastName: "Doe",
9430
+ * role: "member",
9431
+ * redirectTo: "https://app.example.com/welcome",
9432
+ * });
9433
+ * // Email sent automatically, profile.status === "pending"
9434
+ * ```
9435
+ */
9436
+ async inviteUser(data) {
9437
+ const existingEmail = await this.adapter.userProfiles.findByEmail(data.email);
9438
+ if (existingEmail) {
9439
+ throw new Error(`User with email "${data.email}" already exists in this tenant`);
9440
+ }
9441
+ const profile = await this.adapter.userProfiles.invite(data);
9442
+ if (this.auditService && this.userId) {
9443
+ await this.auditService.logUserAction({
9444
+ action: "user.invited",
9445
+ actorId: this.userId,
9446
+ targetUserId: profile.id,
9447
+ targetUserEmail: profile.email
9448
+ });
9449
+ }
9450
+ return profile;
9451
+ }
9342
9452
  };
9343
9453
 
9344
9454
  // src/runtime/services/view.service.ts
@@ -9950,7 +10060,8 @@ export {
9950
10060
  ObjectBuilder,
9951
10061
  object,
9952
10062
  GroupBuilder,
9953
- TableTabConfig,
10063
+ DirectTableTabConfig,
10064
+ InverseTableTabConfig,
9954
10065
  CustomTabConfig,
9955
10066
  NotesTabConfig,
9956
10067
  ActivityTabConfig,
package/dist/index.d.mts CHANGED
@@ -1,5 +1,5 @@
1
- import { D as DateAttribute, U as UserAttribute, A as Attribute, S as SystemResource, a as SystemAction, O as ObjectAction, T as TextAttribute, b as TextAreaAttribute, R as RichtextAttribute, c as RichtextFeature, N as NumberAttribute, C as CheckboxAttribute, P as PhoneAttribute, d as CurrencyAttribute, e as Option, f as StatusAttribute, g as SelectAttribute, M as MultiselectAttribute, L as LocationAttribute, F as FileAttribute, h as SingleRelationAttribute, i as MultiRelationAttribute, j as RelationTarget, k as RatingAttribute, l as FormulaAttribute, m as FormulaReturnType, n as RollupAttribute, o as RollupFunction, p as FlowDefinition, q as FlowPage, r as FlowRow, I as InferAttributeValue, s as ObjectDefinition, t as Field, u as AttributeGroupField, G as Group, V as ViewDefinition, v as Tab, B as BlockNoteContent } from './runtime-hbTw33Gx.mjs';
2
- export { bV as ActivityTab, bb as AddAttribute, ep as AddAttributeInput, aK as AdvancedFilterState, bI as AssignRoleInput, dV as AttributeChange, y as AttributeGroup, ba as AttributeMap, b6 as AttributeSchema, w as AttributeType, e5 as AttributesRepository, ah as AuditAction, ai as AuditActorType, aj as AuditChange, am as AuditListOptions, ak as AuditLogEntry, eb as AuditRepository, ag as AuditResourceType, ee as AuditService, an as AuditServiceOptions, z as BaseAttribute, $ as BlockNoteBlock, a0 as BlockNoteCustomInlineContent, a1 as BlockNoteDefaultProps, a2 as BlockNoteInlineContent, a3 as BlockNoteLink, a4 as BlockNoteStyledText, a5 as BlockNoteStyles, a6 as BlockNoteTableCell, a7 as BlockNoteTableCellProps, a8 as BlockNoteTableContent, av as CheckboxFilterOperator, bw as CompletionStatus, al as CreateAuditLogInput, eo as CreateCustomObjectInput, fd as CreateDBAttribute, fr as CreateDBFlow, f9 as CreateDBObject, fn as CreateDBView, ar as CreateFile, ej as CreateFlowInput, fg as CreateObjectRecord, bH as CreatePermissionInput, bF as CreateRoleInput, bP as CreateUserProfile, eO as CreateViewInput, Q as Currency, aC as CurrencyFilterValue, bf as CustomAttributeValue, bU as CustomTab, fc as DBAttribute, fq as DBFlow, f8 as DBObject, fm as DBView, f3 as DEFAULT_LABEL_FALLBACK, d0 as DatabaseAdapter, aw as DateFilterOperator, H as DateFormat, J as DateValue, bC as EffectivePermissions, aG as ExtendedFilterRule, bp as ExtractAttributes, bj as ExtractRecord, bl as ExtractRecordInput, bm as ExtractRecordInputStrict, bk as ExtractRecordStrict, bn as ExtractRecordUpdate, bo as ExtractRecordUpdateStrict, d1 as FetchResult, aq as File, eR as FileContent, fl as FileListOptions, ei as FileService, eh as FileServiceOptions, ap as FileVisibility, e7 as FilesRepository, aH as FilterCombinator, aJ as FilterGroup, aA as FilterOperator, aF as FilterRule, aI as FilterState, aE as FilterValue, aX as FlowRelation, aW as FlowRowField, el as FlowService, aV as FlowSlot, aY as FlowStatus, ea as FlowsRepository, bS as FormTab, d2 as FormattedRecord, dD as FormulaResult, f1 as FullSyncOptions, f0 as FullSyncResult, b4 as GeocodingAdapter, b1 as GeocodingAutocompleteParams, b3 as GeocodingParams, em as GeocodingService, b0 as GeocodingSuggestion, eB as GetRelationOptionsParams, fj as GlobalSearchOptions, fk as GlobalSearchResultItem, en as GlobalSearchService, d3 as GroupedFetchResult, dW as HookContext, dX as HookDefinition, dY as HookHandler, d$ as HookRegistry, dZ as HookType, bc as InferRecord, b7 as InferRecordFromSchema, bd as InferRecordInput, be as InferRecordUpdate, b8 as InferRecordWithRequirements, d4 as InsertOptions, dH as InvalidPathError, fh as ListOptions, W as Location, X as LocationGranularity, dI as MaxDepthExceededError, ay as MultiselectFilterOperator, aT as NO_VALUE_OPERATORS, aS as NoValueOperator, b5 as NoopGeocodingAdapter, d_ as NoopHookRegistry, bW as NotesTab, au as NumberFilterOperator, E as NumberUnit, aR as OPERATORS_BY_TYPE, bv as ObjectAttribute, bD as ObjectPermissions, bx as ObjectRecord, e8 as ObjectRecordsRepository, es as ObjectSchemaService, er as ObjectSchemaServiceOptions, e4 as ObjectsRepository, ft as OperationResult, a9 as PartialBlockNoteBlock, aa as PartialBlockNoteContent, ab as PartialBlockNoteInlineContent, ac as PartialBlockNoteLink, ad as PartialBlockNoteStyledText, ae as PartialBlockNoteTableCell, af as PartialBlockNoteTableContent, dM as PathCardinality, dN as PathSegment, dO as PathSegmentType, bA as Permission, by as PermissionScope, eu as PermissionService, et as PermissionServiceOptions, ec as PermissionsRepository, K as Phone, aD as PhoneFilterValue, bJ as PolicyContext, e2 as PolicyRegistry, bL as PolicyViolationError, dg as QueryBuilder, dh as QueryBuilderOptions, d5 as QueryBuilderState, dc as QueryMultipleResultsError, dd as QueryNoResultError, aQ as QueryState, Y as RELATION_TARGET_ANY, bq as RESERVED_ATTRIBUTE_NAMES, bh as RecordMetadata, bK as RecordPolicy, ew as RecordService, ev as RecordServiceOptions, d6 as RegistryMap, d7 as RegistryObjectNames, Z as RelationAttribute, az as RelationFilterOperator, ez as RelationOption, eA as RelationOptionsResponse, eE as RelationResolverService, eC as RelationService, ey as RelationValidationError, ex as RelationValidationResult, aB as RelativeDateValue, bs as ReservedAttributeName, eD as ResolvedRelations, b2 as ReverseGeocodingParams, bz as Role, eF as RollupResult, eI as RollupScheduler, eH as RollupSchedulerOptions, eG as RollupService, de as SHORTCUT_TO_FILTER_OPERATOR, br as SYSTEM_FIELD_NAMES, dP as SchemaResolver, fi as SearchOptions, ax as SelectFilterOperator, d8 as ShortcutOperator, eU as SignedUrlOptions, aO as SortDirection, aP as SortRule, x as StatusGroup, eV as StorageAdapter, ao as StorageProvider, eS as StorageUploadInput, eT as StorageUploadResult, eY as SyncOptions, eX as SyncResult, bt as SystemFieldName, bi as SystemFields, bE as SystemPermissions, bR as TabType, bT as TableTab, eg as TenantAwareRepository, ef as TenantAwareService, dq as TenantContext, di as TenantContextError, c1 as TenantId, at as TextFilterOperator, bu as Timestamps, dT as TraversalOptions, dU as TraversalResult, b9 as TypedAttribute, fe as UpdateDBAttribute, fs as UpdateDBFlow, fa as UpdateDBObject, fo as UpdateDBView, as as UpdateFile, ek as UpdateFlowInput, eq as UpdateObjectInput, bG as UpdateRoleInput, bQ as UpdateUserProfile, eP as UpdateViewInput, eW as UploadFileInput, ff as UpsertDBAttribute, fb as UpsertDBObject, fp as UpsertDBView, c2 as UserId, bO as UserProfile, eK as UserProfileService, eJ as UserProfileServiceOptions, e6 as UserProfilesRepository, bM as UserRole, bB as UserRoleAssignment, eN as UserService, bN as UserStatus, eM as UserValidationError, eL as UserValidationResult, c0 as Uuid, cS as ValidationResult, eQ as ViewService, fv as ViewSyncOptions, fu as ViewSyncResult, e9 as ViewsRepository, bg as WithCustomAttributes, c3 as asTenantId, c4 as asUserId, cr as attributeConfigSchemas, ed as buildAuditChanges, cd as checkboxConfigSchema, c$ as computeRecordStatus, cQ as createAttributeValidator, cy as createCheckboxValidator, cB as createCurrencyValidator, cz as createDateValidator, d9 as createDefaultState, cW as createDraftValidator, cG as createFileValidator, cM as createFormulaValidator, cF as createLocationValidator, e0 as createMockAdapter, cJ as createMultiRelationValidator, cE as createMultiselectValidator, cx as createNumberValidator, cR as createObjectValidator, cA as createPhoneValidator, df as createQueryBuilder, cL as createRatingValidator, cK as createRelationValidator, cP as createRichtextValidator, cN as createRollupValidator, cD as createSelectValidator, cI as createSingleRelationValidator, cC as createStatusValidator, cO as createTextAreaValidator, cw as createTextValidator, cH as createUserValidator, cg as currencyConfigSchema, ce as dateConfigSchema, e1 as defaultPolicyRegistry, f7 as enrichValuesWithSelectLabels, dr as evaluateFormula, ds as evaluateFormulaAttribute, dt as evaluateFormulaAttributeWithRelations, du as evaluateFormulaWithRelations, dv as evaluateFormulaWithResult, f6 as extractAttributeNames, dw as extractFormulaVariables, dx as extractRelationNames, dy as extractRelationReferences, cl as fileConfigSchema, dz as flattenRelationsForEval, dA as formatFormulaResult, da as formatRecord, db as formatRecords, cp as formulaConfigSchema, c5 as generateId, c6 as generatePrefixedId, cs as getAttributeConfigSchema, dj as getContext, cZ as getMissingRequiredAttributes, dE as getPathDepth, dF as getRelationPath, e$ as getSyncPreview, dG as getTargetAttributeName, dk as getTenantId, dl as getUserId, fy as getViewSyncPreview, dm as hasContext, dB as hasRelationReferences, b_ as isActivityTab, aL as isAdvancedFilterState, bZ as isCustomTab, aZ as isFlowDefinition, a_ as isFlowPublished, bX as isFormTab, f5 as isLabelExpression, aU as isNoValueOperator, b$ as isNotesTab, c_ as isRecordComplete, a$ as isSystemFlow, bY as isTableTab, _ as isUniversalRelation, ci as locationConfigSchema, ck as multiselectConfigSchema, e3 as notesPolicy, cc as numberConfigSchema, cu as parseAttributeConfig, dJ as parsePath, dK as pathHasManyCardinality, cf as phoneConfigSchema, co as ratingConfigSchema, c7 as registry, cn as relationConfigSchema, f4 as renderLabelExpression, dQ as resolveMultiplePaths, dR as resolveSingleValue, cb as richtextConfigSchema, cq as rollupConfigSchema, dn as runWithContext, cv as safeParseAttributeConfig, cj as selectConfigSchema, ch as statusConfigSchema, f2 as syncAll, eZ as syncNativeObjects, fw as syncNativeViews, c9 as textConfigSchema, ca as textareaConfigSchema, aM as toAdvancedFilterState, aN as toSimpleFilterState, dS as traversePath, cm as userConfigSchema, cT as validateAttribute, ct as validateAttributeConfig, cX as validateDraft, cY as validateDraftOrThrow, dC as validateFormulaExpression, cU as validateObject, cV as validateObjectOrThrow, dL as validatePath, e_ as verifyNativeObjectsSync, fx as verifyNativeViewsSync, c8 as viewRegistry, dp as withTenantContext } from './runtime-hbTw33Gx.mjs';
1
+ import { D as DateAttribute, U as UserAttribute, A as Attribute, S as SystemResource, a as SystemAction, O as ObjectAction, T as TextAttribute, b as TextAreaAttribute, R as RichtextAttribute, c as RichtextFeature, N as NumberAttribute, C as CheckboxAttribute, P as PhoneAttribute, d as CurrencyAttribute, e as Option, f as StatusAttribute, g as SelectAttribute, M as MultiselectAttribute, L as LocationAttribute, F as FileAttribute, h as SingleRelationAttribute, i as MultiRelationAttribute, j as RelationTarget, k as RatingAttribute, l as FormulaAttribute, m as FormulaReturnType, n as RollupAttribute, o as RollupFunction, p as FlowDefinition, q as FlowPage, r as FlowRow, I as InferAttributeValue, s as ObjectDefinition, t as Field, u as AttributeGroupField, G as Group, v as TableTab, w as InverseTableTab, V as ViewDefinition, x as Tab, y as FilterState, z as SortRule, B as DirectTableTab, E as BlockNoteContent } from './runtime-DyTAIaum.mjs';
2
+ export { bY as ActivityTab, be as AddAttribute, eu as AddAttributeInput, aO as AdvancedFilterState, bL as AssignRoleInput, d_ as AttributeChange, K as AttributeGroup, bd as AttributeMap, b9 as AttributeSchema, H as AttributeType, ea as AttributesRepository, am as AuditAction, an as AuditActorType, ao as AuditChange, ar as AuditListOptions, ap as AuditLogEntry, eg as AuditRepository, al as AuditResourceType, ej as AuditService, as as AuditServiceOptions, Q as BaseAttribute, a4 as BlockNoteBlock, a5 as BlockNoteCustomInlineContent, a6 as BlockNoteDefaultProps, a7 as BlockNoteInlineContent, a8 as BlockNoteLink, a9 as BlockNoteStyledText, aa as BlockNoteStyles, ab as BlockNoteTableCell, ac as BlockNoteTableCellProps, ad as BlockNoteTableContent, aA as CheckboxFilterOperator, bz as CompletionStatus, aq as CreateAuditLogInput, et as CreateCustomObjectInput, fi as CreateDBAttribute, fw as CreateDBFlow, fe as CreateDBObject, fs as CreateDBView, aw as CreateFile, eo as CreateFlowInput, fl as CreateObjectRecord, bK as CreatePermissionInput, bI as CreateRoleInput, bS as CreateUserProfile, eT as CreateViewInput, _ as Currency, aH as CurrencyFilterValue, bi as CustomAttributeValue, bX as CustomTab, fh as DBAttribute, fv as DBFlow, fd as DBObject, fr as DBView, f8 as DEFAULT_LABEL_FALLBACK, d5 as DatabaseAdapter, aB as DateFilterOperator, X as DateFormat, Y as DateValue, bF as EffectivePermissions, aL as ExtendedFilterRule, bs as ExtractAttributes, bm as ExtractRecord, bo as ExtractRecordInput, bp as ExtractRecordInputStrict, bn as ExtractRecordStrict, bq as ExtractRecordUpdate, br as ExtractRecordUpdateStrict, d6 as FetchResult, av as File, eW as FileContent, fq as FileListOptions, en as FileService, em as FileServiceOptions, au as FileVisibility, ec as FilesRepository, aM as FilterCombinator, aN as FilterGroup, aF as FilterOperator, aK as FilterRule, aJ as FilterValue, a_ as FlowRelation, aZ as FlowRowField, eq as FlowService, aY as FlowSlot, a$ as FlowStatus, ef as FlowsRepository, bW as FormTab, d7 as FormattedRecord, dI as FormulaResult, f6 as FullSyncOptions, f5 as FullSyncResult, b7 as GeocodingAdapter, b4 as GeocodingAutocompleteParams, b6 as GeocodingParams, er as GeocodingService, b3 as GeocodingSuggestion, eG as GetRelationOptionsParams, fo as GlobalSearchOptions, fp as GlobalSearchResultItem, es as GlobalSearchService, d8 as GroupedFetchResult, d$ as HookContext, e0 as HookDefinition, e1 as HookHandler, e4 as HookRegistry, e2 as HookType, bf as InferRecord, ba as InferRecordFromSchema, bg as InferRecordInput, bh as InferRecordUpdate, bb as InferRecordWithRequirements, d9 as InsertOptions, dM as InvalidPathError, bU as InviteUserInput, fm as ListOptions, $ as Location, a0 as LocationGranularity, dN as MaxDepthExceededError, aD as MultiselectFilterOperator, aW as NO_VALUE_OPERATORS, aV as NoValueOperator, b8 as NoopGeocodingAdapter, e3 as NoopHookRegistry, bZ as NotesTab, az as NumberFilterOperator, W as NumberUnit, aU as OPERATORS_BY_TYPE, by as ObjectAttribute, bG as ObjectPermissions, bA as ObjectRecord, ed as ObjectRecordsRepository, ex as ObjectSchemaService, ew as ObjectSchemaServiceOptions, e9 as ObjectsRepository, fy as OperationResult, ae as PartialBlockNoteBlock, af as PartialBlockNoteContent, ag as PartialBlockNoteInlineContent, ah as PartialBlockNoteLink, ai as PartialBlockNoteStyledText, aj as PartialBlockNoteTableCell, ak as PartialBlockNoteTableContent, dR as PathCardinality, dS as PathSegment, dT as PathSegmentType, bD as Permission, bB as PermissionScope, ez as PermissionService, ey as PermissionServiceOptions, eh as PermissionsRepository, Z as Phone, aI as PhoneFilterValue, bM as PolicyContext, e7 as PolicyRegistry, bO as PolicyViolationError, dl as QueryBuilder, dm as QueryBuilderOptions, da as QueryBuilderState, dh as QueryMultipleResultsError, di as QueryNoResultError, aT as QueryState, a1 as RELATION_TARGET_ANY, bt as RESERVED_ATTRIBUTE_NAMES, bk as RecordMetadata, bN as RecordPolicy, eB as RecordService, eA as RecordServiceOptions, db as RegistryMap, dc as RegistryObjectNames, a2 as RelationAttribute, aE as RelationFilterOperator, eE as RelationOption, eF as RelationOptionsResponse, eJ as RelationResolverService, eH as RelationService, eD as RelationValidationError, eC as RelationValidationResult, aG as RelativeDateValue, bv as ReservedAttributeName, eI as ResolvedRelations, b5 as ReverseGeocodingParams, bC as Role, eK as RollupResult, eN as RollupScheduler, eM as RollupSchedulerOptions, eL as RollupService, dj as SHORTCUT_TO_FILTER_OPERATOR, bu as SYSTEM_FIELD_NAMES, dU as SchemaResolver, fn as SearchOptions, aC as SelectFilterOperator, dd as ShortcutOperator, eZ as SignedUrlOptions, aS as SortDirection, J as StatusGroup, e_ as StorageAdapter, at as StorageProvider, eX as StorageUploadInput, eY as StorageUploadResult, f1 as SyncOptions, f0 as SyncResult, bw as SystemFieldName, bl as SystemFields, bH as SystemPermissions, bV as TabType, el as TenantAwareRepository, ek as TenantAwareService, dv as TenantContext, dn as TenantContextError, c6 as TenantId, ay as TextFilterOperator, bx as Timestamps, dY as TraversalOptions, dZ as TraversalResult, bc as TypedAttribute, fj as UpdateDBAttribute, fx as UpdateDBFlow, ff as UpdateDBObject, ft as UpdateDBView, ax as UpdateFile, ep as UpdateFlowInput, ev as UpdateObjectInput, bJ as UpdateRoleInput, bT as UpdateUserProfile, eU as UpdateViewInput, e$ as UploadFileInput, fk as UpsertDBAttribute, fg as UpsertDBObject, fu as UpsertDBView, c7 as UserId, bR as UserProfile, eP as UserProfileService, eO as UserProfileServiceOptions, eb as UserProfilesRepository, bP as UserRole, bE as UserRoleAssignment, eS as UserService, bQ as UserStatus, eR as UserValidationError, eQ as UserValidationResult, c5 as Uuid, cX as ValidationResult, eV as ViewService, fA as ViewSyncOptions, fz as ViewSyncResult, ee as ViewsRepository, bj as WithCustomAttributes, c8 as asTenantId, c9 as asUserId, cw as attributeConfigSchemas, ei as buildAuditChanges, ci as checkboxConfigSchema, d4 as computeRecordStatus, cV as createAttributeValidator, cD as createCheckboxValidator, cG as createCurrencyValidator, cE as createDateValidator, de as createDefaultState, c$ as createDraftValidator, cL as createFileValidator, cR as createFormulaValidator, cK as createLocationValidator, e5 as createMockAdapter, cO as createMultiRelationValidator, cJ as createMultiselectValidator, cC as createNumberValidator, cW as createObjectValidator, cF as createPhoneValidator, dk as createQueryBuilder, cQ as createRatingValidator, cP as createRelationValidator, cU as createRichtextValidator, cS as createRollupValidator, cI as createSelectValidator, cN as createSingleRelationValidator, cH as createStatusValidator, cT as createTextAreaValidator, cB as createTextValidator, cM as createUserValidator, cl as currencyConfigSchema, cj as dateConfigSchema, e6 as defaultPolicyRegistry, fc as enrichValuesWithSelectLabels, dw as evaluateFormula, dx as evaluateFormulaAttribute, dy as evaluateFormulaAttributeWithRelations, dz as evaluateFormulaWithRelations, dA as evaluateFormulaWithResult, fb as extractAttributeNames, dB as extractFormulaVariables, dC as extractRelationNames, dD as extractRelationReferences, cq as fileConfigSchema, dE as flattenRelationsForEval, dF as formatFormulaResult, df as formatRecord, dg as formatRecords, cu as formulaConfigSchema, ca as generateId, cb as generatePrefixedId, cx as getAttributeConfigSchema, dp as getContext, d2 as getMissingRequiredAttributes, dJ as getPathDepth, dK as getRelationPath, f4 as getSyncPreview, dL as getTargetAttributeName, dq as getTenantId, dr as getUserId, fD as getViewSyncPreview, ds as hasContext, dG as hasRelationReferences, c3 as isActivityTab, aP as isAdvancedFilterState, c2 as isCustomTab, c0 as isDirectTableTab, b0 as isFlowDefinition, b1 as isFlowPublished, b_ as isFormTab, c1 as isInverseTableTab, fa as isLabelExpression, aX as isNoValueOperator, c4 as isNotesTab, d3 as isRecordComplete, b2 as isSystemFlow, b$ as isTableTab, a3 as isUniversalRelation, cn as locationConfigSchema, cp as multiselectConfigSchema, e8 as notesPolicy, ch as numberConfigSchema, cz as parseAttributeConfig, dO as parsePath, dP as pathHasManyCardinality, ck as phoneConfigSchema, ct as ratingConfigSchema, cc as registry, cs as relationConfigSchema, f9 as renderLabelExpression, dV as resolveMultiplePaths, dW as resolveSingleValue, cg as richtextConfigSchema, cv as rollupConfigSchema, dt as runWithContext, cA as safeParseAttributeConfig, co as selectConfigSchema, cm as statusConfigSchema, f7 as syncAll, f2 as syncNativeObjects, fB as syncNativeViews, ce as textConfigSchema, cf as textareaConfigSchema, aQ as toAdvancedFilterState, aR as toSimpleFilterState, dX as traversePath, cr as userConfigSchema, cY as validateAttribute, cy as validateAttributeConfig, d0 as validateDraft, d1 as validateDraftOrThrow, dH as validateFormulaExpression, cZ as validateObject, c_ as validateObjectOrThrow, dQ as validatePath, f3 as verifyNativeObjectsSync, fC as verifyNativeViewsSync, cd as viewRegistry, du as withTenantContext } from './runtime-DyTAIaum.mjs';
3
3
  import { IconName, CountryIso3, CurrencyCode, MimeType, ColorId } from '@stndrds/constants';
4
4
  import 'zod';
5
5
 
@@ -1463,13 +1463,12 @@ interface BaseTabConfig {
1463
1463
  system?: boolean;
1464
1464
  }
1465
1465
  /**
1466
- * Builder for configuring table tabs
1466
+ * Base builder for configuring table tabs (shared between Direct and Inverse)
1467
1467
  */
1468
- declare class TableTabConfig {
1469
- private view;
1470
- private tabData;
1471
- /** @internal */
1472
- constructor(view: ViewBuilder, base: BaseTabConfig, relation: string);
1468
+ declare abstract class BaseTableTabConfig<T extends TableTab> {
1469
+ protected view: ViewBuilder;
1470
+ protected tabData: Partial<T>;
1471
+ constructor(view: ViewBuilder, tabData: Partial<T>);
1473
1472
  /**
1474
1473
  * Set columns to display
1475
1474
  * @example .columns("firstName", "lastName", "email")
@@ -1494,12 +1493,17 @@ declare class TableTabConfig {
1494
1493
  /**
1495
1494
  * Set default filters
1496
1495
  */
1497
- filters(value: Record<string, unknown>): this;
1496
+ filters(value: FilterState): this;
1498
1497
  /**
1499
- * Set default sort
1498
+ * Set default sort rules
1499
+ * @example .sorts([{ attribute: "lastName", direction: "asc" }])
1500
+ */
1501
+ sorts(value: SortRule[]): this;
1502
+ /**
1503
+ * Add a single sort rule (convenience method)
1500
1504
  * @example .sort("lastName") or .sort("createdAt", "desc")
1501
1505
  */
1502
- sort(field: string, order?: "asc" | "desc"): this;
1506
+ sort(attribute: string, direction?: "asc" | "desc"): this;
1503
1507
  /**
1504
1508
  * Continue building with a new tab
1505
1509
  */
@@ -1512,7 +1516,37 @@ declare class TableTabConfig {
1512
1516
  * Build the final view definition
1513
1517
  */
1514
1518
  build(): ViewDefinition;
1515
- private finalize;
1519
+ protected finalize(): void;
1520
+ }
1521
+ /**
1522
+ * Builder for configuring direct table tabs (relation attribute on current object)
1523
+ *
1524
+ * @example
1525
+ * ```typescript
1526
+ * .tab("members", "Members")
1527
+ * .table("members") // Direct: uses the "members" relation attribute on current object
1528
+ * .columns("name", "email")
1529
+ * .crud()
1530
+ * ```
1531
+ */
1532
+ declare class DirectTableTabConfig extends BaseTableTabConfig<DirectTableTab> {
1533
+ /** @internal */
1534
+ constructor(view: ViewBuilder, base: BaseTabConfig, relationAttribute: string);
1535
+ }
1536
+ /**
1537
+ * Builder for configuring inverse table tabs (another object has relation to us)
1538
+ *
1539
+ * @example
1540
+ * ```typescript
1541
+ * .tab("contacts", "Contacts")
1542
+ * .tableFrom("contacts", "company") // Inverse: Contact.company points to us
1543
+ * .columns("firstName", "lastName", "email")
1544
+ * .crud()
1545
+ * ```
1546
+ */
1547
+ declare class InverseTableTabConfig extends BaseTableTabConfig<InverseTableTab> {
1548
+ /** @internal */
1549
+ constructor(view: ViewBuilder, base: BaseTabConfig, sourceObject: string, relationAttribute: string);
1516
1550
  }
1517
1551
  /**
1518
1552
  * Builder for configuring custom tabs
@@ -1626,10 +1660,24 @@ declare class TabBuilder {
1626
1660
  */
1627
1661
  form(...groups: (GroupBuilder | Group)[]): ViewBuilder;
1628
1662
  /**
1629
- * Create a table tab for a relation
1630
- * @example .table("contacts").columns("name", "email").crud()
1663
+ * Create a direct table tab for a relation attribute on the current object
1664
+ *
1665
+ * Use this when the current object has a relation attribute pointing to another object.
1666
+ *
1667
+ * @param relationAttribute - Name of the relation attribute on the current object
1668
+ * @example .table("members").columns("name", "email").crud() // Show users from Project.members
1631
1669
  */
1632
- table(relation: string): TableTabConfig;
1670
+ table(relationAttribute: string): DirectTableTabConfig;
1671
+ /**
1672
+ * Create an inverse table tab showing records from another object that have a relation to us
1673
+ *
1674
+ * Use this when another object has a relation attribute pointing to the current object.
1675
+ *
1676
+ * @param sourceObject - Name of the object that has the relation to us
1677
+ * @param relationAttribute - Name of the relation attribute on the source object
1678
+ * @example .tableFrom("contacts", "company").columns("firstName", "lastName") // Show contacts where Contact.company = this
1679
+ */
1680
+ tableFrom(sourceObject: string, relationAttribute: string): InverseTableTabConfig;
1633
1681
  /**
1634
1682
  * Create a custom tab with a component
1635
1683
  * @example .custom("AnalyticsWidget").props({ period: "12m" })
@@ -1663,11 +1711,17 @@ declare class TabBuilder {
1663
1711
  * group("address", "Address").fields("location").collapsible()
1664
1712
  * )
1665
1713
  *
1714
+ * // Inverse: show Contact records where Contact.company = this Company
1666
1715
  * .tab("contacts", "Contacts").icon("users")
1667
- * .table("contacts")
1716
+ * .tableFrom("contacts", "company")
1668
1717
  * .columns("firstName", "lastName", "email")
1669
1718
  * .crud()
1670
1719
  *
1720
+ * // Direct: show User records linked via Company.members
1721
+ * .tab("members", "Members").icon("users")
1722
+ * .table("members")
1723
+ * .columns("name", "email")
1724
+ *
1671
1725
  * .tab("analytics", "Stats").icon("bar-chart")
1672
1726
  * .custom("CompanyAnalytics")
1673
1727
  * .props({ period: "12m" })
@@ -1810,4 +1864,4 @@ declare const NOTES: ObjectBuilder<{
1810
1864
  linkedTo?: string | undefined;
1811
1865
  }>;
1812
1866
 
1813
- export { ALL_SYSTEM_RESOURCES, ActivityTabConfig, type AnyAttributeBuilder, Attribute, AttributeGroupField, AttributeInUseError, AttributeNotFoundError, type AttributeUsage, BlockNoteContent, type BuilderConfig, CheckboxAttribute, CurrencyAttribute, CustomTabConfig, DEFAULT_ROLES, DEFAULT_ROLE_DESCRIPTIONS, DEFAULT_ROLE_LABELS, DEFAULT_ROLE_PERMISSIONS, DateAttribute, type DefaultRoleName, type DefaultRolePermissionConfig, DuplicateError, EMPTY_VALUE_PLACEHOLDER, type ExtractAttributeName, type ExtractAttributeRequired, Field, FileAttribute, FileNotFoundError, FlowBuilder, FlowDefinition, FlowPage, FlowPageBuilder, FlowRow, FlowRowBuilder, ForbiddenError, FormulaAttribute, FormulaReturnType, Group, GroupBuilder, InferAttributeValue, LocationAttribute, MultiRelationAttribute, MultiselectAttribute, NOTES, NotFoundError, NotSystemObjectError, NotesTabConfig, NumberAttribute, ObjectAction, ObjectBuilder, ObjectDefinition, ObjectNotFoundError, ObjectReferencedError, Option, PhoneAttribute, ProtectedResourceError, ProtectedRoleError, RatingAttribute, RecordNotFoundError, type RecordReference, RecordReferencedError, RelationTarget, RichtextAttribute, RichtextFeature, RoleNotFoundError, RollupAttribute, RollupFunction, SYSTEM_ATTRIBUTES, SYSTEM_RESOURCES, SYSTEM_RESOURCE_LABELS, SchemaError, SchemaErrorCode, SelectAttribute, SingleRelationAttribute, StatusAttribute, SyncError, SystemAction, type SystemAttribute, type SystemAttributeName, SystemResource, Tab, TabBuilder, TableTabConfig, TextAreaAttribute, TextAttribute, type TypedBuilderConfig, UserAttribute, UserProfileNotFoundError, ValidationError, type ValidationErrorDetail, ViewBuilder, ViewDefinition, checkbox, currency, date, file, flow, formatAttributeValue, formula, getSystemAttributeList, group, isDefaultRole, isForbiddenError, isNotFoundError, isProtectedResourceError, isSchemaError, isSystemAttribute, isSystemAttributeObject, isValidationError, location, multiselect, number, object, phone, rating, relation, richtext, rollup, select, status, text, textarea, user, view };
1867
+ export { ALL_SYSTEM_RESOURCES, ActivityTabConfig, type AnyAttributeBuilder, Attribute, AttributeGroupField, AttributeInUseError, AttributeNotFoundError, type AttributeUsage, BlockNoteContent, type BuilderConfig, CheckboxAttribute, CurrencyAttribute, CustomTabConfig, DEFAULT_ROLES, DEFAULT_ROLE_DESCRIPTIONS, DEFAULT_ROLE_LABELS, DEFAULT_ROLE_PERMISSIONS, DateAttribute, type DefaultRoleName, type DefaultRolePermissionConfig, DirectTableTab, DirectTableTabConfig, DuplicateError, EMPTY_VALUE_PLACEHOLDER, type ExtractAttributeName, type ExtractAttributeRequired, Field, FileAttribute, FileNotFoundError, FilterState, FlowBuilder, FlowDefinition, FlowPage, FlowPageBuilder, FlowRow, FlowRowBuilder, ForbiddenError, FormulaAttribute, FormulaReturnType, Group, GroupBuilder, InferAttributeValue, InverseTableTab, InverseTableTabConfig, LocationAttribute, MultiRelationAttribute, MultiselectAttribute, NOTES, NotFoundError, NotSystemObjectError, NotesTabConfig, NumberAttribute, ObjectAction, ObjectBuilder, ObjectDefinition, ObjectNotFoundError, ObjectReferencedError, Option, PhoneAttribute, ProtectedResourceError, ProtectedRoleError, RatingAttribute, RecordNotFoundError, type RecordReference, RecordReferencedError, RelationTarget, RichtextAttribute, RichtextFeature, RoleNotFoundError, RollupAttribute, RollupFunction, SYSTEM_ATTRIBUTES, SYSTEM_RESOURCES, SYSTEM_RESOURCE_LABELS, SchemaError, SchemaErrorCode, SelectAttribute, SingleRelationAttribute, SortRule, StatusAttribute, SyncError, SystemAction, type SystemAttribute, type SystemAttributeName, SystemResource, Tab, TabBuilder, TableTab, TextAreaAttribute, TextAttribute, type TypedBuilderConfig, UserAttribute, UserProfileNotFoundError, ValidationError, type ValidationErrorDetail, ViewBuilder, ViewDefinition, checkbox, currency, date, file, flow, formatAttributeValue, formula, getSystemAttributeList, group, isDefaultRole, isForbiddenError, isNotFoundError, isProtectedResourceError, isSchemaError, isSystemAttribute, isSystemAttributeObject, isValidationError, location, multiselect, number, object, phone, rating, relation, richtext, rollup, select, status, text, textarea, user, view };