{
  "schemaVersion": 1,
  "sensitiveFieldsExcluded": true,
  "generatedAt": "1970-01-01T00:00:00.000Z",
  "packageName": "@happyvertical/smrt-users",
  "packageVersion": "0.43.3",
  "sourceManifestPath": "dist/manifest.json",
  "agentDocPath": "AGENTS.md",
  "sourceHashes": {
    "manifest": "302ea519c8f45474c1a5a3c7b616c43feec2678a8c9a948e7b6fca33244a26c6",
    "packageJson": "4576b05f511cd73d9dbc6e16036e80e86cf550188110666fa87af0a69b75450d",
    "agents": "6ec265b8af7cdfa9fea1a3f128af9bf25cbcdb1353c34a81a7fc5b0d2e4a8f2b",
    "moduleDoc:agents/retention.md": "425c0a34ed33969badfef699751bfa670bdf618eda65e079e00815620aabed68"
  },
  "exports": [
    ".",
    "./app-contract",
    "./manifest",
    "./manifest.json",
    "./playground",
    "./svelte",
    "./sveltekit"
  ],
  "dependencies": {
    "@happyvertical/logger": "catalog:",
    "@happyvertical/smrt-config": "workspace:*",
    "@happyvertical/smrt-core": "workspace:*",
    "@happyvertical/smrt-mobile-contract": "workspace:*",
    "@happyvertical/smrt-profiles": "workspace:*",
    "@happyvertical/smrt-tenancy": "workspace:*",
    "@happyvertical/smrt-types": "workspace:*",
    "@happyvertical/smrt-ui": "workspace:*",
    "@happyvertical/sql": "catalog:",
    "jose": "^6.2.3",
    "@happyvertical/smrt-vitest": "workspace:*",
    "@sveltejs/package": "^2.5.8",
    "@sveltejs/vite-plugin-svelte": "^7.1.2",
    "@types/node": "24.13.2",
    "fast-glob": "^3.3.3",
    "svelte": "^5.56.4",
    "svelte-check": "^4.7.1",
    "typescript": "5.9.3",
    "vite": "8.1.4",
    "vitest": "4.1.10"
  },
  "smrtDependencies": [
    "@happyvertical/smrt-config",
    "@happyvertical/smrt-core",
    "@happyvertical/smrt-mobile-contract",
    "@happyvertical/smrt-profiles",
    "@happyvertical/smrt-tenancy",
    "@happyvertical/smrt-types",
    "@happyvertical/smrt-ui",
    "@happyvertical/smrt-vitest"
  ],
  "sdkDependencies": [
    "@happyvertical/logger",
    "@happyvertical/sql"
  ],
  "tags": [],
  "risks": [],
  "objects": [
    {
      "name": "AccessRequestCollection",
      "qualifiedName": "@happyvertical/smrt-users:AccessRequestCollection",
      "collection": "accessrequests",
      "tableName": "access_requests",
      "packageName": "@happyvertical/smrt-users",
      "extends": "SmrtCollection",
      "fields": [],
      "relationships": [],
      "methods": [
        "findByEmail",
        "findByStatus",
        "findOpen",
        "findOpenByEmail"
      ],
      "methodSignatures": [
        {
          "name": "findByEmail",
          "async": true,
          "params": [
            "email: string"
          ],
          "returns": "Promise<AccessRequest[]>"
        },
        {
          "name": "findByStatus",
          "async": true,
          "params": [
            "status: AccessRequestStatus"
          ],
          "returns": "Promise<AccessRequest[]>"
        },
        {
          "name": "findOpen",
          "async": true,
          "returns": "Promise<AccessRequest[]>"
        },
        {
          "name": "findOpenByEmail",
          "async": true,
          "params": [
            "email: string"
          ],
          "returns": "Promise<AccessRequest | null>"
        }
      ],
      "surfaces": [],
      "relationshipFeatures": [
        "uuidColumns"
      ],
      "tags": [],
      "risks": []
    },
    {
      "name": "UsersCliAuthApproveLimitCollection",
      "qualifiedName": "@happyvertical/smrt-users:UsersCliAuthApproveLimitCollection",
      "collection": "userscliauthapprovelimits",
      "tableName": "users_cli_auth_approve_limits",
      "packageName": "@happyvertical/smrt-users",
      "extends": "SmrtCollection",
      "fields": [],
      "relationships": [],
      "methods": [
        "releaseAttempt",
        "reserveAttempt"
      ],
      "methodSignatures": [
        {
          "name": "releaseAttempt",
          "async": true,
          "params": [
            "userId: string",
            "windowStartedAt: string"
          ],
          "returns": "Promise<void>"
        },
        {
          "name": "reserveAttempt",
          "async": true,
          "params": [
            "input: object"
          ],
          "returns": "Promise<CliAuthApproveReservation>"
        }
      ],
      "surfaces": [],
      "relationshipFeatures": [
        "uuidColumns"
      ],
      "tags": [],
      "risks": []
    },
    {
      "name": "UsersCliAuthRequestCollection",
      "qualifiedName": "@happyvertical/smrt-users:UsersCliAuthRequestCollection",
      "collection": "userscliauthrequests",
      "tableName": "users_cli_auth_requests",
      "packageName": "@happyvertical/smrt-users",
      "extends": "SmrtCollection",
      "fields": [],
      "relationships": [],
      "methods": [
        "approvePendingRequest",
        "consumeApprovedSession",
        "deleteExpired",
        "findByDeviceCodeHash",
        "findByUserCode"
      ],
      "methodSignatures": [
        {
          "name": "approvePendingRequest",
          "async": true,
          "params": [
            "input: ApprovePendingCliAuthRequestInput"
          ],
          "returns": "Promise<ApprovedCliAuthRequestSnapshot | null>"
        },
        {
          "name": "consumeApprovedSession",
          "async": true,
          "params": [
            "deviceCodeHash: string"
          ],
          "returns": "Promise<string | null>"
        },
        {
          "name": "deleteExpired",
          "async": true,
          "params": [
            "options?: object"
          ],
          "returns": "Promise<number>"
        },
        {
          "name": "findByDeviceCodeHash",
          "async": true,
          "params": [
            "deviceCodeHash: string"
          ],
          "returns": "Promise<UsersCliAuthRequest | null>"
        },
        {
          "name": "findByUserCode",
          "async": true,
          "params": [
            "userCode: string"
          ],
          "returns": "Promise<UsersCliAuthRequest | null>"
        }
      ],
      "surfaces": [],
      "relationshipFeatures": [
        "uuidColumns"
      ],
      "tags": [],
      "risks": []
    },
    {
      "name": "GroupCollection",
      "qualifiedName": "@happyvertical/smrt-users:GroupCollection",
      "collection": "groups",
      "tableName": "group_collections",
      "packageName": "@happyvertical/smrt-users",
      "extends": "SmrtCollection",
      "fields": [],
      "relationships": [],
      "methods": [
        "findBySlug",
        "findByTenant"
      ],
      "methodSignatures": [
        {
          "name": "findBySlug",
          "async": true,
          "params": [
            "slug: string",
            "tenantId: string"
          ],
          "returns": "Promise<Group | null>"
        },
        {
          "name": "findByTenant",
          "async": true,
          "params": [
            "tenantId: string"
          ],
          "returns": "Promise<Group[]>"
        }
      ],
      "surfaces": [],
      "relationshipFeatures": [
        "uuidColumns"
      ],
      "tags": [],
      "risks": []
    },
    {
      "name": "GroupMemberCollection",
      "qualifiedName": "@happyvertical/smrt-users:GroupMemberCollection",
      "collection": "groupmembers",
      "tableName": "group_member_collections",
      "packageName": "@happyvertical/smrt-users",
      "extends": "SmrtCollection",
      "fields": [],
      "relationships": [],
      "methods": [
        "addMember",
        "findByGroup",
        "findByUser",
        "getGroupIds",
        "getGroupIdsForTenant",
        "getUserIds",
        "isMember",
        "removeMember"
      ],
      "methodSignatures": [
        {
          "name": "addMember",
          "async": true,
          "params": [
            "groupId: string",
            "userId: string"
          ],
          "returns": "Promise<GroupMember>"
        },
        {
          "name": "findByGroup",
          "async": true,
          "params": [
            "groupId: string"
          ],
          "returns": "Promise<GroupMember[]>"
        },
        {
          "name": "findByUser",
          "async": true,
          "params": [
            "userId: string"
          ],
          "returns": "Promise<GroupMember[]>"
        },
        {
          "name": "getGroupIds",
          "async": true,
          "params": [
            "userId: string"
          ],
          "returns": "Promise<string[]>"
        },
        {
          "name": "getGroupIdsForTenant",
          "async": true,
          "params": [
            "userId: string",
            "tenantId: string"
          ],
          "returns": "Promise<string[]>"
        },
        {
          "name": "getUserIds",
          "async": true,
          "params": [
            "groupId: string"
          ],
          "returns": "Promise<string[]>"
        },
        {
          "name": "isMember",
          "async": true,
          "params": [
            "groupId: string",
            "userId: string"
          ],
          "returns": "Promise<boolean>"
        },
        {
          "name": "removeMember",
          "async": true,
          "params": [
            "groupId: string",
            "userId: string"
          ],
          "returns": "Promise<boolean>"
        }
      ],
      "surfaces": [],
      "relationshipFeatures": [
        "uuidColumns"
      ],
      "tags": [],
      "risks": []
    },
    {
      "name": "GroupRoleCollection",
      "qualifiedName": "@happyvertical/smrt-users:GroupRoleCollection",
      "collection": "grouproles",
      "tableName": "group_role_collections",
      "packageName": "@happyvertical/smrt-users",
      "extends": "SmrtCollection",
      "fields": [],
      "relationships": [],
      "methods": [
        "addRole",
        "findByGroup",
        "findByRole",
        "getRoleIds",
        "hasRole",
        "removeRole"
      ],
      "methodSignatures": [
        {
          "name": "addRole",
          "async": true,
          "params": [
            "groupId: string",
            "roleId: string"
          ],
          "returns": "Promise<GroupRole>"
        },
        {
          "name": "findByGroup",
          "async": true,
          "params": [
            "groupId: string"
          ],
          "returns": "Promise<GroupRole[]>"
        },
        {
          "name": "findByRole",
          "async": true,
          "params": [
            "roleId: string"
          ],
          "returns": "Promise<GroupRole[]>"
        },
        {
          "name": "getRoleIds",
          "async": true,
          "params": [
            "groupId: string"
          ],
          "returns": "Promise<string[]>"
        },
        {
          "name": "hasRole",
          "async": true,
          "params": [
            "groupId: string",
            "roleId: string"
          ],
          "returns": "Promise<boolean>"
        },
        {
          "name": "removeRole",
          "async": true,
          "params": [
            "groupId: string",
            "roleId: string"
          ],
          "returns": "Promise<boolean>"
        }
      ],
      "surfaces": [],
      "relationshipFeatures": [
        "uuidColumns"
      ],
      "tags": [],
      "risks": []
    },
    {
      "name": "UsersMagicLinkTokenCollection",
      "qualifiedName": "@happyvertical/smrt-users:UsersMagicLinkTokenCollection",
      "collection": "usersmagiclinktokens",
      "tableName": "users_magic_link_tokens",
      "packageName": "@happyvertical/smrt-users",
      "extends": "SmrtCollection",
      "fields": [],
      "relationships": [],
      "methods": [
        "deleteExpired",
        "findByNonce",
        "markUsed"
      ],
      "methodSignatures": [
        {
          "name": "deleteExpired",
          "async": true,
          "params": [
            "options?: object"
          ],
          "returns": "Promise<number>"
        },
        {
          "name": "findByNonce",
          "async": true,
          "params": [
            "nonce: string"
          ],
          "returns": "Promise<UsersMagicLinkToken | null>"
        },
        {
          "name": "markUsed",
          "async": true,
          "params": [
            "nonce: string"
          ],
          "returns": "Promise<boolean>"
        }
      ],
      "surfaces": [],
      "relationshipFeatures": [
        "uuidColumns"
      ],
      "tags": [],
      "risks": []
    },
    {
      "name": "MembershipCollection",
      "qualifiedName": "@happyvertical/smrt-users:MembershipCollection",
      "collection": "memberships",
      "tableName": "membership_collections",
      "packageName": "@happyvertical/smrt-users",
      "extends": "SmrtCollection",
      "fields": [],
      "relationships": [],
      "methods": [
        "findActiveByTenant",
        "findActiveByUser",
        "findByRole",
        "findByStatus",
        "findByTenant",
        "findByUser",
        "findByUserAndTenant"
      ],
      "methodSignatures": [
        {
          "name": "findActiveByTenant",
          "async": true,
          "params": [
            "tenantId: string"
          ],
          "returns": "Promise<Membership[]>"
        },
        {
          "name": "findActiveByUser",
          "async": true,
          "params": [
            "userId: string"
          ],
          "returns": "Promise<Membership[]>"
        },
        {
          "name": "findByRole",
          "async": true,
          "params": [
            "roleId: string"
          ],
          "returns": "Promise<Membership[]>"
        },
        {
          "name": "findByStatus",
          "async": true,
          "params": [
            "status: MembershipStatus"
          ],
          "returns": "Promise<Membership[]>"
        },
        {
          "name": "findByTenant",
          "async": true,
          "params": [
            "tenantId: string"
          ],
          "returns": "Promise<Membership[]>"
        },
        {
          "name": "findByUser",
          "async": true,
          "params": [
            "userId: string"
          ],
          "returns": "Promise<Membership[]>"
        },
        {
          "name": "findByUserAndTenant",
          "async": true,
          "params": [
            "userId: string",
            "tenantId: string"
          ],
          "returns": "Promise<Membership | null>"
        }
      ],
      "surfaces": [],
      "relationshipFeatures": [
        "uuidColumns"
      ],
      "tags": [],
      "risks": []
    },
    {
      "name": "MembershipOverrideCollection",
      "qualifiedName": "@happyvertical/smrt-users:MembershipOverrideCollection",
      "collection": "membershipoverrides",
      "tableName": "membership_override_collections",
      "packageName": "@happyvertical/smrt-users",
      "extends": "SmrtCollection",
      "fields": [],
      "relationships": [],
      "methods": [
        "denyPermission",
        "findByMembership",
        "findDenies",
        "findGrants",
        "getDeniedPermissionIds",
        "getGrantedPermissionIds",
        "grantPermission",
        "removeOverride",
        "setOverride"
      ],
      "methodSignatures": [
        {
          "name": "denyPermission",
          "async": true,
          "params": [
            "membershipId: string",
            "permissionId: string"
          ],
          "returns": "Promise<MembershipOverride>"
        },
        {
          "name": "findByMembership",
          "async": true,
          "params": [
            "membershipId: string"
          ],
          "returns": "Promise<MembershipOverride[]>"
        },
        {
          "name": "findDenies",
          "async": true,
          "params": [
            "membershipId: string"
          ],
          "returns": "Promise<MembershipOverride[]>"
        },
        {
          "name": "findGrants",
          "async": true,
          "params": [
            "membershipId: string"
          ],
          "returns": "Promise<MembershipOverride[]>"
        },
        {
          "name": "getDeniedPermissionIds",
          "async": true,
          "params": [
            "membershipId: string"
          ],
          "returns": "Promise<string[]>"
        },
        {
          "name": "getGrantedPermissionIds",
          "async": true,
          "params": [
            "membershipId: string"
          ],
          "returns": "Promise<string[]>"
        },
        {
          "name": "grantPermission",
          "async": true,
          "params": [
            "membershipId: string",
            "permissionId: string"
          ],
          "returns": "Promise<MembershipOverride>"
        },
        {
          "name": "removeOverride",
          "async": true,
          "params": [
            "membershipId: string",
            "permissionId: string"
          ],
          "returns": "Promise<boolean>"
        },
        {
          "name": "setOverride",
          "async": true,
          "params": [
            "membershipId: string",
            "permissionId: string",
            "effect: OverrideEffect"
          ],
          "returns": "Promise<MembershipOverride>"
        }
      ],
      "surfaces": [],
      "relationshipFeatures": [
        "uuidColumns"
      ],
      "tags": [],
      "risks": []
    },
    {
      "name": "PermissionCollection",
      "qualifiedName": "@happyvertical/smrt-users:PermissionCollection",
      "collection": "permissions",
      "tableName": "permission_collections",
      "packageName": "@happyvertical/smrt-users",
      "extends": "SmrtCollection",
      "fields": [],
      "relationships": [],
      "methods": [
        "findByCategory",
        "findByIds",
        "findBySlug",
        "findOrCreate",
        "getCategories"
      ],
      "methodSignatures": [
        {
          "name": "findByCategory",
          "async": true,
          "params": [
            "category: string"
          ],
          "returns": "Promise<Permission[]>"
        },
        {
          "name": "findByIds",
          "async": true,
          "params": [
            "ids: string[]"
          ],
          "returns": "Promise<Map<string, Permission>>"
        },
        {
          "name": "findBySlug",
          "async": true,
          "params": [
            "slug: string"
          ],
          "returns": "Promise<Permission | null>"
        },
        {
          "name": "findOrCreate",
          "async": true,
          "params": [
            "slug: string",
            "defaults?: Partial<object>"
          ],
          "returns": "Promise<Permission>"
        },
        {
          "name": "getCategories",
          "async": true,
          "returns": "Promise<string[]>"
        }
      ],
      "surfaces": [],
      "relationshipFeatures": [
        "uuidColumns"
      ],
      "tags": [],
      "risks": []
    },
    {
      "name": "RoleCollection",
      "qualifiedName": "@happyvertical/smrt-users:RoleCollection",
      "collection": "roles",
      "tableName": "role_collections",
      "packageName": "@happyvertical/smrt-users",
      "extends": "SmrtCollection",
      "fields": [],
      "relationships": [],
      "methods": [
        "findBySlug",
        "findByTenant",
        "findSystemRoleBySlug",
        "findSystemRoles",
        "findTenantRoles",
        "seedSystemRoles"
      ],
      "methodSignatures": [
        {
          "name": "findBySlug",
          "async": true,
          "params": [
            "slug: string",
            "tenantId?: string"
          ],
          "returns": "Promise<Role | null>"
        },
        {
          "name": "findByTenant",
          "async": true,
          "params": [
            "tenantId: string"
          ],
          "returns": "Promise<Role[]>"
        },
        {
          "name": "findSystemRoleBySlug",
          "async": true,
          "params": [
            "slug: string"
          ],
          "returns": "Promise<Role | null>"
        },
        {
          "name": "findSystemRoles",
          "async": true,
          "returns": "Promise<Role[]>"
        },
        {
          "name": "findTenantRoles",
          "async": true,
          "params": [
            "tenantId: string"
          ],
          "returns": "Promise<Role[]>"
        },
        {
          "name": "seedSystemRoles",
          "async": true,
          "params": [
            "options?: SeedSystemRolesOptions"
          ],
          "returns": "Promise<Role[]>"
        }
      ],
      "surfaces": [],
      "relationshipFeatures": [
        "uuidColumns"
      ],
      "tags": [],
      "risks": []
    },
    {
      "name": "RolePermissionCollection",
      "qualifiedName": "@happyvertical/smrt-users:RolePermissionCollection",
      "collection": "rolepermissions",
      "tableName": "role_permission_collections",
      "packageName": "@happyvertical/smrt-users",
      "extends": "SmrtCollection",
      "fields": [],
      "relationships": [],
      "methods": [
        "addPermission",
        "findByPermission",
        "findByRole",
        "getPermissionIds",
        "hasPermission",
        "removePermission",
        "seedDefaultRolePersonalizationPermissions",
        "seedRolePermissions"
      ],
      "methodSignatures": [
        {
          "name": "addPermission",
          "async": true,
          "params": [
            "roleId: string",
            "permissionId: string"
          ],
          "returns": "Promise<RolePermission>"
        },
        {
          "name": "findByPermission",
          "async": true,
          "params": [
            "permissionId: string"
          ],
          "returns": "Promise<RolePermission[]>"
        },
        {
          "name": "findByRole",
          "async": true,
          "params": [
            "roleId: string"
          ],
          "returns": "Promise<RolePermission[]>"
        },
        {
          "name": "getPermissionIds",
          "async": true,
          "params": [
            "roleId: string"
          ],
          "returns": "Promise<string[]>"
        },
        {
          "name": "hasPermission",
          "async": true,
          "params": [
            "roleId: string",
            "permissionId: string"
          ],
          "returns": "Promise<boolean>"
        },
        {
          "name": "removePermission",
          "async": true,
          "params": [
            "roleId: string",
            "permissionId: string"
          ],
          "returns": "Promise<boolean>"
        },
        {
          "name": "seedDefaultRolePersonalizationPermissions",
          "async": true,
          "params": [
            "options?: Omit<SeedRolePermissionsOptions, 'prune'>"
          ],
          "returns": "Promise<SeedRolePermissionsResult>"
        },
        {
          "name": "seedRolePermissions",
          "async": true,
          "params": [
            "matrix?: RolePermissionPatternMatrix",
            "options?: SeedRolePermissionsOptions"
          ],
          "returns": "Promise<SeedRolePermissionsResult>"
        }
      ],
      "surfaces": [],
      "relationshipFeatures": [
        "uuidColumns"
      ],
      "tags": [],
      "risks": []
    },
    {
      "name": "SessionCollection",
      "qualifiedName": "@happyvertical/smrt-users:SessionCollection",
      "collection": "sessions",
      "tableName": "session_collections",
      "packageName": "@happyvertical/smrt-users",
      "extends": "SmrtCollection",
      "fields": [],
      "relationships": [],
      "methods": [
        "countUserSessions",
        "createSession",
        "deleteExpired",
        "deleteUserSessions",
        "findByUser",
        "findValidSession",
        "getSessionData",
        "revokeSession",
        "revokeUserSessions",
        "setSessionData",
        "setSessionTenant",
        "touch"
      ],
      "methodSignatures": [
        {
          "name": "countUserSessions",
          "async": true,
          "params": [
            "userId: string"
          ],
          "returns": "Promise<number>"
        },
        {
          "name": "createSession",
          "async": true,
          "params": [
            "options: CreateSessionOptions"
          ],
          "returns": "Promise<Session>"
        },
        {
          "name": "deleteExpired",
          "async": true,
          "params": [
            "options?: object"
          ],
          "returns": "Promise<number>"
        },
        {
          "name": "deleteUserSessions",
          "async": true,
          "params": [
            "userId: string"
          ],
          "returns": "Promise<number>"
        },
        {
          "name": "findByUser",
          "async": true,
          "params": [
            "userId: string"
          ],
          "returns": "Promise<Session[]>"
        },
        {
          "name": "findValidSession",
          "async": true,
          "params": [
            "sessionId: string"
          ],
          "returns": "Promise<Session | null>"
        },
        {
          "name": "getSessionData",
          "async": true,
          "params": [
            "sessionId: string",
            "key: string"
          ],
          "returns": "Promise<T | undefined>"
        },
        {
          "name": "revokeSession",
          "async": true,
          "params": [
            "sessionId: string"
          ],
          "returns": "Promise<boolean>"
        },
        {
          "name": "revokeUserSessions",
          "async": true,
          "params": [
            "userId: string"
          ],
          "returns": "Promise<number>"
        },
        {
          "name": "setSessionData",
          "async": true,
          "params": [
            "sessionId: string",
            "key: string",
            "value: any"
          ],
          "returns": "Promise<boolean>"
        },
        {
          "name": "setSessionTenant",
          "async": true,
          "params": [
            "sessionId: string",
            "tenantId: string | null"
          ],
          "returns": "Promise<boolean>"
        },
        {
          "name": "touch",
          "async": true,
          "params": [
            "sessionId: string",
            "extendTtl?: boolean",
            "ttl?: number"
          ],
          "returns": "Promise<boolean>"
        }
      ],
      "surfaces": [],
      "relationshipFeatures": [
        "uuidColumns"
      ],
      "tags": [],
      "risks": []
    },
    {
      "name": "TenantCollection",
      "qualifiedName": "@happyvertical/smrt-users:TenantCollection",
      "collection": "tenants",
      "tableName": "tenant_collections",
      "packageName": "@happyvertical/smrt-users",
      "extends": "SmrtCollection",
      "fields": [],
      "relationships": [],
      "methods": [
        "create",
        "createChild",
        "findActive",
        "findBySlug",
        "findByStatus",
        "findChildren",
        "findParent",
        "findRoots",
        "getAncestors",
        "getAncestorsFromRoot",
        "getDescendants",
        "getSiblings",
        "getTree",
        "isAncestorOf",
        "isDescendantOf",
        "makeRoot",
        "moveToParent",
        "validateHierarchy"
      ],
      "methodSignatures": [
        {
          "name": "create",
          "async": true,
          "params": [
            "options: SmrtCreateInput<Tenant>"
          ],
          "returns": "Promise<Tenant>"
        },
        {
          "name": "createChild",
          "async": true,
          "params": [
            "parentTenantId: string",
            "options: CreateChildTenantOptions"
          ],
          "returns": "Promise<Tenant>"
        },
        {
          "name": "findActive",
          "async": true,
          "returns": "Promise<Tenant[]>"
        },
        {
          "name": "findBySlug",
          "async": true,
          "params": [
            "slug: string"
          ],
          "returns": "Promise<Tenant | null>"
        },
        {
          "name": "findByStatus",
          "async": true,
          "params": [
            "status: TenantStatus"
          ],
          "returns": "Promise<Tenant[]>"
        },
        {
          "name": "findChildren",
          "async": true,
          "params": [
            "parentTenantId: string"
          ],
          "returns": "Promise<Tenant[]>"
        },
        {
          "name": "findParent",
          "async": true,
          "params": [
            "tenantId: string"
          ],
          "returns": "Promise<Tenant | null>"
        },
        {
          "name": "findRoots",
          "async": true,
          "returns": "Promise<Tenant[]>"
        },
        {
          "name": "getAncestors",
          "async": true,
          "params": [
            "tenantId: string"
          ],
          "returns": "Promise<Tenant[]>"
        },
        {
          "name": "getAncestorsFromRoot",
          "async": true,
          "params": [
            "tenantId: string"
          ],
          "returns": "Promise<Tenant[]>"
        },
        {
          "name": "getDescendants",
          "async": true,
          "params": [
            "tenantId: string"
          ],
          "returns": "Promise<Tenant[]>"
        },
        {
          "name": "getSiblings",
          "async": true,
          "params": [
            "tenantId: string"
          ],
          "returns": "Promise<Tenant[]>"
        },
        {
          "name": "getTree",
          "async": true,
          "params": [
            "rootTenantId?: string"
          ],
          "returns": "Promise<Array>"
        },
        {
          "name": "isAncestorOf",
          "async": true,
          "params": [
            "potentialAncestorId: string",
            "tenantId: string"
          ],
          "returns": "Promise<boolean>"
        },
        {
          "name": "isDescendantOf",
          "async": true,
          "params": [
            "potentialDescendantId: string",
            "tenantId: string"
          ],
          "returns": "Promise<boolean>"
        },
        {
          "name": "makeRoot",
          "async": true,
          "params": [
            "tenantId: string"
          ],
          "returns": "Promise<Tenant>"
        },
        {
          "name": "moveToParent",
          "async": true,
          "params": [
            "tenantId: string",
            "newParentId: string | null"
          ],
          "returns": "Promise<Tenant>"
        },
        {
          "name": "validateHierarchy",
          "async": true,
          "params": [
            "tenantId: string"
          ],
          "returns": "Promise<string[]>"
        }
      ],
      "surfaces": [],
      "relationshipFeatures": [
        "uuidColumns"
      ],
      "tags": [],
      "risks": []
    },
    {
      "name": "TenantIntegrationCollection",
      "qualifiedName": "@happyvertical/smrt-users:TenantIntegrationCollection",
      "collection": "tenantintegrations",
      "tableName": "tenant_integrations",
      "packageName": "@happyvertical/smrt-users",
      "extends": "SmrtCollection",
      "fields": [],
      "relationships": [],
      "methods": [
        "findFor",
        "findOrInit",
        "listForTenant"
      ],
      "methodSignatures": [
        {
          "name": "findFor",
          "async": true,
          "params": [
            "tenantId: string",
            "provider: TenantIntegrationProvider"
          ],
          "returns": "Promise<TenantIntegration | null>"
        },
        {
          "name": "findOrInit",
          "async": true,
          "params": [
            "tenantId: string",
            "provider: TenantIntegrationProvider"
          ],
          "returns": "Promise<TenantIntegration>"
        },
        {
          "name": "listForTenant",
          "async": true,
          "params": [
            "tenantId: string"
          ],
          "returns": "Promise<TenantIntegration[]>"
        }
      ],
      "surfaces": [],
      "relationshipFeatures": [
        "uuidColumns"
      ],
      "tags": [],
      "risks": []
    },
    {
      "name": "TenantPermissionOverrideCollection",
      "qualifiedName": "@happyvertical/smrt-users:TenantPermissionOverrideCollection",
      "collection": "tenantpermissionoverrides",
      "tableName": "tenant_permission_override_collections",
      "packageName": "@happyvertical/smrt-users",
      "extends": "SmrtCollection",
      "fields": [],
      "relationships": [],
      "methods": [
        "bulkSetOverrides",
        "copyOverrides",
        "denyPermission",
        "findByTenant",
        "findDenies",
        "findGrants",
        "findInherits",
        "getDeniedPermissionIds",
        "getGrantedPermissionIds",
        "getOverridesByEffect",
        "getOverridesByEffectBatch",
        "grantPermission",
        "inheritPermission",
        "removeAllOverrides",
        "removeOverride",
        "setOverride"
      ],
      "methodSignatures": [
        {
          "name": "bulkSetOverrides",
          "async": true,
          "params": [
            "tenantId: string",
            "overrides: Array<object>"
          ],
          "returns": "Promise<TenantPermissionOverride[]>"
        },
        {
          "name": "copyOverrides",
          "async": true,
          "params": [
            "fromTenantId: string",
            "toTenantId: string"
          ],
          "returns": "Promise<TenantPermissionOverride[]>"
        },
        {
          "name": "denyPermission",
          "async": true,
          "params": [
            "tenantId: string",
            "permissionId: string"
          ],
          "returns": "Promise<TenantPermissionOverride>"
        },
        {
          "name": "findByTenant",
          "async": true,
          "params": [
            "tenantId: string"
          ],
          "returns": "Promise<TenantPermissionOverride[]>"
        },
        {
          "name": "findDenies",
          "async": true,
          "params": [
            "tenantId: string"
          ],
          "returns": "Promise<TenantPermissionOverride[]>"
        },
        {
          "name": "findGrants",
          "async": true,
          "params": [
            "tenantId: string"
          ],
          "returns": "Promise<TenantPermissionOverride[]>"
        },
        {
          "name": "findInherits",
          "async": true,
          "params": [
            "tenantId: string"
          ],
          "returns": "Promise<TenantPermissionOverride[]>"
        },
        {
          "name": "getDeniedPermissionIds",
          "async": true,
          "params": [
            "tenantId: string"
          ],
          "returns": "Promise<string[]>"
        },
        {
          "name": "getGrantedPermissionIds",
          "async": true,
          "params": [
            "tenantId: string"
          ],
          "returns": "Promise<string[]>"
        },
        {
          "name": "getOverridesByEffect",
          "async": true,
          "params": [
            "tenantId: string"
          ],
          "returns": "Promise<TenantPermissionOverrideResult>"
        },
        {
          "name": "getOverridesByEffectBatch",
          "async": true,
          "params": [
            "tenantIds: string[]"
          ],
          "returns": "Promise<Map<string, TenantPermissionOverrideResult>>"
        },
        {
          "name": "grantPermission",
          "async": true,
          "params": [
            "tenantId: string",
            "permissionId: string"
          ],
          "returns": "Promise<TenantPermissionOverride>"
        },
        {
          "name": "inheritPermission",
          "async": true,
          "params": [
            "tenantId: string",
            "permissionId: string"
          ],
          "returns": "Promise<TenantPermissionOverride>"
        },
        {
          "name": "removeAllOverrides",
          "async": true,
          "params": [
            "tenantId: string"
          ],
          "returns": "Promise<number>"
        },
        {
          "name": "removeOverride",
          "async": true,
          "params": [
            "tenantId: string",
            "permissionId: string"
          ],
          "returns": "Promise<boolean>"
        },
        {
          "name": "setOverride",
          "async": true,
          "params": [
            "tenantId: string",
            "permissionId: string",
            "effect: TenantPermissionEffect"
          ],
          "returns": "Promise<TenantPermissionOverride>"
        }
      ],
      "surfaces": [],
      "relationshipFeatures": [
        "uuidColumns"
      ],
      "tags": [],
      "risks": []
    },
    {
      "name": "UserCollection",
      "qualifiedName": "@happyvertical/smrt-users:UserCollection",
      "collection": "users",
      "tableName": "user_collections",
      "packageName": "@happyvertical/smrt-users",
      "extends": "SmrtCollection",
      "fields": [],
      "relationships": [],
      "methods": [
        "findActive",
        "findByEmail",
        "findByProfile",
        "findByStatus",
        "findPending",
        "getOrCreateForProfile",
        "getOrCreateFromOidc"
      ],
      "methodSignatures": [
        {
          "name": "findActive",
          "async": true,
          "returns": "Promise<User[]>"
        },
        {
          "name": "findByEmail",
          "async": true,
          "params": [
            "email: string"
          ],
          "returns": "Promise<User | null>"
        },
        {
          "name": "findByProfile",
          "async": true,
          "params": [
            "profileId: string"
          ],
          "returns": "Promise<User | null>"
        },
        {
          "name": "findByStatus",
          "async": true,
          "params": [
            "status: UserStatus"
          ],
          "returns": "Promise<User[]>"
        },
        {
          "name": "findPending",
          "async": true,
          "returns": "Promise<User[]>"
        },
        {
          "name": "getOrCreateForProfile",
          "async": true,
          "params": [
            "profileId: string",
            "email: string",
            "defaults?: Partial<object>"
          ],
          "returns": "Promise<User>"
        },
        {
          "name": "getOrCreateFromOidc",
          "async": true,
          "params": [
            "claims: OidcClaims",
            "provider: string",
            "options?: GetOrCreateFromOidcOptions"
          ],
          "returns": "Promise<OidcIdentityResult>"
        }
      ],
      "surfaces": [],
      "relationshipFeatures": [
        "uuidColumns"
      ],
      "tags": [],
      "risks": []
    },
    {
      "name": "AccessRequest",
      "qualifiedName": "@happyvertical/smrt-users:AccessRequest",
      "collection": "accessrequests",
      "tableName": "access_requests",
      "packageName": "@happyvertical/smrt-users",
      "extends": "SmrtObject",
      "fields": [
        {
          "name": "email",
          "type": "text",
          "required": true,
          "columnType": "TEXT",
          "default": ""
        },
        {
          "name": "name",
          "type": "text",
          "required": false,
          "columnType": "TEXT"
        },
        {
          "name": "status",
          "type": "text",
          "required": false,
          "columnType": "TEXT"
        },
        {
          "name": "source",
          "type": "text",
          "required": false,
          "columnType": "TEXT",
          "default": ""
        },
        {
          "name": "requestContext",
          "type": "text",
          "required": false,
          "columnType": "TEXT",
          "default": "{}"
        },
        {
          "name": "note",
          "type": "text",
          "required": false,
          "columnType": "TEXT"
        },
        {
          "name": "requestedAt",
          "type": "datetime",
          "required": false,
          "columnType": "TIMESTAMP"
        },
        {
          "name": "decidedAt",
          "type": "datetime",
          "required": false,
          "columnType": "TIMESTAMP"
        },
        {
          "name": "decidedBy",
          "type": "text",
          "required": false,
          "columnType": "TEXT"
        },
        {
          "name": "resultingUserId",
          "type": "text",
          "required": false,
          "columnType": "TEXT"
        },
        {
          "name": "tenantHint",
          "type": "text",
          "required": false,
          "columnType": "TEXT"
        }
      ],
      "relationships": [],
      "methods": [
        "getRequestContext",
        "getTenantHint",
        "isApproved",
        "isOpen",
        "isTerminal",
        "setRequestContext",
        "setTenantHint"
      ],
      "methodSignatures": [
        {
          "name": "getRequestContext",
          "returns": "Record<string>"
        },
        {
          "name": "getTenantHint",
          "returns": "Record<string> | null"
        },
        {
          "name": "isApproved",
          "returns": "boolean"
        },
        {
          "name": "isOpen",
          "returns": "boolean"
        },
        {
          "name": "isTerminal",
          "returns": "boolean"
        },
        {
          "name": "setRequestContext",
          "params": [
            "value: Record<string>"
          ],
          "returns": "void"
        },
        {
          "name": "setTenantHint",
          "params": [
            "value: Record<string> | null"
          ],
          "returns": "void"
        }
      ],
      "conflictColumns": [
        "id"
      ],
      "surfaces": [],
      "relationshipFeatures": [
        "uuidColumns"
      ],
      "tags": [],
      "risks": []
    },
    {
      "name": "UsersCliAuthApproveLimit",
      "qualifiedName": "@happyvertical/smrt-users:UsersCliAuthApproveLimit",
      "collection": "userscliauthapprovelimits",
      "tableName": "users_cli_auth_approve_limits",
      "packageName": "@happyvertical/smrt-users",
      "extends": "SmrtObject",
      "fields": [
        {
          "name": "userId",
          "type": "foreignKey",
          "required": true,
          "related": "User",
          "columnType": "UUID"
        },
        {
          "name": "attemptCount",
          "type": "integer",
          "required": true,
          "columnType": "INTEGER",
          "default": 0
        },
        {
          "name": "windowStartedAt",
          "type": "datetime",
          "required": true,
          "columnType": "TIMESTAMP"
        }
      ],
      "relationships": [
        {
          "name": "userId",
          "type": "foreignKey",
          "required": true,
          "related": "User",
          "columnType": "UUID"
        }
      ],
      "methods": [],
      "surfaces": [],
      "relationshipFeatures": [
        "foreignKey",
        "uuidColumns"
      ],
      "tags": [],
      "risks": []
    },
    {
      "name": "UsersCliAuthRequest",
      "qualifiedName": "@happyvertical/smrt-users:UsersCliAuthRequest",
      "collection": "userscliauthrequests",
      "tableName": "users_cli_auth_requests",
      "packageName": "@happyvertical/smrt-users",
      "extends": "SmrtObject",
      "fields": [
        {
          "name": "userCode",
          "type": "text",
          "required": true,
          "columnType": "TEXT"
        },
        {
          "name": "deviceCodeHash",
          "type": "text",
          "required": true,
          "columnType": "TEXT"
        },
        {
          "name": "status",
          "type": "text",
          "required": false,
          "columnType": "TEXT"
        },
        {
          "name": "userId",
          "type": "foreignKey",
          "required": false,
          "related": "User",
          "columnType": "UUID"
        },
        {
          "name": "tenantId",
          "type": "foreignKey",
          "required": false,
          "related": "Tenant",
          "columnType": "UUID"
        },
        {
          "name": "sessionId",
          "type": "foreignKey",
          "required": false,
          "related": "Session",
          "columnType": "UUID"
        },
        {
          "name": "expiresAt",
          "type": "datetime",
          "required": false,
          "columnType": "TIMESTAMP"
        },
        {
          "name": "approvedAt",
          "type": "datetime",
          "required": false,
          "columnType": "TIMESTAMP"
        }
      ],
      "relationships": [
        {
          "name": "userId",
          "type": "foreignKey",
          "required": false,
          "related": "User",
          "columnType": "UUID"
        },
        {
          "name": "tenantId",
          "type": "foreignKey",
          "required": false,
          "related": "Tenant",
          "columnType": "UUID"
        },
        {
          "name": "sessionId",
          "type": "foreignKey",
          "required": false,
          "related": "Session",
          "columnType": "UUID"
        }
      ],
      "methods": [],
      "surfaces": [],
      "relationshipFeatures": [
        "foreignKey",
        "uuidColumns"
      ],
      "tags": [],
      "risks": []
    },
    {
      "name": "Group",
      "qualifiedName": "@happyvertical/smrt-users:Group",
      "collection": "groups",
      "tableName": "groups",
      "packageName": "@happyvertical/smrt-users",
      "extends": "SmrtObject",
      "fields": [
        {
          "name": "tenantId",
          "type": "foreignKey",
          "required": true,
          "related": "Tenant",
          "columnType": "UUID"
        },
        {
          "name": "name",
          "type": "text",
          "required": false,
          "columnType": "TEXT",
          "default": ""
        },
        {
          "name": "description",
          "type": "text",
          "required": false,
          "columnType": "TEXT",
          "default": ""
        }
      ],
      "relationships": [
        {
          "name": "tenantId",
          "type": "foreignKey",
          "required": true,
          "related": "Tenant",
          "columnType": "UUID"
        }
      ],
      "methods": [],
      "surfaces": [
        {
          "kind": "api",
          "name": "groups.list",
          "operation": "list",
          "objectName": "@happyvertical/smrt-users:Group",
          "path": "/groups",
          "method": "GET"
        },
        {
          "kind": "api",
          "name": "groups.get",
          "operation": "get",
          "objectName": "@happyvertical/smrt-users:Group",
          "path": "/groups/[id]",
          "method": "GET"
        },
        {
          "kind": "cli",
          "name": "group_list",
          "operation": "list",
          "objectName": "@happyvertical/smrt-users:Group"
        },
        {
          "kind": "cli",
          "name": "group_get",
          "operation": "get",
          "objectName": "@happyvertical/smrt-users:Group"
        },
        {
          "kind": "cli",
          "name": "group_create",
          "operation": "create",
          "objectName": "@happyvertical/smrt-users:Group"
        },
        {
          "kind": "cli",
          "name": "group_update",
          "operation": "update",
          "objectName": "@happyvertical/smrt-users:Group"
        },
        {
          "kind": "cli",
          "name": "group_delete",
          "operation": "delete",
          "objectName": "@happyvertical/smrt-users:Group"
        },
        {
          "kind": "mcp",
          "name": "group_list",
          "operation": "list",
          "objectName": "@happyvertical/smrt-users:Group"
        },
        {
          "kind": "mcp",
          "name": "group_get",
          "operation": "get",
          "objectName": "@happyvertical/smrt-users:Group"
        }
      ],
      "relationshipFeatures": [
        "foreignKey",
        "uuidColumns"
      ],
      "tags": [],
      "risks": []
    },
    {
      "name": "GroupMember",
      "qualifiedName": "@happyvertical/smrt-users:GroupMember",
      "collection": "groupmembers",
      "tableName": "group_members",
      "packageName": "@happyvertical/smrt-users",
      "extends": "SmrtObject",
      "fields": [
        {
          "name": "groupId",
          "type": "foreignKey",
          "required": true,
          "related": "Group",
          "columnType": "UUID"
        },
        {
          "name": "userId",
          "type": "foreignKey",
          "required": true,
          "related": "User",
          "columnType": "UUID"
        }
      ],
      "relationships": [
        {
          "name": "groupId",
          "type": "foreignKey",
          "required": true,
          "related": "Group",
          "columnType": "UUID"
        },
        {
          "name": "userId",
          "type": "foreignKey",
          "required": true,
          "related": "User",
          "columnType": "UUID"
        }
      ],
      "methods": [],
      "surfaces": [
        {
          "kind": "api",
          "name": "groupmembers.list",
          "operation": "list",
          "objectName": "@happyvertical/smrt-users:GroupMember",
          "path": "/groupmembers",
          "method": "GET"
        },
        {
          "kind": "api",
          "name": "groupmembers.get",
          "operation": "get",
          "objectName": "@happyvertical/smrt-users:GroupMember",
          "path": "/groupmembers/[id]",
          "method": "GET"
        },
        {
          "kind": "cli",
          "name": "groupmember_list",
          "operation": "list",
          "objectName": "@happyvertical/smrt-users:GroupMember"
        },
        {
          "kind": "cli",
          "name": "groupmember_get",
          "operation": "get",
          "objectName": "@happyvertical/smrt-users:GroupMember"
        },
        {
          "kind": "cli",
          "name": "groupmember_create",
          "operation": "create",
          "objectName": "@happyvertical/smrt-users:GroupMember"
        },
        {
          "kind": "cli",
          "name": "groupmember_update",
          "operation": "update",
          "objectName": "@happyvertical/smrt-users:GroupMember"
        },
        {
          "kind": "cli",
          "name": "groupmember_delete",
          "operation": "delete",
          "objectName": "@happyvertical/smrt-users:GroupMember"
        },
        {
          "kind": "mcp",
          "name": "groupmember_list",
          "operation": "list",
          "objectName": "@happyvertical/smrt-users:GroupMember"
        },
        {
          "kind": "mcp",
          "name": "groupmember_get",
          "operation": "get",
          "objectName": "@happyvertical/smrt-users:GroupMember"
        }
      ],
      "relationshipFeatures": [
        "foreignKey",
        "uuidColumns"
      ],
      "tags": [],
      "risks": []
    },
    {
      "name": "GroupRole",
      "qualifiedName": "@happyvertical/smrt-users:GroupRole",
      "collection": "grouproles",
      "tableName": "group_roles",
      "packageName": "@happyvertical/smrt-users",
      "extends": "SmrtObject",
      "fields": [
        {
          "name": "groupId",
          "type": "foreignKey",
          "required": true,
          "related": "Group",
          "columnType": "UUID"
        },
        {
          "name": "roleId",
          "type": "foreignKey",
          "required": true,
          "related": "Role",
          "columnType": "UUID"
        }
      ],
      "relationships": [
        {
          "name": "groupId",
          "type": "foreignKey",
          "required": true,
          "related": "Group",
          "columnType": "UUID"
        },
        {
          "name": "roleId",
          "type": "foreignKey",
          "required": true,
          "related": "Role",
          "columnType": "UUID"
        }
      ],
      "methods": [],
      "surfaces": [
        {
          "kind": "api",
          "name": "grouproles.list",
          "operation": "list",
          "objectName": "@happyvertical/smrt-users:GroupRole",
          "path": "/grouproles",
          "method": "GET"
        },
        {
          "kind": "api",
          "name": "grouproles.get",
          "operation": "get",
          "objectName": "@happyvertical/smrt-users:GroupRole",
          "path": "/grouproles/[id]",
          "method": "GET"
        },
        {
          "kind": "cli",
          "name": "grouprole_list",
          "operation": "list",
          "objectName": "@happyvertical/smrt-users:GroupRole"
        },
        {
          "kind": "cli",
          "name": "grouprole_get",
          "operation": "get",
          "objectName": "@happyvertical/smrt-users:GroupRole"
        },
        {
          "kind": "cli",
          "name": "grouprole_create",
          "operation": "create",
          "objectName": "@happyvertical/smrt-users:GroupRole"
        },
        {
          "kind": "cli",
          "name": "grouprole_update",
          "operation": "update",
          "objectName": "@happyvertical/smrt-users:GroupRole"
        },
        {
          "kind": "cli",
          "name": "grouprole_delete",
          "operation": "delete",
          "objectName": "@happyvertical/smrt-users:GroupRole"
        },
        {
          "kind": "mcp",
          "name": "grouprole_list",
          "operation": "list",
          "objectName": "@happyvertical/smrt-users:GroupRole"
        },
        {
          "kind": "mcp",
          "name": "grouprole_get",
          "operation": "get",
          "objectName": "@happyvertical/smrt-users:GroupRole"
        }
      ],
      "relationshipFeatures": [
        "foreignKey",
        "uuidColumns"
      ],
      "tags": [],
      "risks": []
    },
    {
      "name": "UsersMagicLinkToken",
      "qualifiedName": "@happyvertical/smrt-users:UsersMagicLinkToken",
      "collection": "usersmagiclinktokens",
      "tableName": "users_magic_link_tokens",
      "packageName": "@happyvertical/smrt-users",
      "extends": "SmrtObject",
      "fields": [
        {
          "name": "nonce",
          "type": "text",
          "required": true,
          "columnType": "TEXT",
          "default": ""
        },
        {
          "name": "email",
          "type": "text",
          "required": false,
          "columnType": "TEXT",
          "default": ""
        },
        {
          "name": "used",
          "type": "boolean",
          "required": false,
          "columnType": "BOOLEAN",
          "default": false
        },
        {
          "name": "expiresAt",
          "type": "datetime",
          "required": false,
          "columnType": "TIMESTAMP"
        }
      ],
      "relationships": [],
      "methods": [
        "isExpired",
        "isValid"
      ],
      "methodSignatures": [
        {
          "name": "isExpired",
          "returns": "boolean"
        },
        {
          "name": "isValid",
          "returns": "boolean"
        }
      ],
      "surfaces": [
        {
          "kind": "cli",
          "name": "usersmagiclinktoken_list",
          "operation": "list",
          "objectName": "@happyvertical/smrt-users:UsersMagicLinkToken"
        },
        {
          "kind": "cli",
          "name": "usersmagiclinktoken_get",
          "operation": "get",
          "objectName": "@happyvertical/smrt-users:UsersMagicLinkToken"
        },
        {
          "kind": "cli",
          "name": "usersmagiclinktoken_create",
          "operation": "create",
          "objectName": "@happyvertical/smrt-users:UsersMagicLinkToken"
        },
        {
          "kind": "cli",
          "name": "usersmagiclinktoken_update",
          "operation": "update",
          "objectName": "@happyvertical/smrt-users:UsersMagicLinkToken"
        },
        {
          "kind": "cli",
          "name": "usersmagiclinktoken_delete",
          "operation": "delete",
          "objectName": "@happyvertical/smrt-users:UsersMagicLinkToken"
        }
      ],
      "relationshipFeatures": [
        "uuidColumns"
      ],
      "tags": [],
      "risks": []
    },
    {
      "name": "Membership",
      "qualifiedName": "@happyvertical/smrt-users:Membership",
      "collection": "memberships",
      "tableName": "memberships",
      "packageName": "@happyvertical/smrt-users",
      "extends": "SmrtObject",
      "fields": [
        {
          "name": "userId",
          "type": "foreignKey",
          "required": true,
          "related": "User",
          "columnType": "UUID"
        },
        {
          "name": "tenantId",
          "type": "foreignKey",
          "required": true,
          "related": "Tenant",
          "columnType": "UUID"
        },
        {
          "name": "roleId",
          "type": "foreignKey",
          "required": true,
          "related": "Role",
          "columnType": "UUID"
        },
        {
          "name": "status",
          "type": "text",
          "required": false,
          "columnType": "TEXT"
        }
      ],
      "relationships": [
        {
          "name": "userId",
          "type": "foreignKey",
          "required": true,
          "related": "User",
          "columnType": "UUID"
        },
        {
          "name": "tenantId",
          "type": "foreignKey",
          "required": true,
          "related": "Tenant",
          "columnType": "UUID"
        },
        {
          "name": "roleId",
          "type": "foreignKey",
          "required": true,
          "related": "Role",
          "columnType": "UUID"
        }
      ],
      "methods": [
        "isActive",
        "isPending"
      ],
      "methodSignatures": [
        {
          "name": "isActive",
          "returns": "boolean"
        },
        {
          "name": "isPending",
          "returns": "boolean"
        }
      ],
      "surfaces": [
        {
          "kind": "api",
          "name": "memberships.list",
          "operation": "list",
          "objectName": "@happyvertical/smrt-users:Membership",
          "path": "/memberships",
          "method": "GET"
        },
        {
          "kind": "api",
          "name": "memberships.get",
          "operation": "get",
          "objectName": "@happyvertical/smrt-users:Membership",
          "path": "/memberships/[id]",
          "method": "GET"
        },
        {
          "kind": "cli",
          "name": "membership_list",
          "operation": "list",
          "objectName": "@happyvertical/smrt-users:Membership"
        },
        {
          "kind": "cli",
          "name": "membership_get",
          "operation": "get",
          "objectName": "@happyvertical/smrt-users:Membership"
        },
        {
          "kind": "cli",
          "name": "membership_create",
          "operation": "create",
          "objectName": "@happyvertical/smrt-users:Membership"
        },
        {
          "kind": "cli",
          "name": "membership_update",
          "operation": "update",
          "objectName": "@happyvertical/smrt-users:Membership"
        },
        {
          "kind": "cli",
          "name": "membership_delete",
          "operation": "delete",
          "objectName": "@happyvertical/smrt-users:Membership"
        },
        {
          "kind": "mcp",
          "name": "membership_list",
          "operation": "list",
          "objectName": "@happyvertical/smrt-users:Membership"
        },
        {
          "kind": "mcp",
          "name": "membership_get",
          "operation": "get",
          "objectName": "@happyvertical/smrt-users:Membership"
        }
      ],
      "relationshipFeatures": [
        "foreignKey",
        "uuidColumns"
      ],
      "tags": [],
      "risks": []
    },
    {
      "name": "MembershipOverride",
      "qualifiedName": "@happyvertical/smrt-users:MembershipOverride",
      "collection": "membershipoverrides",
      "tableName": "membership_overrides",
      "packageName": "@happyvertical/smrt-users",
      "extends": "SmrtObject",
      "fields": [
        {
          "name": "membershipId",
          "type": "foreignKey",
          "required": true,
          "related": "Membership",
          "columnType": "UUID"
        },
        {
          "name": "permissionId",
          "type": "foreignKey",
          "required": true,
          "related": "Permission",
          "columnType": "UUID"
        },
        {
          "name": "effect",
          "type": "text",
          "required": false,
          "columnType": "TEXT"
        }
      ],
      "relationships": [
        {
          "name": "membershipId",
          "type": "foreignKey",
          "required": true,
          "related": "Membership",
          "columnType": "UUID"
        },
        {
          "name": "permissionId",
          "type": "foreignKey",
          "required": true,
          "related": "Permission",
          "columnType": "UUID"
        }
      ],
      "methods": [
        "isDeny",
        "isGrant"
      ],
      "methodSignatures": [
        {
          "name": "isDeny",
          "returns": "boolean"
        },
        {
          "name": "isGrant",
          "returns": "boolean"
        }
      ],
      "surfaces": [
        {
          "kind": "api",
          "name": "membershipoverrides.list",
          "operation": "list",
          "objectName": "@happyvertical/smrt-users:MembershipOverride",
          "path": "/membershipoverrides",
          "method": "GET"
        },
        {
          "kind": "api",
          "name": "membershipoverrides.get",
          "operation": "get",
          "objectName": "@happyvertical/smrt-users:MembershipOverride",
          "path": "/membershipoverrides/[id]",
          "method": "GET"
        },
        {
          "kind": "cli",
          "name": "membershipoverride_list",
          "operation": "list",
          "objectName": "@happyvertical/smrt-users:MembershipOverride"
        },
        {
          "kind": "cli",
          "name": "membershipoverride_get",
          "operation": "get",
          "objectName": "@happyvertical/smrt-users:MembershipOverride"
        },
        {
          "kind": "cli",
          "name": "membershipoverride_create",
          "operation": "create",
          "objectName": "@happyvertical/smrt-users:MembershipOverride"
        },
        {
          "kind": "cli",
          "name": "membershipoverride_update",
          "operation": "update",
          "objectName": "@happyvertical/smrt-users:MembershipOverride"
        },
        {
          "kind": "cli",
          "name": "membershipoverride_delete",
          "operation": "delete",
          "objectName": "@happyvertical/smrt-users:MembershipOverride"
        },
        {
          "kind": "mcp",
          "name": "membershipoverride_list",
          "operation": "list",
          "objectName": "@happyvertical/smrt-users:MembershipOverride"
        },
        {
          "kind": "mcp",
          "name": "membershipoverride_get",
          "operation": "get",
          "objectName": "@happyvertical/smrt-users:MembershipOverride"
        }
      ],
      "relationshipFeatures": [
        "foreignKey",
        "uuidColumns"
      ],
      "tags": [],
      "risks": []
    },
    {
      "name": "Permission",
      "qualifiedName": "@happyvertical/smrt-users:Permission",
      "collection": "permissions",
      "tableName": "permissions",
      "packageName": "@happyvertical/smrt-users",
      "extends": "SmrtObject",
      "fields": [
        {
          "name": "name",
          "type": "text",
          "required": false,
          "columnType": "TEXT",
          "default": ""
        },
        {
          "name": "description",
          "type": "text",
          "required": false,
          "columnType": "TEXT",
          "default": ""
        },
        {
          "name": "category",
          "type": "text",
          "required": false,
          "columnType": "TEXT",
          "default": ""
        }
      ],
      "relationships": [],
      "methods": [
        "getAction",
        "getResource",
        "isValidSlug",
        "parseSlug"
      ],
      "methodSignatures": [
        {
          "name": "getAction",
          "returns": "string"
        },
        {
          "name": "getResource",
          "returns": "string"
        },
        {
          "name": "isValidSlug",
          "returns": "boolean"
        },
        {
          "name": "parseSlug",
          "returns": "ParsedPermissionSlug"
        }
      ],
      "surfaces": [
        {
          "kind": "api",
          "name": "permissions.list",
          "operation": "list",
          "objectName": "@happyvertical/smrt-users:Permission",
          "path": "/permissions",
          "method": "GET"
        },
        {
          "kind": "api",
          "name": "permissions.get",
          "operation": "get",
          "objectName": "@happyvertical/smrt-users:Permission",
          "path": "/permissions/[id]",
          "method": "GET"
        },
        {
          "kind": "cli",
          "name": "permission_list",
          "operation": "list",
          "objectName": "@happyvertical/smrt-users:Permission"
        },
        {
          "kind": "cli",
          "name": "permission_get",
          "operation": "get",
          "objectName": "@happyvertical/smrt-users:Permission"
        },
        {
          "kind": "cli",
          "name": "permission_create",
          "operation": "create",
          "objectName": "@happyvertical/smrt-users:Permission"
        },
        {
          "kind": "cli",
          "name": "permission_update",
          "operation": "update",
          "objectName": "@happyvertical/smrt-users:Permission"
        },
        {
          "kind": "cli",
          "name": "permission_delete",
          "operation": "delete",
          "objectName": "@happyvertical/smrt-users:Permission"
        },
        {
          "kind": "mcp",
          "name": "permission_list",
          "operation": "list",
          "objectName": "@happyvertical/smrt-users:Permission"
        },
        {
          "kind": "mcp",
          "name": "permission_get",
          "operation": "get",
          "objectName": "@happyvertical/smrt-users:Permission"
        }
      ],
      "relationshipFeatures": [
        "uuidColumns"
      ],
      "tags": [],
      "risks": []
    },
    {
      "name": "Role",
      "qualifiedName": "@happyvertical/smrt-users:Role",
      "collection": "roles",
      "tableName": "roles",
      "packageName": "@happyvertical/smrt-users",
      "extends": "SmrtObject",
      "fields": [
        {
          "name": "tenantId",
          "type": "foreignKey",
          "required": false,
          "related": "Tenant",
          "columnType": "UUID"
        },
        {
          "name": "name",
          "type": "text",
          "required": false,
          "columnType": "TEXT",
          "default": ""
        },
        {
          "name": "description",
          "type": "text",
          "required": false,
          "columnType": "TEXT",
          "default": ""
        },
        {
          "name": "isSystem",
          "type": "boolean",
          "required": false,
          "columnType": "BOOLEAN",
          "default": false
        },
        {
          "name": "inheritsToDescendants",
          "type": "boolean",
          "required": false,
          "columnType": "BOOLEAN",
          "default": false
        }
      ],
      "relationships": [
        {
          "name": "tenantId",
          "type": "foreignKey",
          "required": false,
          "related": "Tenant",
          "columnType": "UUID"
        }
      ],
      "methods": [
        "canDelete",
        "delete",
        "isSystemRole",
        "isTenantRole"
      ],
      "methodSignatures": [
        {
          "name": "canDelete",
          "returns": "boolean"
        },
        {
          "name": "delete",
          "async": true,
          "returns": "Promise<void>"
        },
        {
          "name": "isSystemRole",
          "returns": "boolean"
        },
        {
          "name": "isTenantRole",
          "returns": "boolean"
        }
      ],
      "surfaces": [
        {
          "kind": "api",
          "name": "roles.list",
          "operation": "list",
          "objectName": "@happyvertical/smrt-users:Role",
          "path": "/roles",
          "method": "GET"
        },
        {
          "kind": "api",
          "name": "roles.get",
          "operation": "get",
          "objectName": "@happyvertical/smrt-users:Role",
          "path": "/roles/[id]",
          "method": "GET"
        },
        {
          "kind": "cli",
          "name": "role_list",
          "operation": "list",
          "objectName": "@happyvertical/smrt-users:Role"
        },
        {
          "kind": "cli",
          "name": "role_get",
          "operation": "get",
          "objectName": "@happyvertical/smrt-users:Role"
        },
        {
          "kind": "cli",
          "name": "role_create",
          "operation": "create",
          "objectName": "@happyvertical/smrt-users:Role"
        },
        {
          "kind": "cli",
          "name": "role_update",
          "operation": "update",
          "objectName": "@happyvertical/smrt-users:Role"
        },
        {
          "kind": "cli",
          "name": "role_delete",
          "operation": "delete",
          "objectName": "@happyvertical/smrt-users:Role"
        },
        {
          "kind": "mcp",
          "name": "role_list",
          "operation": "list",
          "objectName": "@happyvertical/smrt-users:Role"
        },
        {
          "kind": "mcp",
          "name": "role_get",
          "operation": "get",
          "objectName": "@happyvertical/smrt-users:Role"
        }
      ],
      "relationshipFeatures": [
        "foreignKey",
        "uuidColumns"
      ],
      "tags": [],
      "risks": []
    },
    {
      "name": "RolePermission",
      "qualifiedName": "@happyvertical/smrt-users:RolePermission",
      "collection": "rolepermissions",
      "tableName": "role_permissions",
      "packageName": "@happyvertical/smrt-users",
      "extends": "SmrtObject",
      "fields": [
        {
          "name": "roleId",
          "type": "foreignKey",
          "required": true,
          "related": "Role",
          "columnType": "UUID"
        },
        {
          "name": "permissionId",
          "type": "foreignKey",
          "required": true,
          "related": "Permission",
          "columnType": "UUID"
        }
      ],
      "relationships": [
        {
          "name": "roleId",
          "type": "foreignKey",
          "required": true,
          "related": "Role",
          "columnType": "UUID"
        },
        {
          "name": "permissionId",
          "type": "foreignKey",
          "required": true,
          "related": "Permission",
          "columnType": "UUID"
        }
      ],
      "methods": [],
      "surfaces": [
        {
          "kind": "api",
          "name": "rolepermissions.list",
          "operation": "list",
          "objectName": "@happyvertical/smrt-users:RolePermission",
          "path": "/rolepermissions",
          "method": "GET"
        },
        {
          "kind": "api",
          "name": "rolepermissions.get",
          "operation": "get",
          "objectName": "@happyvertical/smrt-users:RolePermission",
          "path": "/rolepermissions/[id]",
          "method": "GET"
        },
        {
          "kind": "cli",
          "name": "rolepermission_list",
          "operation": "list",
          "objectName": "@happyvertical/smrt-users:RolePermission"
        },
        {
          "kind": "cli",
          "name": "rolepermission_get",
          "operation": "get",
          "objectName": "@happyvertical/smrt-users:RolePermission"
        },
        {
          "kind": "cli",
          "name": "rolepermission_create",
          "operation": "create",
          "objectName": "@happyvertical/smrt-users:RolePermission"
        },
        {
          "kind": "cli",
          "name": "rolepermission_update",
          "operation": "update",
          "objectName": "@happyvertical/smrt-users:RolePermission"
        },
        {
          "kind": "cli",
          "name": "rolepermission_delete",
          "operation": "delete",
          "objectName": "@happyvertical/smrt-users:RolePermission"
        },
        {
          "kind": "mcp",
          "name": "rolepermission_list",
          "operation": "list",
          "objectName": "@happyvertical/smrt-users:RolePermission"
        },
        {
          "kind": "mcp",
          "name": "rolepermission_get",
          "operation": "get",
          "objectName": "@happyvertical/smrt-users:RolePermission"
        }
      ],
      "relationshipFeatures": [
        "foreignKey",
        "uuidColumns"
      ],
      "tags": [],
      "risks": []
    },
    {
      "name": "Session",
      "qualifiedName": "@happyvertical/smrt-users:Session",
      "collection": "sessions",
      "tableName": "sessions",
      "packageName": "@happyvertical/smrt-users",
      "extends": "SmrtObject",
      "fields": [
        {
          "name": "userId",
          "type": "foreignKey",
          "required": false,
          "related": "User",
          "columnType": "UUID"
        },
        {
          "name": "tenantId",
          "type": "foreignKey",
          "required": false,
          "related": "Tenant",
          "columnType": "UUID"
        },
        {
          "name": "status",
          "type": "text",
          "required": false,
          "columnType": "TEXT"
        },
        {
          "name": "expiresAt",
          "type": "datetime",
          "required": false,
          "columnType": "TIMESTAMP"
        },
        {
          "name": "userAgent",
          "type": "text",
          "required": false,
          "columnType": "TEXT",
          "default": ""
        },
        {
          "name": "ipAddress",
          "type": "text",
          "required": false,
          "columnType": "TEXT",
          "default": ""
        },
        {
          "name": "lastAccessedAt",
          "type": "datetime",
          "required": false,
          "columnType": "TIMESTAMP"
        },
        {
          "name": "data",
          "type": "json",
          "required": false,
          "columnType": "JSON",
          "default": {}
        }
      ],
      "relationships": [
        {
          "name": "userId",
          "type": "foreignKey",
          "required": false,
          "related": "User",
          "columnType": "UUID"
        },
        {
          "name": "tenantId",
          "type": "foreignKey",
          "required": false,
          "related": "Tenant",
          "columnType": "UUID"
        }
      ],
      "methods": [
        "extend",
        "getData",
        "isExpired",
        "isRevoked",
        "isValid",
        "removeData",
        "revoke",
        "setData",
        "setTenant",
        "touch"
      ],
      "methodSignatures": [
        {
          "name": "extend",
          "params": [
            "ttlSeconds?: number"
          ],
          "returns": "void"
        },
        {
          "name": "getData",
          "params": [
            "key: string"
          ],
          "returns": "T | undefined"
        },
        {
          "name": "isExpired",
          "returns": "boolean"
        },
        {
          "name": "isRevoked",
          "returns": "boolean"
        },
        {
          "name": "isValid",
          "returns": "boolean"
        },
        {
          "name": "removeData",
          "params": [
            "key: string"
          ],
          "returns": "void"
        },
        {
          "name": "revoke",
          "returns": "void"
        },
        {
          "name": "setData",
          "params": [
            "key: string",
            "value: any"
          ],
          "returns": "void"
        },
        {
          "name": "setTenant",
          "params": [
            "tenantId: string | null"
          ],
          "returns": "void"
        },
        {
          "name": "touch",
          "returns": "void"
        }
      ],
      "surfaces": [
        {
          "kind": "api",
          "name": "sessions.get",
          "operation": "get",
          "objectName": "@happyvertical/smrt-users:Session",
          "path": "/sessions/[id]",
          "method": "GET"
        },
        {
          "kind": "api",
          "name": "sessions.delete",
          "operation": "delete",
          "objectName": "@happyvertical/smrt-users:Session",
          "path": "/sessions/[id]",
          "method": "DELETE"
        },
        {
          "kind": "cli",
          "name": "session_list",
          "operation": "list",
          "objectName": "@happyvertical/smrt-users:Session"
        },
        {
          "kind": "cli",
          "name": "session_get",
          "operation": "get",
          "objectName": "@happyvertical/smrt-users:Session"
        },
        {
          "kind": "cli",
          "name": "session_create",
          "operation": "create",
          "objectName": "@happyvertical/smrt-users:Session"
        },
        {
          "kind": "cli",
          "name": "session_update",
          "operation": "update",
          "objectName": "@happyvertical/smrt-users:Session"
        },
        {
          "kind": "cli",
          "name": "session_delete",
          "operation": "delete",
          "objectName": "@happyvertical/smrt-users:Session"
        }
      ],
      "relationshipFeatures": [
        "foreignKey",
        "uuidColumns"
      ],
      "tags": [],
      "risks": []
    },
    {
      "name": "Tenant",
      "qualifiedName": "@happyvertical/smrt-users:Tenant",
      "collection": "tenants",
      "tableName": "tenants",
      "packageName": "@happyvertical/smrt-users",
      "extends": "SmrtObject",
      "fields": [
        {
          "name": "created_at",
          "type": "datetime",
          "required": false,
          "columnType": "TIMESTAMP"
        },
        {
          "name": "updated_at",
          "type": "datetime",
          "required": false,
          "columnType": "TIMESTAMP"
        },
        {
          "name": "name",
          "type": "text",
          "required": false,
          "columnType": "TEXT",
          "default": ""
        },
        {
          "name": "status",
          "type": "text",
          "required": false,
          "columnType": "TEXT"
        },
        {
          "name": "description",
          "type": "text",
          "required": false,
          "columnType": "TEXT",
          "default": ""
        },
        {
          "name": "parentTenantId",
          "type": "foreignKey",
          "required": false,
          "related": "Tenant",
          "columnType": "UUID"
        },
        {
          "name": "hierarchyLevel",
          "type": "integer",
          "required": false,
          "columnType": "INTEGER",
          "default": 0
        },
        {
          "name": "hierarchyPath",
          "type": "text",
          "required": false,
          "columnType": "TEXT",
          "default": ""
        },
        {
          "name": "cascadePermissions",
          "type": "boolean",
          "required": false,
          "columnType": "BOOLEAN",
          "default": true
        },
        {
          "name": "inheritPermissions",
          "type": "boolean",
          "required": false,
          "columnType": "BOOLEAN",
          "default": true
        }
      ],
      "relationships": [
        {
          "name": "parentTenantId",
          "type": "foreignKey",
          "required": false,
          "related": "Tenant",
          "columnType": "UUID"
        }
      ],
      "methods": [
        "_setLoadedRelationship",
        "acceptsInheritance",
        "canCascadeToChildren",
        "classifyConstraintError",
        "clearEmbeddings",
        "delete",
        "describe",
        "destroy",
        "do",
        "executeToolCall",
        "forget",
        "forgetScope",
        "generateEmbeddings",
        "getAiUsageSnapshot",
        "getAncestorIds",
        "getAvailableTools",
        "getEmbedding",
        "getFields",
        "getId",
        "getRelated",
        "getSavedId",
        "getSlug",
        "hasStaleEmbeddings",
        "initialize",
        "is",
        "isActive",
        "isRelatedLoaded",
        "isRoot",
        "isSaved",
        "isSuspended",
        "listAiUsage",
        "loadDataFromDb",
        "loadFromId",
        "loadFromSlug",
        "loadRelated",
        "loadRelatedMany",
        "markAsPersisted",
        "recall",
        "recallAll",
        "remember",
        "requireInsertOnSave",
        "resetAiUsage",
        "save",
        "summarizeAiUsage",
        "toJSON",
        "toPlainObject",
        "toPublicJSON",
        "withDatabase"
      ],
      "methodSignatures": [
        {
          "name": "_setLoadedRelationship",
          "params": [
            "fieldName: string",
            "value: any"
          ],
          "returns": "void"
        },
        {
          "name": "acceptsInheritance",
          "returns": "boolean"
        },
        {
          "name": "canCascadeToChildren",
          "returns": "boolean"
        },
        {
          "name": "classifyConstraintError",
          "static": true,
          "params": [
            "message: string"
          ],
          "returns": "'unique' | 'not_null' | null"
        },
        {
          "name": "clearEmbeddings",
          "async": true,
          "returns": "Promise<void>"
        },
        {
          "name": "delete",
          "async": true,
          "returns": "Promise<void>"
        },
        {
          "name": "describe",
          "async": true,
          "params": [
            "options?: AiOperationOptions"
          ],
          "returns": "any"
        },
        {
          "name": "destroy",
          "returns": "void"
        },
        {
          "name": "do",
          "async": true,
          "params": [
            "instructions: string",
            "options?: AiOperationOptions"
          ],
          "returns": "any"
        },
        {
          "name": "executeToolCall",
          "async": true,
          "params": [
            "toolCall: ToolCall"
          ],
          "returns": "Promise<ToolCallResult>"
        },
        {
          "name": "forget",
          "async": true,
          "params": [
            "options: object"
          ],
          "returns": "Promise<void>"
        },
        {
          "name": "forgetScope",
          "async": true,
          "params": [
            "options: object"
          ],
          "returns": "Promise<number>"
        },
        {
          "name": "generateEmbeddings",
          "async": true,
          "params": [
            "options?: GenerateEmbeddingsOptions"
          ],
          "returns": "Promise<void>"
        },
        {
          "name": "getAiUsageSnapshot",
          "returns": "AiUsageSnapshot | undefined"
        },
        {
          "name": "getAncestorIds",
          "returns": "string[]"
        },
        {
          "name": "getAvailableTools",
          "returns": "AITool[]"
        },
        {
          "name": "getEmbedding",
          "async": true,
          "params": [
            "fieldName: string",
            "model?: string"
          ],
          "returns": "Promise<number[] | null>"
        },
        {
          "name": "getFields",
          "async": true,
          "returns": "Promise<any>"
        },
        {
          "name": "getId",
          "async": true,
          "returns": "any"
        },
        {
          "name": "getRelated",
          "async": true,
          "params": [
            "fieldName: string",
            "opts?: LoadRelatedOptions"
          ],
          "returns": "Promise<any>"
        },
        {
          "name": "getSavedId",
          "async": true,
          "returns": "any"
        },
        {
          "name": "getSlug",
          "async": true,
          "returns": "any"
        },
        {
          "name": "hasStaleEmbeddings",
          "async": true,
          "returns": "Promise<boolean>"
        },
        {
          "name": "initialize",
          "async": true,
          "returns": "Promise"
        },
        {
          "name": "is",
          "async": true,
          "params": [
            "criteria: string",
            "options?: AiOperationOptions"
          ],
          "returns": "any"
        },
        {
          "name": "isActive",
          "returns": "boolean"
        },
        {
          "name": "isRelatedLoaded",
          "params": [
            "fieldName: string"
          ],
          "returns": "boolean"
        },
        {
          "name": "isRoot",
          "returns": "boolean"
        },
        {
          "name": "isSaved",
          "async": true,
          "returns": "any"
        },
        {
          "name": "isSuspended",
          "returns": "boolean"
        },
        {
          "name": "listAiUsage",
          "async": true,
          "params": [
            "options?: AiUsageListOptions"
          ],
          "returns": "Promise<SmrtAiUsageRecord[]>"
        },
        {
          "name": "loadDataFromDb",
          "async": true,
          "params": [
            "data: Record<string>"
          ],
          "returns": "any"
        },
        {
          "name": "loadFromId",
          "async": true,
          "returns": "any"
        },
        {
          "name": "loadFromSlug",
          "async": true,
          "returns": "any"
        },
        {
          "name": "loadRelated",
          "async": true,
          "params": [
            "fieldName: string",
            "opts?: LoadRelatedOptions"
          ],
          "returns": "Promise<any>"
        },
        {
          "name": "loadRelatedMany",
          "async": true,
          "params": [
            "fieldName: string",
            "opts?: LoadRelatedOptions"
          ],
          "returns": "Promise<any[]>"
        },
        {
          "name": "markAsPersisted",
          "returns": "void"
        },
        {
          "name": "recall",
          "async": true,
          "params": [
            "options: object"
          ],
          "returns": "Promise"
        },
        {
          "name": "recallAll",
          "async": true,
          "params": [
            "options?: object"
          ],
          "returns": "Promise<Map<string>>"
        },
        {
          "name": "remember",
          "async": true,
          "params": [
            "options: object"
          ],
          "returns": "Promise<void>"
        },
        {
          "name": "requireInsertOnSave",
          "returns": "void"
        },
        {
          "name": "resetAiUsage",
          "returns": "void"
        },
        {
          "name": "save",
          "async": true,
          "returns": "any"
        },
        {
          "name": "summarizeAiUsage",
          "async": true,
          "params": [
            "options?: AiUsageSummaryOptions"
          ],
          "returns": "Promise<Record<string, AiUsageStats>>"
        },
        {
          "name": "toJSON",
          "returns": "any"
        },
        {
          "name": "toPlainObject",
          "returns": "Record<string>"
        },
        {
          "name": "toPublicJSON",
          "params": [
            "options?: PublicJsonOptions"
          ],
          "returns": "Record<string>"
        },
        {
          "name": "withDatabase",
          "async": true,
          "params": [
            "db: DatabaseInterface",
            "operation: Function"
          ],
          "returns": "Promise<T>"
        }
      ],
      "tableStrategy": "sti",
      "surfaces": [
        {
          "kind": "api",
          "name": "tenants.list",
          "operation": "list",
          "objectName": "@happyvertical/smrt-users:Tenant",
          "path": "/tenants",
          "method": "GET"
        },
        {
          "kind": "api",
          "name": "tenants.get",
          "operation": "get",
          "objectName": "@happyvertical/smrt-users:Tenant",
          "path": "/tenants/[id]",
          "method": "GET"
        },
        {
          "kind": "cli",
          "name": "tenant_list",
          "operation": "list",
          "objectName": "@happyvertical/smrt-users:Tenant"
        },
        {
          "kind": "cli",
          "name": "tenant_get",
          "operation": "get",
          "objectName": "@happyvertical/smrt-users:Tenant"
        },
        {
          "kind": "cli",
          "name": "tenant_create",
          "operation": "create",
          "objectName": "@happyvertical/smrt-users:Tenant"
        },
        {
          "kind": "cli",
          "name": "tenant_update",
          "operation": "update",
          "objectName": "@happyvertical/smrt-users:Tenant"
        },
        {
          "kind": "cli",
          "name": "tenant_delete",
          "operation": "delete",
          "objectName": "@happyvertical/smrt-users:Tenant"
        },
        {
          "kind": "mcp",
          "name": "tenant_list",
          "operation": "list",
          "objectName": "@happyvertical/smrt-users:Tenant"
        },
        {
          "kind": "mcp",
          "name": "tenant_get",
          "operation": "get",
          "objectName": "@happyvertical/smrt-users:Tenant"
        }
      ],
      "relationshipFeatures": [
        "foreignKey",
        "uuidColumns"
      ],
      "tags": [],
      "risks": []
    },
    {
      "name": "TenantIntegration",
      "qualifiedName": "@happyvertical/smrt-users:TenantIntegration",
      "collection": "tenantintegrations",
      "tableName": "tenant_integrations",
      "packageName": "@happyvertical/smrt-users",
      "extends": "SmrtObject",
      "fields": [
        {
          "name": "tenantId",
          "type": "text",
          "required": true,
          "columnType": "UUID"
        },
        {
          "name": "provider",
          "type": "text",
          "required": false,
          "columnType": "TEXT",
          "default": "aws"
        },
        {
          "name": "externalIds",
          "type": "text",
          "required": false,
          "columnType": "TEXT"
        },
        {
          "name": "status",
          "type": "text",
          "required": false,
          "columnType": "TEXT",
          "default": "unprovisioned"
        },
        {
          "name": "lastCheckedAt",
          "type": "datetime",
          "required": false,
          "columnType": "TIMESTAMP"
        },
        {
          "name": "lastCheckSummary",
          "type": "text",
          "required": false,
          "columnType": "TEXT"
        },
        {
          "name": "lastError",
          "type": "text",
          "required": false,
          "columnType": "TEXT"
        }
      ],
      "relationships": [],
      "methods": [
        "getExternalId",
        "getExternalIds",
        "getLastCheckSummary",
        "initialize",
        "recordDoctorRun",
        "setExternalId",
        "setExternalIds",
        "setLastCheckSummary"
      ],
      "methodSignatures": [
        {
          "name": "getExternalId",
          "params": [
            "key: string"
          ],
          "returns": "string | undefined"
        },
        {
          "name": "getExternalIds",
          "returns": "Record<string, string>"
        },
        {
          "name": "getLastCheckSummary",
          "returns": "TenantIntegrationCheckSummary[]"
        },
        {
          "name": "initialize",
          "async": true,
          "returns": "Promise"
        },
        {
          "name": "recordDoctorRun",
          "params": [
            "outcome: object"
          ],
          "returns": "void"
        },
        {
          "name": "setExternalId",
          "params": [
            "key: string",
            "value: string | undefined"
          ],
          "returns": "void"
        },
        {
          "name": "setExternalIds",
          "params": [
            "externalIds: Record<string, string> | string"
          ],
          "returns": "void"
        },
        {
          "name": "setLastCheckSummary",
          "params": [
            "summary: TenantIntegrationCheckSummary[] | string"
          ],
          "returns": "void"
        }
      ],
      "tenant": {
        "scoped": true,
        "mode": "required",
        "field": "tenantId"
      },
      "conflictColumns": [
        "tenant_id",
        "provider"
      ],
      "surfaces": [
        {
          "kind": "api",
          "name": "tenantintegrations.list",
          "operation": "list",
          "objectName": "@happyvertical/smrt-users:TenantIntegration",
          "path": "/tenantintegrations",
          "method": "GET"
        },
        {
          "kind": "api",
          "name": "tenantintegrations.get",
          "operation": "get",
          "objectName": "@happyvertical/smrt-users:TenantIntegration",
          "path": "/tenantintegrations/[id]",
          "method": "GET"
        },
        {
          "kind": "cli",
          "name": "tenantintegration_list",
          "operation": "list",
          "objectName": "@happyvertical/smrt-users:TenantIntegration"
        },
        {
          "kind": "cli",
          "name": "tenantintegration_get",
          "operation": "get",
          "objectName": "@happyvertical/smrt-users:TenantIntegration"
        },
        {
          "kind": "cli",
          "name": "tenantintegration_create",
          "operation": "create",
          "objectName": "@happyvertical/smrt-users:TenantIntegration"
        },
        {
          "kind": "cli",
          "name": "tenantintegration_update",
          "operation": "update",
          "objectName": "@happyvertical/smrt-users:TenantIntegration"
        },
        {
          "kind": "cli",
          "name": "tenantintegration_delete",
          "operation": "delete",
          "objectName": "@happyvertical/smrt-users:TenantIntegration"
        },
        {
          "kind": "mcp",
          "name": "tenantintegration_list",
          "operation": "list",
          "objectName": "@happyvertical/smrt-users:TenantIntegration"
        },
        {
          "kind": "mcp",
          "name": "tenantintegration_get",
          "operation": "get",
          "objectName": "@happyvertical/smrt-users:TenantIntegration"
        }
      ],
      "relationshipFeatures": [
        "uuidColumns"
      ],
      "tags": [],
      "risks": []
    },
    {
      "name": "TenantPermissionOverride",
      "qualifiedName": "@happyvertical/smrt-users:TenantPermissionOverride",
      "collection": "tenantpermissionoverrides",
      "tableName": "tenant_permission_overrides",
      "packageName": "@happyvertical/smrt-users",
      "extends": "SmrtObject",
      "fields": [
        {
          "name": "tenantId",
          "type": "foreignKey",
          "required": true,
          "related": "Tenant",
          "columnType": "UUID"
        },
        {
          "name": "permissionId",
          "type": "foreignKey",
          "required": true,
          "related": "Permission",
          "columnType": "UUID"
        },
        {
          "name": "effect",
          "type": "text",
          "required": false,
          "columnType": "TEXT"
        }
      ],
      "relationships": [
        {
          "name": "tenantId",
          "type": "foreignKey",
          "required": true,
          "related": "Tenant",
          "columnType": "UUID"
        },
        {
          "name": "permissionId",
          "type": "foreignKey",
          "required": true,
          "related": "Permission",
          "columnType": "UUID"
        }
      ],
      "methods": [
        "hasExplicitEffect",
        "isDeny",
        "isGrant",
        "isInherit"
      ],
      "methodSignatures": [
        {
          "name": "hasExplicitEffect",
          "returns": "boolean"
        },
        {
          "name": "isDeny",
          "returns": "boolean"
        },
        {
          "name": "isGrant",
          "returns": "boolean"
        },
        {
          "name": "isInherit",
          "returns": "boolean"
        }
      ],
      "surfaces": [
        {
          "kind": "api",
          "name": "tenantpermissionoverrides.list",
          "operation": "list",
          "objectName": "@happyvertical/smrt-users:TenantPermissionOverride",
          "path": "/tenantpermissionoverrides",
          "method": "GET"
        },
        {
          "kind": "api",
          "name": "tenantpermissionoverrides.get",
          "operation": "get",
          "objectName": "@happyvertical/smrt-users:TenantPermissionOverride",
          "path": "/tenantpermissionoverrides/[id]",
          "method": "GET"
        },
        {
          "kind": "cli",
          "name": "tenantpermissionoverride_list",
          "operation": "list",
          "objectName": "@happyvertical/smrt-users:TenantPermissionOverride"
        },
        {
          "kind": "cli",
          "name": "tenantpermissionoverride_get",
          "operation": "get",
          "objectName": "@happyvertical/smrt-users:TenantPermissionOverride"
        },
        {
          "kind": "cli",
          "name": "tenantpermissionoverride_create",
          "operation": "create",
          "objectName": "@happyvertical/smrt-users:TenantPermissionOverride"
        },
        {
          "kind": "cli",
          "name": "tenantpermissionoverride_update",
          "operation": "update",
          "objectName": "@happyvertical/smrt-users:TenantPermissionOverride"
        },
        {
          "kind": "cli",
          "name": "tenantpermissionoverride_delete",
          "operation": "delete",
          "objectName": "@happyvertical/smrt-users:TenantPermissionOverride"
        },
        {
          "kind": "mcp",
          "name": "tenantpermissionoverride_list",
          "operation": "list",
          "objectName": "@happyvertical/smrt-users:TenantPermissionOverride"
        },
        {
          "kind": "mcp",
          "name": "tenantpermissionoverride_get",
          "operation": "get",
          "objectName": "@happyvertical/smrt-users:TenantPermissionOverride"
        }
      ],
      "relationshipFeatures": [
        "foreignKey",
        "uuidColumns"
      ],
      "tags": [],
      "risks": []
    },
    {
      "name": "User",
      "qualifiedName": "@happyvertical/smrt-users:User",
      "collection": "users",
      "tableName": "users",
      "packageName": "@happyvertical/smrt-users",
      "extends": "SmrtObject",
      "fields": [
        {
          "name": "profileId",
          "type": "crossPackageRef",
          "required": false,
          "related": "@happyvertical/smrt-profiles:Profile",
          "columnType": "UUID"
        },
        {
          "name": "email",
          "type": "text",
          "required": false,
          "columnType": "TEXT",
          "default": ""
        },
        {
          "name": "emailKey",
          "type": "text",
          "required": false,
          "columnType": "TEXT",
          "readonly": true
        },
        {
          "name": "status",
          "type": "text",
          "required": false,
          "columnType": "TEXT"
        },
        {
          "name": "lastLoginAt",
          "type": "datetime",
          "required": false,
          "columnType": "TIMESTAMP"
        }
      ],
      "relationships": [
        {
          "name": "profileId",
          "type": "crossPackageRef",
          "required": false,
          "related": "@happyvertical/smrt-profiles:Profile",
          "columnType": "UUID"
        }
      ],
      "methods": [
        "hasValidEmail",
        "isActive",
        "isPending",
        "isSuspended",
        "recordLogin",
        "save"
      ],
      "methodSignatures": [
        {
          "name": "hasValidEmail",
          "returns": "boolean"
        },
        {
          "name": "isActive",
          "returns": "boolean"
        },
        {
          "name": "isPending",
          "returns": "boolean"
        },
        {
          "name": "isSuspended",
          "returns": "boolean"
        },
        {
          "name": "recordLogin",
          "returns": "void"
        },
        {
          "name": "save",
          "async": true,
          "returns": "Promise"
        }
      ],
      "surfaces": [
        {
          "kind": "api",
          "name": "users.list",
          "operation": "list",
          "objectName": "@happyvertical/smrt-users:User",
          "path": "/users",
          "method": "GET"
        },
        {
          "kind": "api",
          "name": "users.get",
          "operation": "get",
          "objectName": "@happyvertical/smrt-users:User",
          "path": "/users/[id]",
          "method": "GET"
        },
        {
          "kind": "cli",
          "name": "user_list",
          "operation": "list",
          "objectName": "@happyvertical/smrt-users:User"
        },
        {
          "kind": "cli",
          "name": "user_get",
          "operation": "get",
          "objectName": "@happyvertical/smrt-users:User"
        },
        {
          "kind": "cli",
          "name": "user_create",
          "operation": "create",
          "objectName": "@happyvertical/smrt-users:User"
        },
        {
          "kind": "cli",
          "name": "user_update",
          "operation": "update",
          "objectName": "@happyvertical/smrt-users:User"
        },
        {
          "kind": "cli",
          "name": "user_delete",
          "operation": "delete",
          "objectName": "@happyvertical/smrt-users:User"
        },
        {
          "kind": "mcp",
          "name": "user_list",
          "operation": "list",
          "objectName": "@happyvertical/smrt-users:User"
        },
        {
          "kind": "mcp",
          "name": "user_get",
          "operation": "get",
          "objectName": "@happyvertical/smrt-users:User"
        }
      ],
      "relationshipFeatures": [
        "crossPackageRef",
        "uuidColumns"
      ],
      "tags": [],
      "risks": []
    }
  ],
  "surfaces": [
    {
      "kind": "api",
      "name": "groups.list",
      "operation": "list",
      "objectName": "@happyvertical/smrt-users:Group",
      "path": "/groups",
      "method": "GET"
    },
    {
      "kind": "api",
      "name": "groups.get",
      "operation": "get",
      "objectName": "@happyvertical/smrt-users:Group",
      "path": "/groups/[id]",
      "method": "GET"
    },
    {
      "kind": "cli",
      "name": "group_list",
      "operation": "list",
      "objectName": "@happyvertical/smrt-users:Group"
    },
    {
      "kind": "cli",
      "name": "group_get",
      "operation": "get",
      "objectName": "@happyvertical/smrt-users:Group"
    },
    {
      "kind": "cli",
      "name": "group_create",
      "operation": "create",
      "objectName": "@happyvertical/smrt-users:Group"
    },
    {
      "kind": "cli",
      "name": "group_update",
      "operation": "update",
      "objectName": "@happyvertical/smrt-users:Group"
    },
    {
      "kind": "cli",
      "name": "group_delete",
      "operation": "delete",
      "objectName": "@happyvertical/smrt-users:Group"
    },
    {
      "kind": "mcp",
      "name": "group_list",
      "operation": "list",
      "objectName": "@happyvertical/smrt-users:Group"
    },
    {
      "kind": "mcp",
      "name": "group_get",
      "operation": "get",
      "objectName": "@happyvertical/smrt-users:Group"
    },
    {
      "kind": "api",
      "name": "groupmembers.list",
      "operation": "list",
      "objectName": "@happyvertical/smrt-users:GroupMember",
      "path": "/groupmembers",
      "method": "GET"
    },
    {
      "kind": "api",
      "name": "groupmembers.get",
      "operation": "get",
      "objectName": "@happyvertical/smrt-users:GroupMember",
      "path": "/groupmembers/[id]",
      "method": "GET"
    },
    {
      "kind": "cli",
      "name": "groupmember_list",
      "operation": "list",
      "objectName": "@happyvertical/smrt-users:GroupMember"
    },
    {
      "kind": "cli",
      "name": "groupmember_get",
      "operation": "get",
      "objectName": "@happyvertical/smrt-users:GroupMember"
    },
    {
      "kind": "cli",
      "name": "groupmember_create",
      "operation": "create",
      "objectName": "@happyvertical/smrt-users:GroupMember"
    },
    {
      "kind": "cli",
      "name": "groupmember_update",
      "operation": "update",
      "objectName": "@happyvertical/smrt-users:GroupMember"
    },
    {
      "kind": "cli",
      "name": "groupmember_delete",
      "operation": "delete",
      "objectName": "@happyvertical/smrt-users:GroupMember"
    },
    {
      "kind": "mcp",
      "name": "groupmember_list",
      "operation": "list",
      "objectName": "@happyvertical/smrt-users:GroupMember"
    },
    {
      "kind": "mcp",
      "name": "groupmember_get",
      "operation": "get",
      "objectName": "@happyvertical/smrt-users:GroupMember"
    },
    {
      "kind": "api",
      "name": "grouproles.list",
      "operation": "list",
      "objectName": "@happyvertical/smrt-users:GroupRole",
      "path": "/grouproles",
      "method": "GET"
    },
    {
      "kind": "api",
      "name": "grouproles.get",
      "operation": "get",
      "objectName": "@happyvertical/smrt-users:GroupRole",
      "path": "/grouproles/[id]",
      "method": "GET"
    },
    {
      "kind": "cli",
      "name": "grouprole_list",
      "operation": "list",
      "objectName": "@happyvertical/smrt-users:GroupRole"
    },
    {
      "kind": "cli",
      "name": "grouprole_get",
      "operation": "get",
      "objectName": "@happyvertical/smrt-users:GroupRole"
    },
    {
      "kind": "cli",
      "name": "grouprole_create",
      "operation": "create",
      "objectName": "@happyvertical/smrt-users:GroupRole"
    },
    {
      "kind": "cli",
      "name": "grouprole_update",
      "operation": "update",
      "objectName": "@happyvertical/smrt-users:GroupRole"
    },
    {
      "kind": "cli",
      "name": "grouprole_delete",
      "operation": "delete",
      "objectName": "@happyvertical/smrt-users:GroupRole"
    },
    {
      "kind": "mcp",
      "name": "grouprole_list",
      "operation": "list",
      "objectName": "@happyvertical/smrt-users:GroupRole"
    },
    {
      "kind": "mcp",
      "name": "grouprole_get",
      "operation": "get",
      "objectName": "@happyvertical/smrt-users:GroupRole"
    },
    {
      "kind": "cli",
      "name": "usersmagiclinktoken_list",
      "operation": "list",
      "objectName": "@happyvertical/smrt-users:UsersMagicLinkToken"
    },
    {
      "kind": "cli",
      "name": "usersmagiclinktoken_get",
      "operation": "get",
      "objectName": "@happyvertical/smrt-users:UsersMagicLinkToken"
    },
    {
      "kind": "cli",
      "name": "usersmagiclinktoken_create",
      "operation": "create",
      "objectName": "@happyvertical/smrt-users:UsersMagicLinkToken"
    },
    {
      "kind": "cli",
      "name": "usersmagiclinktoken_update",
      "operation": "update",
      "objectName": "@happyvertical/smrt-users:UsersMagicLinkToken"
    },
    {
      "kind": "cli",
      "name": "usersmagiclinktoken_delete",
      "operation": "delete",
      "objectName": "@happyvertical/smrt-users:UsersMagicLinkToken"
    },
    {
      "kind": "api",
      "name": "memberships.list",
      "operation": "list",
      "objectName": "@happyvertical/smrt-users:Membership",
      "path": "/memberships",
      "method": "GET"
    },
    {
      "kind": "api",
      "name": "memberships.get",
      "operation": "get",
      "objectName": "@happyvertical/smrt-users:Membership",
      "path": "/memberships/[id]",
      "method": "GET"
    },
    {
      "kind": "cli",
      "name": "membership_list",
      "operation": "list",
      "objectName": "@happyvertical/smrt-users:Membership"
    },
    {
      "kind": "cli",
      "name": "membership_get",
      "operation": "get",
      "objectName": "@happyvertical/smrt-users:Membership"
    },
    {
      "kind": "cli",
      "name": "membership_create",
      "operation": "create",
      "objectName": "@happyvertical/smrt-users:Membership"
    },
    {
      "kind": "cli",
      "name": "membership_update",
      "operation": "update",
      "objectName": "@happyvertical/smrt-users:Membership"
    },
    {
      "kind": "cli",
      "name": "membership_delete",
      "operation": "delete",
      "objectName": "@happyvertical/smrt-users:Membership"
    },
    {
      "kind": "mcp",
      "name": "membership_list",
      "operation": "list",
      "objectName": "@happyvertical/smrt-users:Membership"
    },
    {
      "kind": "mcp",
      "name": "membership_get",
      "operation": "get",
      "objectName": "@happyvertical/smrt-users:Membership"
    },
    {
      "kind": "api",
      "name": "membershipoverrides.list",
      "operation": "list",
      "objectName": "@happyvertical/smrt-users:MembershipOverride",
      "path": "/membershipoverrides",
      "method": "GET"
    },
    {
      "kind": "api",
      "name": "membershipoverrides.get",
      "operation": "get",
      "objectName": "@happyvertical/smrt-users:MembershipOverride",
      "path": "/membershipoverrides/[id]",
      "method": "GET"
    },
    {
      "kind": "cli",
      "name": "membershipoverride_list",
      "operation": "list",
      "objectName": "@happyvertical/smrt-users:MembershipOverride"
    },
    {
      "kind": "cli",
      "name": "membershipoverride_get",
      "operation": "get",
      "objectName": "@happyvertical/smrt-users:MembershipOverride"
    },
    {
      "kind": "cli",
      "name": "membershipoverride_create",
      "operation": "create",
      "objectName": "@happyvertical/smrt-users:MembershipOverride"
    },
    {
      "kind": "cli",
      "name": "membershipoverride_update",
      "operation": "update",
      "objectName": "@happyvertical/smrt-users:MembershipOverride"
    },
    {
      "kind": "cli",
      "name": "membershipoverride_delete",
      "operation": "delete",
      "objectName": "@happyvertical/smrt-users:MembershipOverride"
    },
    {
      "kind": "mcp",
      "name": "membershipoverride_list",
      "operation": "list",
      "objectName": "@happyvertical/smrt-users:MembershipOverride"
    },
    {
      "kind": "mcp",
      "name": "membershipoverride_get",
      "operation": "get",
      "objectName": "@happyvertical/smrt-users:MembershipOverride"
    },
    {
      "kind": "api",
      "name": "permissions.list",
      "operation": "list",
      "objectName": "@happyvertical/smrt-users:Permission",
      "path": "/permissions",
      "method": "GET"
    },
    {
      "kind": "api",
      "name": "permissions.get",
      "operation": "get",
      "objectName": "@happyvertical/smrt-users:Permission",
      "path": "/permissions/[id]",
      "method": "GET"
    },
    {
      "kind": "cli",
      "name": "permission_list",
      "operation": "list",
      "objectName": "@happyvertical/smrt-users:Permission"
    },
    {
      "kind": "cli",
      "name": "permission_get",
      "operation": "get",
      "objectName": "@happyvertical/smrt-users:Permission"
    },
    {
      "kind": "cli",
      "name": "permission_create",
      "operation": "create",
      "objectName": "@happyvertical/smrt-users:Permission"
    },
    {
      "kind": "cli",
      "name": "permission_update",
      "operation": "update",
      "objectName": "@happyvertical/smrt-users:Permission"
    },
    {
      "kind": "cli",
      "name": "permission_delete",
      "operation": "delete",
      "objectName": "@happyvertical/smrt-users:Permission"
    },
    {
      "kind": "mcp",
      "name": "permission_list",
      "operation": "list",
      "objectName": "@happyvertical/smrt-users:Permission"
    },
    {
      "kind": "mcp",
      "name": "permission_get",
      "operation": "get",
      "objectName": "@happyvertical/smrt-users:Permission"
    },
    {
      "kind": "api",
      "name": "roles.list",
      "operation": "list",
      "objectName": "@happyvertical/smrt-users:Role",
      "path": "/roles",
      "method": "GET"
    },
    {
      "kind": "api",
      "name": "roles.get",
      "operation": "get",
      "objectName": "@happyvertical/smrt-users:Role",
      "path": "/roles/[id]",
      "method": "GET"
    },
    {
      "kind": "cli",
      "name": "role_list",
      "operation": "list",
      "objectName": "@happyvertical/smrt-users:Role"
    },
    {
      "kind": "cli",
      "name": "role_get",
      "operation": "get",
      "objectName": "@happyvertical/smrt-users:Role"
    },
    {
      "kind": "cli",
      "name": "role_create",
      "operation": "create",
      "objectName": "@happyvertical/smrt-users:Role"
    },
    {
      "kind": "cli",
      "name": "role_update",
      "operation": "update",
      "objectName": "@happyvertical/smrt-users:Role"
    },
    {
      "kind": "cli",
      "name": "role_delete",
      "operation": "delete",
      "objectName": "@happyvertical/smrt-users:Role"
    },
    {
      "kind": "mcp",
      "name": "role_list",
      "operation": "list",
      "objectName": "@happyvertical/smrt-users:Role"
    },
    {
      "kind": "mcp",
      "name": "role_get",
      "operation": "get",
      "objectName": "@happyvertical/smrt-users:Role"
    },
    {
      "kind": "api",
      "name": "rolepermissions.list",
      "operation": "list",
      "objectName": "@happyvertical/smrt-users:RolePermission",
      "path": "/rolepermissions",
      "method": "GET"
    },
    {
      "kind": "api",
      "name": "rolepermissions.get",
      "operation": "get",
      "objectName": "@happyvertical/smrt-users:RolePermission",
      "path": "/rolepermissions/[id]",
      "method": "GET"
    },
    {
      "kind": "cli",
      "name": "rolepermission_list",
      "operation": "list",
      "objectName": "@happyvertical/smrt-users:RolePermission"
    },
    {
      "kind": "cli",
      "name": "rolepermission_get",
      "operation": "get",
      "objectName": "@happyvertical/smrt-users:RolePermission"
    },
    {
      "kind": "cli",
      "name": "rolepermission_create",
      "operation": "create",
      "objectName": "@happyvertical/smrt-users:RolePermission"
    },
    {
      "kind": "cli",
      "name": "rolepermission_update",
      "operation": "update",
      "objectName": "@happyvertical/smrt-users:RolePermission"
    },
    {
      "kind": "cli",
      "name": "rolepermission_delete",
      "operation": "delete",
      "objectName": "@happyvertical/smrt-users:RolePermission"
    },
    {
      "kind": "mcp",
      "name": "rolepermission_list",
      "operation": "list",
      "objectName": "@happyvertical/smrt-users:RolePermission"
    },
    {
      "kind": "mcp",
      "name": "rolepermission_get",
      "operation": "get",
      "objectName": "@happyvertical/smrt-users:RolePermission"
    },
    {
      "kind": "api",
      "name": "sessions.get",
      "operation": "get",
      "objectName": "@happyvertical/smrt-users:Session",
      "path": "/sessions/[id]",
      "method": "GET"
    },
    {
      "kind": "api",
      "name": "sessions.delete",
      "operation": "delete",
      "objectName": "@happyvertical/smrt-users:Session",
      "path": "/sessions/[id]",
      "method": "DELETE"
    },
    {
      "kind": "cli",
      "name": "session_list",
      "operation": "list",
      "objectName": "@happyvertical/smrt-users:Session"
    },
    {
      "kind": "cli",
      "name": "session_get",
      "operation": "get",
      "objectName": "@happyvertical/smrt-users:Session"
    },
    {
      "kind": "cli",
      "name": "session_create",
      "operation": "create",
      "objectName": "@happyvertical/smrt-users:Session"
    },
    {
      "kind": "cli",
      "name": "session_update",
      "operation": "update",
      "objectName": "@happyvertical/smrt-users:Session"
    },
    {
      "kind": "cli",
      "name": "session_delete",
      "operation": "delete",
      "objectName": "@happyvertical/smrt-users:Session"
    },
    {
      "kind": "api",
      "name": "tenants.list",
      "operation": "list",
      "objectName": "@happyvertical/smrt-users:Tenant",
      "path": "/tenants",
      "method": "GET"
    },
    {
      "kind": "api",
      "name": "tenants.get",
      "operation": "get",
      "objectName": "@happyvertical/smrt-users:Tenant",
      "path": "/tenants/[id]",
      "method": "GET"
    },
    {
      "kind": "cli",
      "name": "tenant_list",
      "operation": "list",
      "objectName": "@happyvertical/smrt-users:Tenant"
    },
    {
      "kind": "cli",
      "name": "tenant_get",
      "operation": "get",
      "objectName": "@happyvertical/smrt-users:Tenant"
    },
    {
      "kind": "cli",
      "name": "tenant_create",
      "operation": "create",
      "objectName": "@happyvertical/smrt-users:Tenant"
    },
    {
      "kind": "cli",
      "name": "tenant_update",
      "operation": "update",
      "objectName": "@happyvertical/smrt-users:Tenant"
    },
    {
      "kind": "cli",
      "name": "tenant_delete",
      "operation": "delete",
      "objectName": "@happyvertical/smrt-users:Tenant"
    },
    {
      "kind": "mcp",
      "name": "tenant_list",
      "operation": "list",
      "objectName": "@happyvertical/smrt-users:Tenant"
    },
    {
      "kind": "mcp",
      "name": "tenant_get",
      "operation": "get",
      "objectName": "@happyvertical/smrt-users:Tenant"
    },
    {
      "kind": "api",
      "name": "tenantintegrations.list",
      "operation": "list",
      "objectName": "@happyvertical/smrt-users:TenantIntegration",
      "path": "/tenantintegrations",
      "method": "GET"
    },
    {
      "kind": "api",
      "name": "tenantintegrations.get",
      "operation": "get",
      "objectName": "@happyvertical/smrt-users:TenantIntegration",
      "path": "/tenantintegrations/[id]",
      "method": "GET"
    },
    {
      "kind": "cli",
      "name": "tenantintegration_list",
      "operation": "list",
      "objectName": "@happyvertical/smrt-users:TenantIntegration"
    },
    {
      "kind": "cli",
      "name": "tenantintegration_get",
      "operation": "get",
      "objectName": "@happyvertical/smrt-users:TenantIntegration"
    },
    {
      "kind": "cli",
      "name": "tenantintegration_create",
      "operation": "create",
      "objectName": "@happyvertical/smrt-users:TenantIntegration"
    },
    {
      "kind": "cli",
      "name": "tenantintegration_update",
      "operation": "update",
      "objectName": "@happyvertical/smrt-users:TenantIntegration"
    },
    {
      "kind": "cli",
      "name": "tenantintegration_delete",
      "operation": "delete",
      "objectName": "@happyvertical/smrt-users:TenantIntegration"
    },
    {
      "kind": "mcp",
      "name": "tenantintegration_list",
      "operation": "list",
      "objectName": "@happyvertical/smrt-users:TenantIntegration"
    },
    {
      "kind": "mcp",
      "name": "tenantintegration_get",
      "operation": "get",
      "objectName": "@happyvertical/smrt-users:TenantIntegration"
    },
    {
      "kind": "api",
      "name": "tenantpermissionoverrides.list",
      "operation": "list",
      "objectName": "@happyvertical/smrt-users:TenantPermissionOverride",
      "path": "/tenantpermissionoverrides",
      "method": "GET"
    },
    {
      "kind": "api",
      "name": "tenantpermissionoverrides.get",
      "operation": "get",
      "objectName": "@happyvertical/smrt-users:TenantPermissionOverride",
      "path": "/tenantpermissionoverrides/[id]",
      "method": "GET"
    },
    {
      "kind": "cli",
      "name": "tenantpermissionoverride_list",
      "operation": "list",
      "objectName": "@happyvertical/smrt-users:TenantPermissionOverride"
    },
    {
      "kind": "cli",
      "name": "tenantpermissionoverride_get",
      "operation": "get",
      "objectName": "@happyvertical/smrt-users:TenantPermissionOverride"
    },
    {
      "kind": "cli",
      "name": "tenantpermissionoverride_create",
      "operation": "create",
      "objectName": "@happyvertical/smrt-users:TenantPermissionOverride"
    },
    {
      "kind": "cli",
      "name": "tenantpermissionoverride_update",
      "operation": "update",
      "objectName": "@happyvertical/smrt-users:TenantPermissionOverride"
    },
    {
      "kind": "cli",
      "name": "tenantpermissionoverride_delete",
      "operation": "delete",
      "objectName": "@happyvertical/smrt-users:TenantPermissionOverride"
    },
    {
      "kind": "mcp",
      "name": "tenantpermissionoverride_list",
      "operation": "list",
      "objectName": "@happyvertical/smrt-users:TenantPermissionOverride"
    },
    {
      "kind": "mcp",
      "name": "tenantpermissionoverride_get",
      "operation": "get",
      "objectName": "@happyvertical/smrt-users:TenantPermissionOverride"
    },
    {
      "kind": "api",
      "name": "users.list",
      "operation": "list",
      "objectName": "@happyvertical/smrt-users:User",
      "path": "/users",
      "method": "GET"
    },
    {
      "kind": "api",
      "name": "users.get",
      "operation": "get",
      "objectName": "@happyvertical/smrt-users:User",
      "path": "/users/[id]",
      "method": "GET"
    },
    {
      "kind": "cli",
      "name": "user_list",
      "operation": "list",
      "objectName": "@happyvertical/smrt-users:User"
    },
    {
      "kind": "cli",
      "name": "user_get",
      "operation": "get",
      "objectName": "@happyvertical/smrt-users:User"
    },
    {
      "kind": "cli",
      "name": "user_create",
      "operation": "create",
      "objectName": "@happyvertical/smrt-users:User"
    },
    {
      "kind": "cli",
      "name": "user_update",
      "operation": "update",
      "objectName": "@happyvertical/smrt-users:User"
    },
    {
      "kind": "cli",
      "name": "user_delete",
      "operation": "delete",
      "objectName": "@happyvertical/smrt-users:User"
    },
    {
      "kind": "mcp",
      "name": "user_list",
      "operation": "list",
      "objectName": "@happyvertical/smrt-users:User"
    },
    {
      "kind": "mcp",
      "name": "user_get",
      "operation": "get",
      "objectName": "@happyvertical/smrt-users:User"
    }
  ],
  "prompts": [],
  "relationshipsV2": {
    "foreignKeyFields": 22,
    "crossPackageRefFields": 1,
    "junctionCollections": 0,
    "hierarchicalObjects": 0,
    "polymorphicAssociations": 0,
    "uuidColumns": 58
  },
  "agentDoc": "# @happyvertical/smrt-users\n\nMulti-tenant user management with RBAC, hierarchical tenants, session handling, and SvelteKit integration.\n\n## Modules\n\n| Module | Scope | Module doc |\n|---|---|---|\n| `src/retention.ts` | expired session/token/CLI-auth reaping and its wiring into the framework retention sweep | [agents/retention.md](agents/retention.md) |\n\n## Models (14)\n\n| Model | Key Pattern |\n|-------|-------------|\n| User | Auth identity. `profileId` is a unique cross-package reference to smrt-profiles (one User per non-null Profile). Email auto-lowercased; readonly nullable unique `emailKey` is derived on save for durable normalized uniqueness. |\n| AccessRequest | \"Request access / waitlist\" record captured before a `User` exists. CLOSED generated surface (`api`/`mcp`/`cli` = `[]`) — all access via `AccessRequestService`. Email normalized + indexed; JSON `requestContext` (NOT `context` — reserved for slug scoping). |\n| Tenant | **STI** + hierarchical parent-child. `hierarchyPath` (materialized path), `hierarchyLevel`. Max depth 10. |\n| Session | Server-side. Secure UUID. TTL in **seconds** (not ms). Status auto-updates to EXPIRED on access. |\n| MagicLinkToken | Single-use email login token. Backed by `MagicLinkService`. |\n| Role | `tenantId = null` → system role (available to all tenants). `isSystem: true` blocks deletion. `inheritsToDescendants: true` (default false) opts the role's membership authority into descendant tenants. |\n| Permission | Slug format: `resource.action`. Parsed by PermissionResolver. |\n| Membership | User + Tenant + Role junction. UNIQUE(userId, tenantId). |\n| Group | Team within a tenant. Multiple roles via GroupRole. |\n| GroupMember, GroupRole, RolePermission | Join tables. |\n| MembershipOverride | Per-user permission grant/deny. **DENY always wins.** |\n| TenantPermissionOverride | Tenant-level cascade overrides. Effect: INHERIT/GRANT/DENY. |\n\n## Permission Resolution — Precedence (broad → specific, most-specific wins)\n\n`PermissionResolver.resolvePermissions` builds the effective set in this order;\neach later layer overrides earlier ones:\n\n1. **Tenant-inherited** — walk ancestors, apply each `TenantPermissionOverride`\n   down the cascade (GRANT adds, DENY removes within the hierarchy)\n2. **Membership role** — base permissions from the user's role in the tenant\n3. **Group roles** — permissions from all groups the user belongs to **in that tenant**\n4. **Tenant-level DENY** *(removes; overrides role/group grants, tenant-wide)* — a\n   `TenantPermissionOverride` with effect `DENY` is a HARD, tenant-wide block: it\n   subtracts the DENY'd slug even if a role or group granted it (steps 2–3). It\n   sits just **above** the per-user membership overrides and **below** role/group.\n5. **Membership GRANT override** *(re-adds; most specific)* — a per-user GRANT can\n   re-add a slug a tenant DENY'd in step 4, because it is more specific.\n6. **Membership DENY override** *(absolute; always wins)* — a per-user DENY removes\n   the slug last and is never overridden.\n\nSo a permission a role grants but the tenant DENYs is **removed**, unless that\nexact user also has a membership-GRANT override for it. A membership-DENY always\nwins. Tenant-DENY of an inherited/cascade grant still blocks it (unchanged).\nThe hard block reflects the tenant cascade's **net** resolution, not an\nunconditional union of every DENY in the chain — so a more-specific tenant GRANT\n(e.g. a child sub-tenant re-granting a permission its parent DENYs) still wins.\n\n### Membership selection — hierarchical inheritance (opt-in, #1866)\n\nWhich membership feeds step 2 above:\n\n1. **A direct membership row in the target tenant always pins resolution to\n   itself** — active rows resolve normally; an inactive (pending/suspended)\n   row resolves to the **empty set**. A direct row therefore *attenuates*\n   rather than unions: \"viewer here, despite being network admin\" gives\n   viewer, and a suspension in the child is effective even for users holding\n   inheritable authority on an ancestor.\n2. **No direct row** → the resolver walks the tenant's ancestors (nearest\n   first, from `hierarchyPath`) and resolves through the **nearest ACTIVE\n   ancestor membership whose role has `inheritsToDescendants: true`**.\n   Unflagged or inactive ancestor memberships are skipped (they neither confer\n   nor block); there is **no union across the chain** — the nearest flagged\n   membership alone is used. To attenuate a specific descendant, create a\n   direct membership there or use a tenant-level DENY.\n3. **No qualifying ancestor** → empty set (byte-identical to the\n   pre-inheritance resolver; with no role flagged, nothing changes).\n\nAll later layers run unchanged against the **target** tenant: the tenant\ncascade and tenant-DENY hard block come from the target tenant (a child can\ncarve authority out of an inherited role), group roles stay exact-tenant (only\ntarget-tenant groups contribute; ancestor groups never flow down), and\nmembership GRANT/DENY overrides travel with the ancestor membership used.\n`PermissionResolutionResult.inheritedFromTenantId` reports the ancestor tenant\nwhen inheritance was used (`null` for direct resolution).\n\nSafety: resolution is bounded by `MAX_TENANT_HIERARCHY_DEPTH`; malformed\n`hierarchyPath` values fail closed to the empty set — too deep,\nself-referential, duplicate ancestors, or inconsistent with the actual\n`parentTenantId` chain (the path is verified link-by-link against the loaded\nancestor rows before it is trusted as an authorization source). Tenant `status` is not consulted (parity with direct\nresolution). Caching: a long-lived `(user, tenant)` permission cache must also\ninvalidate on ancestor-membership changes and on `Role.inheritsToDescendants`\nflips — request-scoped caches (the common pattern) are unaffected.\n\nFlag roles at seed time with\n`seedSystemRoles({ inheritsToDescendants: ['owner', 'admin'] })` (additive:\nlisted slugs are flagged, omitted slugs are never unflagged; unknown slugs\nthrow). The default seed leaves every role exact-tenant.\n\n## Operation Permission Guards\n\nSMRT derives a fine-grained, per-`<collection>.<action>` permission catalog **from the\nmanifest** (`PermissionCatalogService`, including custom `@smrt` actions — not just CRUD)\nand enforces it two ways: app-side via `assertOperationPermission()` / `PermissionResolver`,\nand at the database via generated **Postgres RLS** policies\n(`generatePostgresPermissionSql()` / `applyPostgresPermissionPolicies()`) that read the\nsession-injected `smrt.permissions` / `smrt.tenant_id` (set by `withSessionPermissionContext`\nvia `set_config`). Because the RLS teeth are at the data layer, enforcement is door-agnostic\n— REST, MCP, and in-process callers are all bounded once the principal's context is set.\nSetup: README → *Manifest-derived permission catalog* and *Postgres RLS enforcement*.\n\n- Use `assertOperationPermission()` for hand-written mutations in SvelteKit form\n  actions, custom endpoints, CLI scripts, and jobs. It derives the same\n  `<collection>.<action>` slugs as `PermissionCatalogService` (`list`/`get` →\n  `read`), requires the slug to exist in the catalog, then resolves permissions\n  through `PermissionResolver`.\n- `assertOperationPermission()` throws fail-closed by default. Use\n  `{ onDeny: 'return' }`, `checkOperationPermission()`, or\n  `hasOperationPermission()` when a structured/boolean result is needed.\n- **Resource-tenant calling convention**: for resource-anchored authorization,\n  pass the **resource's** tenant id — `tenantId: resourceTenantId` — not the\n  session's current tenant. With `Role.inheritsToDescendants` flagged, a\n  root-tenant admin then passes for any descendant resource with no app-side\n  authority logic (and no membership fan-out), while per-child delegation and\n  DENY precedence keep working. Do NOT pass a session-scoped `membership`\n  alongside a different resource `tenantId` — a membership/tenant mismatch\n  fails closed by design; omit `membership` and let the resolver look it up.\n- System context and super-admin bypass context are honored for parity with\n  Postgres RLS. Pass `{ allowSuperAdminBypass: false }` on money-class or\n  separation-of-duties operations that must require an explicit permission grant.\n- **Postgres RLS and membership inheritance**: RLS policies check the\n  session-injected `smrt.permissions` list (resolved app-side by\n  `PermissionResolver`), so a session whose `smrt.tenant_id` IS the child\n  tenant gets inherited authority in RLS automatically. But RLS row filtering\n  stays bound to the session's tenant setting — a root-tenant session acting\n  on child-tenant rows is authorized by the app-level guard (resource-tenant\n  convention above), not by RLS. This is a documented divergence, mirroring\n  how #1829 handled bypass parity.\n- Seed role mappings with `RolePermissionCollection.seedRolePermissions()` or\n  `RoleCollection.seedSystemRoles({ seedPermissions: true })`. The default\n  matrix maps owner/admin to all catalog permissions, member to read/create for\n  ordinary app resources, and viewer to read-only. Member create grants\n  intentionally exclude users/RBAC authority and security resources (`users`,\n  `tenants`, `roles`, `permissions`, memberships, groups, sessions, magic-link\n  tokens, and related join/override tables). Re-seeding is additive and\n  idempotent; pruning stale mappings requires `{ prune: true }`. When a\n  contributing package registers a new built-in self-personalization\n  permission after system roles already exist, call the explicit,\n  idempotent `RolePermissionCollection.seedDefaultRolePersonalizationPermissions()`\n  upgrade helper; it targets owner/admin/member/viewer only and never grants\n  custom roles.\n\n**Critical**: `getGroupIdsForTenant(userId, tenantId)` (joins with groups table to scope by tenant). Never use `getGroupIds()` — it's cross-tenant.\n\n## Hierarchical Tenants\n\n- `TenantCollection.createChild()` auto-calculates hierarchy fields, enforces depth limit\n- `moveToParent()` updates tenant + ALL descendants' paths/levels\n- `cascadePermissions` (parent pushes down) + `inheritPermissions` (child accepts) — both must be true\n- `getTree(rootId?)` returns nested structure for UI\n- Two independent downward flows: the `TenantPermissionOverride` **cascade**\n  (tenant-level permission config, flags above) and **membership-role\n  inheritance** (`Role.inheritsToDescendants`, per-role opt-in — see\n  \"Membership selection\" above). The cascade flags do not gate membership\n  inheritance.\n\n## SvelteKit Integration\n\n```typescript\n// hooks.server.ts\nexport const handle = createSessionHandler({ db, ttl: 604800, skipPaths: ['/api/public'] });\n// Populates event.locals: { user, membership, permissions: string[], tenantId, sessionId }\n\n// +page.server.ts\nawait createSessionCookie(event, userId, tenantId, { db });\nawait destroySessionCookie(event, { db });\nawait switchSessionTenant(event, tenantId, { db });\n```\n\n## Mobile `/api/mobile` Handlers (ADR 0001 Phase 3.5, #1748)\n\n`createMobileAuthHandlers(options)` (from `/sveltekit`) returns the mountable\nserver side of the KMP mobile contract: `authStart` (`POST auth/start`,\nserver-brokered PKCE via `OidcLoginService`), `authComplete`\n(`POST auth/complete`, code + echoed `state`/`codeVerifier` → bearer\nsession), `session.GET`/`session.DELETE` (bootstrap/logout), and\n`guard`/`withSession` — the bearer middleware for app-owned mobile routes.\nCore logic lives in `MobileAuthService` (framework-agnostic; exported from\nthe package root).\n\n- **Bearer = session id** (same convention as `TerminalAuthService`); 401\n  bodies are `{ error, code }` and drive the mobile client's re-auth flow.\n- **Stateless handshake**: the OAuth `state` is an HMAC-signed token\n  (secret: `stateSecret` ?? provider `clientSecret`) carrying\n  nonce/provider/createdAt — full ID-token nonce verification with no\n  server-side pending state. The `codeVerifier` never enters a URL: it is\n  client-held per the frozen contract.\n- **Wire DTOs** come from `@happyvertical/smrt-mobile-contract`\n  (`MobileAuthStartRequest` etc.) — one owning package for the Kotlin,\n  Swift, and TypeScript shapes (compile-checked descriptors + parity test).\n- **Tenant options** honor `Role.inheritsToDescendants` (#1867): direct\n  ACTIVE memberships plus descendants of flagged memberships (nearest\n  flagged ancestor labels the option; any direct row pins; inactive direct\n  rows exclude). Session binding defaults to the first DIRECT tenant —\n  override with `resolveTenantId`.\n- **Hooks**: `resolveUser` (invite-gating; default provisions via\n  `getOrCreateFromOidc`), `resolveTenantId`, `buildExtras` (bootstrap\n  `extras`; model JSON must use `toPublicJSON({ permissions })` — #1822).\n  `buildExtras` is the only app-domain bootstrap extension point. Never emit\n  app fields such as `dashboard` at the response top level: they are outside\n  `MobileSessionBootstrap` and the Kotlin decoder ignores them.\n- **Guard** wraps `withSessionPermissionContext`, so\n  `assertOperationPermission`, tenancy context, and Postgres RLS all see the\n  bearer caller; `OperationPermissionError` maps to 403 with a\n  machine-readable `reason`.\n- **Uploads**: `resolveMobileUploadDedupKey` + the documented contract in\n  `docs/content/architecture/mobile-upload-contract.md` (`clientCaptureId`\n  field, `Idempotency-Key` header fallback); domain ingestion stays\n  app-side. Framework-model writes ride `sync/apply`, not this path.\n- Configure `redirectUris` in production — RFC 8252 scheme rules always\n  apply, but the allow list is the defense against redirecting authorization\n  responses to attacker-controlled URIs.\n\n## Security (S5 #1400)\n\n- **Generated REST/MCP surface is READ-ONLY for every RBAC/identity model.**\n  User, Tenant, Group, Membership, MembershipOverride, Role, Permission,\n  RolePermission, GroupRole, GroupMember, and TenantPermissionOverride generate\n  `list`/`get` only — `create`/`update`/`delete` are intentionally NOT\n  generated. The merged `requireRouteAuth` gate (#1540) enforces *authentication*,\n  not *authorization*, and these models are not `@TenantScoped`, so an\n  auto-generated mutating route would let any authenticated user self-grant a\n  role/permission, flip a tenant's cascade flags, or change another user's auth\n  identity. Mutate them through the permission-gated services (`TenantService`,\n  collection helpers) or consumer-owned, permission-checked handlers. A\n  structural regression test (`security-audit-1400.test.ts`) enumerates the\n  registry to assert no authority model exposes a mutating op. (`cli` stays\n  enabled — local-operator surface, outside the network/agent threat model.)\n- **`switchTenant` is fail-closed AND rotates the session id.**\n  `SessionService.switchTenant` / `switchSessionTenant` verify the session's user\n  has an ACTIVE membership in the target tenant before any write (the tenant id\n  is the isolation key for every `@TenantScoped` query). A non-member/unknown-\n  session switch returns `{ switched: false, sessionId: null, ... }` and mutates\n  nothing. On a successful switch into a NON-null tenant the session id is\n  ROTATED: a fresh `Session` (new secure id, fresh TTL, same user, new tenant,\n  device context carried over) is minted and the old session is REVOKED — so a\n  captured pre-switch id immediately stops validating, shrinking the blast radius\n  of a leaked id across a tenant boundary. `switchTenant` returns a\n  `SwitchTenantResult` (`{ switched, sessionId, session, rotated }`); callers MUST\n  persist the returned `sessionId`. `switchSessionTenant` does this for you by\n  re-setting the session cookie (preserving httpOnly/secure/sameSite) to the new\n  id. A `null` clear stays in place (no rotation, no cookie change). The\n  low-level `SessionCollection.setSessionTenant` is the UNGUARDED primitive (used\n  for the null-clear path) — never call it with an untrusted tenant id.\n- **OIDC `email_verified` is enforced.** `UserCollection.getOrCreateFromOidc`\n  refuses to provision a user when the IdP explicitly returns\n  `email_verified: false` (opt out with `{ allowUnverifiedEmail: true }`). An\n  absent claim makes no assertion and is not enforced.\n- **RFC 9207 response issuer is exact.** OIDC callbacks validate a supplied\n  `iss` against discovered metadata with exact string comparison before trusting\n  a code or error. If metadata advertises issuer-response support, `iss` is\n  required.\n- **Verified-email Profile reuse is fail-closed.** The typed canonical scenarios\n  live in\n  `packages/profiles/src/testing/oidcProvisioningDecisionMatrix.ts`; both\n  package suites execute that matrix and public docs reference it rather than\n  maintaining another behavioral table. Default provisioning reuses only one\n  unowned, global `Person`. Tenant-scoped, non-Person, duplicate-email,\n  and already-owned matches fail before User/session creation. An existing\n  issuer/subject link without a User must still be the unique global Person for\n  the current verified claim email; once owned, the stable issuer/subject link\n  reuses its canonical Person and owner.\n  Issuer and subject are opaque, case-sensitive identifiers; preserve their\n  exact value and use trim only to reject blank claims.\n- **`resolveProfile` is the application reconciliation boundary.** The\n  SvelteKit handlers, `OidcLoginService`, and `getOrCreateFromOidc` accept the\n  same hook inside the provisioning transaction. The service/handler path\n  supplies protocol-validated claims; direct collection callers must validate\n  and trust their claim source before calling `getOrCreateFromOidc`.\n  Token/userinfo merging keeps `email` and `email_verified` paired to the same\n  claim source; verification is never borrowed across sources.\n  Resolver reads/writes use the supplied `db`, and the hook must be idempotent\n  because a concurrent unique-key conflict can retry it. `undefined` chooses\n  the secure default and `null` rejects, including exact issuer/subject reuse.\n  For a new identity, a supplied Profile is still validated as the unique,\n  unowned global Person for the verified email. For an exact existing identity,\n  it must be the already-linked Profile and cannot rebind identity authority;\n  stable-link owner and canonical-Person checks still apply. The hook receives a\n  separate frozen claims snapshot; internal retry and persistence state is not\n  exposed for mutation.\n- **Owned first binding requires `authorizeProfileOwner`.** An invitation or\n  approval workflow may explicitly return both its pre-provisioned canonical\n  global `Person` and existing approved `User` from this transaction-bound\n  hook. `undefined` keeps the secure `profile_owned` default and `null`\n  rejects. SMRT treats only the selected IDs as input, reloads them in the\n  provisioning transaction, and requires `email_verified === true`, the unique\n  canonical global Person for the normalized claim email, exactly one owner,\n  that owner as the selected User, and the same normalized User email. The\n  hook runs before identity/User/session creation and may be retried, so use\n  only its supplied `db` and `users` handles and keep application authorization\n  idempotent. Never authorize from email matching alone. Existing exact\n  identities cannot be rebound; when `resolveProfile` is also present both\n  hooks must select the same Profile.\n- **OIDC first login is atomic.** The Profile, `OidcIdentity`, and User are one\n  transaction. The database arbiters are `OidcIdentity.identityKey`,\n  private `oidc_profile_email_reservations.email_key`, `User.emailKey`, and the\n  unique `User.profileId`; local callbacks acquire exact issuer/subject and normalized\n  email locks in deterministic order so changed email claims also serialize.\n  SQLite and DuckDB callbacks additionally serialize every root-handle statement\n  the coordinator owns per database URL — `_smrt_backfills` initialization, the\n  transaction, and the post-commit rebind — because one adapter multiplexes a\n  single native connection and cannot safely overlap unrelated root\n  transactions. Never overlap two statements on one such handle, inside a\n  transaction or not: rebind and owner/email candidate reads are sequential,\n  never `Promise.all`. Owner-authorized DuckDB callbacks use that same\n  root-handle serialization;\n  PostgreSQL deadlock and serialization errors use a bounded transaction retry.\n  Newly provisioned Profiles use non-semantic per-profile slugs so equal IdP\n  display names cannot trigger a natural-key upsert;\n  run\n  `smrt db:status`, `smrt db:migrate`, then `smrt db:status` before deployment.\n  Stop or upgrade old writers first. Before migration, group\n  non-null `users.profile_id` values, then reconcile duplicates. After\n  migration, run public `backfillProfileEmailKeys(db)` followed by\n  `backfillUserEmailKeys(db)` from one deploy process. Both use the shared\n  TypeScript `normalizeIdentityEmail()` implementation transactionally and are\n  idempotent; the User backfill fails before writes if normalized duplicates\n  remain. Every OIDC path requires the Profile email-key readiness marker;\n  creating a User or checking User email uniqueness additionally requires the\n  User marker. A stable issuer/subject with an existing owning User skips only\n  the User email-key lookup and marker. Full scans remain in the explicit deploy\n  step; guarded runtime paths use indexed keys and validate only returned\n  candidates. Multiple null links remain valid.\n  Legacy race keys backfill only after canonical validation. Pass a root\n  database on adapters such as DuckDB that cannot create nested savepoints.\n  Root adapters must expose `beginTransaction`; transaction-only handles are\n  ambiguous and fail closed before provisioning writes. Caller-owned\n  transactions never run `_smrt_backfills` DDL and require that table to\n  already exist; use the root database when initialization or recovery is\n  needed.\n\n## Gotchas\n\n- **seedSystemRoles() required**: call `RoleCollection.seedSystemRoles()` at app init (creates owner/admin/member/viewer)\n- **PermissionResolver casts `as any`**: collections have protected constructors — known framework limitation\n- **Session TTL in seconds**: `DEFAULT_SESSION_TTL = 7 * 24 * 60 * 60` (not milliseconds)\n- **Users are cross-tenant**: one user, many tenants via Membership. Email globally unique.\n- **Batch permission queries**: resolver fetches all permission IDs in one query, then maps to slugs (avoids N+1)\n",
  "moduleDocs": [
    {
      "path": "agents/retention.md",
      "module": "retention",
      "content": "# smrt-users/credential retention\n\nModule semantics for `src/retention.ts` and the three `deleteExpired()` paths\nit drives. Package orientation, the permission model, and the security rules\nthat apply before editing anything live in [../AGENTS.md](../AGENTS.md) — read\nthat first.\n\n## Credential retention (#2375)\n\n`SessionCollection.deleteExpired()`,\n`UsersMagicLinkTokenCollection.deleteExpired()` and\n`UsersCliAuthRequestCollection.deleteExpired()` all existed, and all waited for\nan application to remember to call them. Expired credential rows are the worst\nkind of unbounded growth: worthless the moment they expire, and exactly the\nrows an attacker would like to still find in the table.\n\n`src/retention.ts` contributes the three to the framework retention sweep in\n`@happyvertical/smrt-core`, so `smrt db:prune` and a running jobs `TaskRunner`\nreap them.\n\n- **The entry point registers on import.** `src/index.ts` calls\n  `registerUserRetentionTasks()`, so any process that loaded this package\n  contributes the tasks — including `smrt db:prune`, which imports the package\n  optionally for exactly that reason. Registering is not scheduling: nothing is\n  deleted until something runs a sweep.\n- **Task names** are `users-sessions`, `users-magic-link-tokens`,\n  `users-cli-auth-requests` — prefixed with the package's short name because\n  the retention registry is one process-global namespace. Opt one out with\n  `runRetentionSweep(db, { tasks: { 'users-sessions': false } })` or\n  `smrt db:prune --skip users-sessions`; `unregisterUserRetentionTasks()`\n  removes all three.\n- **There is no retention window to configure.** An expired credential has\n  nothing worth retaining, so each task deletes only already-expired rows. An\n  application that keeps expired sessions for audit should opt the task out and\n  archive them itself.\n- **All three are a single counted DELETE**, not a hydrate-and-delete loop.\n  They now run unattended on a timer, and a per-row delete that throws part-way\n  leaves the rest of the expired rows un-reaped — the #1400 reasoning that\n  already applied to sessions, now applied to the other two. Counting first\n  also gives a usable figure where `rowCount` is not populated, and is what\n  makes `{ dryRun }` preview the same predicate rather than an estimate. The\n  count and the delete are not one transaction, so the figure is approximate\n  under concurrent writers.\n- **`expiresAt` is `@field({ indexed: true })`** on `Session`,\n  `UsersMagicLinkToken` and `UsersCliAuthRequest`: the prune predicate scans\n  that column on every pass.\n- **CLI bearer handoff is single-use.** An approved request becomes `consumed`\n  and clears its `sessionId` when one poller wins the exchange. The CLI\n  retention task deletes pending requests past their TTL, requests already\n  marked `expired` by lazy expiry, and consumed history; it retains approved\n  requests until exchange so a near-expiry approval cannot orphan its bearer\n  session.\n"
    }
  ]
}