Skip to content

Commit 9d8c348

Browse files
authored
Merge pull request #8 from instytutfi/feature/accounts-loader
2 parents 91dae03 + 74b343c commit 9d8c348

12 files changed

+192
-17
lines changed

README.md

+15-3
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,10 @@ Or use our favorite package manager.
1818

1919
## Usage
2020

21-
### Hive Blog Loader
21+
In your Astro project, edit the `/src/content/config.ts` and define any collections using the loaders
22+
that this package provides:
2223

23-
In your Astro project, edit the `/src/content/config.ts`:
24+
### Hive Blog Loader
2425

2526
```ts
2627
import { defineCollection } from "astro:content";
@@ -30,11 +31,22 @@ export const collections = {
3031
blog: defineCollection({
3132
type: "content_layer",
3233
loader: hiveBlogLoader("hive.coding") // Selected username
34+
}),
35+
accounts: defineCollection({
36+
type: "content_layer",
37+
loader: hiveAccountsLoader("hive.coding") // or ["acc1", "acc2"] for multiple accounts
3338
})
3439
};
3540
```
3641

37-
For now only `hiveBlogLoader` is available, more coming soon!
42+
## Learn more
43+
44+
- [Astro](https://astro.build/)
45+
- [Content Layer API](https://astro.build/blog/content-layer-deep-dive/)
46+
47+
## Support
48+
49+
If you have any questions or need help, please join our [Discord server](https://discord.gg/3u9v7b4w).
3850

3951
## Contributing
4052

bun.lockb

5.51 KB
Binary file not shown.

package.json

+10-10
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@onhive.io/astro-loader",
3-
"version": "0.1.2",
3+
"version": "0.2.0",
44
"author": "mietek.dev <hi@mietek.dev>",
55
"repository": {
66
"type": "git",
@@ -22,21 +22,21 @@
2222
"prepare": "bunx husky"
2323
},
2424
"dependencies": {
25-
"@hiveio/dhive": "^1.3.1-beta"
25+
"@hiveio/dhive": "^1.3.2"
2626
},
2727
"devDependencies": {
28-
"@eslint/js": "^9.13.0",
29-
"@faker-js/faker": "^9.1.0",
28+
"@eslint/js": "^9.15.0",
29+
"@faker-js/faker": "^9.2.0",
3030
"@types/bun": "latest",
31-
"eslint": "^9.13.0",
31+
"eslint": "^9.15.0",
3232
"eslint-config-prettier": "^9.1.0",
33-
"globals": "^15.11.0",
34-
"husky": "^9.1.6",
33+
"globals": "^15.12.0",
34+
"husky": "^9.1.7",
3535
"lint-staged": "^15.2.10",
3636
"prettier": "^3.3.3",
37-
"tsup": "^8.3.0",
38-
"typescript": "^5.6.3",
39-
"typescript-eslint": "^8.11.0"
37+
"tsup": "^8.3.5",
38+
"typescript": "^5.7.2",
39+
"typescript-eslint": "^8.15.0"
4040
},
4141
"peerDependencies": {
4242
"astro": "^4.16.7"

src/adapters/accounts.ts

+37
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import type { DynamicGlobalProperties, ExtendedAccount } from "@hiveio/dhive";
2+
import { type Account } from "~/schema/accounts.ts";
3+
import { balanceToMoney, vestsToHive } from "~/schema/utils.ts";
4+
5+
const adaptAccount = (
6+
account: ExtendedAccount,
7+
params: DynamicGlobalProperties
8+
): Account => {
9+
const jsonMetadata = JSON.parse(account.posting_json_metadata);
10+
11+
return {
12+
id: account.id.toString(),
13+
name: account.name,
14+
created: new Date(account.created),
15+
wallet: {
16+
hive: {
17+
liquid: balanceToMoney(account.balance as string, 3)!,
18+
frozen: vestsToHive(account.vesting_shares as string, params)
19+
},
20+
hbd: {
21+
liquid: balanceToMoney(account.hbd_balance as string, 3)!,
22+
frozen: balanceToMoney(account.savings_hbd_balance as string, 3)!
23+
}
24+
},
25+
postCount: account.post_count,
26+
profile: {
27+
name: jsonMetadata.profile.name,
28+
about: jsonMetadata.profile.about,
29+
coverImage: jsonMetadata.profile.cover_image,
30+
profileImage: jsonMetadata.profile.profile_image,
31+
website: jsonMetadata.profile.website,
32+
location: jsonMetadata.profile.location
33+
}
34+
};
35+
};
36+
37+
export { adaptAccount };

src/api/accounts.ts

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import { hive } from "~/api/common";
2+
import type { Account } from "~/schema/accounts.ts";
3+
import { adaptAccount } from "~/adapters/accounts.ts";
4+
5+
export async function getAccounts(usernames: string[]): Promise<Account[]> {
6+
const params = await hive.database.getDynamicGlobalProperties();
7+
const accounts = await hive.database.getAccounts(usernames);
8+
return accounts.map((acc) => adaptAccount(acc, params));
9+
}

src/index.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
export { hiveBlogLoader } from "~/loaders/blogLoader";
22

33
export type { Post } from "~/schema/posts.ts";
4-
export type { Community } from "~/schema/community.ts";
4+
export type { Communities } from "~/schema/communities.ts";

src/loaders/accountsLoader.ts

+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import type { Loader } from "astro/loaders";
2+
import { typeToZ } from "~/schema/utils.ts";
3+
import type { Account } from "~/schema/accounts.ts";
4+
import { getAccounts } from "~/api/accounts.ts";
5+
6+
export function hiveAccountsLoader(username: string | string[]): Loader {
7+
return {
8+
name: "hive-accounts-loader",
9+
load: async function (this: Loader, { store, logger }) {
10+
logger.debug(`Fetching accounts [usernames: ${username}]`);
11+
const data = await getAccounts(
12+
Array.isArray(username) ? username : [username]
13+
);
14+
store.clear();
15+
data.forEach((account) => {
16+
store.set({
17+
id: account.id.toString(),
18+
data: { ...account }
19+
});
20+
});
21+
},
22+
schema: typeToZ<Account[]>
23+
};
24+
}

src/schema/accounts.ts

+52
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
export type Account = {
2+
id: string;
3+
name: string;
4+
created: Date;
5+
wallet: Wallet;
6+
postCount: number;
7+
profile: Profile;
8+
};
9+
10+
export type Profile = {
11+
name: string;
12+
about: string;
13+
coverImage: string;
14+
profileImage: string;
15+
website: string;
16+
location: string;
17+
};
18+
19+
export type Wallet = {
20+
hive: {
21+
liquid: Money;
22+
frozen: Money;
23+
};
24+
hbd: {
25+
liquid: Money;
26+
frozen: Money;
27+
};
28+
};
29+
30+
export interface MoneyInterface {
31+
currency: string;
32+
amount: string;
33+
precision: number;
34+
35+
asFloat(): number;
36+
}
37+
38+
export class Money implements MoneyInterface {
39+
currency: string;
40+
amount: string;
41+
precision: number;
42+
43+
constructor(currency: string, amount: string, precision: number) {
44+
this.currency = currency;
45+
this.amount = parseFloat(amount).toFixed(precision).toString();
46+
this.precision = precision;
47+
}
48+
49+
asFloat(): number {
50+
return parseFloat(this.amount);
51+
}
52+
}
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
export type Community = {
1+
export type Communities = {
22
id: string;
33
name: string;
44
};

src/schema/posts.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import type { Community } from "~/schema/community.ts";
1+
import type { Communities } from "~/schema/communities.ts";
22

33
export type Post = {
44
id: string;
@@ -7,7 +7,7 @@ export type Post = {
77
description: string;
88
created: Date;
99
updated?: Date;
10-
community?: Community;
10+
community?: Communities;
1111
category: string;
1212
tags: string[];
1313
image?: string;

src/schema/utils.ts

+25
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,30 @@
11
import { z } from "astro/zod";
2+
import { Money } from "~/schema/accounts.ts";
3+
import type { DynamicGlobalProperties } from "@hiveio/dhive";
24

35
export function typeToZ<T>() {
46
return z.custom<T>(() => true) as z.ZodType<T>;
57
}
8+
9+
export function balanceToMoney(
10+
balance: string,
11+
precision: number
12+
): Money | null {
13+
const [amount, currency] = balance.split(" ");
14+
if (!amount || !currency) {
15+
throw new Error(`Invalid balance: ${balance}`);
16+
}
17+
return new Money(currency, amount, precision);
18+
}
19+
20+
export const vestsToHive = (
21+
vests: string,
22+
params: DynamicGlobalProperties
23+
): Money => {
24+
const [v] = vests.split(" ");
25+
const [totalFund] = (params.total_vesting_fund_hive as string).split(" ");
26+
const [totalShares] = (params.total_vesting_shares as string).split(" ");
27+
const hive =
28+
(parseFloat(v!) * parseFloat(totalFund!)) / parseFloat(totalShares!);
29+
return new Money("HIVE", hive.toString(), 3);
30+
};

src/tests/api/accounts.test.ts

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import { describe, test, expect } from "bun:test";
2+
import { getAccounts } from "~/api/accounts.ts";
3+
4+
describe("getAccounts", () => {
5+
test("returns accounts", async () => {
6+
const accounts = await getAccounts(["hive.coding", "mciszczon"]);
7+
expect(accounts).toBeArray();
8+
expect(accounts.length).toEqual(2);
9+
const acc1 = accounts[0]!;
10+
expect(acc1.name).toEqual("hive.coding");
11+
const acc2 = accounts[1]!;
12+
expect(acc2.name).toEqual("mciszczon");
13+
expect(acc2.wallet.hive.liquid.asFloat()).toBeNumber();
14+
expect(acc2.wallet.hive.frozen.asFloat()).toBeNumber();
15+
});
16+
});

0 commit comments

Comments
 (0)