This SDK provides a set of libraries designed as foundational building blocks for developers to create and interact with applications on Arweave"s permaweb. These libraries aim to contribute building on the composable web, promoting interoperability and reusability across decentralized applications. With libraries for managing profiles, atomic assets, collections, and more, this SDK simplifies the development of decentralized, permanent applications.
- Prerequisites
- Installation
- Initialization
- Usage
- Examples
- Resources
node >= v18.0
npm
oryarn
arweave
@permaweb/aoconnect
If arweave
or @permaweb/aoconnect
is not already installed, add them to the installation command below as additional packages
npm install @permaweb/libs
or
yarn add @permaweb/libs
import Arweave from "arweave";
import { connect, createDataItemSigner } from "@permaweb/aoconnect";
import Permaweb from "@permaweb/libs";
// Browser Usage
const wallet = window.arweaveWallet;
// NodeJS Usage
const wallet = JSON.parse(readFileSync(process.env.PATH_TO_WALLET, "utf-8"));
const permaweb = Permaweb.init({
ao: connect(),
arweave: Arweave.init(),
signer: createDataItemSigner(wallet),
});
Zones are representations of entities on the permaweb that contain relevant information and can perform actions on the entity"s behalf. A profile is an instance of a zone with specific metadata (Read the spec).
const zoneId = await permaweb.createZone();
Parameters
tags (optional)
: Additional tags
Response
ZoneProcessId;
const zoneUpdateId = await permaweb.updateZone({
name: "Sample Zone",
metadata: {
description: "A sample zone for testing",
version: "1.0.0",
},
}, zoneId
);
Parameters
args
: Zone data to update, specified in an objectzoneId
: The ID of the zone to update
Response
ZoneUpdateId;
const zone = await permaweb.getZone(zoneId);
Parameters
zoneId
: The ID of the zone to fetch
Response
{ store: [], assets: [] };
Profiles are a digital representation of entities, such as users, organizations, or channels. They instantiate zones with specific metadata that describes the entity and can be associated with various digital assets and collections. Profiles are created, updated, and fetched using the following functions.
const profileId = await permaweb.createProfile({
username: "My username",
displayName: "My display name",
description: "My description",
thumbnail: "Thumbnail image data",
banner: "Banner image data",
});
Parameters
args
: Object containing profile details, includingusername
,displayName
,description
,thumbnail (optional)
, andbanner (optional)
callback (optional)
: Callback function for client use
Response
ProfileProcessId;
const profileId = await permaweb.updateProfile({
username: "My usename",
displayName: "My display name",
description: "My description",
thumbnail: "Thumbnail image data",
banner: "Banner image data",
}, profileId
);
Parameters
args
: Profile details to update, structured similarly tocreateProfile
profileId
: The ID of the profile to updatecallback (optional)
: Callback function for client use
Response
ProfileProcessUpdateId;
const profile = await permaweb.getProfileById(profileId);
Parameters
profileId
: The ID of the profile to fetch
Response
{
id: "ProfileProcessId",
walletAddress: "WalletAddress",
username: "Sample username",
displayName: "Sample display name",
description: "Sample description",
thumbnail: "ThumbnailTxId",
banner: "BannerTxId",
assets: [
{ id: "AssetProcessId1", quantity: "1", dateCreated: 123456789, lastUpdate: 123456789 },
{ id: "AssetProcessId2", quantity: "1", dateCreated: 123456789, lastUpdate: 123456789 },
{ id: "AssetProcessId3", quantity: "1", dateCreated: 123456789, lastUpdate: 123456789 },
]
}
const profile = await permaweb.getProfileByWalletAddress(walletAddress);
Parameters
walletAddress
: The wallet address associated with the profile
Response
{
id: "ProfileProcessId",
walletAddress: "WalletAddress",
username: "Sample username",
displayName: "Sample display name",
description: "Sample description",
thumbnail: "ThumbnailTxId",
banner: "BannerTxId",
assets: [
{ id: "AssetProcessId1", quantity: "1", dateCreated: 123456789, lastUpdate: 123456789 },
{ id: "AssetProcessId2", quantity: "1", dateCreated: 123456789, lastUpdate: 123456789 },
{ id: "AssetProcessId3", quantity: "1", dateCreated: 123456789, lastUpdate: 123456789 },
]
}
Atomic assets are unique digital item consisting of an AO process and its associated data which are stored together in a single transaction on Arweave (Read the spec).
const assetId = await permaweb.createAtomicAsset({
title: "Example Title",
description: "Example Description",
type: "Example Atomic Asset Type",
topics: ["Topic 1", "Topic 2", "Topic 3"],
contentType: "text/plain",
data: "1234"
});
Parameters
args
: Object containing profile details, includingtitle
,description
,type
,topics
,contentType
, anddata
callback (optional)
: Callback function for client use
Response
AssetProcessId;
const asset = await permaweb.getAtomicAsset(assetId);
Parameters
assetId
: The ID of the asset to fetch
Response
{
id: "z0f2O9Fs3yb_EMXtPPwKeb2O0WueIG5r7JLs5UxsA4I",
title: "City",
description: "A collection of AI generated images of different settings and areas",
type: null,
topics: null,
contentType: "image/png",
renderWith: null,
thumbnail: null,
udl: {
access: { value: "One-Time-0.1" },
derivations: { value: "Allowed-With-One-Time-Fee-0.1" },
commercialUse: { value: "Allowed-With-One-Time-Fee-0.1" },
dataModelTraining: { value: "Disallowed" },
paymentMode: "Single",
paymentAddress: "uf_FqRvLqjnFMc8ZzGkF4qWKuNmUIQcYP0tPlCGORQk",
currency: "xU9zFkq3X2ZQ6olwNVvr1vUWIjc3kXTWr7xKQD6dh10"
},
creator: "SaXnsUgxJLkJRghWQOUs9-wB0npVviewTkUbh2Yk64M",
collectionId: "XcfPzHzxt2H8FC03MAC_78U1YwO9Gdk72spbq70NuNc",
implementation: "ANS-110",
dateCreated: 1717663091000,
blockHeight: 1439467,
ticker: "ATOMIC",
denomination: "1",
balances: {
"SaXnsUgxJLkJRghWQOUs9-wB0npVviewTkUbh2Yk64M": "1",
cfQOZc7saMMizHtBKkBoF_QuH5ri0Bmb5KSf_kxQsZE: "1",
U3TjJAZWJjlWBB4KAXSHKzuky81jtyh0zqH8rUL4Wd0: "98"
},
transferable: true,
tags: [{ name: "Remaining", value: "Tag" }]
}
const assets = await permaweb.getAtomicAssets(assetIds);
Parameters
assetIds
: A list of the asset IDs to fetch
Response
[
{
id: "AssetProcessId1",
title: "City",
description:
"A collection of AI generated images of different settings and areas",
type: null,
topics: null,
contentType: "image/png",
renderWith: null,
thumbnail: null,
udl: {
access: { value: "One-Time-0.1" },
derivations: { value: "Allowed-With-One-Time-Fee-0.1" },
commercialUse: { value: "Allowed-With-One-Time-Fee-0.1" },
dataModelTraining: { value: "Disallowed" },
paymentMode: "Single",
paymentAddress: "uf_FqRvLqjnFMc8ZzGkF4qWKuNmUIQcYP0tPlCGORQk",
currency: "xU9zFkq3X2ZQ6olwNVvr1vUWIjc3kXTWr7xKQD6dh10",
},
creator: "SaXnsUgxJLkJRghWQOUs9-wB0npVviewTkUbh2Yk64M",
collectionId: "XcfPzHzxt2H8FC03MAC_78U1YwO9Gdk72spbq70NuNc",
implementation: "ANS-110",
dateCreated: 1717663091000,
blockHeight: 1439467,
tags: [{ name: "Remaining", value: "Tag" }],
},
{
id: "AssetProcessId2",
title: "City",
description:
"A collection of AI generated images of different settings and areas",
type: null,
topics: null,
contentType: "image/png",
renderWith: null,
thumbnail: null,
udl: {
access: { value: "One-Time-0.1" },
derivations: { value: "Allowed-With-One-Time-Fee-0.1" },
commercialUse: { value: "Allowed-With-One-Time-Fee-0.1" },
dataModelTraining: { value: "Disallowed" },
paymentMode: "Single",
paymentAddress: "uf_FqRvLqjnFMc8ZzGkF4qWKuNmUIQcYP0tPlCGORQk",
currency: "xU9zFkq3X2ZQ6olwNVvr1vUWIjc3kXTWr7xKQD6dh10",
},
creator: "SaXnsUgxJLkJRghWQOUs9-wB0npVviewTkUbh2Yk64M",
collectionId: "XcfPzHzxt2H8FC03MAC_78U1YwO9Gdk72spbq70NuNc",
implementation: "ANS-110",
dateCreated: 1717663091000,
blockHeight: 1439467,
tags: [{ name: "Remaining", value: "Tag" }],
},
];
Comments are an instantiation of atomic assets created with additional tags to link them with other comments / atomic assets with specific data or root contexts.
const commentId = await permaweb.createComment({
content: "Sample comment on an atomic asset",
creator: profileId,
parentId: atomicAssetId,
});
Parameters
args
: Object containingcontent
,creator
,parentId
, androotId (optional)
callback (optional)
: Callback function for status updates.
Response
CommentProcessId;
const comment = await permaweb.getComment(commentId);
Parameters
commentId
: The ID of the comment to fetch.
Response
{
id: "CommentProcessId",
title: "Comment Title",
description: "Comment Description",
parentId: "ParentProcessId",
rootId: "RootProcessId",
content: "My Comment",
contentType: "text/plain",
creator: "Creator Identifier",
collectionId: "Collection Identifier",
transferable: true,
tags: [
{ name: "Data-Source", value: "Data Source Identifier" },
{ name: "Root-Source", value: "Root Source Identifier" }
]
}
const comments = await permaweb.getComments({
parentId: atomicAssetId,
});
Parameters
args
: Object containingparentId
orrootId
Response
[
{
id: "CommentProcessId1",
title: "Comment Title 1",
description: "Comment Description 1",
parentId: "ParentProcessId",
rootId: "RootProcessId",
content: "My Comment",
contentType: "text/plain",
creator: "Creator Identifier",
collectionId: "Collection Identifier",
transferable: true,
tags: [
{ name: "Data-Source", value: "Data Source Identifier" },
{ name: "Root-Source", value: "Root Source Identifier" },
],
},
{
id: "CommentProcessId2",
title: "Comment Title 2",
description: "Comment Description 2",
parentId: "ParentProcessId",
rootId: "RootProcessId",
content: "My Comment",
contentType: "text/plain",
data: "Comment data 2",
creator: "Creator Identifier",
collectionId: "Collection Identifier",
transferable: true,
tags: [
{ name: "Data-Source", value: "Data Source Identifier" },
{ name: "Root-Source", value: "Root Source Identifier" },
],
},
];
Collections are structured groups of atomic assets, allowing for cohesive representation, management, and categorization of digital items. Collections extend the concept of atomic assets by introducing an organized layer to group and manage related assets. (Read the spec).
const collectionId = await permaweb.createCollection({
title: "Example Title",
description: "Example Description",
creator: profileId
});
Parameters
args
: Object containingtitle
,description
,creator
,thumbnail (optional)
, andbanner (optional)
Response
CollectionProcessId;
const collectionUpdateId = await permaweb.updateCollectionAssets({
collectionId: collectionId,
assetIds: ["AssetId1", "AssetId2", "AssetId3"],
creator: creator,
updateType: "Add",
});
Parameters
args
: Object containingcollectionId
,assetIds
,profileId
, andupdateType ("Add" | "Remove")
Response
CollectionProcessUpdateId;
const collection = await permaweb.getCollection(collectionId);
Parameters
collectionId
: The ID of the collection to fetch
Response
{
id: "Id",
title: "Title",
description: "Description",
creator: "Creator",
dateCreated: "DateCreated",
thumbnail: "ThumbnailTx",
banner: "BannerTx",
assets: ["AssetId1", "AssetId2", "AssetId3"]
}
const collections = await permaweb.getCollections();
Parameters
args
: Object containingcreator (optional)
Response
[
{
id: "Id",
title: "Title",
description: "Description",
creator: "Creator",
dateCreated: "DateCreated",
thumbnail: "ThumbnailTx",
banner: "BannerTx",
assets: ["AssetId1", "AssetId2", "AssetId3"],
},
{
id: "Id",
title: "Title",
description: "Description",
creator: "Creator",
dateCreated: "DateCreated",
thumbnail: "ThumbnailTx",
banner: "BannerTx",
assets: ["AssetId1", "AssetId2", "AssetId3"],
},
];
To streamline the integration of @permaweb/libs
into your React applications, you can use the following PermawebProvider
. This provider simplifies dependency management and avoids the need to create multiple SDK instances across different components in your frontend application. By leveraging React Context, the provider ensures the Permaweb SDK is initialized once and is accessible throughout your component tree.
- Global Initialization: The
PermawebProvider
initializes the necessary dependencies (e.g., Arweave, AO Connect, and optional wallet signing). - React Context Integration: It makes the initialized
libs
instance globally available to all child components without requiring prop drilling. - Reusable Hook: The
usePermawebProvider
hook offers a convenient way to access the SDK in any component.
The following example demonstrates how to create a React Context and Provider for @permaweb/libs
.
import React from "react";
import Arweave from "arweave";
import { connect, createDataItemSigner } from "@permaweb/aoconnect";
import Permaweb from "@permaweb/libs";
// Define the context shape
interface PermawebContextState {
libs: Permaweb | null;
}
// Create a React context for Permaweb
const PermawebContext = React.createContext<PermawebContextState>({ libs: null });
// Hook to access the Permaweb context
export function usePermawebProvider(): PermawebContextState {
return React.useContext(PermawebContext);
}
// Provider component for initializing and sharing the Permaweb instance
export function PermawebProvider(props: { children: React.ReactNode }) {
const [libs, setLibs] = React.useState<Permaweb | null>(null);
React.useEffect(() => {
// Initialize dependencies
const dependencies: any = { ao: connect(), arweave: Arweave.init() };
if (wallet) {
dependencies.signer = createDataItemSigner(wallet);
}
// Initialize Permaweb SDK and set it in the state
const permawebInstance = Permaweb.init(dependencies);
setLibs(permawebInstance);
}, []);
return (
<PermawebContext.Provider value={{ libs }}>
{props.children}
</PermawebContext.Provider>
);
}
- React Context: The
PermawebContext
is used to store the initializedlibs
object, making it accessible across your application. - Dynamic Initialization: In the
useEffect
hook, the dependencies are initialized once when the provider mounts, including optional wallet signing logic. - Encapsulation: The
PermawebProvider
ensures the SDK logic is abstracted, keeping the rest of your app clean and focused.
Here's how you can use the usePermawebProvider
hook to access the libs
instance in a React component:
import React from "react";
import { usePermawebProvider } from "providers/PermawebProvider";
export default function MyComponent() {
const { libs } = usePermawebProvider();
React.useEffect(() => {
(async function fetchAsset() {
if (libs) {
try {
const asset = await libs.getAtomicAsset(id);
console.log("Fetched Asset:", asset);
} catch (error) {
console.error("Error fetching asset:", error);
}
}
})();
}, [libs]);
return <h1>Permaweb Libs Component</h1>;
}