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 🙏

© 2026 – Pkg Stats / Ryan Hefner

@moonmath-ai/client

v0.4.1

Published

Client SDK for interacting with the MoonMath AI Inference API

Readme

MoonMath AI Client

The official Node.js client for interacting with the MoonMath AI API.

Installation

You can install the client using npm:

npm install @moonmath-ai/client

Usage

First, import and initialize the client.

import { MoonMathClient } from '@moonmath-ai/client';

const client = new MoonMathClient();

For development or testing, you can provide a custom baseURL to connect to a local or staging environment.

import { MoonMathClient } from '@moonmath-ai/client';

// Example for connecting to a local server
const localClient = new MoonMathClient('http://localhost:8000');

Uploading Files

To generate a video, you first need to upload an image file. The create method takes a file path or a public URL and returns a file ID that you can use in your video generation request.

async function uploadImage(filePathOrUrl: string) {
  try {
    const response = await client.files.create(filePathOrUrl);
    console.log('File uploaded successfully. File ID:', response.id);
    return response.id;
  } catch (error) {
    console.error('File upload failed:', error);
  }
}

// Example:
// const imageId = await uploadImage('./path/to/your/image.png');

Batch File Uploads

You can also upload multiple (up to 10) files at once using createFromFiles or createFromUrls.

// Upload multiple images from local files
const fileResponses = await client.files.createFromFiles(['./image1.png', './image2.png']);
fileResponses.forEach(file => console.log('Uploaded file ID:', file.id));

// Upload multiple images from public URLs
const urlResponses = await client.files.createFromUrls([
  'https://example.com/image1.jpg',
  'https://example.com/image2.jpg'
]);
urlResponses.forEach(file => console.log('Uploaded file ID:', file.id));

Generating a Video

Once you have an image ID, you can submit a job to generate a video. The images parameter for client.videos.create is an array of objects, where each object specifies an image and its properties. The url can be either an ID of a previously uploaded file (using client.files.create) or a public URL to an image.

Asynchronous Generation

For long-running jobs, it's best to use the asynchronous mode. The API will immediately return a job ID.

async function generateVideoAsync(prompt: string, urlOrImageId: string) {
  try {
    const response = await client.videos.create({
      prompt: prompt,
      images: [{ url: urlOrImageId, start_frame_num: 0 }],
      is_async: true,
    });
    console.log('Async job submitted. Job ID:', response.id);
    return response.id;
  } catch (error) {
    console.error('Video generation failed:', error);
  }
}

Synchronous Generation

For quick tests, you can use the synchronous mode. The request will hang until the video is generated and then return the final result, which includes the video data as a base64-encoded string.

import { JobStatus } from '@moonmath-ai/client';
import fs from 'fs';

async function generateVideoSync(prompt: string, imageId: string) {
  try {
    const response = await client.videos.create({
      prompt: prompt,
      images: [{ url: imageId, start_frame_num: 0 }],
      is_async: false,
    });

    if (response.status === JobStatus.SUCCEEDED && response.data?.[0]?.b64_json) {
      console.log('Video generated successfully!');
      
      // Decode the base64 string and save it to a file
      const videoData = Buffer.from(response.data[0].b64_json, 'base64');
      fs.writeFileSync('generated-video.mp4', videoData);
      console.log('Video saved as generated-video.mp4');

      return response;
    } else {
      console.error('Sync generation failed:', response.error);
    }
  } catch (error) {
    console.error('Video generation failed:', error);
  }
}

Retrieving a Video

If you submitted an asynchronous job, you can check its status and retrieve the result using the job ID. When the job status is SUCCEEDED, the response from client.videos.retrieve(jobId) will contain a public URL to download the video.

The client.videos.retrieveContent(jobId) method is a convenient way to download the video file's raw data.

import { JobStatus } from '@moonmath-ai/client';
import fs from 'fs';

async function retrieveVideo(jobId: string) {
  try {
    const statusResponse = await client.videos.retrieve(jobId);

    if (statusResponse.status === JobStatus.SUCCEEDED) {
      console.log('Job succeeded! Downloading video...');
      
      // The `retrieve` response contains the public URL which can be used to download the resulting video.
      console.log(`Video URL: ${statusResponse.data[0]?.url}`);

      // Alternatively, once the job status is SUCCEEDED, retreiveContent can be used with the same jobId
      const videoData = await client.videos.retrieveContent(jobId);
      
      // Save the video to a file
      fs.writeFileSync(`${jobId}.mp4`, Buffer.from(videoData));
      console.log(`Video saved as ${jobId}.mp4`);

    } else if (statusResponse.status === JobStatus.FAILED) {
      console.error('Job failed:', statusResponse.error);

    } else {
      console.log(`Job status: ${statusResponse.status}. Checking again in 10 seconds...`);
      // Implement polling logic here if needed
    }
  } catch (error) {
    console.error('Failed to retrieve video:', error);
  }
}

Cancelling a Video Generation Job

