Skip to content

Commit

Permalink
feat: accounts sdk (#1)
Browse files Browse the repository at this point in the history
* feat: initial accounts sdk

* chore: initial tests

* chore: improved naming

* chore: rename a bit + one more test

* feat: configurable host via platform env

* feat: find by type + test

* test: add memcmp test

* tests: fix broken test

* chore: move tests

* ci: add github action

* chore: add yarn.lock

* chore: use api key secret

* deps: add node types

* ci: remove trigger

* ci: correct node definition types

* ci: triage build issue

* build: remove node types

* build: triage build

* build: triage

* build: triage

* build: triage

* build: triage

* ci: install deps

* types: don't depend on node fetch type

* lint: fix

* ci: add status badge

* chore: improve types

* chore: minor fixes while using to render

* chore: rename to sdk
  • Loading branch information
thlorenz authored Aug 21, 2023
1 parent b86fb99 commit 3e05ccd
Show file tree
Hide file tree
Showing 19 changed files with 821 additions and 24 deletions.
44 changes: 44 additions & 0 deletions .github/workflows/build-test-lint.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
name: Build+Test+Lint
on:
push:
branches: [master]
pull_request:
branches: [master]

jobs:
build-test-lint:
runs-on:
group: Default
timeout-minutes: 5
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest]
node-version: [18.x]

steps:
- uses: actions/checkout@master

- name: Install Node.js
uses: actions/setup-node@v3
with:
node-version: ${{ matrix.node-version }}
cache: 'yarn'

- name: Install Dependencies
run: yarn install
shell: bash

- name: Build
run: yarn build
shell: bash

- name: Test
env:
IF_PLATFORM_API_KEY: ${{ secrets.IF_PLATFORM_API_KEY }}
run: yarn test
shell: bash

- name: Lint
run: yarn lint
shell: bash
1 change: 0 additions & 1 deletion .gitignore

This file was deleted.

4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# @ironforge-cloud/platform-sdk
# @ironforge-cloud/sdk [![Build+Test+Lint](https://github.com/ironforge-cloud/sdk/actions/workflows/build-test-lint.yml/badge.svg)](https://github.com/ironforge-cloud/sdk/actions/workflows/build-test-lint.yml)

IronForge platform SDK
IronForge SDK

## LICENSE

