Skip to content
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

feature: add package for client sdk #45

Open
wants to merge 11 commits into
base: main
Choose a base branch
from
Open
1 change: 1 addition & 0 deletions packages/relay-sdk/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
index.js
5 changes: 5 additions & 0 deletions packages/relay-sdk/.npmignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Ignore all files and directories starting with a dot
.*

# Build related stuff
node_modules/
44 changes: 44 additions & 0 deletions packages/relay-sdk/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# Relay SDK

## Description

The Lit Network Relay SDK is a lightweight JavaScript library that can be used for setting up payment delegations using the Lit Network Relay Server. The SDK provides a simple interface to connect to the Relay server, register a new payer, and add payees.

## Features

- Connect to the Relay server
- Register a new payer
- Add payees to the payer's delegation

## Installation

```bash
npm install @lit-protocol/relay-sdk

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why doesn't this package live in the js-sdk repository? It has dependencies on many packages there -- we're going to need to keep it up-to-date with the SDK, and our release process for publishing NPM packages is already defined there and for publishing the relay server to our hosting is already defined here but no client -- this is even listed as an sdk package, and we even have a relayer object defined in the js sdk in the lit-auth-client package.

```

or

```bash
yarn add @lit-protocol/relay-sdk
```

## Usage

### Registering a new payer:

```javascript
import { LitRelayClient } from '@lit-protocol/relay-sdk';

const client = await LitRelayClient.register('habanero', 'you-api-key');
const secret = client.secret;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This property was renamed since this was written, I think?

```

### Adding a payee:

```javascript
import { LitRelayClient } from '@lit-protocol/relay-sdk';

const client = await LitRelayClient.connect('habanero', 'you-api-key', 'your-payer-secret');
await client.addPayee('user-wallet-address');
```

14 changes: 14 additions & 0 deletions packages/relay-sdk/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"name": "@litnetwork/relay-sdk",
"version": "0.0.1",
"description": "Lightweight client for interacting with Lit Network relay server.",
"main": "index.js",
"scripts": {
"build": "esbuild src/index.ts --bundle --platform=node --target=node12 --outfile=index.js"
},
"license": "ISC",
"devDependencies": {
"esbuild": "^0.21.4"
},
"dependencies": {}
}
151 changes: 151 additions & 0 deletions packages/relay-sdk/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@

type SupportedNetworks = 'habanero' | 'manzano';

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we should use LIT_NETWORKS for this instead of our own string values

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there some way to filter the networks by supported features? I looked into this, but I would have ended up needing to hard code a union anyways since I need to filter out the other networks.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we need to define networks w/ specific behaviours, it'd be great to implement those maps in our sdk's constants similarly to how we define some things in lit-core here:
https://github.com/LIT-Protocol/js-sdk/blob/d8c7dc55febb262154061aaac01daad4aae1b239/packages/core/src/lib/lit-core.ts#L105-L117

This is related to my above question -- why not have this package live in the js-sdk? Then we could have single PRs that include updates to constants or other packages and this code as well. A good example of this in action is that we just refactored how we select relayer URLs in the SDK; this code would've been updated as a matter-of-course if it was in the same repo. See PR


function getRelayURLByNetwork(network: SupportedNetworks): string {
switch (network) {
case 'habanero':
return 'https://habanero-relayer.getlit.dev';
case 'manzano':
return 'https://manzano-relayer.getlit.dev';
joshLong145 marked this conversation as resolved.
Show resolved Hide resolved
}
}

export class LitRelayClient {

private readonly baseUrl: string;
private readonly apiKey: string;

private payerSecret: string | undefined = undefined;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

:nit: can just be ? optional :)

Suggested change
private payerSecret: string | undefined = undefined;
private payerSecret?: string