If you need to cancel a running job, you can use the cancel method.

async function cancelJob(jobId: string) {
  try {
    const response = await client.videos.cancel(jobId);
    console.log('Job cancelled. Status:', response.status);
  } catch (error) {
    console.error('Failed to cancel job:', error);
  }
}

Batch Video Generation

The API supports batch processing for generating multiple videos from a .jsonl file. This is efficient for running large numbers of jobs without having to make individual API requests for each one.

A batch job is created by uploading a .jsonl file where each line is a JSON object representing a video generation request.

1. Create a .jsonl File

Each line in the file should be a valid JSON object. You MUST provide a line with default parameters that will be applied to all subsequent jobs in the file. If you don't want any default params then this line should be an empty json object {}.

Example my-batch-jobs.jsonl:

{"is_async": true, "video_length": 1, "frames_per_second": 24}
{"prompt": "a photo of a cat", "images": [{"url": "file-id-or-url-abc", "start_frame_num": 0}]}
{"prompt": "a photo of a dog", "images": [{"url": "file-id-or-url-xyz", "start_frame_num": 0}]}

In this example, the is_async, video_length and frames_per_second parameters from the first line will be applied to both the "cat" and "dog" jobs.

2. Create a Batch Job

Upload the .jsonl file using the client.batch.create method.

import fs from 'fs';

async function createBatchJob(filePath: string) {
  try {
    const response = await client.batch.create(filePath);
    console.log('Batch job submitted. Batch ID:', response.id);
    return response.id;
  } catch (error) {
    console.error('Batch job creation failed:', error);
  }
}

// Example:
// const batchJobId = await createBatchJob('./my-batch-jobs.jsonl');

3. Retrieve Batch Status and Results

You can poll the batch job's status using client.batch.retrieve. Once the batch job has SUCCEEDED, you can get a list of all the individual jobs and their results using client.batch.listJobs.

import { JobStatus } from '@moonmath-ai/client';
import fs from 'fs';

async function retrieveBatchResults(batchJobId: string) {
  try {
    // Poll for completion
    let batchStatusResponse = await client.batch.retrieve(batchJobId);
    while (
      batchStatusResponse.status === JobStatus.QUEUED ||
      batchStatusResponse.status === JobStatus.RUNNING
    ) {
      console.log(`Batch job status: ${batchStatusResponse.status}. Checking again in 10 seconds...`);
      await new Promise(resolve => setTimeout(resolve, 10000));
      batchStatusResponse = await client.batch.retrieve(batchJobId);
    }

    if (batchStatusResponse.status === JobStatus.SUCCEEDED) {
      console.log('Batch job succeeded! Retrieving individual jobs...');
      const jobsResponse = await client.batch.listJobs(batchJobId);

      console.log(`Found ${jobsResponse.jobs.length} completed jobs.`);
      for (const job of jobsResponse.jobs) {
        console.log(`- Job ID: ${job.id}, Status: ${job.status}, URL: ${job.download_url}`);
        // You can now download the video from job.download_url
      }
    } else {
      console.error(`Batch job failed with status: ${batchStatusResponse.status}`, batchStatusResponse.error);
    }
  } catch (error) {
    console.error('Failed to retrieve batch results:', error);
  }
}

4. Cancelling a Batch Job

You can cancel a batch job and all its pending sub-jobs using the cancel method.

async function cancelBatchJob(batchJobId: string) {
  try {
    const response = await client.batch.cancel(batchJobId);
    console.log('Batch job cancelled. Status:', response.status);
    console.log('Cancelled sub-jobs:', response.cancelled_jobs);
  } catch (error) {
    console.error('Failed to cancel batch job:', error);
  }
}

5. Retrieving Batch Results as a Zip

For convenience, you can request a zip archive containing all generated videos from a batch job.

import { ZipStatus } from '@moonmath-ai/client';

async function downloadBatchZip(batchJobId: string) {
  try {
    // 1. Request the zip creation
    let zipResponse = await client.batch.createZip(batchJobId);
    console.log('Zip creation requested. Status:', zipResponse.status);

    // 2. Poll for completion
    while (
      zipResponse.status === ZipStatus.QUEUED || 
      zipResponse.status === ZipStatus.ZIPPING
    ) {
      console.log(`Zip status: ${zipResponse.status}. Checking again in 5 seconds...`);
      await new Promise(resolve => setTimeout(resolve, 5000));
      zipResponse = await client.batch.retrieveZipStatus(batchJobId);
    }

    if (zipResponse.status === ZipStatus.SUCCEEDED && zipResponse.zip_url) {
      console.log('Zip ready! Downloading from:', zipResponse.zip_url);
      // You can now download the zip file using the URL
    } else {
      console.error('Zip creation failed:', zipResponse.error);
    }
  } catch (error) {
    console.error('Failed to download batch zip:', error);
  }
}

You can also cancel a running zip generation job:

await client.batch.cancelZip(batchJobId);