From f54eec676cf44db85059f3a34059cb0af07426c3 Mon Sep 17 00:00:00 2001 From: Tomek Marciniak Date: Mon, 2 Sep 2024 16:00:23 +0200 Subject: [PATCH] feat(klesia): add simple docs --- apps/klesia/package.json | 2 ++ apps/klesia/src/custom.d.ts | 1 + apps/klesia/src/docs.md | 49 ++++++++++++++++++++++++++++++++ apps/klesia/src/index.ts | 24 ++++++++++++++-- apps/klesia/src/methods/mina.ts | 8 ++++-- bun.lockb | Bin 85208 -> 85968 bytes turbo.json | 24 ++++++++-------- 7 files changed, 90 insertions(+), 18 deletions(-) create mode 100644 apps/klesia/src/custom.d.ts create mode 100644 apps/klesia/src/docs.md diff --git a/apps/klesia/package.json b/apps/klesia/package.json index 5f0bbf4..49d24a2 100644 --- a/apps/klesia/package.json +++ b/apps/klesia/package.json @@ -13,6 +13,8 @@ "@urql/core": "^5.0.6", "dayjs": "^1.11.13", "hono": "^4.5.10", + "hono-rate-limiter": "^0.4.0", + "nanoid": "^5.0.7", "ofetch": "^1.3.4", "ts-pattern": "^5.3.1", "zod": "^3.23.8" diff --git a/apps/klesia/src/custom.d.ts b/apps/klesia/src/custom.d.ts new file mode 100644 index 0000000..18f423b --- /dev/null +++ b/apps/klesia/src/custom.d.ts @@ -0,0 +1 @@ +declare module "*.md"; diff --git a/apps/klesia/src/docs.md b/apps/klesia/src/docs.md new file mode 100644 index 0000000..34a92ce --- /dev/null +++ b/apps/klesia/src/docs.md @@ -0,0 +1,49 @@ +# Klesia RPC + +Klesia RPC is a JSON-RPC 2.0 wrapper over common Mina Protocol tools and services. The intention is to provide an outstanding Developer Experience for Mina Protocol's zkApp Developers. + +## Methods + +### mina_getTransactionCount + +Returns the number of transactions sent from an address. Usually you may want to use this number to determine the nonce for the next transaction. + +#### Parameters + +Array of strings: +- `publicKey` - Address to check for transaction count. + +--- + +### mina_getBalance + +Returns the balance of the account of given address. + +#### Parameters + +Array of strings: +- `publicKey` - Address to check for transaction count. + +--- + +### mina_blockHash + +Returns the hash of the most recent block. + +--- + +### mina_chainId + +Returns the currently configured chain ID. + +--- + +### mina_sendTransaction + +Broadcasts a signed transaction to the network. + +#### Parameters + +Array of strings: +- `input` - Signed transaction or zkApp input. +- `type` - Transaction type. Can be `payment`, `delegation`, or `zkapp`. diff --git a/apps/klesia/src/index.ts b/apps/klesia/src/index.ts index 230a2a2..7793208 100644 --- a/apps/klesia/src/index.ts +++ b/apps/klesia/src/index.ts @@ -1,15 +1,25 @@ import { OpenAPIHono, createRoute } from "@hono/zod-openapi"; +import { PublicKeySchema } from "@mina-js/shared"; import { apiReference } from "@scalar/hono-api-reference"; +import { rateLimiter } from "hono-rate-limiter"; +import { getConnInfo } from "hono/bun"; import { logger } from "hono/logger"; +import { nanoid } from "nanoid"; import { match } from "ts-pattern"; +import rpcDocs from "./docs.md" with { type: "text" }; import { mina } from "./methods/mina"; import { RpcMethodSchema, RpcResponseSchema } from "./schema"; import { buildResponse } from "./utils/build-response"; -import { PublicKeySchema } from "@mina-js/shared"; const api = new OpenAPIHono(); api.use(logger()); +api.use( + rateLimiter({ + keyGenerator: (c) => getConnInfo(c).remote.address ?? nanoid(), + limit: 10, + }), +); api.doc("/api/openapi", { openapi: "3.0.0", @@ -22,6 +32,7 @@ api.doc("/api/openapi", { const rpcRoute = createRoute({ method: "post", path: "/api", + description: rpcDocs, request: { body: { content: { "application/json": { schema: RpcMethodSchema } } }, }, @@ -37,17 +48,23 @@ const rpcRoute = createRoute({ }, }); +api.get("/", ({ redirect }) => redirect("/api", 301)); + api.openapi(rpcRoute, async ({ req, json }) => { const body = req.valid("json"); return match(body) .with({ method: "mina_getTransactionCount" }, async ({ params }) => { const [publicKey] = params; - const result = await mina.getTransactionCount({ publicKey: PublicKeySchema.parse(publicKey) }); + const result = await mina.getTransactionCount({ + publicKey: PublicKeySchema.parse(publicKey), + }); return json(buildResponse(result), 200); }) .with({ method: "mina_getBalance" }, async ({ params }) => { const [publicKey] = params; - const result = await mina.getBalance({ publicKey: PublicKeySchema.parse(publicKey) }); + const result = await mina.getBalance({ + publicKey: PublicKeySchema.parse(publicKey), + }); return json(buildResponse(result), 200); }) .with({ method: "mina_blockHash" }, async () => { @@ -72,6 +89,7 @@ api.get( spec: { url: "/api/openapi", }, + theme: "deepSpace", }), ); diff --git a/apps/klesia/src/methods/mina.ts b/apps/klesia/src/methods/mina.ts index cef574a..19c8928 100644 --- a/apps/klesia/src/methods/mina.ts +++ b/apps/klesia/src/methods/mina.ts @@ -1,7 +1,7 @@ +import { SignedTransactionSchema } from "@mina-js/shared"; import { gql } from "@urql/core"; import { match } from "ts-pattern"; import { getNodeClient } from "../utils/node"; -import { SignedTransactionSchema } from "@mina-js/shared"; const getTransactionCount = async ({ publicKey }: { publicKey: string }) => { const client = getNodeClient(); @@ -76,7 +76,8 @@ const sendTransaction = async ({ const client = getNodeClient(); return match(type) .with("payment", async () => { - const { signature, data: input } = SignedTransactionSchema.parse(signedTransaction) + const { signature, data: input } = + SignedTransactionSchema.parse(signedTransaction); const { data } = await client.mutation( gql` mutation { @@ -92,7 +93,8 @@ const sendTransaction = async ({ return data.sendPayment.payment.hash; }) .with("delegation", async () => { - const { signature, data: input } = SignedTransactionSchema.parse(signedTransaction) + const { signature, data: input } = + SignedTransactionSchema.parse(signedTransaction); const { data } = await client.mutation( gql` mutation { diff --git a/bun.lockb b/bun.lockb index df0c653d99bbeb4f219f98de4f2edfe96d470650..b975fc1fc8ab9ab488a8034038a4d6b0356e6191 100755 GIT binary patch delta 2719 zcmdT`ZBSI_6~5=fF5Hcatb_nXf-uI)BrG7{#zvN17KmZ_h|y$CYDElW#3&?4)uc6| zX?_&PY4C{a7edAuNK-S>O{1OYXsl@f;|EdW8stm-NHP;=w3*f_VxO}gqm4iMr+<28 zpFQvMyyu?#e%yQB>)ot7*{XZnoRYQ5w)%SAa|@s8|F+xqeZhcp&tE=KM(&)hZQoZo z=g50UZDpj0U1)M8s^1LkUJnRYq~$7;s&_zyA`r-1T}u_Xha0-s!d(uA%zEH6O#{ry|yK9+K%fRBbz-P#=&%L4kmzKgN~cVS!e@yS#z~> z5X{hsdm=1qSPmEETD6%uzHv6F-1MMDdmAjvcbRFDMLPmk1g3D4!=gr5xjWaY=33cc zvuaDRQd51AJtm8`9}Kf?&~uN~LRY!VmaERpWrN+SeT*ghg)d3ZLl!O37EEc1v8dHH z?zUU$J=XGawPAEg4wYv{S=4AdH|AN@5<7S2S+&1ng=hGZm~giTupYC)!q|k!MS0xl zuu=ziISy*kSXzvwA%rmjb*_WE^R3!Oh%#1U)A+|jL8kGsaZjj``P^7w)t(eD6~ zO%?GcUiw1=`n^6BdN_3HHw63`cnLL<@(i4>;Y%C|H4Ho^5Ev&>uzS5EiVx`bdKuWm z(8;s1@Q&{PYZXdmlCm8Cn^o|0*0#Uk#f1sp#`bl8n=pvZy+jhb6>g$!OCJuj9@%i&%f4r1=sjz6>2Rkm_Jkfh9E$Oj$OXJJi&68ql z-u=L2PgpW<`T6v1vLVXo*irZ|*uKfdGd3G}=O!n0@inj;V9#!L(oueAvx_^n7+JT) zNym8R78lRiYUDqIonYGP;_z)ouG;FP9^MVM4=j3{lTLBPHWx2!G4khNXV}!@;@ItD zxW1*B&hlqqonXJ+UQFls)$J}`(Q4!~+nv^3J2@ai@f z4e~ks4|y`)@r>m|5uwIl34RlG#>h!KW_jj+7)sLRnY?E-h39{`fYUu0o^;Re$uMEi zx1&nr5P#oiD;T}wHxbVQSPdmf2rS6uxjybw6vYcKG4f1T1T;*bKPu;&fU1K>l~CmM z>H{QN4?GEo^#hVo-lnGju|fW zh-Q-{u=5xB@`Ys1A9y@^9P}vQK_D7<2pG#v1Btr7Bk)JwHLx}%0h+wpv4GSF9U!$u z>dq}ds?|S%8=i{6Srj4VLQ0O@l86rvy`)Lykm?h{85jPf$q-?``%XroJBOy%V;pV| zF`YtlKky~c1$6R(%Revq0=7y%Ao~|DA~J3M=wq{$=asYRn%9dF0NiuU0+qV_qLs~ z$+)1pCe2?P%!`(~o5CnQ+E3F`1A3}&x7^o^l$df~7DU~rrDEgVR7gpCOB~dvH#}Y9 zAImEx?nWm~az9r@$%cIaaYd<&I^Nwc Ak^lez delta 2342 zcmd^BZBUd|6u$R`-Q`_a1OfRHSsg{t+F?OmKVVrv1zj-5!gc&%Vc`fGrs51bQ$UV0 z)?~??AFrUWU}KrpB(oNd;|Jbc;4qe=bZb& zx%a;BUUlm_Yjk@pNi%;sGhFw}z}~R@&~y3bakU@V)SO8r?hPsC6P2rHoes*)lY*_c z+7++#b~lv==w&)p=_5m$(}V~WqVkQRtz}z~LC5vxB$Hi;FgT+Ti~$E`2w?)3f+N7M zfrG&-NE+fR!ZW?ugAO4k!FwJ$5WKzc&5b;13J?N~X-1|h&GN>Z!7BV~Hx_OvD%mR5 zLI*(?XM5vIpn2AnK7X1|7j&jMa$S9Q-P0;xn7OOS<2FR=J*}qRWHkrt#b2e4n#SAY zPU^R3sI72V;FB~EY*Pl)s3gO#I?_j$RjE)@xJ}uTP9+Yz@^LyHaoE+Hh|L)pWFXY0 zno$b;1C@Fju-oJcD$dMMzP8hmOuHI|D$GYn(7*(nx)W;Yh_Xi7l*<`Zl4X}h`YbC$ z&2fy*wmHnEY)K-o1k8SGLSXQrnW(0`bvMYI&3nCiWil-^C$S?W10O?KL1$e{;?8I>50o3*8SfL;hA4>Et^i& zIB8Xli6Uy9@>?pbbx}aAi7r50q|p5?Iu5mMzf)eKvry~zn`qhrr@Ty?54b4mfQdSw zuF&K<7qvp|s&mSAYKJPXGtumNr@Tg0^)5=RH_=0=4zjvk)L9=yKfCkfP3nW%?GB=a z4SDhwRX4b3Zi9)QHaKM$Wj4C#G1Q?(r|hNysC|tlDmdtrJ)Xvco^hVuV-88Z!Tz2W z&rp)beD{PjCf>y!!=ifVL60L|h@oMxv9klf77gb|~J5VEM7rX>u<8|-|0e}-=>j8KKzJSXCJ#dfudczX#qs7^H zm5OBm_j&-ZFPFQ)?%bo8zSR-q;0pmlf$=~X5Jd0w#naKg-AOS}d^I8fzG4c%ca!h+ z?*QNTr@)}6@ZQTZm~R_j*}s4xLFewTQ~BZzLkhA!_(J7{!O9+6MB^-YIqqPAL@ zBG*_gsg_wnq-#}*%$LpD6-A~>lNRSE7peQ~Ld0Q&Ky8B`yel-fpNyV3`bqrg$iuGm zkhVBQCR^rNQsxR#nxS3ylX#u{c{>qnA;!qu