-
Notifications
You must be signed in to change notification settings - Fork 4
Description
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
accessControland it's automatically inpermissions - 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 userGenerates Proposal 1 (Helper Function Approach)
Advanced behavior (with --advanced flag):
npx arkos g a -m user --advancedGenerates 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
- Separated
authenticationControlandaccessControl- Easier to reference and reuse - Exportable objects - Can be imported and used across the application
- DRY principle - No repetition of model name or accessControl reference
- Type safety - Full TypeScript support with
as const satisfies - 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