/**
* Create a new LitRelayClient instance. Requires that the payer is already registered.
* and the the payer secret is known.
*
* ```typescript
* const client = new LitRelayClient('https://habanero.lit.dev', 'my-api-key', 'my-payer-secret');
* ```
*
* @param baseUrl
* @param apiKey
* @param payerSecret
*/
private constructor(baseUrl: string, apiKey: string, payerSecret: string) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wild -- a constructor can actually be private?! I learned something new today. if this is actually true though, why make it private? Why not allow someone to construct an instance of the object?

this.baseUrl = baseUrl;
this.apiKey = apiKey;

if (payerSecret) {
this.payerSecret = payerSecret;
}
}

/**
* Adds a new payee to the payer's delegation list.
*
* ```typescript
* const client = await LitRelayClient.connect('habanero', 'my-api-key', 'my-payer-secret');
* const result = await client.addPayee('payee-wallet-address');
* ```
* @param payeeAddress
*
* @returns Promise<{

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we just throw an instance of Error if it fails, and return the tokenId if it succeeds? People will want to try { } catch { } around our API as it's an idiomatic paradigm in JS -- a promise already implicitly models this, given a rejected promise has a reason and a fulfilled one has a value, so if someone wants to follow this type of paradigm they could use Promise.allSettled() on our API that just throws an error or returns the value. That way they also get a stack trace with more context than a custom composed string if they want to understand what happened

* success: false;
* error: string;
* } | {
* success: true;
* tokenId: string;
* }>
*/
public async addPayee(payeeAddress: string) {
if (!this.payerSecret) {
throw new Error('Payer secret not set');
}

const res = await fetch(`${this.baseUrl}/add-users`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'api-key': this.apiKey,
'payer-secret-key': this.payerSecret,
},
body: JSON.stringify([payeeAddress]),
});

if (res.status !== 200) {
return {
success: false,
error: 'Failed to add payee: request failed',
};
}

const data = await res.json();

return {
success: true,
tokenId: data.tokenId,
joshLong145 marked this conversation as resolved.
Show resolved Hide resolved
};
joshLong145 marked this conversation as resolved.
Show resolved Hide resolved
}

/**
* Registers a new payer with the Lit Relay server using the provided API key. Returns
* a new LitRelayClient instance with the payer secret key.
*
* ```typescript
* const client = await LitRelayClient.register('habanero', 'my-api-key');
* ```
*
* @param network
* @param apiKey
*
* @returns LitRelayClient
*/
public static async register(network: SupportedNetworks, apiKey: string) {
if (network !== 'habanero' && network !== 'manzano') {
throw new Error('Invalid network');
}

const baseUrl = getRelayURLByNetwork(network);
const res = await fetch(`${baseUrl}/register-payer`, {
joshLong145 marked this conversation as resolved.
Show resolved Hide resolved
method: 'POST',
headers: {
'Content-Type': 'application/json',
'api-key': apiKey,
},
});

if (res.status !== 200) {
throw new Error('Failed to register payer: request failed');
}

const data = await res.json();

if (!data.payerSecretKey) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the API is going to return payerSecretKey, can we name it the same thing on this object? It'd be nice for the same magic strings to be used in both the client and server contexts for easier discoverability

throw new Error('Failed to register payer: missing secret key');
}

return new LitRelayClient(baseUrl, apiKey, data.payerSecretKey);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

payerSecret is private (so shouldn't be referenced), and there is no getter to expose it... but consumers of this client will need that secret later on in order to add more payees -- and likely they will need to do so at some point in the future when this instance has gone out of scope. My understanding is that they will need to call register() somewhere and then stash that secret somewhere for future use.

If that's true, rather than create a new instance with the secret injected, can we just return the secret to the caller so that they can either store it for later use or use it to create a new instance? Even better, they could call setPayerSecretKey(payerSecretKey) on the instance that they already have rather than having 2 instances in scope -- one with only the apiKey and another with both the apiKey and the payerSecretKey.

}

