Skip to content

[QOL]: The npx arkos g a -m user should include a helper function createUserPermission, and authenticationControl and accessControl as separated objects #119

@Uanela

Description

@Uanela

Current Experience

When using the Arkos.js CLI command npx arkos g a -m <module> to generate auth configurations, the generated code does not include a helper function for creating permissions. Developers must manually add this boilerplate code themselves.

Current generated output:

import { AuthConfigs } from "arkos/auth";
import { authService } from "arkos/services";

const userAuthConfigs: AuthConfigs = {
  authenticationControl: {
    Create: true,
    Update: true,
    Delete: true,
    View: true,
  },
  accessControl: {
    Create: {
      roles: ["Member"],
      name: "Create User",
      description: "Permission to create new user records",
    },
    // ... other permissions
  },
};

export const userPermissions = {
  canCreate: authService.permission("Create", "user", userAuthConfigs.accessControl),
  canUpdate: authService.permission("Update", "user", userAuthConfigs.accessControl),
  canDelete: authService.permission("Delete", "user", userAuthConfigs.accessControl),
  canView: authService.permission("View", "user", userAuthConfigs.accessControl),
};

export default userAuthConfigs;

This results in repetitive code with the model name and accessControl reference repeated for each permission.

Improved Experience

Proposal 1: Helper Function Approach

Generated by default with npx arkos g a -m user:

import { AuthConfigs } from "arkos/auth";
import { authService } from "arkos/services";

export const userAuthenticationControl = {
  Create: true,
  Update: true,
  Delete: true,
  View: true,
};

export const userAccessControl = {
  Create: {
    roles: ["Member"],
    name: "Create User",
    description: "Permission to create new user records",
  },
  Update: {
    roles: ["Admin"],
    name: "Update User",
    description: "Permission to update existing user records",
  },
  Delete: {
    roles: ["Admin"],
    name: "Delete User",
    description: "Permission to delete user records",
  },
  View: {
    roles: ["Member"],
    name: "View User",
    description: "Permission to view user records",
  },
} as const satisfies AuthConfigs["accessControl"];

function createUserPermission(action: string) {
  return authService.permission(action, "user", userAccessControl);
}

export const userPermissions = {
  canCreate: createUserPermission("Create"),
  canUpdate: createUserPermission("Update"),
  canDelete: createUserPermission("Delete"),
  canView: createUserPermission("View"),
};

const userAuthConfigs: AuthConfigs = {
  authenticationControl: userAuthenticationControl,
  accessControl: userAccessControl,
};

export default userAuthConfigs;

Benefits:

  • Clear, readable, and easy to understand
  • Great for beginners
  • Easy to debug
  • Provides intellisense/autocomplete when adding new permissions
  • Can be customized per permission if needed

Proposal 2: Auto-Generated Permissions

Generated with npx arkos g a -m user --advanced:

import { AuthConfigs } from "arkos/auth";
import { authService } from "arkos/services";

export const userAuthenticationControl = {
  Create: true,
  Update: true,
  Delete: true,
  View: true,
};

export const userAccessControl = {
  Create: {
    roles: ["Member"],
    name: "Create User",
    description: "Permission to create new user records",
  },
  Update: {
    roles: ["Admin"],
    name: "Update User",
    description: "Permission to update existing user records",
  },
  Delete: {
    roles: ["Admin"],
    name: "Delete User",
    description: "Permission to delete user records",
  },
  View: {
    roles: ["Member"],
    name: "View User",
    description: "Permission to view user records",
  },
} as const satisfies AuthConfigs["accessControl"];

export const userPermissions = Object.keys(userAccessControl).reduce(
  (acc, key) => {
    acc[`can${key}` as const] = authService.permission(
      key,
      "user",
      userAccessControl
    );
    return acc;
  },
  {} as Record<string, ReturnType<typeof authService.permission>>
) as {
  [K in keyof typeof userAccessControl as `can${K & string}`]: ReturnType<
    typeof authService.permission
  >;
};

const userAuthConfigs: AuthConfigs = {
  authenticationControl: userAuthenticationControl,
  accessControl: userAccessControl,
};

export default userAuthConfigs;

Benefits:

  • Fully automated - add a permission to accessControl and it's automatically in permissions
  • Maximum DRY principle
  • Type-safe with full TypeScript support
  • Zero boilerplate for adding new permissions

Trade-offs:

  • More complex code
  • Harder to debug for beginners
  • No autocomplete when referencing permission keys

Proposed Implementation

Both approaches should be available via a CLI flag:

Default behavior (without flag):

npx arkos g a -m user

Generates Proposal 1 (Helper Function Approach)

Advanced behavior (with --advanced flag):

npx arkos g a -m user --advanced

Generates Proposal 2 (Auto-Generated Permissions)

This gives developers the flexibility to choose the pattern that best fits their project needs and experience level.

Key Improvements in Both Proposals

  1. Separated authenticationControl and accessControl - Easier to reference and reuse
  2. Exportable objects - Can be imported and used across the application
  3. DRY principle - No repetition of model name or accessControl reference
  4. Type safety - Full TypeScript support with as const satisfies
  5. Scalability - Easy to add new permissions

Area of Improvement

Code Generation / CLI

Impact on Workflow

Frequency: Every time a developer generates auth configurations for a new model (potentially dozens of times per project)

Time Saved:

  • ~2-3 minutes per model to manually add the helper function and separate objects
  • Reduces cognitive load and potential for copy-paste errors
  • Makes the codebase more consistent across all generated auth files
  • Easier to add custom permissions later (just one line instead of three)
  • Separated objects make it easier to reference auth configs across the application

Overall Impact: Medium-High - While not a huge time saver per instance, it adds up across a project and significantly improves code quality, maintainability, and developer experience.

Package

arkos

Arkos.js Version

1.4.0-beta

Examples from Other Tools

NestJS CLI - When generating modules, services, and controllers, it includes all necessary boilerplate and helper patterns automatically.

Rails Generators - Rails scaffolding generates complete, DRY code with helper methods rather than repetitive boilerplate.

Prisma - Generated client code includes helper functions and abstractions rather than forcing developers to write repetitive code.

The pattern of including helper functions in generated code is a common best practice that:

  • Reduces boilerplate
  • Encourages DRY principles
  • Makes the generated code more maintainable
  • Provides a consistent pattern across the codebase
  • Improves developer experience and onboarding

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions