diff --git a/CLAUDE.md b/CLAUDE.md index 63517b8618e82a9f4c133fe34a2b9e361d1b9601..a35d88493235c5c4076df94cbf58bf2df5e8b874 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -5,6 +5,12 @@ This project uses **gitlab.syncad.com**, NOT gitlab.com. - Repository: https://gitlab.syncad.com/hive/denser - Use `glab api "projects/hive%2Fdenser/..."` for API calls +## Git Branching +- **Default branch**: `develop` (NOT `main`) +- Create feature branches from `develop` +- MRs should target `develop`, not `main` +- Example: `git checkout develop && git checkout -b fix/my-feature` + ## Package Management - Check `.gitlab-ci.yml` for current Node/pnpm versions - Example: `docker run --rm -v "$(pwd)":/app -w /app node: sh -c "corepack enable && pnpm install"` diff --git a/apps/blog/utils/validate-links.ts b/apps/blog/utils/validate-links.ts index fec5dfefc3a89eec87cff0b785d10c6469c6c760..bfc19671bf32145bab22e46f740ddd7e3009c026 100644 --- a/apps/blog/utils/validate-links.ts +++ b/apps/blog/utils/validate-links.ts @@ -1,12 +1,39 @@ import { getChain } from '@hive/transaction/lib/chain'; +import { getLogger } from '@ui/lib/logging'; + +const logger = getLogger('validate-links'); export function isPermlinkValid(permlink: string): boolean { if (typeof permlink !== 'string') return false; return /^[a-z0-9-]{1,255}$/.test(permlink); } +/** + * Regex fallback for Hive account name validation. + * TODO: Verify against blockchain consensus code (see TODO/003-hive-username-validation.md) + */ +function isValidAccountNameFallback(name: string): boolean { + if (typeof name !== 'string') return false; + // Hive account rules: 3-16 chars, lowercase, numbers, single dots (not consecutive, not at edges) + if (name.length < 3 || name.length > 16) return false; + if (!/^[a-z]/.test(name)) return false; // must start with letter + if (!/^[a-z0-9.-]+$/.test(name)) return false; // allowed chars + if (/\.\./.test(name)) return false; // no consecutive dots + if (/^\./.test(name) || /\.$/.test(name)) return false; // no dot at edges + if (/^-/.test(name) || /-$/.test(name)) return false; // no dash at edges + return true; +} + export async function isUsernameValid(accountName: string): Promise { if (typeof accountName !== 'string') return false; - const chain = await getChain(); - return chain.isValidAccountName(accountName); + + try { + const chain = await getChain(); + return chain.isValidAccountName(accountName); + } catch (err) { + // WASM can fail with memory errors under concurrent load + // Fall back to regex validation + logger.warn(err, 'WASM isValidAccountName failed, using regex fallback'); + return isValidAccountNameFallback(accountName); + } }