/**
* Connects to the Relay server for the specified network using the provided API key and payer secret
* and returns a new LitRelayClient instance.
*
* ```typescript
* const client = await LitRelayClient.connect('habanero', 'my-api-key', 'my-payer-secret');
* ```
*
* @param network
* @param apiKey
* @param payerSecret
*
* @returns LitRelayClient
*/
public static async connect(network: SupportedNetworks, apiKey: string, payerSecret: string) {
if (network !== 'habanero' && network !== 'manzano') {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since we run this check in all methods, it'd be nice if it was standardized to a single assert function

throw new Error('Invalid network');
}

const baseUrl = getRelayURLByNetwork(network);

return new LitRelayClient(baseUrl, apiKey, payerSecret);
}
}
147 changes: 147 additions & 0 deletions packages/relay-sdk/yarn.lock
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
# yarn lockfile v1


"@esbuild/aix-ppc64@0.21.4":
version "0.21.4"
resolved "https://registry.yarnpkg.com/@esbuild/aix-ppc64/-/aix-ppc64-0.21.4.tgz#f83eb142df3ca7b49531c1ed680b81e484316508"
integrity sha512-Zrm+B33R4LWPLjDEVnEqt2+SLTATlru1q/xYKVn8oVTbiRBGmK2VIMoIYGJDGyftnGaC788IuzGFAlb7IQ0Y8A==

"@esbuild/android-arm64@0.21.4":
version "0.21.4"
resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.21.4.tgz#dd328039daccd6033b2d1e536c054914bfc92287"
integrity sha512-fYFnz+ObClJ3dNiITySBUx+oNalYUT18/AryMxfovLkYWbutXsct3Wz2ZWAcGGppp+RVVX5FiXeLYGi97umisA==

"@esbuild/android-arm@0.21.4":
version "0.21.4"
resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.21.4.tgz#76767a989720a97b206ea14c52af6e4589e48b0d"
integrity sha512-E7H/yTd8kGQfY4z9t3nRPk/hrhaCajfA3YSQSBrst8B+3uTcgsi8N+ZWYCaeIDsiVs6m65JPCaQN/DxBRclF3A==

"@esbuild/android-x64@0.21.4":
version "0.21.4"
resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.21.4.tgz#14a8ae3c35702d882086efb5a8f8d7b0038d8d35"
integrity sha512-mDqmlge3hFbEPbCWxp4fM6hqq7aZfLEHZAKGP9viq9wMUBVQx202aDIfc3l+d2cKhUJM741VrCXEzRFhPDKH3Q==

"@esbuild/darwin-arm64@0.21.4":
version "0.21.4"
resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.21.4.tgz#7e735046005e4c12e9139e0bdd1fa6a754430d57"
integrity sha512-72eaIrDZDSiWqpmCzVaBD58c8ea8cw/U0fq/PPOTqE3c53D0xVMRt2ooIABZ6/wj99Y+h4ksT/+I+srCDLU9TA==

"@esbuild/darwin-x64@0.21.4":
version "0.21.4"
resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.21.4.tgz#db623553547a5fe3502a63aa88306e9023178482"
integrity sha512-uBsuwRMehGmw1JC7Vecu/upOjTsMhgahmDkWhGLWxIgUn2x/Y4tIwUZngsmVb6XyPSTXJYS4YiASKPcm9Zitag==

"@esbuild/freebsd-arm64@0.21.4":
version "0.21.4"
resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.4.tgz#91cbad647c079bf932086fbd4749d7f563df67b8"
integrity sha512-8JfuSC6YMSAEIZIWNL3GtdUT5NhUA/CMUCpZdDRolUXNAXEE/Vbpe6qlGLpfThtY5NwXq8Hi4nJy4YfPh+TwAg==

"@esbuild/freebsd-x64@0.21.4":
version "0.21.4"
resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.21.4.tgz#723299b9859ccbe5532fecbadba3ac33019ba8e8"
integrity sha512-8d9y9eQhxv4ef7JmXny7591P/PYsDFc4+STaxC1GBv0tMyCdyWfXu2jBuqRsyhY8uL2HU8uPyscgE2KxCY9imQ==

