refactor(core): remove legacy plebbit terminology

This commit is contained in:
Tommaso Casaburi
2026-04-17 10:48:27 +07:00
parent e366dac25c
commit ee7a5b5778
158 changed files with 626 additions and 836 deletions
@@ -9,9 +9,7 @@ describe('buildEditableAccountJson', () => {
author: { address: '0x123', shortAddress: '0x1...3', avatar: { url: 'https://example.com' } },
pkc: { someOption: true },
pkcReactOptions: { foo: 'baz' },
plebbit: { someOption: true },
karma: 42,
plebbitReactOptions: { foo: 'bar' },
unreadNotificationCount: 5,
};
const result = JSON.parse(buildEditableAccountJson(account));
@@ -21,9 +19,7 @@ describe('buildEditableAccountJson', () => {
expect(result.account.author.avatar).toBeUndefined();
expect(result.account.pkc).toBeUndefined();
expect(result.account.pkcReactOptions).toBeUndefined();
expect(result.account.plebbit).toBeUndefined();
expect(result.account.karma).toBeUndefined();
expect(result.account.plebbitReactOptions).toBeUndefined();
expect(result.account.unreadNotificationCount).toBeUndefined();
});
@@ -26,14 +26,14 @@ describe('challenge-utils', () => {
challengeSuccess: false,
reason: 'try again later',
} as never,
{ subplebbitAddress: 'business-and-finance.bso' },
{ communityAddress: 'business-and-finance.bso' },
);
expect(warnSpy).toHaveBeenCalledWith(
'Challenge Verification Failed:',
expect.objectContaining({ challengeSuccess: false }),
'Publication:',
expect.objectContaining({ subplebbitAddress: 'business-and-finance.bso' }),
expect.objectContaining({ communityAddress: 'business-and-finance.bso' }),
);
expect(alertMock).toHaveBeenCalledWith('Error from /biz/: invalid captcha try again later');
});
@@ -44,13 +44,13 @@ describe('challenge-utils', () => {
challengeErrors: ['first error', 'second error'],
challengeSuccess: false,
} as never,
{ subplebbitAddress: 'unknown-board.eth' },
{ communityAddress: 'unknown-board.eth' },
);
expect(alertMock).toHaveBeenCalledWith('Error from unknown-board.eth: first error second error');
});
it('uses communityAddress when the upgraded publication no longer exposes subplebbitAddress', () => {
it('uses communityAddress when the upgraded publication no longer exposes communityAddress', () => {
alertChallengeVerificationFailed(
{
challengeErrors: ['first error'],
@@ -76,7 +76,7 @@ describe('challenge-utils', () => {
});
it('logs successful challenge verification instead of alerting', () => {
alertChallengeVerificationFailed({ challengeSuccess: true } as never, { subplebbitAddress: 'business-and-finance.bso' });
alertChallengeVerificationFailed({ challengeSuccess: true } as never, { communityAddress: 'business-and-finance.bso' });
expect(logSpy).toHaveBeenCalledWith('Challenge verification succeeded:', expect.objectContaining({ challengeSuccess: true }));
expect(alertMock).not.toHaveBeenCalled();
@@ -72,18 +72,18 @@ describe('pattern-utils', () => {
it('matches roles with moderator aliases and rejects missing role metadata', () => {
const modComment = {
author: { address: 'author-1' },
subplebbitAddress: 'music-posting.eth',
communityAddress: 'music-posting.eth',
};
const ownerComment = {
author: { address: 'author-2' },
subplebbitAddress: 'music-posting.eth',
communityAddress: 'music-posting.eth',
};
expect(userHasRole(modComment as never, 'moderator')).toBe(true);
expect(userHasRole(modComment as never, 'mod')).toBe(true);
expect(userHasRole(ownerComment as never, 'owner')).toBe(true);
expect(userHasRole(ownerComment as never, 'admin')).toBe(false);
expect(userHasRole({ author: { address: 'missing' }, subplebbitAddress: 'unknown.eth' } as never, 'moderator')).toBe(false);
expect(userHasRole({ author: { address: 'missing' }, communityAddress: 'unknown.eth' } as never, 'moderator')).toBe(false);
});
it('parses mixed special filters and content filters', () => {
@@ -109,7 +109,7 @@ describe('pattern-utils', () => {
shortAddress: 'auth1',
},
content: 'That feel when the girlfriend texts back',
subplebbitAddress: 'music-posting.eth',
communityAddress: 'music-posting.eth',
title: 'TFW',
};
@@ -14,13 +14,13 @@ describe('post-page-resolution', () => {
it('only accepts strict board feed options for the active single-board feed', () => {
const baseOptions = {
sortType: 'active',
subplebbitAddresses: ['music.eth'],
communityAddresses: ['music.eth'],
};
expect(isBoardFeedOptions(baseOptions, 'music.eth')).toBe(true);
expect(isBoardFeedOptions({ ...baseOptions, sortType: 'new' }, 'music.eth')).toBe(false);
expect(isBoardFeedOptions({ ...baseOptions, subplebbitAddresses: ['music.eth', 'tech.eth'] }, 'music.eth')).toBe(false);
expect(isBoardFeedOptions({ ...baseOptions, subplebbitAddresses: ['tech.eth'] }, 'music.eth')).toBe(false);
expect(isBoardFeedOptions({ ...baseOptions, communityAddresses: ['music.eth', 'tech.eth'] }, 'music.eth')).toBe(false);
expect(isBoardFeedOptions({ ...baseOptions, communityAddresses: ['tech.eth'] }, 'music.eth')).toBe(false);
expect(isBoardFeedOptions({ ...baseOptions, filter: { title: 'test' } }, 'music.eth')).toBe(false);
expect(isBoardFeedOptions({ ...baseOptions, newerThan: 3600 }, 'music.eth')).toBe(false);
expect(isBoardFeedOptions({ ...baseOptions, modQueue: true }, 'music.eth')).toBe(false);
@@ -31,16 +31,16 @@ describe('post-page-resolution', () => {
const feedsOptions = {
allFeed: {
sortType: 'active',
subplebbitAddresses: ['all.eth'],
communityAddresses: ['all.eth'],
},
catalogFilterFeed: {
filter: { title: 'match' },
sortType: 'active',
subplebbitAddresses: ['music.eth'],
communityAddresses: ['music.eth'],
},
boardFeed: {
sortType: 'active',
subplebbitAddresses: ['music.eth'],
communityAddresses: ['music.eth'],
},
};
const loadedFeeds = {
@@ -6,7 +6,7 @@ const createReply = (overrides: Partial<Comment> = {}) =>
({
cid: 'reply-cid',
parentCid: 'target-cid',
subplebbitAddress: 'music.eth',
communityAddress: 'music.eth',
...overrides,
}) as Comment;
+4 -4
View File
@@ -6,7 +6,7 @@ import {
getFeedCacheKey,
getFeedType,
getPageFromFeedPath,
getSubplebbitAddress,
getCommunityAddress,
isArchiveRoute,
isBoardModRoute,
isDirectoryBoard,
@@ -44,9 +44,9 @@ describe('directory mapping helpers', () => {
expect(getBoardPath('12D3KooWQdQ6TkVA1Xe9zzaFP6vXBgsLeMAewpLpLwbsAYKivnQy', communities)).toBe('mu');
expect(getBoardPath('unknown.example', communities)).toBe('unknown.example');
expect(getSubplebbitAddress('biz', communities)).toBe('business.eth');
expect(getSubplebbitAddress('b', communities)).toBe('random.eth');
expect(getSubplebbitAddress('unknown.example', communities)).toBe('unknown.example');
expect(getCommunityAddress('biz', communities)).toBe('business.eth');
expect(getCommunityAddress('b', communities)).toBe('random.eth');
expect(getCommunityAddress('unknown.example', communities)).toBe('unknown.example');
});
it('compares aliases and directory identifiers correctly', () => {
+2 -2
View File
@@ -38,9 +38,9 @@ describe('view-utils', () => {
expect(isSettingsView('/music.eth/thread/cid-123/settings', params)).toBe(true);
});
it('supports deprecated subplebbitAddress params and marks unknown routes as not found', () => {
it('supports emoji board identifiers and marks unknown routes as not found', () => {
const params = {
subplebbitAddress: 'emoji-🎵.eth',
boardIdentifier: 'emoji-🎵.eth',
commentCid: 'cid-123',
};
-4
View File
@@ -6,9 +6,7 @@ type AccountLike = {
author?: { address?: string; shortAddress?: string; avatar?: unknown };
pkc?: unknown;
pkcReactOptions?: unknown;
plebbit?: unknown;
karma?: unknown;
plebbitReactOptions?: unknown;
unreadNotificationCount?: unknown;
[key: string]: unknown;
};
@@ -23,9 +21,7 @@ export const buildEditableAccountJson = (account: AccountLike | undefined): stri
author: { ...account?.author, avatar: undefined },
pkc: undefined,
pkcReactOptions: undefined,
plebbit: undefined,
karma: undefined,
plebbitReactOptions: undefined,
unreadNotificationCount: undefined,
},
});
+2 -1
View File
@@ -1,5 +1,6 @@
import { ChallengeVerification } from '@bitsocialnet/bitsocial-react-hooks';
import { getFallbackDirectoriesData } from '../../hooks/use-directories';
import { getCommentCommunityAddress } from './comment-utils';
import { getBoardPath } from './route-utils';
const resolveBoardIdentifier = (communityAddress: unknown): string => {
@@ -35,7 +36,7 @@ export const alertChallengeVerificationFailed = (challengeVerification: Challeng
}
const finalMessage = errorMessages.filter(Boolean).join(' ');
const publicationCommunityAddress = publication?.communityAddress || publication?.subplebbitAddress;
const publicationCommunityAddress = getCommentCommunityAddress(publication);
alert(`Error from ${resolveBoardIdentifier(publicationCommunityAddress)}: ${finalMessage || 'unknown error'}`);
} else {
+5 -9
View File
@@ -1,15 +1,14 @@
type CommentWithLegacyCommunityAddress = {
type CommentWithCommunityAddress = {
communityAddress?: string;
replies?: {
pages?: Record<
string,
| {
comments?: Array<CommentWithLegacyCommunityAddress | undefined>;
comments?: Array<CommentWithCommunityAddress | undefined>;
}
| undefined
>;
};
subplebbitAddress?: string;
};
export const getCommentCommunityAddress = (comment?: unknown) => {
@@ -17,18 +16,15 @@ export const getCommentCommunityAddress = (comment?: unknown) => {
return undefined;
}
const record = comment as { communityAddress?: unknown; subplebbitAddress?: unknown };
const record = comment as { communityAddress?: unknown };
if (typeof record.communityAddress === 'string' && record.communityAddress) {
return record.communityAddress;
}
if (typeof record.subplebbitAddress === 'string' && record.subplebbitAddress) {
return record.subplebbitAddress;
}
return undefined;
};
const withResolvedReplyPages = (replies?: CommentWithLegacyCommunityAddress['replies']) => {
const withResolvedReplyPages = (replies?: CommentWithCommunityAddress['replies']) => {
if (!replies?.pages) {
return replies;
}
@@ -82,7 +78,7 @@ const withResolvedReplyPages = (replies?: CommentWithLegacyCommunityAddress['rep
};
};
export const withResolvedCommentCommunityAddress = <T extends CommentWithLegacyCommunityAddress | undefined | null>(comment: T): T => {
export const withResolvedCommentCommunityAddress = <T extends CommentWithCommunityAddress | undefined | null>(comment: T): T => {
if (!comment) {
return comment;
}
+2 -1
View File
@@ -6,6 +6,7 @@ import type { DirectoryCommunity } from '../../hooks/use-directories';
import usePostNumberStore from '../../stores/use-post-number-store';
import type { ExternalQuoteReference, ExternalQuoteSearchStatus } from './external-quote-utils';
import { getExternalQuoteBoardAddress, getExternalQuoteBoardLabel } from './external-quote-utils';
import { getCommentCommunityAddress } from './comment-utils';
import { getBoardPath } from './route-utils';
const BOARD_FEED_SORT_TYPE = 'new';
@@ -63,7 +64,7 @@ const findLoadedCommentByNumber = ({ number, communityAddress }: { number: numbe
const comments = Object.values(communitiesPagesStore.getState().comments) as Array<Comment | undefined>;
return comments.find((comment) => {
const address = (comment as { communityAddress?: string }).communityAddress || comment?.subplebbitAddress;
const address = getCommentCommunityAddress(comment);
return address === communityAddress && comment?.number === number && comment?.cid;
});
};
+1 -1
View File
@@ -163,7 +163,7 @@ const fetchWebpageThumbnail = async (url: string): Promise<string | undefined> =
});
html = response.data.slice(0, MAX_HTML_SIZE);
} else {
// some sites have CORS access, from which the thumbnail can be fetched client-side, which is helpful if subplebbit.settings.fetchThumbnailUrls is false
// some sites have CORS access, so the thumbnail can be fetched client-side when community thumbnail fetching is disabled
const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), TIMEOUT);
+5 -4
View File
@@ -1,5 +1,6 @@
import type { Comment } from '@bitsocialnet/bitsocial-react-hooks';
import communitiesStore from '@bitsocialnet/bitsocial-react-hooks/dist/stores/communities';
import { getCommentCommunityAddress } from './comment-utils';
type CommunityLike = {
roles?: Record<string, { role?: string }>;
@@ -142,20 +143,20 @@ export const displayNameMatchesPattern = (comment: Comment, pattern: string): bo
* @returns True if the user has the specified role, false otherwise
*/
export const userHasRole = (comment: Comment, role: string): boolean => {
const communityAddress = (comment as { communityAddress?: string }).communityAddress ?? comment?.subplebbitAddress;
const communityAddress = getCommentCommunityAddress(comment);
if (!role || !comment?.author?.address || !communityAddress) {
return false;
}
const communities = communitiesStore.getState().communities;
const subplebbit = communities[communityAddress] as CommunityLike | undefined;
const community = communities[communityAddress] as CommunityLike | undefined;
if (!subplebbit?.roles) {
if (!community?.roles) {
return false;
}
const userRole = subplebbit.roles[comment.author.address]?.role;
const userRole = community.roles[comment.author.address]?.role;
// Handle different role names (moderator/mod)
if ((role.toLowerCase() === 'moderator' || role.toLowerCase() === 'mod') && userRole === 'moderator') {
+1 -1
View File
@@ -1,6 +1,6 @@
export const approvePendingCommentModeration = { approved: true } as const;
// plebbit-js clears pendingApproval only when rejection is published as approved:false.
// pkc-js clears pendingApproval only when rejection is published as approved:false.
// Sending removed:true marks the comment removed but can leave it in the mod queue.
export const rejectPendingCommentModeration = { approved: false } as const;
-2
View File
@@ -6,7 +6,6 @@ export type PostMenuProps = {
postCid?: string;
parentCid?: string;
communityAddress?: string;
subplebbitAddress?: string;
authorAddress?: string;
link?: string;
linkWidth?: number;
@@ -24,7 +23,6 @@ export const selectPostMenuProps = (post?: Comment): PostMenuProps => {
postCid: post?.postCid,
parentCid: post?.parentCid,
communityAddress,
subplebbitAddress: post?.subplebbitAddress,
authorAddress: post?.author?.address,
link: post?.link,
linkWidth: post?.linkWidth,
-4
View File
@@ -16,7 +16,6 @@ type CommunityIdentifierLike = {
};
type LegacyFeedOptionsLike = {
subplebbitAddresses?: string[];
sortType: string;
postsPerPage?: number;
filter?: unknown;
@@ -72,9 +71,6 @@ const getCommunityIdentifiers = (opts: FeedOptionsLike | LegacyFeedOptionsLike):
if ('communityAddresses' in opts && Array.isArray(opts.communityAddresses)) {
return opts.communityAddresses.map((communityAddress) => ({ name: communityAddress }));
}
if ('subplebbitAddresses' in opts && Array.isArray(opts.subplebbitAddresses)) {
return opts.subplebbitAddresses.map((communityAddress) => ({ name: communityAddress }));
}
return [];
};
-5
View File
@@ -104,11 +104,6 @@ export const getCommunityAddress = (boardIdentifier: string, communities: Direct
return boardIdentifier;
};
/**
* Back-compat alias kept for route params and comments.
*/
export const getSubplebbitAddress = getCommunityAddress;
/**
* Compare two addresses; returns true if they refer to the same board (handles .bso/.eth aliases).
*/
+3 -3
View File
@@ -64,15 +64,15 @@ export const is5chanLink = (url: string): boolean => {
// For pleb.bz, only support the exact sharelink format (legacy /p/... format)
if (hostname === 'pleb.bz') {
// Must match exactly: /p/{subplebbitAddress}/c/{cid}
// Must match exactly: /p/{communityAddress}/c/{cid}
// Allow redirect parameter since these are still valid internal links
return /^\/p\/[^/]+\/c\/[^/]+$/.test(routePath);
}
// For other 5chan hostnames, support both old and new formats:
// Old format (for backward compatibility):
// - /p/{subplebbitAddress}
// - /p/{subplebbitAddress}/c/{commentCid}
// - /p/{communityAddress}
// - /p/{communityAddress}/c/{commentCid}
// New format:
// - /{boardIdentifier} (directory code or address)
// - /{boardIdentifier}/thread/{commentCid}
+8 -9
View File
@@ -4,7 +4,6 @@ type ParamsType = {
accountCommentIndex?: string;
boardIdentifier?: string;
commentCid?: string;
subplebbitAddress?: string; // deprecated, kept for backward compatibility
};
export const isAllView = (pathname: string): boolean => {
@@ -28,13 +27,13 @@ export const isBoardView = (pathname: string, params: ParamsType): boolean => {
) {
return false;
}
const identifier = params.boardIdentifier || params.subplebbitAddress;
const identifier = params.boardIdentifier;
return identifier ? decodedPathname.startsWith(`/${identifier}`) : false;
};
export const isCatalogView = (pathname: string, params: ParamsType): boolean => {
const { boardIdentifier, subplebbitAddress } = params;
const identifier = boardIdentifier || subplebbitAddress;
const { boardIdentifier } = params;
const identifier = boardIdentifier;
const decodedPathname = decodeURIComponent(pathname);
return (
@@ -66,13 +65,13 @@ export const isPendingPostView = (pathname: string, params: ParamsType): boolean
export const isPostPageView = (pathname: string, params: ParamsType): boolean => {
const decodedPathname = decodeURIComponent(pathname);
const identifier = params.boardIdentifier || params.subplebbitAddress;
const identifier = params.boardIdentifier;
return identifier && params.commentCid ? decodedPathname.startsWith(`/${identifier}/thread/${params.commentCid}`) : false;
};
export const isSettingsView = (pathname: string, params: ParamsType): boolean => {
const { accountCommentIndex, boardIdentifier, commentCid, subplebbitAddress } = params;
const identifier = boardIdentifier || subplebbitAddress;
const { accountCommentIndex, boardIdentifier, commentCid } = params;
const identifier = boardIdentifier;
const decodedPathname = decodeURIComponent(pathname);
return (
(identifier && commentCid && decodedPathname === `/${identifier}/thread/${commentCid}/settings`) || decodedPathname === `/pending/${accountCommentIndex}/settings`
@@ -84,8 +83,8 @@ export const isSubscriptionsView = (pathname: string, params: ParamsType): boole
};
export const isArchiveView = (pathname: string, params: ParamsType): boolean => {
const { boardIdentifier, subplebbitAddress } = params;
const identifier = boardIdentifier || subplebbitAddress;
const { boardIdentifier } = params;
const identifier = boardIdentifier;
const decodedPathname = decodeURIComponent(pathname);
return Boolean(identifier && isArchiveRoute(decodedPathname) && decodedPathname === `/${identifier}/archive`);