-
Notifications
You must be signed in to change notification settings - Fork 0
Development registrar client #4
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from 6 commits
Commits
Show all changes
25 commits
Select commit
Hold shift + click to select a range
381fc7c
implement account, farm, node services for registrar
SalmaElsoly 3010a97
refactor to take private key in the intilization of the client
SalmaElsoly 56136ee
fix return type of farm creation + add error handling in config
SalmaElsoly 41a10fb
add integration tests
SalmaElsoly 5f5f17f
add intial README
SalmaElsoly b737d50
configure eslint
SalmaElsoly a546fa6
add utils for signature and auth header + add keyed parameters to client
SalmaElsoly 809aa51
fix json writing convention
SalmaElsoly 397ab7f
update repo README
SalmaElsoly 10f5896
adjust package exports
SalmaElsoly fc8e8a0
update dirs structure + use latest js + update package.json
SalmaElsoly 232d833
add more tests and validation for node data
SalmaElsoly db36618
add scripts for usage
SalmaElsoly bec1da1
update README
SalmaElsoly 4664bac
skip failed tests because of server bug
SalmaElsoly 0d30268
update scripts to use config.json + update yarn version
SalmaElsoly 0443d0c
update declarations in tsconfig
SalmaElsoly 1b6ab88
updates tests to config.json + fix build module types
SalmaElsoly 79df76d
fix uri
SalmaElsoly 1e321b4
support stellar address in farm creation and update + fix tests
SalmaElsoly 142087d
update scripts + fix package.json
SalmaElsoly 6b287e9
disable workspace in pkg.json
SalmaElsoly f4d8f84
update readme
SalmaElsoly 1e4e107
fix scripts + update readme
SalmaElsoly 0bab692
fix requests timeout
SalmaElsoly File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
node_modules/ | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
{ | ||
"printWidth": 120, | ||
"tabWidth": 2, | ||
"useTabs": false, | ||
"semi": true, | ||
"singleQuote": false, | ||
"quoteProps": "as-needed", | ||
"jsxSingleQuote": false, | ||
"trailingComma": "all", | ||
"bracketSpacing": true, | ||
"arrowParens": "avoid", | ||
"endOfLine": "auto" | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
// eslint.config.mjs | ||
import js from "@eslint/js"; | ||
import ts from "@typescript-eslint/eslint-plugin"; | ||
import tsParser from "@typescript-eslint/parser"; | ||
import prettier from "eslint-plugin-prettier"; | ||
import prettierConfig from "eslint-config-prettier"; | ||
import globals from "globals"; | ||
|
||
|
||
export default [ | ||
js.configs.recommended, | ||
{ | ||
files : ["**/*.ts"], | ||
languageOptions: { | ||
parser: tsParser, | ||
ecmaVersion: "latest", | ||
sourceType: "module", | ||
globals: { | ||
...globals.node | ||
} | ||
}, | ||
plugins: { | ||
"@typescript-eslint": ts, | ||
prettier, | ||
}, | ||
rules: { | ||
}, | ||
}, | ||
prettierConfig, | ||
]; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
{ | ||
"$schema": "node_modules/lerna/schemas/lerna-schema.json", | ||
"version": "independent", | ||
"npmClient": "yarn" | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
{ | ||
"name": "root", | ||
SalmaElsoly marked this conversation as resolved.
Show resolved
Hide resolved
|
||
"private": true, | ||
"workspaces": [ | ||
"packages/*" | ||
], | ||
"dependencies": { | ||
"cosmiconfig": "^9.0.0", | ||
"globals": "^15.15.0" | ||
}, | ||
"devDependencies": { | ||
"@typescript-eslint/eslint-plugin": "^8.24.0", | ||
"@typescript-eslint/parser": "^8.24.0", | ||
"eslint": "^9.20.1", | ||
"eslint-config-prettier": "^10.0.1", | ||
"eslint-plugin-prettier": "^5.2.3", | ||
"lerna": "^8.1.9", | ||
"prettier": "^3.5.1", | ||
"typescript": "^5.7.3" | ||
} | ||
} |
SalmaElsoly marked this conversation as resolved.
Show resolved
Hide resolved
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
# Registrar Client | ||
|
||
This package provides a client for interacting with the TFGrid v4 Node Registrar. | ||
|
||
## Getting Started | ||
|
||
Set the `REGISTRAR_URL` in your environment variables to point to the TFGrid v4 Node Registrar. | ||
SalmaElsoly marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
```sh | ||
export REGISTRAR_URL=https://your-registrar-url | ||
``` | ||
|
||
## Usage | ||
|
||
Here is an example of how to use the Registrar Client: | ||
|
||
```typescript | ||
const privateKey = "your_private_key"; | ||
const client = new RegistrarClient(privateKey); | ||
|
||
const accountRequest: CreateAccountRequest = { | ||
SalmaElsoly marked this conversation as resolved.
Show resolved
Hide resolved
|
||
// your create account request data | ||
}; | ||
client.account | ||
.createAccount(accountRequest) | ||
.then(account => { | ||
console.log("Account created:", account); | ||
}) | ||
.catch(error => { | ||
console.error("Failed to create account:", error); | ||
}); | ||
``` |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
// jest.config.js | ||
module.exports = { | ||
preset: "ts-jest/presets/default-esm", | ||
transform: { | ||
"^.+\\.(ts|tsx)$": ["ts-jest", { useESM: true }], | ||
}, | ||
extensionsToTreatAsEsm: [".ts", ".tsx"], | ||
globals: { | ||
"ts-jest": { | ||
useESM: true, | ||
}, | ||
}, | ||
testEnvironment: "node", | ||
setupFiles: ["dotenv/config"], | ||
}; |
SalmaElsoly marked this conversation as resolved.
Show resolved
Hide resolved
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
{ | ||
"name": "registrar_client", | ||
SalmaElsoly marked this conversation as resolved.
Show resolved
Hide resolved
|
||
"version": "1.0.0", | ||
SalmaElsoly marked this conversation as resolved.
Show resolved
Hide resolved
|
||
"description": "Now I’m the model of a modern major general / The venerated Virginian veteran whose men are all / Lining up, to put me up on a pedestal / Writin’ letters to relatives / Embellishin’ my elegance and eloquence / But the elephant is in the room / The truth is in ya face when ya hear the British cannons go / BOOM", | ||
"keywords": [], | ||
"author": "Salma Elsoly <salmaelsoly@gmail.com>", | ||
"license": "ISC", | ||
"main": "lib/registrar_client.js", | ||
"directories": { | ||
"lib": "src", | ||
"test": "tests" | ||
}, | ||
"files": [ | ||
"lib" | ||
], | ||
"repository": { | ||
"type": "git", | ||
"url": "git+https://github.com/threefoldtech/tfgridv4-sdk-ts.git" | ||
}, | ||
"scripts": { | ||
SalmaElsoly marked this conversation as resolved.
Show resolved
Hide resolved
|
||
"test": "node ./__tests__/registrar_client.test.js" | ||
}, | ||
SalmaElsoly marked this conversation as resolved.
Show resolved
Hide resolved
|
||
"bugs": { | ||
"url": "https://github.com/threefoldtech/tfgridv4-sdk-ts/issues" | ||
}, | ||
"homepage": "https://github.com/threefoldtech/tfgridv4-sdk-ts#readme", | ||
"devDependencies": { | ||
"@types/jest": "^29.5.14", | ||
"@types/node": "^22.13.4", | ||
"jest": "^29.7.0", | ||
"ts-jest": "^29.2.5", | ||
"typescript": "^5.7.3" | ||
}, | ||
"dependencies": { | ||
"@types/jest": "^29.5.14", | ||
"dotenv": "^16.4.7", | ||
"jest": "^29.7.0", | ||
"ts-jest": "^29.2.5", | ||
"tweetnacl": "^1.0.3" | ||
} | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
import axios, { AxiosInstance, AxiosRequestConfig } from "axios"; | ||
import { Accounts } from "../modules/account/service"; | ||
import { Config } from "../config"; | ||
import { Farms } from "../modules/farm/service"; | ||
import { Nodes } from "../modules/node/service"; | ||
import { Zos } from "../modules/zos/service"; | ||
|
||
export abstract class BaseClient { | ||
private client: AxiosInstance; | ||
|
||
constructor() { | ||
this.client = axios.create({ | ||
baseURL: Config.getInstance().registrarUrl, | ||
}); | ||
} | ||
|
||
async get<T>(uri: string, config?: AxiosRequestConfig): Promise<T> { | ||
const response = await this.client.get<T>(uri, config); | ||
return response.data; | ||
} | ||
|
||
async post<T>(uri: string, data: any, config?: AxiosRequestConfig): Promise<T> { | ||
const response = await this.client.post<T>(uri, data, config); | ||
return response.data; | ||
} | ||
|
||
async patch<T>(uri: string, data: any, config?: AxiosRequestConfig): Promise<T> { | ||
const response = await this.client.patch<T>(uri, data, config); | ||
return response.data; | ||
} | ||
|
||
async put<T>(uri: string, data: any, config?: AxiosRequestConfig): Promise<T> { | ||
const response = await this.client.put<T>(uri, data, config); | ||
return response.data; | ||
} | ||
} | ||
|
||
export class RegistrarClient extends BaseClient { | ||
public readonly private_key: string; | ||
accounts: Accounts; | ||
farms: Farms; | ||
nodes: Nodes; | ||
zos: Zos; | ||
|
||
constructor(private_key: string) { | ||
SalmaElsoly marked this conversation as resolved.
Show resolved
Hide resolved
|
||
super(); | ||
this.private_key = private_key; | ||
this.accounts = new Accounts(this); | ||
this.farms = new Farms(this); | ||
this.nodes = new Nodes(this); | ||
this.zos = new Zos(this); | ||
} | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
export class Config { | ||
SalmaElsoly marked this conversation as resolved.
Show resolved
Hide resolved
|
||
private static _instance: Config; | ||
public readonly registrarUrl: string; | ||
|
||
private constructor() { | ||
if (!process.env.REGISTRAR_URL) { | ||
throw new Error("REGISTRAR_URL environment variable is not defined"); | ||
} | ||
this.registrarUrl = process.env.REGISTRAR_URL; | ||
} | ||
|
||
public static getInstance(): Config { | ||
if (!Config._instance) { | ||
Config._instance = new Config(); | ||
} | ||
return Config._instance; | ||
} | ||
} |
SalmaElsoly marked this conversation as resolved.
Show resolved
Hide resolved
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
import { RegistrarClient } from "../../client/client"; | ||
import { Account, CreateAccountRequest, UpdateAccountRequest } from "./types"; | ||
import * as tweetnacl from "tweetnacl"; | ||
import * as base64 from "base64-js"; | ||
|
||
export class Accounts { | ||
private client: RegistrarClient; | ||
|
||
private readonly accountUri = "/accounts"; | ||
|
||
constructor(client: RegistrarClient) { | ||
this.client = client; | ||
} | ||
|
||
async createAccount(request: Partial<CreateAccountRequest>): Promise<Account | null> { | ||
const timestamp = Math.floor(Date.now() / 1000); | ||
|
||
const privateKey = this.client.private_key; | ||
let publicKey; | ||
try { | ||
publicKey = base64.fromByteArray(tweetnacl.sign.keyPair.fromSecretKey(base64.toByteArray(privateKey)).publicKey); | ||
} catch (e) { | ||
console.error("Failed to generate public key: ", e); | ||
return null; | ||
SalmaElsoly marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
|
||
const challenge = `${timestamp}:${publicKey}`; | ||
const signature = base64.fromByteArray( | ||
tweetnacl.sign.detached(Buffer.from(challenge, "utf-8"), base64.toByteArray(privateKey)), | ||
SalmaElsoly marked this conversation as resolved.
Show resolved
Hide resolved
|
||
); | ||
|
||
request.public_key = publicKey; | ||
request.signature = signature; | ||
request.timestamp = timestamp; | ||
|
||
try { | ||
const data = await this.client.post<Account>(this.accountUri, request); | ||
return data; | ||
} catch (e) { | ||
console.error("Failed to create account: ", e); | ||
return null; | ||
} | ||
} | ||
|
||
async getAccountByPublicKey(publicKey: string): Promise<Account | null> { | ||
try { | ||
const data = await this.client.get<Account>(this.accountUri, { | ||
params: { | ||
public_key: publicKey, | ||
}, | ||
}); | ||
return data; | ||
} catch (e) { | ||
console.error("Failed to get account: ", e); | ||
return null; | ||
} | ||
} | ||
|
||
async getAccountByTwinId(twinId: number): Promise<Account | null> { | ||
try { | ||
const data = await this.client.get<Account>(this.accountUri, { | ||
params: { | ||
twin_id: twinId, | ||
}, | ||
}); | ||
|
||
return data; | ||
} catch (e) { | ||
console.error("Failed to get account: ", e); | ||
return null; | ||
} | ||
} | ||
|
||
async updateAccount(twinID: number, body: UpdateAccountRequest): Promise<any> { | ||
const timestamp = Math.floor(Date.now() / 1000); | ||
const challenge = `${timestamp}:${twinID}`; | ||
const privateKey = this.client.private_key; | ||
if (!privateKey) { | ||
throw new Error("Private key is not found"); | ||
} | ||
const signature = tweetnacl.sign.detached(Buffer.from(challenge, "utf-8"), base64.toByteArray(privateKey)); | ||
const config = { | ||
SalmaElsoly marked this conversation as resolved.
Show resolved
Hide resolved
|
||
headers: { | ||
"X-Auth": `${Buffer.from(challenge).toString("base64")}:${base64.fromByteArray(signature)}`, | ||
}, | ||
}; | ||
try { | ||
const data = await this.client.patch<any>(`${this.accountUri}/${twinID}`, body, config); | ||
return data; | ||
} catch (e) { | ||
console.error("Failed to update account: ", e); | ||
return null; | ||
} | ||
} | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
import { Farm } from "../farm/types"; | ||
|
||
export interface Account { | ||
createdAt: string; | ||
public_key: string; | ||
twin_id: number; | ||
relays: string[]; | ||
rmb_enc_key: string; | ||
farms: Farm[]; | ||
updatedAt: string; | ||
} | ||
|
||
export interface CreateAccountRequest { | ||
public_key: string; | ||
relays: string[]; | ||
rmb_enc_key: string; | ||
signature: string; | ||
timestamp: number; | ||
} | ||
|
||
export interface UpdateAccountRequest { | ||
relays: string[]; | ||
rmb_enc_key: string; | ||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.