"@esbuild/linux-arm64@0.21.4":
version "0.21.4"
resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.21.4.tgz#531743f861e1ef6e50b874d6c784cda37aa5e685"
integrity sha512-/GLD2orjNU50v9PcxNpYZi+y8dJ7e7/LhQukN3S4jNDXCKkyyiyAz9zDw3siZ7Eh1tRcnCHAo/WcqKMzmi4eMQ==

"@esbuild/linux-arm@0.21.4":
version "0.21.4"
resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.21.4.tgz#1144b5654764960dd97d90ddf0893a9afc63ad91"
integrity sha512-2rqFFefpYmpMs+FWjkzSgXg5vViocqpq5a1PSRgT0AvSgxoXmGF17qfGAzKedg6wAwyM7UltrKVo9kxaJLMF/g==

"@esbuild/linux-ia32@0.21.4":
version "0.21.4"
resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.21.4.tgz#c81b6f2ed3308d3b75ccefb5ac63bc4cf3a9d2e9"
integrity sha512-pNftBl7m/tFG3t2m/tSjuYeWIffzwAZT9m08+9DPLizxVOsUl8DdFzn9HvJrTQwe3wvJnwTdl92AonY36w/25g==

"@esbuild/linux-loong64@0.21.4":
version "0.21.4"
resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.21.4.tgz#87b6af7cd0f2551653955fc2dc465b7f4464af0a"
integrity sha512-cSD2gzCK5LuVX+hszzXQzlWya6c7hilO71L9h4KHwqI4qeqZ57bAtkgcC2YioXjsbfAv4lPn3qe3b00Zt+jIfQ==

"@esbuild/linux-mips64el@0.21.4":
version "0.21.4"
resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.21.4.tgz#fec73cd39490a0c45d052bef03e011a0ad366c06"
integrity sha512-qtzAd3BJh7UdbiXCrg6npWLYU0YpufsV9XlufKhMhYMJGJCdfX/G6+PNd0+v877X1JG5VmjBLUiFB0o8EUSicA==

"@esbuild/linux-ppc64@0.21.4":
version "0.21.4"
resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.21.4.tgz#ea3b5e13b0fc8666bd4c6f7ea58bd1830f3e6e78"
integrity sha512-yB8AYzOTaL0D5+2a4xEy7OVvbcypvDR05MsB/VVPVA7nL4hc5w5Dyd/ddnayStDgJE59fAgNEOdLhBxjfx5+dg==

"@esbuild/linux-riscv64@0.21.4":
version "0.21.4"
resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.21.4.tgz#80d406f653fc6b193edaeb55ac88d4ac22c8f155"
integrity sha512-Y5AgOuVzPjQdgU59ramLoqSSiXddu7F3F+LI5hYy/d1UHN7K5oLzYBDZe23QmQJ9PIVUXwOdKJ/jZahPdxzm9w==

"@esbuild/linux-s390x@0.21.4":
version "0.21.4"
resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.21.4.tgz#9cbd26854b5b12cf22fb54c96cd1adffaf6ace6f"
integrity sha512-Iqc/l/FFwtt8FoTK9riYv9zQNms7B8u+vAI/rxKuN10HgQIXaPzKZc479lZ0x6+vKVQbu55GdpYpeNWzjOhgbA==

"@esbuild/linux-x64@0.21.4":
version "0.21.4"
resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.21.4.tgz#44dfe1c5cad855362c830c604dba97fbb16fc114"
integrity sha512-Td9jv782UMAFsuLZINfUpoF5mZIbAj+jv1YVtE58rFtfvoKRiKSkRGQfHTgKamLVT/fO7203bHa3wU122V/Bdg==

