@gumhq/react-sdk
Version:
React SDK for Gum
1,382 lines (1,360 loc) • 65.9 kB
JavaScript
"use strict";
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
// If the importer is in node compatibility mode or this is not an ESM
// file that has been converted to a CommonJS file using a Babel-
// compatible transform (i.e. "__esModule" has not been set), then set
// "default" to the CommonJS "module.exports" for node compatibility.
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
mod
));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
// src/index.ts
var src_exports = {};
__export(src_exports, {
GATEWAY_SERVICE_URL: () => import_sdk6.GATEWAY_SERVICE_URL,
GPLCORE_PROGRAMS: () => import_sdk6.GPLCORE_PROGRAMS,
GPLSESSION_PROGRAMS: () => import_sdk6.GPLSESSION_PROGRAMS,
GPL_NAMESERVICE_PROGRAMS: () => import_sdk6.GPL_NAMESERVICE_PROGRAMS,
GRAPHQL_ENDPOINTS: () => import_sdk6.GRAPHQL_ENDPOINTS,
GRAPHQL_ENDPOINTS_OLD: () => import_sdk6.GRAPHQL_ENDPOINTS_OLD,
GUM_TLD_ACCOUNT: () => import_sdk6.GUM_TLD_ACCOUNT,
GumNameService: () => import_sdk6.GumNameService,
GumProvider: () => GumProvider,
OLD_GPLCORE_PROGRAMS: () => import_sdk6.OLD_GPLCORE_PROGRAMS,
SDK: () => import_sdk6.SDK,
SessionWalletProvider: () => SessionWalletProvider,
UploaderProvider: () => UploaderProvider,
useArweaveStorage: () => useArweaveStorage,
useBadge: () => useBadge,
useCreatePost: () => useCreatePost,
useCreateProfile: () => useCreateProfile,
useDomains: () => useDomains,
useExploreFeed: () => useExploreFeed,
useFeed: () => useFeed,
useFollow: () => useFollow,
useGum: () => useGum,
useGumContext: () => useGumContext,
useNameService: () => useNameService,
usePost: () => usePost,
useProfile: () => useProfile,
useReaction: () => useReaction,
useSessionKeyManager: () => useSessionKeyManager,
useSessionWallet: () => useSessionWallet,
useShadowStorage: () => useShadowStorage,
useUnfollow: () => useUnfollow,
useUploader: () => useUploader,
useUploaderContext: () => useUploaderContext
});
module.exports = __toCommonJS(src_exports);
// src/hooks/profile/useProfile.ts
var import_react = require("react");
var useProfile = (sdk, profileAccount) => {
const [profile, setProfile] = (0, import_react.useState)(null);
const [profileLoading, setProfileLoading] = (0, import_react.useState)(false);
const [profileError, setProfileError] = (0, import_react.useState)(null);
const fetchProfile = (0, import_react.useCallback)(
async () => {
setProfileLoading(true);
setProfileError(null);
try {
const data = await sdk.profile.getProfilesByProfileAccount(profileAccount);
setProfile(data);
} catch (err) {
setProfileError(err);
} finally {
setProfileLoading(false);
}
},
[sdk, profileAccount]
);
(0, import_react.useEffect)(() => {
fetchProfile();
}, []);
return { profile, profileLoading, profileError };
};
// src/hooks/profile/useCreateProfile.ts
var import_react2 = require("react");
var useCreateProfile = (sdk) => {
const [state, setState] = (0, import_react2.useState)({
isCreatingProfile: false,
createProfileError: null
});
const create = (0, import_react2.useCallback)(
async (metadataUri, screenNameAccount, owner, payer = owner) => {
setState({ isCreatingProfile: true, createProfileError: null });
try {
const ixMethodBuilder = await createProfileIxMethodBuilder(metadataUri, screenNameAccount, owner, payer);
await ixMethodBuilder?.instructionMethodBuilder.rpc();
setState({ isCreatingProfile: false, createProfileError: null });
return ixMethodBuilder?.profilePDA;
} catch (err) {
setState({ isCreatingProfile: false, createProfileError: err });
}
},
[sdk]
);
const getOrCreate = (0, import_react2.useCallback)(
async (metadataUri, screenNameAccount, owner, payer = owner) => {
setState({ isCreatingProfile: true, createProfileError: null });
try {
const profilePDA = await sdk.profile.getOrCreate(metadataUri, screenNameAccount, owner, payer);
setState({ isCreatingProfile: false, createProfileError: null });
return profilePDA;
} catch (err) {
setState({ isCreatingProfile: false, createProfileError: err });
}
},
[sdk]
);
const createProfileWithDomain = (0, import_react2.useCallback)(
async (metadataUri, domainName, authority, payer = authority) => {
setState({ isCreatingProfile: true, createProfileError: null });
try {
const ixMethodBuilder = await sdk.profile.createProfileWithGumDomain(metadataUri, domainName, authority, payer);
await ixMethodBuilder?.instructionMethodBuilder.rpc();
setState({ isCreatingProfile: false, createProfileError: null });
return ixMethodBuilder?.profilePDA;
} catch (err) {
setState({ isCreatingProfile: false, createProfileError: err });
}
},
[sdk]
);
const createProfileIxMethodBuilder = (0, import_react2.useCallback)(
async (metadataUri, screenNameAccount, authority, payer) => {
setState({ isCreatingProfile: true, createProfileError: null });
try {
const createProfile = await sdk.profile.create(metadataUri, screenNameAccount, authority, payer);
const data = {
instructionMethodBuilder: createProfile.instructionMethodBuilder,
profilePDA: createProfile.profilePDA
};
setState({ isCreatingProfile: false, createProfileError: null });
return data;
} catch (err) {
setState({ isCreatingProfile: false, createProfileError: err });
return null;
}
},
[sdk]
);
return {
create,
getOrCreate,
createProfileWithDomain,
createProfileIxMethodBuilder,
...state
};
};
// src/hooks/badge/index.ts
var import_sdk = require("@gumhq/sdk");
var import_react3 = require("react");
var import_web3 = require("@solana/web3.js");
var import_axios = __toESM(require("axios"));
var useBadge = (sdk) => {
const [state, setState] = (0, import_react3.useState)({
isProcessing: false,
processingError: null
});
const createBadge = (0, import_react3.useCallback)(
async (metadataUri, issuer, schema, holder, updateAuthority, authority) => {
setState({ isProcessing: true, processingError: null });
try {
const { badgePDA, instructionMethodBuilder } = await sdk.badge.createBadge(metadataUri, issuer, schema, holder, updateAuthority, authority);
await instructionMethodBuilder.rpc();
setState({ isProcessing: false, processingError: null });
return badgePDA;
} catch (err) {
setState({ isProcessing: false, processingError: err });
}
},
[sdk.badge]
);
const updateBadge = (0, import_react3.useCallback)(
async (metadataUri, badgeAccount, issuer, schema, signer) => {
setState({ isProcessing: true, processingError: null });
try {
const instructionMethodBuilder = await sdk.badge.updateBadge(metadataUri, badgeAccount, issuer, schema, signer);
await instructionMethodBuilder.rpc();
setState({ isProcessing: false, processingError: null });
} catch (err) {
setState({ isProcessing: false, processingError: err });
}
},
[sdk.badge]
);
const createIssuer = (0, import_react3.useCallback)(
async (authority) => {
setState({ isProcessing: true, processingError: null });
try {
const { issuerPDA, instructionMethodBuilder } = await sdk.badge.createIssuer(authority);
await instructionMethodBuilder.rpc();
setState({ isProcessing: false, processingError: null });
return issuerPDA;
} catch (err) {
setState({ isProcessing: false, processingError: err });
}
},
[sdk.badge]
);
const createSchema = (0, import_react3.useCallback)(
async (metadataUri, authority) => {
setState({ isProcessing: true, processingError: null });
try {
const { schemaPDA, instructionMethodBuilder } = await sdk.badge.createSchema(metadataUri, authority);
await instructionMethodBuilder.rpc();
setState({ isProcessing: false, processingError: null });
return schemaPDA;
} catch (err) {
setState({ isProcessing: false, processingError: err });
}
},
[sdk.badge]
);
const issueGatewayBadge = (0, import_react3.useCallback)(
async (wallet, holderWallet, holderProfile, schemaAccount, issuer, gumTld, appId, dateJoined, authority, updateAuthority) => {
setState({ isProcessing: true, processingError: null });
const message = new TextEncoder().encode("Issue Gateway Badge");
if (!wallet.signMessage) {
throw new Error("Wallet does not support signMessage");
}
const signature = await wallet.signMessage(message);
const [badgePDA, _] = import_web3.PublicKey.findProgramAddressSync(
[
Buffer.from("badge"),
issuer.toBuffer(),
schemaAccount.toBuffer(),
holderProfile.toBuffer()
],
sdk.program.programId
);
try {
const gatewayResponse = await import_axios.default.post(`${import_sdk.GATEWAY_SERVICE_URL}/issueBadge`, {
signature,
userWallet: holderWallet.toBase58(),
profileAddress: holderProfile.toBase58(),
issuerAddress: issuer.toBase58(),
badgeAddress: badgePDA.toBase58(),
gumTld: gumTld.toBase58(),
appName: appId,
dateJoined,
authority: authority.toBase58()
});
const gatewayBadge = gatewayResponse.data.createCredential;
if (!gatewayBadge) {
throw new Error("Failed to issue gateway badge");
}
const metadataUri = `gateway://${gatewayBadge.id}`;
const badge = await createBadge(
metadataUri,
issuer,
schemaAccount,
holderProfile,
updateAuthority || authority,
authority
);
setState({ isProcessing: false, processingError: null });
return badge;
} catch (err) {
setState({ isProcessing: false, processingError: err });
}
},
[sdk.badge]
);
return {
createBadge,
updateBadge,
createIssuer,
createSchema,
issueGatewayBadge,
...state
};
};
// src/hooks/nameservice/index.ts
var import_react5 = require("react");
// src/hooks/nameservice/useDomains.ts
var import_react4 = require("react");
var useDomains = (sdk, authority) => {
const [userDomainAccounts, setUserDomainAccounts] = (0, import_react4.useState)([]);
const [domainsLoading, setDomainsLoading] = (0, import_react4.useState)(false);
const [domainsError, setDomainsError] = (0, import_react4.useState)(null);
const fetchDomains = (0, import_react4.useCallback)(
async () => {
setDomainsLoading(true);
setDomainsError(null);
try {
const accounts = await sdk.nameservice.getNameservicesByAuthority(authority.toBase58());
if (!accounts)
return;
const domainOptions = accounts.map((account) => {
return {
domainPDA: account.address,
domainName: account.name
};
});
setUserDomainAccounts(domainOptions);
} catch (err) {
setDomainsError(err);
} finally {
setDomainsLoading(false);
}
},
[authority, sdk]
);
(0, import_react4.useEffect)(() => {
fetchDomains();
}, [fetchDomains]);
return { userDomainAccounts, domainsLoading, domainsError };
};
// src/hooks/nameservice/index.ts
var useNameService = (sdk) => {
const [state, setState] = (0, import_react5.useState)({
isCreating: false,
creationError: null
});
const getOrCreateDomain = (0, import_react5.useCallback)(
async (tldPDA, domain, authority) => {
setState({ isCreating: true, creationError: null });
try {
const gumDomainPDA = await sdk.nameservice.getOrCreateDomain(tldPDA, domain, authority);
setState({ isCreating: false, creationError: null });
return gumDomainPDA;
} catch (err) {
setState({ isCreating: false, creationError: err });
}
},
[sdk]
);
const transferDomain = (0, import_react5.useCallback)(
async (domainPDA, currentAuthority, newAuthority) => {
setState({ isCreating: true, creationError: null });
try {
const instructionMethodBuilder = await sdk.nameservice.transferDomain(domainPDA, currentAuthority, newAuthority);
await instructionMethodBuilder.rpc();
setState({ isCreating: false, creationError: null });
} catch (err) {
setState({ isCreating: false, creationError: err });
}
},
[sdk]
);
return {
getOrCreateDomain,
transferDomain,
...state
};
};
// src/hooks/post/usePost.ts
var import_react6 = require("react");
var usePost = (sdk, postAccount) => {
const [post, setPost] = (0, import_react6.useState)(null);
const [postLoading, setPostLoading] = (0, import_react6.useState)(false);
const [postError, setPostError] = (0, import_react6.useState)(null);
const fetchPost = (0, import_react6.useCallback)(
async () => {
setPostLoading(true);
setPostError(null);
try {
const data = await sdk.post.get(postAccount);
setPost(data);
} catch (err) {
setPostError(err);
} finally {
setPostLoading(false);
}
},
[sdk, postAccount]
);
(0, import_react6.useEffect)(() => {
fetchPost();
}, []);
return { post, postLoading, postError };
};
// src/hooks/post/useCreatePost.ts
var import_react7 = require("react");
var useCreatePost = (sdk) => {
const [postPDA, setPostPDA] = (0, import_react7.useState)(null);
const [isCreatingPost, setIsCreatingPost] = (0, import_react7.useState)(false);
const [createPostError, setCreatePostError] = (0, import_react7.useState)(null);
const create = (0, import_react7.useCallback)(
async (metadataUri, profileAccount, owner, payer = owner) => {
setIsCreatingPost(true);
setCreatePostError(null);
try {
const ixMethodBuilder = await createPostIxMethodBuilder(metadataUri, profileAccount, owner, payer);
return await ixMethodBuilder?.rpc();
} catch (err) {
setCreatePostError(err);
} finally {
setIsCreatingPost(false);
}
},
[sdk]
);
const createWithSession = (0, import_react7.useCallback)(
async (metadataUri, profileAccount, sessionPublicKey, sessionAccount, sendTransaction, payer = sessionPublicKey, connection, options) => {
setIsCreatingPost(true);
setCreatePostError(null);
try {
const ixMethodBuilder = await createPostWithSessionIxMethodBuilder(metadataUri, profileAccount, sessionPublicKey, sessionAccount, payer);
const tx = await ixMethodBuilder?.transaction();
if (tx) {
return await sendTransaction(tx, connection, options);
}
} catch (err) {
setCreatePostError(err);
} finally {
setIsCreatingPost(false);
}
},
[sdk]
);
const createPostIxMethodBuilder = (0, import_react7.useCallback)(
async (metadataUri, profileAccount, owner, payer = owner) => {
setCreatePostError(null);
try {
const data = await sdk.post.create(metadataUri, profileAccount, owner, payer);
setPostPDA(data.postPDA);
return data.instructionMethodBuilder;
} catch (err) {
setCreatePostError(err);
return null;
}
},
[sdk]
);
const createPostWithSessionIxMethodBuilder = (0, import_react7.useCallback)(
async (metadataUri, profileAccount, sessionPublicKey, sessionAccount, payer = sessionPublicKey) => {
setCreatePostError(null);
try {
const data = await sdk.post.createWithSession(metadataUri, profileAccount, sessionPublicKey, sessionAccount, payer);
setPostPDA(data.postPDA);
return data.instructionMethodBuilder;
} catch (err) {
setCreatePostError(err);
return null;
}
},
[sdk]
);
return {
create,
createWithSession,
createPostIxMethodBuilder,
createPostWithSessionIxMethodBuilder,
postPDA,
isCreatingPost,
createPostError
};
};
// src/hooks/post/useFeed.ts
var import_react8 = require("react");
var useFeed = (sdk, profileAccount) => {
const [feedData, setFeedData] = (0, import_react8.useState)(null);
const [feedLoading, setFeedLoading] = (0, import_react8.useState)(false);
const [feedError, setFeedError] = (0, import_react8.useState)(null);
const fetchFeed = (0, import_react8.useCallback)(
async () => {
setFeedLoading(true);
setFeedError(null);
try {
const data = await sdk.post.getFeedsByFollowedUsers(profileAccount);
setFeedData(data);
} catch (err) {
setFeedError(err);
} finally {
setFeedLoading(false);
}
},
[sdk, profileAccount]
);
(0, import_react8.useEffect)(() => {
fetchFeed();
}, []);
return { feedData, feedLoading, feedError };
};
// src/hooks/post/useExploreFeed.ts
var import_react9 = require("react");
var useExploreFeed = (sdk) => {
const [exploreFeedData, setExploreFeedData] = (0, import_react9.useState)(null);
const [exploreFeedLoading, setExploreFeedLoading] = (0, import_react9.useState)(false);
const [exploreFeedError, setExploreFeedError] = (0, import_react9.useState)(null);
const fetchExploreFeed = (0, import_react9.useCallback)(
async () => {
setExploreFeedLoading(true);
setExploreFeedError(null);
try {
const data = await sdk.post.getAllPosts();
setExploreFeedData(data);
} catch (err) {
setExploreFeedError(err);
} finally {
setExploreFeedLoading(false);
}
},
[sdk]
);
(0, import_react9.useEffect)(() => {
fetchExploreFeed();
}, []);
return { exploreFeedData, exploreFeedLoading, exploreFeedError };
};
// src/hooks/reaction/useReaction.ts
var import_react10 = require("react");
var useReaction = (sdk) => {
const [reactionPDA, setReactionPDA] = (0, import_react10.useState)(null);
const [isReacting, setIsReacting] = (0, import_react10.useState)(false);
const [createReactionError, setCreateReactionError] = (0, import_react10.useState)(null);
const createReaction = (0, import_react10.useCallback)(
async (reaction, fromProfile, toPostAccount, owner, payer = owner) => {
setIsReacting(true);
setCreateReactionError(null);
try {
const ixMethodBuilder = await createReactionIxMethodBuilder(reaction, fromProfile, toPostAccount, owner, payer);
if (ixMethodBuilder) {
return await ixMethodBuilder.rpc();
} else {
throw new Error("ixMethodBuilder is undefined");
}
} catch (err) {
setCreateReactionError(err);
} finally {
setIsReacting(false);
}
},
[sdk]
);
const createReactionWithSession = (0, import_react10.useCallback)(
async (reaction, fromProfile, toPostAccount, sessionPublicKey, sessionAccount, payer = sessionPublicKey, sendTransactionFn, connection, options) => {
setIsReacting(true);
setCreateReactionError(null);
try {
const ixMethodBuilder = await createReactionWithSessionIxMethodBuilder(reaction, fromProfile, toPostAccount, sessionPublicKey, sessionAccount, payer);
if (ixMethodBuilder) {
const tx = await ixMethodBuilder.transaction();
if (tx) {
return await sendTransactionFn(tx, connection, options);
}
} else {
throw new Error("ixMethodBuilder is undefined");
}
} catch (err) {
setCreateReactionError(err);
} finally {
setIsReacting(false);
}
},
[sdk]
);
const createReactionIxMethodBuilder = (0, import_react10.useCallback)(
async (reaction, fromProfile, toPostAccount, owner, payer = owner) => {
try {
const data = await sdk.reaction.create(fromProfile, toPostAccount, reaction, owner, payer);
setReactionPDA(data.reactionPDA);
return data.instructionMethodBuilder;
} catch (err) {
setCreateReactionError(err);
return null;
}
},
[sdk]
);
const createReactionWithSessionIxMethodBuilder = (0, import_react10.useCallback)(
async (reaction, fromProfile, toPostAccount, sessionPublicKey, sessionTokenAccount, payer = sessionPublicKey) => {
try {
const data = await sdk.reaction.createWithSession(fromProfile, toPostAccount, reaction, sessionPublicKey, sessionTokenAccount, payer);
setReactionPDA(data.reactionPDA);
return data.instructionMethodBuilder;
} catch (err) {
setCreateReactionError(err);
return null;
}
},
[sdk]
);
const deleteReaction = (0, import_react10.useCallback)(
async (reactionAccount, fromProfile, toPostAccount, owner, refundReceiver = owner) => {
setIsReacting(true);
try {
const ixMethodBuilder = deleteReactionIxMethodBuilder(reactionAccount, fromProfile, toPostAccount, owner, refundReceiver);
if (ixMethodBuilder) {
return await ixMethodBuilder.rpc();
} else {
throw new Error("ixMethodBuilder is undefined");
}
} catch (err) {
setCreateReactionError(err);
} finally {
setIsReacting(false);
}
},
[sdk]
);
const deleteReactionWithSession = (0, import_react10.useCallback)(
async (reactionAccount, fromProfile, toPostAccount, sessionPublicKey, sessionAccount, refundReceiver = sessionPublicKey, sendTransaction, connection, options) => {
setIsReacting(true);
try {
const ixMethodBuilder = deleteReactionWithSessionIxMethodBuilder(reactionAccount, fromProfile, toPostAccount, sessionPublicKey, sessionAccount, refundReceiver);
if (ixMethodBuilder) {
const tx = await ixMethodBuilder.transaction();
if (tx) {
return await sendTransaction(tx, connection, options);
}
} else {
throw new Error("ixMethodBuilder is undefined");
}
} catch (err) {
setCreateReactionError(err);
} finally {
setIsReacting(false);
}
},
[sdk]
);
const deleteReactionIxMethodBuilder = (0, import_react10.useCallback)((reactionAccount, fromProfile, toPostAccount, owner, refundReceiver = owner) => {
setCreateReactionError(null);
try {
const data = sdk.reaction.delete(reactionAccount, toPostAccount, fromProfile, owner, refundReceiver);
return data;
} catch (err) {
setCreateReactionError(err);
return null;
}
}, [sdk]);
const deleteReactionWithSessionIxMethodBuilder = (0, import_react10.useCallback)((reactionAccount, fromProfile, toPostAccount, sessionPublicKey, sessionAccount, refundReceiver = sessionPublicKey) => {
setCreateReactionError(null);
try {
const data = sdk.reaction.deleteWithSession(reactionAccount, toPostAccount, fromProfile, sessionPublicKey, sessionAccount, refundReceiver);
return data;
} catch (err) {
setCreateReactionError(err);
return null;
}
}, [sdk]);
return {
createReaction,
createReactionWithSession,
createReactionIxMethodBuilder,
createReactionWithSessionIxMethodBuilder,
deleteReaction,
deleteReactionWithSession,
deleteReactionIxMethodBuilder,
deleteReactionWithSessionIxMethodBuilder,
reactionPDA,
isReacting,
createReactionError
};
};
// src/hooks/connection/useFollow.ts
var import_react11 = require("react");
var useFollow = (sdk) => {
const [connectionPDA, setConnectionPDA] = (0, import_react11.useState)(null);
const [connectionLoading, setConnectionLoading] = (0, import_react11.useState)(false);
const [connectionError, setConnectionError] = (0, import_react11.useState)(null);
const follow = (0, import_react11.useCallback)(
async (fromProfile, toProfile, owner, payer = owner) => {
setConnectionLoading(true);
setConnectionError(null);
try {
const ixMethodBuilder = await createConnectionIxMethodBuilder(
fromProfile,
toProfile,
owner,
payer
);
if (ixMethodBuilder) {
return await ixMethodBuilder.rpc();
} else {
const error = new Error("ixMethodBuilder is undefined");
setConnectionError(error);
return Promise.reject(error);
}
} catch (err) {
setConnectionError(err);
} finally {
setConnectionLoading(false);
}
},
[sdk]
);
const followWithSession = (0, import_react11.useCallback)(
async (fromProfile, toProfile, sessionPublicKey, sessionAccount, sendTransaction, payer = sessionPublicKey, connection, options) => {
setConnectionLoading(true);
setConnectionError(null);
try {
const ixMethodBuilder = await createConnectionWithSessionIxMethodBuilder(
fromProfile,
toProfile,
sessionPublicKey,
sessionAccount,
payer
);
if (ixMethodBuilder) {
const tx = await ixMethodBuilder.transaction();
if (tx) {
return await sendTransaction(tx, connection, options);
}
} else {
const error = new Error("ixMethodBuilder is undefined");
setConnectionError(error);
return Promise.reject(error);
}
} catch (err) {
setConnectionError(err);
} finally {
setConnectionLoading(false);
}
},
[sdk]
);
const createConnectionIxMethodBuilder = (0, import_react11.useCallback)(
async (fromProfile, toProfile, owner, payer = owner) => {
try {
const connection = await sdk.connection.create(
fromProfile,
toProfile,
owner,
payer
);
setConnectionPDA(connection.connectionPDA);
return connection.instructionMethodBuilder;
} catch (err) {
setConnectionError(err);
return null;
}
},
[sdk]
);
const createConnectionWithSessionIxMethodBuilder = (0, import_react11.useCallback)(
async (fromProfile, toProfile, sessionPublicKey, sessionAccount, payer = sessionPublicKey) => {
try {
const connection = await sdk.connection.createWithSession(
fromProfile,
toProfile,
sessionPublicKey,
sessionAccount,
payer
);
setConnectionPDA(connection.connectionPDA);
return connection.instructionMethodBuilder;
} catch (err) {
setConnectionError(err);
return null;
}
},
[sdk]
);
return {
follow,
followWithSession,
createConnectionIxMethodBuilder,
createConnectionWithSessionIxMethodBuilder,
connectionPDA,
connectionLoading,
connectionError
};
};
// src/hooks/connection/useUnfollow.ts
var import_react12 = require("react");
var useUnfollow = (sdk) => {
const [connectionLoading, setConnectionLoading] = (0, import_react12.useState)(false);
const [connectionError, setConnectionError] = (0, import_react12.useState)(null);
const unfollow = (0, import_react12.useCallback)(
async (connectionAccount, fromProfile, toProfile, owner, refundReceiver = owner) => {
setConnectionLoading(true);
setConnectionError(null);
try {
const ixMethodBuilder = await deleteConnectionIxMethodBuilder(
connectionAccount,
fromProfile,
toProfile,
owner,
refundReceiver
);
if (ixMethodBuilder) {
return await ixMethodBuilder.rpc();
} else {
const error = new Error("ixMethodBuilder is undefined");
setConnectionError(error);
return Promise.reject(error);
}
} catch (err) {
setConnectionError(err);
} finally {
setConnectionLoading(false);
}
},
[sdk]
);
const unfollowWithSession = (0, import_react12.useCallback)(
async (connectionAccount, fromProfile, toProfile, sessionPublicKey, sessionAccount, sendTransaction, refundReceiver = sessionPublicKey, connection, options) => {
setConnectionLoading(true);
setConnectionError(null);
try {
const ixMethodBuilder = await deleteConnectionWithSessionIxMethodBuilder(
connectionAccount,
fromProfile,
toProfile,
sessionPublicKey,
sessionAccount,
refundReceiver
);
if (ixMethodBuilder) {
const tx = await ixMethodBuilder.transaction();
if (tx) {
return await sendTransaction(tx, connection, options);
}
} else {
const error = new Error("ixMethodBuilder is undefined");
setConnectionError(error);
return Promise.reject(error);
}
} catch (err) {
setConnectionError(err);
} finally {
setConnectionLoading(false);
}
},
[sdk]
);
const deleteConnectionIxMethodBuilder = (0, import_react12.useCallback)(
async (connectionAccount, fromProfile, toProfile, owner, refundReceiver = owner) => {
try {
const connection = sdk.connection.delete(
connectionAccount,
fromProfile,
toProfile,
owner,
refundReceiver
);
return connection;
} catch (err) {
setConnectionError(err);
return null;
}
},
[sdk]
);
const deleteConnectionWithSessionIxMethodBuilder = (0, import_react12.useCallback)(
async (connectionAccount, fromProfile, toProfile, sessionPublicKey, sessionAccount, refundReceiver = sessionPublicKey) => {
try {
const connection = sdk.connection.deleteWithSession(
connectionAccount,
fromProfile,
toProfile,
sessionPublicKey,
sessionAccount,
refundReceiver
);
return connection;
} catch (err) {
setConnectionError(err);
return null;
}
},
[sdk]
);
return {
unfollow,
unfollowWithSession,
deleteConnectionIxMethodBuilder,
deleteConnectionWithSessionIxMethodBuilder,
connectionLoading,
connectionError
};
};
// src/hooks/session/useSessionKeyManager.ts
var import_web32 = require("@solana/web3.js");
var import_react13 = require("react");
// src/utils/crypto.ts
var CryptoJS = __toESM(require("crypto-js"));
var ENCRYPTION_KEY_LENGTH = 32;
function generateEncryptionKey() {
const key = CryptoJS.lib.WordArray.random(ENCRYPTION_KEY_LENGTH);
return CryptoJS.enc.Base64.stringify(key);
}
function encrypt(data, password) {
const iv = CryptoJS.lib.WordArray.random(16);
const passwordHash = CryptoJS.SHA256(password);
const cipher = CryptoJS.AES.encrypt(data, passwordHash, { iv });
const encryptedData = cipher.ciphertext.toString(CryptoJS.enc.Base64);
return `${encryptedData}.${iv.toString(CryptoJS.enc.Base64)}`;
}
function decrypt(data, password) {
const [encryptedDataString, ivString] = data.split(".");
const encryptedData = CryptoJS.enc.Base64.parse(encryptedDataString);
const iv = CryptoJS.enc.Base64.parse(ivString);
const passwordHash = CryptoJS.SHA256(password);
const cipherParams = CryptoJS.lib.CipherParams.create({ ciphertext: encryptedData });
const decryptedData = CryptoJS.AES.decrypt(cipherParams, passwordHash, { iv });
return decryptedData.toString(CryptoJS.enc.Utf8);
}
// src/hooks/session/useSessionKeyManager.ts
var import_sdk2 = require("@gumhq/sdk");
var nacl = __toESM(require("tweetnacl"));
var import_anchor = require("@project-serum/anchor");
// src/utils/indexedDB.ts
var DB_NAME = "session_data";
var SESSION_OBJECT_STORE = "sessions";
var WALLET_PUBKEY_TO_SESSION_STORE = "walletPublicKeyToSessionData";
var ENCRYPTION_KEY_OBJECT_STORE = "user_preferences";
var openIndexedDB = async () => {
return new Promise((resolve, reject) => {
const request = indexedDB.open(DB_NAME, 1);
request.onupgradeneeded = (event) => {
const db = request.result;
db.createObjectStore(SESSION_OBJECT_STORE);
db.createObjectStore(ENCRYPTION_KEY_OBJECT_STORE);
db.createObjectStore(WALLET_PUBKEY_TO_SESSION_STORE);
};
request.onsuccess = (event) => {
resolve(request.result);
};
request.onerror = (event) => {
reject(request.error);
};
});
};
var getItemFromIndexedDB = async (storeName, key) => {
const db = await openIndexedDB();
return new Promise((resolve, reject) => {
const transaction = db.transaction(storeName, "readonly");
const store = transaction.objectStore(storeName);
const request = store.get(key);
request.onsuccess = (event) => {
resolve(request.result);
};
request.onerror = (event) => {
reject(request.error);
};
});
};
var setItemToIndexedDB = async (storeName, data, key) => {
const db = await openIndexedDB();
return new Promise((resolve, reject) => {
const transaction = db.transaction(storeName, "readwrite");
const store = transaction.objectStore(storeName);
const request = store.put(data, key);
request.onsuccess = (event) => {
resolve();
};
request.onerror = (event) => {
reject(request.error);
};
});
};
var deleteItemFromIndexedDB = async (storeName, key) => {
const db = await openIndexedDB();
return new Promise((resolve, reject) => {
const transaction = db.transaction(storeName, "readwrite");
const store = transaction.objectStore(storeName);
const request = store.delete(key);
request.onsuccess = (event) => {
resolve();
};
request.onerror = (event) => {
reject(request.error);
};
});
};
// src/hooks/session/useSessionKeyManager.ts
var SESSION_OBJECT_STORE2 = "sessions";
var WALLET_PUBKEY_TO_SESSION_STORE2 = "walletPublicKeyToSessionData";
var ENCRYPTION_KEY_OBJECT_STORE2 = "user_preferences";
function useSessionKeyManager(wallet, connection, cluster) {
const keypairRef = (0, import_react13.useRef)(null);
const sessionTokenRef = (0, import_react13.useRef)(null);
const [, forceUpdate] = (0, import_react13.useState)({});
const [isLoading, setIsLoading] = (0, import_react13.useState)(false);
const [error, setError] = (0, import_react13.useState)(null);
const sessionConnection = connection;
const sdk = new import_sdk2.SessionTokenManager(wallet, connection, cluster);
const generateKeypair = () => {
keypairRef.current = import_web32.Keypair.generate();
};
const loadKeypairFromDecryptedSecret = (decryptedKeypair) => {
keypairRef.current = import_web32.Keypair.fromSecretKey(new Uint8Array(Buffer.from(decryptedKeypair, "base64")));
};
const triggerRerender = () => {
forceUpdate({});
};
(0, import_react13.useEffect)(() => {
if (!wallet) {
return;
}
getSessionToken().then((token) => {
if (!token) {
resetSessionData();
}
}).catch(() => {
resetSessionData();
});
}, [wallet, wallet?.publicKey, cluster]);
const deleteSessionData = async () => {
try {
const walletPublicKey = wallet.publicKey.toBase58();
const sessionKey = await getItemFromIndexedDB(WALLET_PUBKEY_TO_SESSION_STORE2, walletPublicKey);
if (sessionKey) {
await deleteItemFromIndexedDB(SESSION_OBJECT_STORE2, sessionKey);
await deleteItemFromIndexedDB(WALLET_PUBKEY_TO_SESSION_STORE2, walletPublicKey);
}
await deleteItemFromIndexedDB(ENCRYPTION_KEY_OBJECT_STORE2, walletPublicKey);
} catch (error2) {
console.error("Error deleting session data:", error2);
setError(error2);
}
};
const withLoading = async (asyncFunction) => {
setError(null);
setIsLoading(true);
try {
const result = await asyncFunction();
return result;
} finally {
setIsLoading(false);
}
};
const signTransaction = async (transaction) => {
return withLoading(async () => {
if (!keypairRef.current || !sessionTokenRef.current) {
throw new Error("Cannot sign transaction - keypair or session token not loaded. Please create a session first.");
}
const { blockhash } = await connection.getLatestBlockhash("finalized");
const feePayer = keypairRef.current.publicKey;
transaction.recentBlockhash = transaction.recentBlockhash || blockhash;
transaction.feePayer = transaction.feePayer || feePayer;
transaction.sign(keypairRef.current);
return transaction;
});
};
const signAllTransactions = async (transactions) => {
return withLoading(async () => {
return Promise.all(transactions.map((transaction) => signTransaction(transaction)));
});
};
const signMessage = async (message) => {
return withLoading(async () => {
if (!keypairRef.current) {
throw new Error("Cannot sign message - keypair not loaded. Please create a session first.");
}
return nacl.sign.detached(message, keypairRef.current.secretKey);
});
};
const sendTransaction = async (transaction, connection2, options = {}) => {
return withLoading(async () => {
const keypair = keypairRef.current;
const sessionToken = sessionTokenRef.current;
if (!connection2) {
connection2 = sessionConnection;
}
if (!keypair || !sessionToken) {
throw new Error(
"Cannot sign transaction - keypair or session token not loaded. Please create a session first."
);
}
const { signers, ...sendOptions } = options;
const publicKey = keypair.publicKey;
if (!publicKey) {
throw new Error(
"Cannot send transaction - keypair not loaded. Please create a session first."
);
}
transaction.feePayer = transaction.feePayer || publicKey;
transaction.recentBlockhash = transaction.recentBlockhash || (await connection2.getLatestBlockhash({
commitment: sendOptions.preflightCommitment,
minContextSlot: sendOptions.minContextSlot
})).blockhash;
if (signers?.length) {
transaction.partialSign(...signers);
}
transaction = await signTransaction(transaction);
const txid = await connection2.sendRawTransaction(
transaction.serialize(),
sendOptions
);
return txid;
});
};
const signAndSendTransaction = async (transaction, connection2, options = {}) => {
return withLoading(async () => {
if (!connection2) {
connection2 = sessionConnection;
}
const transactionsArray = Array.isArray(transaction) ? transaction : [transaction];
const txids = await Promise.all(transactionsArray.map((signedTransaction) => sendTransaction(signedTransaction, connection2, options)));
return txids;
});
};
const getSessionToken = async () => {
try {
const sessionKey = await getItemFromIndexedDB(WALLET_PUBKEY_TO_SESSION_STORE2, wallet.publicKey.toString());
if (!sessionKey) {
resetSessionData();
return null;
}
const encryptedSessionData = await getItemFromIndexedDB(SESSION_OBJECT_STORE2, sessionKey);
const encryptionKey = await getItemFromIndexedDB(ENCRYPTION_KEY_OBJECT_STORE2, wallet.publicKey.toString());
if (!encryptedSessionData || !encryptionKey) {
resetSessionData();
return null;
}
if (encryptedSessionData && encryptionKey) {
const { encryptedToken, encryptedKeypair, validUntilTimestamp } = encryptedSessionData;
const { userPreferences: storedEncryptionKey, validUntilTimestamp: encryptionKeyExpiry } = encryptionKey;
const currentTimestamp = Math.ceil(Date.now() / 1e3);
if (currentTimestamp > encryptionKeyExpiry || currentTimestamp > validUntilTimestamp) {
await deleteSessionData();
return null;
}
const decryptedToken = decrypt(encryptedToken, storedEncryptionKey);
const decryptedKeypair = decrypt(encryptedKeypair, storedEncryptionKey);
loadKeypairFromDecryptedSecret(decryptedKeypair);
sessionTokenRef.current = decryptedToken;
triggerRerender();
return decryptedToken;
}
} catch (error2) {
console.error("Error getting session data from IndexedDB:", error2);
setError(error2);
}
return null;
};
const createSession = async (targetProgramPublicKey, topUp = false, expiryInMinutes = 60, sessionCreatedCallback) => {
return withLoading(async () => {
try {
if (expiryInMinutes > 24 * 60) {
throw new Error("Expiry cannot be more than 24 hours.");
}
if (!keypairRef.current) {
generateKeypair();
}
const expiryTimestamp = Math.ceil((Date.now() + expiryInMinutes * 60 * 1e3) / 1e3);
const validUntilBN = new import_anchor.BN(expiryTimestamp);
const sessionKeypair = keypairRef.current;
if (!sessionKeypair) {
throw new Error("Session keypair not generated.");
}
const sessionSignerPublicKey = sessionKeypair.publicKey;
const instructionMethodBuilder = sdk.program.methods.createSession(topUp, validUntilBN).accounts({
targetProgram: targetProgramPublicKey,
sessionSigner: sessionSignerPublicKey,
authority: wallet.publicKey
});
const pubKeys = await instructionMethodBuilder.pubkeys();
const sessionToken = pubKeys.sessionToken;
await instructionMethodBuilder.signers([sessionKeypair]).rpc();
await deleteSessionData();
const encryptionKey = generateEncryptionKey();
const sessionTokenString = sessionToken.toBase58();
const keypairSecretBase64String = Buffer.from(sessionKeypair.secretKey).toString("base64");
const encryptedToken = encrypt(sessionTokenString, encryptionKey);
const encryptedKeypair = encrypt(keypairSecretBase64String, encryptionKey);
const encryptedSessionData = {
encryptedToken,
encryptedKeypair,
validUntilTimestamp: expiryTimestamp
};
await setItemToIndexedDB(SESSION_OBJECT_STORE2, encryptedSessionData, sessionTokenString);
await setItemToIndexedDB(WALLET_PUBKEY_TO_SESSION_STORE2, sessionTokenString, wallet.publicKey.toBase58());
await setItemToIndexedDB(ENCRYPTION_KEY_OBJECT_STORE2, { "userPreferences": encryptionKey, validUntilTimestamp: expiryTimestamp }, wallet.publicKey.toBase58());
sessionTokenRef.current = sessionTokenString;
triggerRerender();
if (!sessionTokenRef.current) {
console.error("Session token not generated.");
}
if (sessionCreatedCallback) {
sessionCreatedCallback({ sessionToken: sessionTokenRef.current, publicKey: sessionSignerPublicKey.toBase58() });
}
return {
ownerPublicKey: wallet.publicKey,
isLoading: false,
error: null,
sessionToken: sessionTokenRef.current,
publicKey: sessionSignerPublicKey,
signMessage,
signTransaction,
signAllTransactions,
signAndSendTransaction,
sendTransaction
};
} catch (error2) {
console.error("Error creating session:", error2);
setError(error2);
return {
publicKey: wallet.publicKey,
ownerPublicKey: null,
isLoading: false,
error: error2.message,
sessionToken: null,
signTransaction: null,
signAllTransactions: null,
signMessage: null,
sendTransaction: null,
signAndSendTransaction: null,
getSessionToken: null,
createSession: null,
revokeSession: null
};
}
});
};
const resetSessionData = () => {
keypairRef.current = null;
sessionTokenRef.current = null;
triggerRerender();
};
const revokeSession = async () => {
return withLoading(async () => {
try {
if (!sessionTokenRef.current || !keypairRef.current) {
return;
}
const sessionTokenPublicKey = keypairRef.current.publicKey;
const instructionMethodBuilder = sdk.program.methods.revokeSession().accounts({
sessionToken: sessionTokenRef.current,
authority: wallet.publicKey
});
const txId = await instructionMethodBuilder.rpc();
const sessionSignerSolanaBalance = await connection.getBalance(sessionTokenPublicKey);
if (sessionSignerSolanaBalance > 0) {
const tx = new import_web32.Transaction().add(
import_web32.SystemProgram.transfer({
fromPubkey: sessionTokenPublicKey,
toPubkey: wallet.publicKey,
lamports: sessionSignerSolanaBalance
})
);
tx.feePayer = sessionTokenPublicKey;
tx.recentBlockhash = (await connection.getLatestBlockhash()).blockhash;
const estimatedFee = await tx.getEstimatedFee(connection);
if (estimatedFee && sessionSignerSolanaBalance > estimatedFee) {
const transaction = new import_web32.Transaction().add(
import_web32.SystemProgram.transfer({
fromPubkey: sessionTokenPublicKey,
toPubkey: wallet.publicKey,
lamports: sessionSignerSolanaBalance - estimatedFee
})
);
await sendTransaction(transaction);
}
}
const walletPublicKey = wallet.publicKey.toBase58();
await deleteItemFromIndexedDB(SESSION_OBJECT_STORE2, sessionTokenRef.current);
await deleteItemFromIndexedDB(ENCRYPTION_KEY_OBJECT_STORE2, walletPublicKey);
await deleteItemFromIndexedDB(WALLET_PUBKEY_TO_SESSION_STORE2, walletPublicKey);
resetSessionData();
return txId;
} catch (error2) {
console.error("Error revoking session:", error2);
setError(error2);
return null;
}
});
};
if (!wallet) {
return {
publicKey: null,
ownerPublicKey: null,
isLoading: false,
sessionToken: null,
signTransaction: void 0,
signAllTransactions: void 0,
signMessage: void 0,
sendTransaction: void 0,
signAndSendTransaction: void 0,
getSessionToken: async () => null,
createSession: async () => void 0,
revokeSession: async () => null,
error
};
}
return {
publicKey: sessionTokenRef.current && keypairRef.current ? keypairRef.current.publicKey : null,
ownerPublicKey: wallet.publicKey,
isLoading,
error,
sessionToken: sessionTokenRef.current,
signTransaction,
signAllTransactions,
signMessage,
sendTransaction,
signAndSendTransaction,
getSessionToken,
createSession,
revokeSession
};
}
// src/hooks/storage/useUploader.ts
var import_react16 = require("react");
// src/hooks/storage/arweave/useArweave.ts
var import_react14 = require("react");
var import_client = require("@bundlr-network/client");
var import_web33 = require("@solana/web3.js");
function isSessionWallet(wallet) {
return "sessionToken" in wallet;
}
var useArweaveStorage = (connection, cluster) => {
const BUNDLR_URL = cluster === "devnet" ? "https://devnet.bundlr.network" : "https://node2.bundlr.network";
const initializeBundlr = async (wallet) => {
if (isSessionWallet(wallet) && !wallet.sessionToken) {
throw new Error("Session is required for arweave uploader");
}
const newBundlr = new import_client.WebBundlr(BUNDLR_URL, "solana", wallet, {
providerUrl: connection.rpcEndpoint
});
await newBundlr.ready();
return newBundlr;
};
const withErrorHandling = (0, import_react14.useCallback)(
(fn) => async (...args) => {
try {
const result = await fn(...args);
return { ...result, error: null };
} catch (e) {
return { url: null, error: e.message };
}
},
[]
);
const uploadData = (0, import_react14.useCallback)(
withErrorHandling(async (data, wallet) => {
const bundlr = await initializeBundlr(wallet);
if (!bundlr) {
throw new Error("Bundlr not initialized");
}
const publicKey = wallet?.publicKey;
if (!publicKey) {
throw new Error("Public key not found");
}
if (typeof data === "object") {
data = JSON.stringify(data);
}
const transaction = bundlr.createTransaction(data);
try {
await transaction.sign();
await transaction.upload();
} catch (e) {
if (e.message.includes("Not enough funds to send data")) {
const price = await bundlr.getPrice(data.length);
const minimumFunds = price.multipliedBy(1);
const balance = await bundlr.getBalance(publicKey.toBase58());
if (balance.isLessThan(minimumFunds)) {
await bundlr.fund(minimumFunds);