diff --git a/README.md b/README.md index ebd21f67..f45433c6 100644 --- a/README.md +++ b/README.md @@ -171,6 +171,13 @@ usePublishCommentEdit(options: UsePublishCommentEditOptions): UsePublishCommentE usePublishCommentModeration(options: UsePublishCommentModerationOptions): UsePublishCommentModerationResult usePublishCommunityEdit(options: UsePublishCommunityEditOptions): UsePublishCommunityEditResult useCreateCommunity(options: CreateCommunityOptions): {createdCommunity: Community | undefined, createCommunity: Function} +useExportCommunity(options?: UseExportCommunityOptions): { + communityExports: {communityAddress: string, exportId: string}[], + exportCommunity: () => Promise, + state: string, + error: Error | undefined, + errors: Error[] +} ``` #### States Hooks @@ -1120,6 +1127,33 @@ const communities = useCommunities({ const _community = useCommunity({ community: { name: createdCommunity.address } }); ``` +#### (Desktop only) Export communities + +```jsx +// Export one community. +const { communityExports, exportCommunity, state, error } = useExportCommunity({ + communityAddress: "your-community-address.eth", +}); +await exportCommunity(); + +// Export several communities at the same time. +const exportMany = useExportCommunity({ + communityAddresses: ["community-1.eth", "community-2.eth"], +}); +await exportMany.exportCommunity(); + +// Export every community listed by the active account's pkc client. +const exportAll = useExportCommunity(); +await exportAll.exportCommunity(); + +if (state === "succeeded") { + console.log("started exports", communityExports); +} +if (state === "failed") { + console.log("failed to start export", error.message); +} +``` + #### (Desktop only) List the communities you created ```jsx diff --git a/llms-full.txt b/llms-full.txt index cf2100a9..44da0a61 100644 --- a/llms-full.txt +++ b/llms-full.txt @@ -201,6 +201,13 @@ usePublishCommentEdit(options: UsePublishCommentEditOptions): UsePublishCommentE usePublishCommentModeration(options: UsePublishCommentModerationOptions): UsePublishCommentModerationResult usePublishCommunityEdit(options: UsePublishCommunityEditOptions): UsePublishCommunityEditResult useCreateCommunity(options: CreateCommunityOptions): {createdCommunity: Community | undefined, createCommunity: Function} +useExportCommunity(options?: UseExportCommunityOptions): { + communityExports: {communityAddress: string, exportId: string}[], + exportCommunity: () => Promise, + state: string, + error: Error | undefined, + errors: Error[] +} ``` #### States Hooks @@ -1150,6 +1157,33 @@ const communities = useCommunities({ const _community = useCommunity({ community: { name: createdCommunity.address } }); ``` +#### (Desktop only) Export communities + +```jsx +// Export one community. +const { communityExports, exportCommunity, state, error } = useExportCommunity({ + communityAddress: "your-community-address.eth", +}); +await exportCommunity(); + +// Export several communities at the same time. +const exportMany = useExportCommunity({ + communityAddresses: ["community-1.eth", "community-2.eth"], +}); +await exportMany.exportCommunity(); + +// Export every community listed by the active account's pkc client. +const exportAll = useExportCommunity(); +await exportAll.exportCommunity(); + +if (state === "succeeded") { + console.log("started exports", communityExports); +} +if (state === "failed") { + console.log("failed to start export", error.message); +} +``` + #### (Desktop only) List the communities you created ```jsx diff --git a/package.json b/package.json index cd024cb8..723b08c0 100644 --- a/package.json +++ b/package.json @@ -48,7 +48,7 @@ }, "dependencies": { "@bitsocial/bso-resolver": "0.0.8", - "@pkcprotocol/pkc-js": "0.0.38", + "@pkcprotocol/pkc-js": "0.0.41", "@pkcprotocol/pkc-logger": "0.1.0", "assert": "2.0.0", "ethers": "5.8.0", diff --git a/src/hooks/actions/actions.test.ts b/src/hooks/actions/actions.test.ts index b4d43f19..f40933fd 100644 --- a/src/hooks/actions/actions.test.ts +++ b/src/hooks/actions/actions.test.ts @@ -10,6 +10,7 @@ import { useBlock, useAccount, useCreateCommunity, + useExportCommunity, setPkcJs, useAccountVote, useAccountComments, @@ -556,6 +557,185 @@ describe("actions", () => { }); }); + describe("useExportCommunity", () => { + let rendered: any, waitFor: Function; + + beforeEach(async () => { + rendered = renderHook((options = []) => { + const result1 = useExportCommunity(options[0]); + const result2 = useExportCommunity(options[1]); + return [result1, result2]; + }); + waitFor = testUtils.createWaitFor(rendered); + }); + + afterEach(async () => { + await testUtils.resetDatabasesAndStores(); + }); + + test("can export one community", async () => { + const communityAddress = "export-one.eth"; + expect(rendered.result.current[0].communityExports).toEqual([]); + expect(typeof rendered.result.current[0].exportCommunity).toBe("function"); + + rendered.rerender([{ communityAddress }]); + await waitFor(() => rendered.result.current[0].state === "ready"); + + await act(async () => { + await rendered.result.current[0].exportCommunity(); + }); + + await waitFor(() => rendered.result.current[0].state === "succeeded"); + expect(rendered.result.current[0].communityExports).toEqual([ + { + communityAddress, + exportId: `${communityAddress} export 1`, + }, + ]); + expect(rendered.result.current[0].error).toBe(undefined); + }); + + test("is initializing while the account is unavailable", () => { + const activeAccountId = useAccountsStore.getState().activeAccountId; + useAccountsStore.setState({ activeAccountId: undefined }); + + try { + const initializing = renderHook(() => + useExportCommunity({ communityAddress: "initializing-export.eth" }), + ); + expect(initializing.result.current.state).toBe("initializing"); + } finally { + useAccountsStore.setState({ activeAccountId }); + } + }); + + test("returns initializing and hides stale exports when the account becomes unavailable", async () => { + rendered.rerender([{ communityAddress: "logout-export.eth" }]); + await waitFor(() => rendered.result.current[0].state === "ready"); + + await act(async () => { + await rendered.result.current[0].exportCommunity(); + }); + await waitFor(() => rendered.result.current[0].state === "succeeded"); + + const activeAccountId = useAccountsStore.getState().activeAccountId; + try { + await act(async () => { + useAccountsStore.setState({ activeAccountId: undefined }); + }); + + expect(rendered.result.current[0].state).toBe("initializing"); + expect(rendered.result.current[0].communityExports).toEqual([]); + } finally { + useAccountsStore.setState({ activeAccountId }); + } + }); + + test("returns ready and hides stale exports when export targets change", async () => { + rendered.rerender([{ communityAddress: "old-export-target.eth" }]); + await waitFor(() => rendered.result.current[0].state === "ready"); + + await act(async () => { + await rendered.result.current[0].exportCommunity(); + }); + await waitFor(() => rendered.result.current[0].state === "succeeded"); + + rendered.rerender([{ communityAddress: "new-export-target.eth" }]); + + expect(rendered.result.current[0].state).toBe("ready"); + expect(rendered.result.current[0].communityExports).toEqual([]); + + rendered.rerender([{ communityAddress: "old-export-target.eth" }]); + + expect(rendered.result.current[0].state).toBe("ready"); + expect(rendered.result.current[0].communityExports).toEqual([]); + }); + + test("can export multiple communities", async () => { + const communityAddresses = ["export-many-1.eth", "export-many-2.eth"]; + rendered.rerender([{ communityAddresses }]); + await waitFor(() => rendered.result.current[0].state === "ready"); + + await act(async () => { + await rendered.result.current[0].exportCommunity(); + }); + + await waitFor(() => rendered.result.current[0].state === "succeeded"); + expect(rendered.result.current[0].communityExports).toEqual([ + { + communityAddress: communityAddresses[0], + exportId: `${communityAddresses[0]} export 1`, + }, + { + communityAddress: communityAddresses[1], + exportId: `${communityAddresses[1]} export 1`, + }, + ]); + }); + + test("exports listed account communities when no address is provided", async () => { + await act(async () => { + await useAccountsStore.getState().accountsActions.createCommunity({ title: "Export all" }); + }); + + rendered.rerender([undefined]); + await waitFor(() => rendered.result.current[0].state === "ready"); + await act(async () => { + await rendered.result.current[0].exportCommunity(); + }); + + await waitFor(() => rendered.result.current[0].state === "succeeded"); + expect(rendered.result.current[0].communityExports).toEqual([ + { + communityAddress: "list community address 1", + exportId: "list community address 1 export 1", + }, + { + communityAddress: "list community address 2", + exportId: "list community address 2 export 1", + }, + { + communityAddress: "created community address", + exportId: "created community address export 1", + }, + ]); + }); + + test("useExportCommunity onError callback when export fails", async () => { + const original = useAccountsStore.getState().accountsActions.exportCommunity; + useAccountsStore.setState((state: any) => ({ + ...state, + accountsActions: { + ...state.accountsActions, + exportCommunity: async () => { + throw Error("store exportCommunity error"); + }, + }, + })); + + const onError = vi.fn(); + rendered.rerender([{ communityAddress: "export-error.eth", onError }]); + await waitFor(() => rendered.result.current[0].state === "ready"); + + await act(async () => { + await rendered.result.current[0].exportCommunity(); + }); + + expect(rendered.result.current[0].state).toBe("failed"); + expect(rendered.result.current[0].errors.length).toBe(1); + expect(rendered.result.current[0].error.message).toBe("store exportCommunity error"); + expect(onError).toHaveBeenCalledWith(expect.any(Error)); + + useAccountsStore.setState((state: any) => ({ + ...state, + accountsActions: { + ...state.accountsActions, + exportCommunity: original, + }, + })); + }); + }); + // retry usePublish because publishing state is flaky describe("usePublishComment", { retry: 3 }, () => { let rendered: any, waitFor: Function; diff --git a/src/hooks/actions/actions.ts b/src/hooks/actions/actions.ts index 6ca023c8..5120ea14 100644 --- a/src/hooks/actions/actions.ts +++ b/src/hooks/actions/actions.ts @@ -50,6 +50,8 @@ import type { UseBlockResult, UseCreateCommunityOptions, UseCreateCommunityResult, + UseExportCommunityOptions, + UseExportCommunityResult, UsePublishVoteOptions, UsePublishVoteResult, UsePublishCommentEditOptions, @@ -66,6 +68,7 @@ import type { CommunityEdit, Vote, Community, + CommunityExport, } from "../../types"; type PublishChallengeAnswers = (challengeAnswers: string[]) => Promise; @@ -711,3 +714,73 @@ export function useCreateCommunity(options?: UseCreateCommunityOptions): UseCrea [state, errors, createdCommunity, options, accountName], ); } + +export function useExportCommunity(options?: UseExportCommunityOptions): UseExportCommunityResult { + assert( + !options || typeof options === "object", + `useExportCommunity options argument '${options}' not an object`, + ); + const { accountName, communityAddress, communityAddresses, onError, ...exportCommunityOptions } = + options || {}; + const accountsActions = useAccountsStore((state) => state.accountsActions); + const accountId = useAccountId(accountName); + const [errors, setErrors] = useState([]); + const [exportingState, setExportingState] = useState(); + const [communityExports, setCommunityExports] = useState([]); + const targetCommunityAddresses = + communityAddresses || (communityAddress ? [communityAddress] : undefined); + const exportContextKey = JSON.stringify([ + accountId || null, + targetCommunityAddresses || null, + exportCommunityOptions.includePrivateKey === true, + exportCommunityOptions.exportPath, + ]); + const previousExportContextKeyRef = useRef(exportContextKey); + const exportContextVersionRef = useRef(0); + if (previousExportContextKeyRef.current !== exportContextKey) { + previousExportContextKeyRef.current = exportContextKey; + exportContextVersionRef.current += 1; + } + const [exportingContext, setExportingContext] = useState<{ + key: string; + version: number; + }>(); + + let initialState = "initializing"; + if (accountId) { + initialState = "ready"; + } + const hasCurrentExportState = + accountId && + exportingContext?.key === exportContextKey && + exportingContext.version === exportContextVersionRef.current; + + const exportCommunity = async () => { + try { + setExportingContext({ + key: exportContextKey, + version: exportContextVersionRef.current, + }); + setExportingState("exporting"); + const communityExports = await accountsActions.exportCommunity( + targetCommunityAddresses, + exportCommunityOptions, + accountName, + ); + setCommunityExports(communityExports); + setExportingState("succeeded"); + } catch (e: any) { + setExportingState("failed"); + setErrors((errors) => [...errors, e]); + onError?.(e); + } + }; + + return { + communityExports: hasCurrentExportState ? communityExports : [], + exportCommunity, + state: hasCurrentExportState ? exportingState! : initialState, + error: hasCurrentExportState ? errors[errors.length - 1] : undefined, + errors: hasCurrentExportState ? errors : [], + }; +} diff --git a/src/index.ts b/src/index.ts index 435e7384..37f10d4b 100644 --- a/src/index.ts +++ b/src/index.ts @@ -55,6 +55,7 @@ import { usePublishCommentEdit, usePublishCommentModeration, usePublishCommunityEdit, + useExportCommunity, } from "./hooks/actions"; // actions that don't have their own hooks yet @@ -136,6 +137,7 @@ export { usePublishCommentModeration, usePublishCommunityEdit, useCreateCommunity, + useExportCommunity, // actions that don't have their own hooks yet createAccount, deleteAccount, @@ -208,6 +210,7 @@ const hooks = { usePublishCommentModeration, usePublishCommunityEdit, useCreateCommunity, + useExportCommunity, // actions that don't have their own hooks yet createAccount, deleteAccount, diff --git a/src/lib/pkc-js/pkc-js-mock.ts b/src/lib/pkc-js/pkc-js-mock.ts index 7e58a670..77e66512 100644 --- a/src/lib/pkc-js/pkc-js-mock.ts +++ b/src/lib/pkc-js/pkc-js-mock.ts @@ -296,10 +296,12 @@ export class Community extends EventEmitter { updating = false; firstUpdate = true; address: string | undefined; + publicKey: string | undefined; title: string | undefined; description: string | undefined; posts: Pages; modQueue: Pages; + exportRecords: any[]; updatedAt: number | undefined; statsCid: string | undefined; state: string; @@ -311,12 +313,14 @@ export class Community extends EventEmitter { createCommunityOptions?.address || createCommunityOptions?.name || createCommunityOptions?.publicKey; + this.publicKey = createCommunityOptions?.publicKey || this.address; this.title = createCommunityOptions?.title; this.description = createCommunityOptions?.description; this.statsCid = "statscid"; this.state = "stopped"; this.updatingState = "stopped"; this.updatedAt = createCommunityOptions?.updatedAt; + this.exportRecords = []; this.posts = new Pages({ community: this }); // add community.posts from createCommunityOptions @@ -394,6 +398,27 @@ export class Community extends EventEmitter { } } + get exports() { + return this.exportRecords.map((record) => ({ ...record })); + } + + async export(exportCommunityOptions: any = {}) { + if (!this.address) { + throw Error(`can't community.export with no community.address`); + } + const exportRecord = { + exportId: `${this.address} export ${this.exportRecords.length + 1}`, + name: this.address, + publicKey: this.publicKey || this.address, + includePrivateKey: exportCommunityOptions.includePrivateKey === true, + progress: 1, + url: `file://${this.address}.zip`, + }; + this.exportRecords.push(exportRecord); + this.emit("exportschange", this.exports); + return { exportId: exportRecord.exportId }; + } + simulateUpdateEvent() { if (this.firstUpdate) { this.simulateFirstUpdateEvent(); diff --git a/src/stores/accounts/accounts-actions.test.ts b/src/stores/accounts/accounts-actions.test.ts index 305b96f8..d42e3a16 100644 --- a/src/stores/accounts/accounts-actions.test.ts +++ b/src/stores/accounts/accounts-actions.test.ts @@ -6,7 +6,11 @@ import * as accountsActionsInternal from "./accounts-actions-internal"; import accountsDatabase from "./accounts-database"; import accountsStore from "./accounts-store"; import communitiesStore from "../communities"; -import PkcJsMock, { PKC as BasePkc, Comment as BaseComment } from "../../lib/pkc-js/pkc-js-mock"; +import PkcJsMock, { + PKC as BasePkc, + Comment as BaseComment, + Community as BaseCommunity, +} from "../../lib/pkc-js/pkc-js-mock"; import { setPkcJs } from "../../lib/pkc-js"; import * as protocolCompat from "../../lib/pkc-compat"; @@ -670,6 +674,157 @@ describe("accounts-actions", () => { expect(sub?.address).toBeDefined(); }); + test("exportCommunity exports one community from the active account", async () => { + const communityExports = await accountsActions.exportCommunity("single-export.eth", { + includePrivateKey: true, + }); + + expect(communityExports).toEqual([ + { + communityAddress: "single-export.eth", + exportId: "single-export.eth export 1", + }, + ]); + }); + + test("exportCommunity exports multiple communities concurrently", async () => { + const originalExport = BaseCommunity.prototype.export; + let activeExports = 0; + let maxActiveExports = 0; + BaseCommunity.prototype.export = async function (options: any) { + activeExports++; + maxActiveExports = Math.max(maxActiveExports, activeExports); + await new Promise((resolve) => setTimeout(resolve, 20)); + const result = await originalExport.call(this, options); + activeExports--; + return result; + }; + + try { + const communityExports = await accountsActions.exportCommunity([ + "bulk-export-1.eth", + "bulk-export-2.eth", + ]); + + expect(communityExports).toEqual([ + { + communityAddress: "bulk-export-1.eth", + exportId: "bulk-export-1.eth export 1", + }, + { + communityAddress: "bulk-export-2.eth", + exportId: "bulk-export-2.eth export 1", + }, + ]); + expect(maxActiveExports).toBe(2); + } finally { + BaseCommunity.prototype.export = originalExport; + } + }); + + test("exportCommunity keeps the requested communityAddress when export metadata conflicts", async () => { + const originalExport = BaseCommunity.prototype.export; + BaseCommunity.prototype.export = async function (options: any) { + const result = await originalExport.call(this, options); + return { ...result, communityAddress: "wrong-export-address.eth" }; + }; + + try { + const communityExports = await accountsActions.exportCommunity("requested-export.eth"); + + expect(communityExports).toEqual([ + { + communityAddress: "requested-export.eth", + exportId: "requested-export.eth export 1", + }, + ]); + } finally { + BaseCommunity.prototype.export = originalExport; + } + }); + + test("exportCommunity defaults to account pkc communities", async () => { + await act(async () => { + await accountsActions.createCommunity({ title: "Export default list" }); + }); + + const communityExports = await accountsActions.exportCommunity(); + + expect(communityExports).toEqual([ + { + communityAddress: "list community address 1", + exportId: "list community address 1 export 1", + }, + { + communityAddress: "list community address 2", + exportId: "list community address 2 export 1", + }, + { + communityAddress: "created community address", + exportId: "created community address export 1", + }, + ]); + }); + + test("exportCommunity with accountName uses named account", async () => { + await act(async () => { + await accountsActions.createAccount(); + await accountsActions.createAccount("ExportSubAccount"); + }); + + const communityExports = await accountsActions.exportCommunity( + "named-export.eth", + {}, + "ExportSubAccount", + ); + + expect(communityExports).toEqual([ + { + communityAddress: "named-export.eth", + exportId: "named-export.eth export 1", + }, + ]); + }); + + test("exportCommunity validates inputs", async () => { + const { accounts, activeAccountId } = accountsStore.getState(); + const account = accounts[activeAccountId || ""]; + accountsStore.setState({ + accounts: { + ...accounts, + [account.id]: { ...account, pkc: { communities: [] } }, + }, + }); + try { + await expect(accountsActions.exportCommunity()).rejects.toThrow( + "accountsActions.exportCommunity no community addresses to export", + ); + } finally { + accountsStore.setState({ accounts }); + } + await expect(accountsActions.exportCommunity([undefined as any])).rejects.toThrow( + "accountsActions.exportCommunity invalid communityAddress 'undefined'", + ); + await expect( + accountsActions.exportCommunity("bad-options.eth", "bad" as any), + ).rejects.toThrow( + "accountsActions.exportCommunity invalid exportCommunityOptions argument 'bad'", + ); + }); + + test("exportCommunity requires community.export", async () => { + const createCommunity = BasePkc.prototype.createCommunity; + BasePkc.prototype.createCommunity = async () => ({ address: "no-export.eth" }) as any; + + try { + await expect(accountsActions.exportCommunity("no-export.eth")).rejects.toThrow( + "accountsActions.exportCommunity community.export missing for communityAddress 'no-export.eth'", + ); + } finally { + BasePkc.prototype.createCommunity = createCommunity; + } + }); + test("publishCommunityEdit uses local owner state when pkc communities list is stale", async () => { const account = Object.values(accountsStore.getState().accounts)[0]; const getPkcCommunityAddressesSpy = vi diff --git a/src/stores/accounts/accounts-actions.ts b/src/stores/accounts/accounts-actions.ts index 887ca1ba..5e5c48f5 100644 --- a/src/stores/accounts/accounts-actions.ts +++ b/src/stores/accounts/accounts-actions.ts @@ -20,12 +20,15 @@ import { PublishCommentModerationOptions, PublishCommunityEditOptions, CreateCommunityOptions, + ExportCommunityOptions, + CommunityExport, Communities, AccountComment, } from "../../types"; import * as accountsActionsInternal from "./accounts-actions-internal"; import { backfillPublicationCommunityAddress, + createPkcCommunity, createPkcCommunityEdit, getPkcCommunityAddresses, normalizeCommunityEditOptionsForPkc, @@ -749,6 +752,74 @@ export const exportAccount = async (accountName?: string) => { return exportedAccountJson; }; +const getCommunityAddressesToExport = ( + communityAddressOrAddresses: string | string[] | undefined, + account: Account, +) => { + if (Array.isArray(communityAddressOrAddresses)) { + return communityAddressOrAddresses; + } + if (communityAddressOrAddresses) { + return [communityAddressOrAddresses]; + } + return getPkcCommunityAddresses(account.pkc); +}; + +export const exportCommunity = async ( + communityAddressOrAddresses?: string | string[], + exportCommunityOptions: ExportCommunityOptions = {}, + accountName?: string, +): Promise => { + const { accounts, accountNamesToAccountIds, activeAccountId } = accountsStore.getState(); + assert( + accounts && accountNamesToAccountIds && activeAccountId, + `can't use accountsStore.accountsActions before initialized`, + ); + assert( + !exportCommunityOptions || typeof exportCommunityOptions === "object", + `accountsActions.exportCommunity invalid exportCommunityOptions argument '${exportCommunityOptions}'`, + ); + let account = accounts[activeAccountId]; + if (accountName) { + const accountId = accountNamesToAccountIds[accountName]; + account = accounts[accountId]; + } + assert( + account?.id, + `accountsActions.exportCommunity account.id '${account?.id}' doesn't exist, activeAccountId '${activeAccountId}' accountName '${accountName}'`, + ); + + const communityAddresses = getCommunityAddressesToExport(communityAddressOrAddresses, account); + assert( + communityAddresses.length > 0, + `accountsActions.exportCommunity no community addresses to export`, + ); + for (const communityAddress of communityAddresses) { + assert( + communityAddress && typeof communityAddress === "string", + `accountsActions.exportCommunity invalid communityAddress '${communityAddress}'`, + ); + } + + const communityExports = await Promise.all( + [...new Set(communityAddresses)].map(async (communityAddress) => { + const community = await createPkcCommunity(account.pkc, { address: communityAddress }); + assert( + typeof community?.export === "function", + `accountsActions.exportCommunity community.export missing for communityAddress '${communityAddress}'`, + ); + const exportedCommunity = await community.export(exportCommunityOptions); + return { ...exportedCommunity, communityAddress }; + }), + ); + log("accountsActions.exportCommunity", { + communityAddresses, + includePrivateKey: exportCommunityOptions.includePrivateKey === true, + communityExportCount: communityExports.length, + }); + return communityExports; +}; + export const subscribe = async (communityAddress: string, accountName?: string) => { const { accounts, accountNamesToAccountIds, activeAccountId } = accountsStore.getState(); assert( diff --git a/src/types.ts b/src/types.ts index 886e197d..6526a1ff 100644 --- a/src/types.ts +++ b/src/types.ts @@ -464,6 +464,19 @@ export interface UseCreateCommunityResult extends Result { createCommunity(): Promise; } +// useExportCommunity(options): result +export interface UseExportCommunityOptions extends Options { + communityAddress?: string; + communityAddresses?: string[]; + includePrivateKey?: boolean; + exportPath?: string; + signal?: AbortSignal; +} +export interface UseExportCommunityResult extends Result { + communityExports: CommunityExport[]; + exportCommunity(): Promise; +} + // useDeleteCommunity(options): result // export interface UseDeleteCommunityOptions extends Options { // communityAddress?: string @@ -578,6 +591,12 @@ export type PublishVoteOptions = { [key: string]: any }; export type PublishCommentEditOptions = { [key: string]: any }; export type PublishCommentModerationOptions = { [key: string]: any }; export type PublishCommunityEditOptions = { [key: string]: any }; +export interface ExportCommunityOptions { + includePrivateKey?: boolean; + exportPath?: string; + signal?: AbortSignal; + [key: string]: unknown; +} export type Challenge = { [key: string]: any }; export type ChallengeVerification = { [key: string]: any }; export type CreateCommentOptions = { [key: string]: any }; @@ -589,6 +608,16 @@ export type CommentEdit = { [key: string]: any }; export type CommentModeration = { [key: string]: any }; export type CommunityEdit = { [key: string]: any }; export type Community = { [key: string]: any }; +export type CommunityExport = { + communityAddress: string; + exportId: string; + name?: string; + publicKey?: string; + includePrivateKey?: boolean; + progress?: number; + url?: string; + [key: string]: unknown; +}; export type CommunityStats = { [key: string]: any }; export type Notification = { [key: string]: any }; export type Nft = { [key: string]: any }; diff --git a/yarn.lock b/yarn.lock index 61836b7e..7585fae3 100644 --- a/yarn.lock +++ b/yarn.lock @@ -284,7 +284,7 @@ __metadata: resolution: "@bitsocial/bitsocial-react-hooks@workspace:." dependencies: "@bitsocial/bso-resolver": "npm:0.0.8" - "@pkcprotocol/pkc-js": "npm:0.0.38" + "@pkcprotocol/pkc-js": "npm:0.0.41" "@pkcprotocol/pkc-logger": "npm:0.1.0" "@testing-library/dom": "npm:10.4.1" "@testing-library/react": "npm:16.3.2" @@ -3168,9 +3168,9 @@ __metadata: languageName: node linkType: hard -"@pkcprotocol/pkc-js@npm:0.0.38": - version: 0.0.38 - resolution: "@pkcprotocol/pkc-js@npm:0.0.38" +"@pkcprotocol/pkc-js@npm:0.0.41": + version: 0.0.41 + resolution: "@pkcprotocol/pkc-js@npm:0.0.41" dependencies: "@enhances/with-resolvers": "npm:0.0.5" "@helia/block-brokers": "npm:5.2.4" @@ -3219,7 +3219,7 @@ __metadata: typestub-ipfs-only-hash: "npm:4.0.0" uuid: "npm:13.0.0" zod: "npm:4.3.6" - checksum: 10c0/97f94ca73911a6acc58658c3e6356f17ebf2388f88965052da8176759b297030a0933c874ab287c31e32d717bff7709a76df91d438b8bd010801be6a25fd873b + checksum: 10c0/4ecff61239f79e84665b2a44507b067711f9a6d04a766e651bbd5f95d663624b8573c6449d3959b80851efcfa2635b8139782bedcf0f2dffdd76418a05e6259b languageName: node linkType: hard