npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

@brandon.cs/bnjs

v0.1.37

Published

Gelato Automate JS resolvers sdk

Readme

JsResolver Proof Of Concept

Playground repo to prototype JsResolvers

Project Setup

  1. Install project dependencies
yarn install
  1. If you want to use a private RPC provider,
    • Copy .env_example to init your own .env file
cp .env_example .env
  • Complete your .env file with your private settings

Write a Js Resolver

  • Create a new file in src/resolvers
  • Register your resolver main function using JsResolverSdk.onChecker
  • Example:
import { JsResolverSdk, JsResolverContext } from "../lib";
import { Contract, ethers } from "ethers";
import axios from "axios";

const ORACLE_ABI = [
  "function lastUpdated() external view returns(uint256)",
  "function updatePrice(uint256)",
];

JsResolverSdk.onChecker(async (context: JsResolverContext) => {
  const { userArgs, gelatoArgs, secrets } = context;

  // Use default ethers provider or your own using secrets api key
  console.log('ChainId:', context.gelatoArgs.chainId)
  const rpcProvider = ethers.getDefaultProvider(context.gelatoArgs.chainId, {
    alchemy: await secrets.get("ALCHEMY_ID"),
  });

  // Retrieve Last oracle update time
  const oracleAddress = "0x6a3c82330164822A8a39C7C0224D20DB35DD030a";
  const oracle = new Contract(oracleAddress, ORACLE_ABI, rpcProvider);
  const lastUpdated = parseInt(await oracle.lastUpdated());
  console.log(`Last oracle update: ${lastUpdated}`);

  // Check if it's ready for a new update
  const nextUpdateTime = lastUpdated + 300; // 5 min
  const timestamp = gelatoArgs.blockTime;
  console.log(`Next oracle update: ${nextUpdateTime}`);
  if (timestamp < nextUpdateTime) {
    return { canExec: false, message: `Time not elapsed` };
  }

  // Get current price on coingecko
  const currency = "ethereum";
  const priceData = await axios.get(
    `https://api.coingecko.com/api/v3/simple/price?ids=${currency}&vs_currencies=usd`
  );
  const price = Math.floor(priceData.data[currency].usd);
  console.log(`Updating price: ${price}`);

  // Return execution call data
  return {
    canExec: true,
    callData: oracle.interface.encodeFunctionData("updatePrice", [price]),
  };
});
  • create your resolver schema.json to specify your runtime configuration:
{
  "jsResolverVersion": "1.0.0",
  "runtime": "node-18",
  "memory": 128, 
  "timeout": 60,
  "userArgs": {}
}

Test your resolver

  • Use yarn test FILENAME command to test your resolver

  • Options:

    • --show-logs Show internal Resolver logs
    • --runtime=thread|docker Use thread if you don't have dockerset up locally (default: docker)
    • --debug Show Runtime debug messages
    • --user-args=[key]:[value] Set your Resolver user args
  • Example: yarn test src/resolvers/index.ts --show-logs --runtime=thread

  • Output:

    JsResolver Build result:
    ✓ File: ./.tmp/resolver.cjs
    ✓ File size: 1.70mb
    ✓ Build time: 109.93ms
    
    JsResolver running logs:
    > ChainId: 5
    > Last oracle update: 1665512172
    > Next oracle update: 1665512472
    > Updating price: 1586
    
    JsResolver Result:
    ✓ Return value: {
      canExec: true,
      callData: '0x8d6cc56d0000000000000000000000000000000000000000000000000000000000000632'
    }
    
    JsResolver Runtime stats:
    ✓ Duration: 5.41s
    ✓ Memory: 57.77mb

Upload / fetch Js Resolver

Use yarn upload FILENAME command to upload your resolver.

> yarn upload ./src/resolvers/index.ts

## Use User arguments
1. Declare your expected `userArgs` in you schema, accepted types are 'string', 'number' or 'float':
```json
{
  "jsResolverVersion": "1.0.0",
  "runtime": "node-18",
  "memory": 128, 
  "timeout": 60,
  "userArgs": {
    "currency": "string",
    "oracle": "string"
  }
}
  1. Access your userArgs from the JsResolver context:
JsResolverSdk.onChecker(async (context: JsResolverContext) => {
  const { userArgs, gelatoArgs, secrets } = context;

  // User args:
  console.log('Currency:', userArgs.currency)
  console.log('Oracle:', userArgs.oracle)
  
});
  1. Pass user-args to the CLI to test your resolver:
yarn test src/resolvers/oracle/index.ts --show-logs --user-args=currency:ethereum --user-args=oracle:0x6a3c82330164822A8a39C7C0224D20DB35DD030a

Benchmark / Load testing

  • Use yarn benchmark FILENAME command to run a test load

  • Options:

    • all test command options
    • --load=100 configure the number of resolver you want to run for your load test (default: 10)
    • --pool=10 configure the pool size, ie max number of concurrent worker (default: 10)
  • Example: yarn benchmark src/resolvers/index.ts --load=100 --pool=10

  • Output:

    Benchmark result:
    - nb success: 100/100
    - duration: 64s

Failure tests

Some example failing file to test error handling

  • Syntax error in the resolver:

    • Run: yarn test src/resolvers/fails/syntax-error.js
    • Result:
    JsResolver building...
    ✘ [ERROR] Could not resolve "nothing"
    
        src/resolvers/fails/syntax-error.js:1:30:
          1 │ import { JsResolverSdk } from "nothing";
            ╵                               ~~~~~~~~~
    
      You can mark the path "nothing" as external to exclude it from the bundle, which will remove this
      error.
    
    
    JsResolver Build result:
    ✗ Error: Build failed with 1 error:
    src/resolvers/fails/syntax-error.js:1:30: ERROR: Could not resolve "nothing"
  • No checker function registered in the resolver:

    • Run: yarn test src/resolvers/fails/not-registered.ts
    • Result:
    JsResolver Result:
    ✗ Error: JsResolver start-up timeout (5s)
    Make sure you registered your checker function correctly in your script.
  • Resolver run out of memory:

    • Run: yarn test src/resolvers/fails/escape-memory.ts
    • Result
    JsResolver Result:
    ✗ Error: JsResolver sandbox exited with code=137
    
    JsResolver Runtime stats:
    ✓ Duration: 1.91s
    ✗ Memory: 31.97mb
  • Resolver exceed timeout:

    • Run: yarn test src/resolvers/fails/escape-timeout.ts
    • Result:
    JsResolver Result:
    ✗ Error: JsResolver exceed execution timeout (10s)
    
    JsResolver Runtime stats:
    ✗ Duration: 10.97s
    ✓ Memory: 25.34mb
  • Resolver ends without returning result:

    • Run: yarn test src/resolvers/fails/no-result.js
    • Result:
    JsResolver Result:
    ✗ Error: JsResolver exited without returning result