fix: address PR review comments

- nostr-kinds.ts: clarify exclusive boundary comments for kind ranges
- useStable.ts: use JSON.stringify instead of join(",") to prevent
  false positives with arrays containing commas
- useProfile.ts: check abort signal before initiating database writes
  to prevent race conditions
- KindRenderer.tsx: rename "Regular Lists" to "Replaceable Events",
  simplify redundant condition (isReplaceableKind includes kinds 0, 3),
  remove unused `kinds` import
- BaseEventRenderer.tsx: remove duplicate comment
This commit is contained in:
Claude
2025-12-21 11:57:19 +00:00
parent 7a71b481c2
commit b9180868b7
5 changed files with 21 additions and 24 deletions

View File

@@ -1,5 +1,4 @@
import { getKindInfo } from "@/constants/kinds";
import { kinds } from "nostr-tools";
import { NIPBadge } from "./NIPBadge";
import { Copy, CopyCheck } from "lucide-react";
import { Button } from "./ui/button";
@@ -190,7 +189,7 @@ function getKindCategory(kind: number): string {
if (kind >= 20 && kind <= 39) return "Media & Content";
if (kind >= 40 && kind <= 49) return "Channels";
if (kind >= 1000 && kind <= 9999) return "Application Specific";
if (isReplaceableKind(kind)) return "Regular Lists";
if (isReplaceableKind(kind)) return "Replaceable Events";
if (isEphemeralKind(kind)) return "Ephemeral Events";
if (isParameterizedReplaceableKind(kind)) return "Parameterized Replaceable";
if (kind >= 40000) return "Custom/Experimental";
@@ -201,7 +200,8 @@ function getKindCategory(kind: number): string {
* Determine the replaceability of an event kind
*/
function getEventType(kind: number): string {
if (kind === kinds.Metadata || kind === kinds.Contacts || isReplaceableKind(kind)) {
// nostr-tools' isReplaceableKind already includes kinds 0 (Metadata) and 3 (Contacts)
if (isReplaceableKind(kind)) {
return "Replaceable";
}
if (isParameterizedReplaceableKind(kind)) {

View File

@@ -225,7 +225,6 @@ export function ClickableEventTitle({
// For replaceable/parameterized replaceable events, use AddressPointer
if (isAddressableKind(event.kind)) {
// For replaceable/parameterized replaceable events, use AddressPointer
const dTag = getTagValue(event, "d") || "";
pointer = {
kind: event.kind,

View File

@@ -50,21 +50,18 @@ export function useProfile(pubkey?: string): ProfileContent | undefined {
return;
}
// Save to IndexedDB (fire and forget if aborted)
const savePromise = db.profiles.put({
...profileData,
pubkey,
created_at: fetchedEvent.created_at,
});
// Only update state and cache if not aborted
if (controller.signal.aborted) return;
// Only update state if not aborted
if (!controller.signal.aborted) {
setProfile(profileData);
}
setProfile(profileData);
// Await save after state update to avoid blocking UI
// Save to IndexedDB after state update to avoid blocking UI
try {
await savePromise;
await db.profiles.put({
...profileData,
pubkey,
created_at: fetchedEvent.created_at,
});
} catch (err) {
// Log but don't throw - cache failure shouldn't break the UI
console.error("[useProfile] Failed to cache profile:", err);

View File

@@ -30,21 +30,20 @@ export function useStableValue<T>(
/**
* Stabilize a string array for use in dependency arrays
*
* Optimized version of useStableValue for string arrays.
* Uses join(",") instead of JSON.stringify for better performance.
* Uses JSON.stringify for safe serialization (handles arrays with commas in elements).
*
* @param arr - The array to stabilize
* @returns The memoized array
*
* @example
* ```typescript
* // Instead of: useMemo(() => relays, [relays.join(",")])
* // Instead of: useMemo(() => relays, [JSON.stringify(relays)])
* const stableRelays = useStableArray(relays);
* ```
*/
export function useStableArray<T extends string>(arr: T[]): T[] {
// eslint-disable-next-line react-hooks/exhaustive-deps
return useMemo(() => arr, [arr.join(",")]);
return useMemo(() => arr, [JSON.stringify(arr)]);
}
/**

View File

@@ -26,14 +26,16 @@ import {
} from "nostr-tools/kinds";
// Kind range boundaries (NIP-01) - exported for display purposes only
// Note: END values are exclusive (e.g., REGULAR covers 0-9999, not 10000)
// Exception: kinds 0 (Metadata) and 3 (Contacts) are replaceable despite being < 10000
export const REGULAR_START = 0;
export const REGULAR_END = 10000;
export const REGULAR_END = 10000; // exclusive: regular kinds are 0-9999 (except 0, 3)
export const REPLACEABLE_START = 10000;
export const REPLACEABLE_END = 20000;
export const REPLACEABLE_END = 20000; // exclusive: replaceable kinds are 10000-19999
export const EPHEMERAL_START = 20000;
export const EPHEMERAL_END = 30000;
export const EPHEMERAL_END = 30000; // exclusive: ephemeral kinds are 20000-29999
export const PARAMETERIZED_REPLACEABLE_START = 30000;
export const PARAMETERIZED_REPLACEABLE_END = 40000;
export const PARAMETERIZED_REPLACEABLE_END = 40000; // exclusive: parameterized replaceable are 30000-39999
/**
* Check if a kind is parameterized replaceable (NIP-01)