feat: Configurable short code lengths & progressive generation#214
feat: Configurable short code lengths & progressive generation#214mfcarroll wants to merge 3 commits intopiffio:mainfrom
Conversation
|
I realized the progressive generator in router.rs was making separate database calls to fetch each length limit so I pushed an optimization to fetch all settings in a single D1 query instead. |
d86454b to
f9e56a7
Compare
|
Last update: In the process of deploying this for my own use I realised I should have added the |
- Documented optional COLLISION_THRESHOLD in example config files - Updated ci/cd scripts to pass vars.COLLISION_THRESHOLD - Updated common.sh and deployment.sh to pass env.COLLISION_THRESHOLD
f208728 to
375c451
Compare
|
Hey @mfcarroll I'll get back to this proposal after 0.7.0 has been released. I'll introduce frontend linting and formatting at that moment too, which means every single frontend file will be updated. Expect some merge issues. Thanks for your patience. |
|
Sounds good, and no worries I can deal with the merge issues down the road after 0.7.0. |
|
Hello @mfcarroll, I've just merged the massive #252, which means there are all sorts of conflicts now due to the changes in the frontend formatting. The good news is that this will stay consistent and enforced going forward. The bad news is that you'll need to do some rebasing/merge conflict handling to get this PR back to a mergeable state. Thanks again for all your contributions! PS: I'll review the reported issue on |
|
All good. I'll take a look this week sometime and get that rebased. |
Hi @piffio, this is actually the main piece I was working on. Being able to generate random codes shorter than 6 digits is an essential feature for us, and I think will also be quite desirable for other users. I believe it is implemented here in a way that improves the app overall, centralises the defaults and settings, while maintaining the current status quo and safeguarding speed and resiliency. I realise this is a significant architectural change so I apologise for not discussing before hand. Thank you for clarifying the process and I will be sure to follow that in future. 🙏
Overview
This PR introduces the ability for instance administrators to configure the minimum lengths for both random and custom short codes, replacing the previous hard-coded 6-character and 3-character defaults. It implements a self-healing progressive generation system to ensure that namespaces can scale automatically as they fill up, with essentially no performance impact.
Rationale / Namespace Mathematics
Previously, Rushomon enforced a strict 6-character minimum for generated codes. Using a Base62 alphabet (A-Z, a-z, 0-9), a 6-character code yields 56.8 billion combinations.
While robust, and great for public SaaS platform, this is overkill for many self-hosted, single-tenant, or internal team deployments (i.e. my use case).
For most self-hosted instances, 238k to 14M links is more than sufficient for their lifespan. This feature allows administrators to configure shorter, more aesthetic URLs out of the box, drastically improving the UX for instances that do not need billions of unique paths, in cases where short urls are typed manually.
Collision Handling & Progressive Scaling
To safely allow smaller namespaces without risking infinite collision loops when the namespace eventually saturates, I've implemented a Progressive Short Code Generator:
effective_min_length.system_min_code_length"high-watermark" in the database.This means the application is completely self-healing. An admin can start their instance at 3 characters or less. Once ~14-17k links are generated, the system will seamlessly upgrade itself to 4 characters, completely invisibly to the user and with zero downtime. (The cost along the way is a few hundred collisions total.)
Power-User Override: For self-hosters who want to stretch their short namespaces and accept the mild performance cost of extra RNG loops, the collision exhaustion trigger can be explicitly overridden via the
COLLISION_THRESHOLDenvironment variable inwrangler.tomlor.dev.vars. It seemed best to not include that in the admin UI as for the vast majority of users that would likely cause unnecessary confusion.Local testing
COLLISION_THRESHOLD=1in your.dev.varsBackend Changes
min_random_code_length,min_custom_code_length, andsystem_min_code_lengthto thesettingstable (seeded via a new migration).src/utils/short_code.rsto ensure a single source of truth across the backend.utils::validation::validate_short_codeto check for absolute system limits (1toMAX_SHORT_CODE_LENGTH[100]). Runtime minimums are now enforced at the route level.GET /api/settingsendpoint now computes and returns the effective minimums, so the frontend doesn't have to duplicate the business logic.Frontend Changes
frontend/src/lib/constants.tsfile.system_min_code_lengthto prevent an admin from trying to force the system into an already-exhausted namespace.<LinkModal>now consumes the effective minimum lengths passed down from thepublicSettingsloaded in the dashboard layout, dynamically updating its validation rules and helper text.The existing defaults have been preserved throughout, but this feature could also be used to allow for shorter defaults as standard, by changing the two default constants files, at the maintainer's discretion.
Note on Orphaned Component
While adding this feature, I noticed that
frontend/src/lib/components/CreateLinkForm.svelteis currently an orphaned component (all active link creation is handled viaLinkModal.svelte). I have updated it to accept the newminShortCodeLengthprop and use the dynamic validation rules. However it appears to lag significantly behind LinkModal.svelts in terms of features and validation so it may be better to simply remove it.