"@esbuild/netbsd-x64@0.21.4":
version "0.21.4"
resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.21.4.tgz#89b97d823e1cc4bf8c4e5dc8f76c8d6ceb1c87f3"
integrity sha512-Awn38oSXxsPMQxaV0Ipb7W/gxZtk5Tx3+W+rAPdZkyEhQ6968r9NvtkjhnhbEgWXYbgV+JEONJ6PcdBS+nlcpA==

"@esbuild/openbsd-x64@0.21.4":
version "0.21.4"
resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.21.4.tgz#080715bb4981c326364320d7b56835608e2bd98d"
integrity sha512-IsUmQeCY0aU374R82fxIPu6vkOybWIMc3hVGZ3ChRwL9hA1TwY+tS0lgFWV5+F1+1ssuvvXt3HFqe8roCip8Hg==

"@esbuild/sunos-x64@0.21.4":
version "0.21.4"
resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.21.4.tgz#8d838a8ac80e211536490108b72fb0091a811626"
integrity sha512-hsKhgZ4teLUaDA6FG/QIu2q0rI6I36tZVfM4DBZv3BG0mkMIdEnMbhc4xwLvLJSS22uWmaVkFkqWgIS0gPIm+A==

"@esbuild/win32-arm64@0.21.4":
version "0.21.4"
resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.21.4.tgz#94afb4c2ac89b0f09791606d6d93fdab322f81c8"
integrity sha512-UUfMgMoXPoA/bvGUNfUBFLCh0gt9dxZYIx9W4rfJr7+hKe5jxxHmfOK8YSH4qsHLLN4Ck8JZ+v7Q5fIm1huErg==

"@esbuild/win32-ia32@0.21.4":
version "0.21.4"
resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.21.4.tgz#822085cd52f2f1dd90eabb59346ffa779c0bab83"
integrity sha512-yIxbspZb5kGCAHWm8dexALQ9en1IYDfErzjSEq1KzXFniHv019VT3mNtTK7t8qdy4TwT6QYHI9sEZabONHg+aw==

"@esbuild/win32-x64@0.21.4":
version "0.21.4"
resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.21.4.tgz#11ef0398f9abee161193461910a507ef0d4c0c32"
integrity sha512-sywLRD3UK/qRJt0oBwdpYLBibk7KiRfbswmWRDabuncQYSlf8aLEEUor/oP6KRz8KEG+HoiVLBhPRD5JWjS8Sg==

esbuild@^0.21.4:
version "0.21.4"
resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.21.4.tgz#ceb501def8edb12a5bfd9c55f3a96db698edf022"
integrity sha512-sFMcNNrj+Q0ZDolrp5pDhH0nRPN9hLIM3fRPwgbLYJeSHHgnXSnbV3xYgSVuOeLWH9c73VwmEverVzupIv5xuA==
optionalDependencies:
"@esbuild/aix-ppc64" "0.21.4"
"@esbuild/android-arm" "0.21.4"
"@esbuild/android-arm64" "0.21.4"
"@esbuild/android-x64" "0.21.4"
"@esbuild/darwin-arm64" "0.21.4"
"@esbuild/darwin-x64" "0.21.4"
"@esbuild/freebsd-arm64" "0.21.4"
"@esbuild/freebsd-x64" "0.21.4"
"@esbuild/linux-arm" "0.21.4"
"@esbuild/linux-arm64" "0.21.4"
"@esbuild/linux-ia32" "0.21.4"
"@esbuild/linux-loong64" "0.21.4"
"@esbuild/linux-mips64el" "0.21.4"
"@esbuild/linux-ppc64" "0.21.4"
"@esbuild/linux-riscv64" "0.21.4"
"@esbuild/linux-s390x" "0.21.4"
"@esbuild/linux-x64" "0.21.4"
"@esbuild/netbsd-x64" "0.21.4"
"@esbuild/openbsd-x64" "0.21.4"
"@esbuild/sunos-x64" "0.21.4"
"@esbuild/win32-arm64" "0.21.4"
"@esbuild/win32-ia32" "0.21.4"
"@esbuild/win32-x64" "0.21.4"