Expand Down
13 changes: 7 additions & 6 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
{
"name": "platform-sdk",
"name": "@ironforge-cloud/sdk",
"version": "0.0.0",
"description": "IronForge platform SDK.",
"main": "src/platform-sdk.ts",
"description": "IronForge SDK.",
"main": "src/sdk.ts",
"types": "src/sdk.ts",
"scripts": {
"build": "tsc",
"lint": "prettier --check .",
Expand All @@ -13,11 +14,11 @@
"license": "MIT",
"private": true,
"devDependencies": {
"@types/node": "^20.5.0",
"@types/node": "^20.5.1",
"esbuild": "^0.19.2",
"esbuild-runner": "^2.2.2",
"prettier": "^3.0.2",
"typescript": "^5.1.6",
"undici": "^5.23.0"
"spok": "^1.5.5",
"typescript": "^5.1.6"
}
}
27 changes: 27 additions & 0 deletions src/accounts/aggregate.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { AccountsRequestResult } from '../types'
import { requestHeaders, tryExtractResultFromResponse } from '../utils'

export type AccountsAggregateConfig = {
query: object
cluster: string
program: string
cacheControl?: string
}

export async function accountsAggregate<T = any>(
apiKey: string,
host: string,
config: AccountsAggregateConfig
) {
const { query, cluster, program, cacheControl } = config

const res = await fetch(
`https://${host}/v1/${cluster}/${program}/aggregate` + `?apiKey=${apiKey}`,
{
headers: requestHeaders({ cacheControl }),
body: JSON.stringify(query),
method: 'POST',
}
)
return tryExtractResultFromResponse<AccountsRequestResult<T>>(res)
}
32 changes: 32 additions & 0 deletions src/accounts/filter-by-type.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { AccountsRequestResultWithMetadata } from '../types'
import { requestHeaders, tryExtractResultFromResponse } from '../utils'

export type AccountsFilterByTypeConfig = {
accountType: string
query: object
cluster: string
program: string
limit: number
offset: number
cacheControl?: string
}

export async function accountsFilterByType<T = any>(
apiKey: string,
host: string,
config: AccountsFilterByTypeConfig
) {
const { accountType, query, cluster, program, limit, offset, cacheControl } =
config

const res = await fetch(
`https://${host}/v1/${cluster}/${program}/filter` +
`/${accountType}?limit=${limit}&offset=${offset}&apiKey=${apiKey}`,
{
headers: requestHeaders({ cacheControl }),
body: JSON.stringify(query),
method: 'POST',
}
)
return tryExtractResultFromResponse<AccountsRequestResultWithMetadata<T>>(res)
}
30 changes: 30 additions & 0 deletions src/accounts/filter.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { AccountsRequestResultWithMetadata } from '../types'
import { requestHeaders, tryExtractResultFromResponse } from '../utils'

export type AccountsFilterConfig = {
query: object
cluster: string
program: string
limit: number
offset: number
cacheControl?: string
}

export async function accountsFilter<T = any>(
apiKey: string,
host: string,
config: AccountsFilterConfig
) {
const { query, cluster, program, limit, offset, cacheControl } = config

const res = await fetch(
`https://${host}/v1/${cluster}/${program}/filter` +
`?limit=${limit}&offset=${offset}&apiKey=${apiKey}`,
{
headers: requestHeaders({ cacheControl }),
body: JSON.stringify(query),
method: 'POST',
}
)
return tryExtractResultFromResponse<AccountsRequestResultWithMetadata<T>>(res)
}
29 changes: 29 additions & 0 deletions src/accounts/find-by-type.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { AccountsRequestResultWithMetadata } from '../types'
import { requestHeaders, tryExtractResultFromResponse } from '../utils'

export type AccountsFindByTypeConfig = {
accountType: string
cluster: string
program: string
limit: number
offset: number
cacheControl?: string
}

export async function accountsFindByType<T = any>(
apiKey: string,
host: string,
config: AccountsFindByTypeConfig
) {
const { accountType, cluster, program, limit, offset, cacheControl } = config

const res = await fetch(
`https://${host}/v1/${cluster}/${program}/find/${accountType}` +
`?limit=${limit}&offset=${offset}&apiKey=${apiKey}`,
{
headers: requestHeaders({ cacheControl }),
method: 'GET',
}
)
return tryExtractResultFromResponse<AccountsRequestResultWithMetadata<T>>(res)
}
27 changes: 27 additions & 0 deletions src/accounts/find-one.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { AccountsRequestResult } from '../types'
import { requestHeaders, tryExtractResultFromResponse } from '../utils'

export type AccountsFindOneConfig = {
cluster: string
program: string
address: string
cacheControl?: string
}

export async function accountsFindOne<T = any>(
apiKey: string,
host: string,
config: AccountsFindOneConfig
) {
const { cluster, program, address, cacheControl } = config

const res = await fetch(
`https://${host}/v1/${cluster}/${program}/findOne` +
`/${address}?apiKey=${apiKey}`,
{
headers: requestHeaders({ cacheControl }),
method: 'GET',
}
)
return tryExtractResultFromResponse<AccountsRequestResult<T>>(res)
}
47 changes: 47 additions & 0 deletions src/accounts/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import { accountsAggregate, AccountsAggregateConfig } from './aggregate'
import { accountsFilter, AccountsFilterConfig } from './filter'
import {
accountsFilterByType,
AccountsFilterByTypeConfig,
} from './filter-by-type'
import { accountsFindByType, AccountsFindByTypeConfig } from './find-by-type'
import { accountsFindOne, AccountsFindOneConfig } from './find-one'
import { accountsMemcmp, AccountsMemcmpConfig } from './memcmp'

export { AccountsAggregateConfig } from './aggregate'
export { AccountsFilterByTypeConfig } from './filter-by-type'
export { AccountsFilterConfig } from './filter'
export { AccountsFindByTypeConfig } from './find-by-type'
export { AccountsFindOneConfig } from './find-one'
export { AccountsMemcmpConfig } from './memcmp'

export class AccountsSdk {
constructor(
public readonly apiKey: string,
public readonly host: string
) {}

aggregate<T = any>(config: AccountsAggregateConfig) {
return accountsAggregate<T>(this.apiKey, this.host, config)
}

filterByType<T = any>(config: AccountsFilterByTypeConfig) {
return accountsFilterByType<T>(this.apiKey, this.host, config)
}

filter<T = any>(config: AccountsFilterConfig) {
return accountsFilter<T>(this.apiKey, this.host, config)
}

findByType<T = any>(config: AccountsFindByTypeConfig) {
return accountsFindByType<T>(this.apiKey, this.host, config)
}

findOne<T = any>(config: AccountsFindOneConfig) {
return accountsFindOne<T>(this.apiKey, this.host, config)
}

memcmp<T = any>(config: AccountsMemcmpConfig) {
return accountsMemcmp<T>(this.apiKey, this.host, config)
}
}
30 changes: 30 additions & 0 deletions src/accounts/memcmp.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { AccountsRequestResultWithMetadata } from '../types'
import { requestHeaders, tryExtractResultFromResponse } from '../utils'

export type AccountsMemcmpConfig = {
query: object
cluster: string
program: string
limit: number
offset: number
cacheControl?: string
}

export async function accountsMemcmp<T = any>(
apiKey: string,
host: string,
config: AccountsMemcmpConfig
) {
const { query, cluster, program, limit, offset, cacheControl } = config

const res = await fetch(
`https://${host}/v1/${cluster}/${program}/memcmp` +
`?limit=${limit}&offset=${offset}&apiKey=${apiKey}`,
{
headers: requestHeaders({ cacheControl }),
body: JSON.stringify(query),
method: 'POST',
}
)
return tryExtractResultFromResponse<AccountsRequestResultWithMetadata<T>>(res)
}
1 change: 0 additions & 1 deletion src/platform-sdk.ts

This file was deleted.

21 changes: 21 additions & 0 deletions src/sdk.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { AccountsSdk } from './accounts'
import { PLATFORM_ENV_PROD, PlatformEnv } from './types'
import { accountsHostForEnv } from './utils'

export * from './accounts'
export * from './types'
export { accountsHostForEnv } from './utils'

export class IronforgeSdk {
private readonly _accountsHost: string
constructor(
public apiKey: string,
env: PlatformEnv = PLATFORM_ENV_PROD
) {
this._accountsHost = accountsHostForEnv(env)
}

get accounts() {
return new AccountsSdk(this.apiKey, this._accountsHost)
}
}
50 changes: 50 additions & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
// -----------------
// AccountsRequestResult
// -----------------
type SuccessAccountsRequestResult<T> = {
error: null | undefined
data: T
}
type FailureAccountsRequestResult = {
error: string
data: null | undefined
}

export type AccountsRequestResult<T> =
| SuccessAccountsRequestResult<T>
| FailureAccountsRequestResult

export function isFailureResult<T>(
result: AccountsRequestResult<T>
): result is FailureAccountsRequestResult {
return result.error != null
}
export function isSuccessResult<T>(
result: AccountsRequestResult<T>
): result is SuccessAccountsRequestResult<T> {
return result.error == null && result.data != null
}

export type AccountsRequestResultWithMetadata<T> = AccountsRequestResult<
T[]
> & {
metadata: {
count: number
offset: number
limit: number
hasMore: boolean
}
}

// -----------------
// PlatformEnv
// -----------------
export const PLATFORM_ENV_DEV = 'dev'
export const PLATFORM_ENV_STAGE = 'stage'
export const PLATFORM_ENV_PROD = 'prod'
export const PLATFORM_ENVS = [
PLATFORM_ENV_DEV,
PLATFORM_ENV_STAGE,
PLATFORM_ENV_PROD,
] as const
export type PlatformEnv = (typeof PLATFORM_ENVS)[number]
Loading

0 comments on commit 3e05ccd

Please sign in to comment.