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 🙏

© 2024 – Pkg Stats / Ryan Hefner

@hexagramio/saga-ts

v0.9.434-0

Published

Saga SDK

Downloads

254

Readme

Table of Contents

Saga Typescript SDK

Install

npm install @hexagramio/saga-ts

Description

Typescript SDK to interface with a Saga API. The implementation is inspired by the Command Design Pattern. A command is send to a Reveiver. A command encapsulates all the data needed to call the API except the domain name. Currently there two kinds of command receivers, HTTP and Socket. Almost all commands except log in and some user creation methods require a accessToken. If a command fails an exception is being thrown that mirrors SAGA API errors.

SDK Documentation

Fundamental Types

Both HTTPCommand and SocketCommand below show the entire complexity of both types. Easy to adopt for specialized and new commands or to use for HTTP Scripts.

HTTPCommand

/**
 * Interfaces to represent the various mutations of a HTTP Command profile.
 */
export interface HTTPGetCommand<T> {
  method: "GET" ,
  path: string,
  params?: URLSearchParams,
  accessToken?: string
}
export interface HTTPPostPutCommand<T> {
  method: "PUT" | "POST",
  path: string,
  data: any ,
  accessToken?: string
}

export interface HTTPDeleteCommand<T> {
  method: "DELETE",
  path: string,
  params?: URLSearchParams,
  accessToken?: string
}

export type HTTPCommand<T> = HTTPGetCommand<T> | HTTPPostPutCommand<T> | HTTPDeleteCommand<T>

Example Custom Command

Sends HTTP post to requests/slack with the assembled body.

/**
 * Get a bot command
 * @param id the id of the bot
 * @param accessToken the required accessToken
 * @group HTTP Commands
 */
export const PostSlackMessageCommand = (accessToken: string, slack_id: string, slack_channel: string, message: string):HTTPCommand<{ok:boolean}> =>{
  return {
    method:"POST",
    path:`requests/slack`,
    accessToken,
    data: {slack_id,slack_channel,message}
  }
}

SocketCommand

/**
 * A socket join command
 */
export interface SocketJoinCommand {
    method: "/users" | "/bots" | "/globals" |
    "/jobs/runnable_calls" | "/jobs/versions" |
    "/scripts/runnable_calls" | "/scripts/versions" |
    "/system" | "/npm_packages"
    id: string, 
    join: boolean,
  }

Quickstart

For the unhurried among us ;)

Register User

import {
  RegisterUserCommand,
  sendHTTPCommand} from "saga-ts";

const baseURL=new URL("https://saga-api.com");
const user = await sendHTTPCommand(baseUrl,RegisterUserCommand({username:`foo`,password:`bar`}))

Login User and Add User Property

import {
  AddUserPropertyCommand,
  LoginUserCommand,
  sendHTTPCommand} from "saga-ts";

const baseURL=new URL("https://saga-api.com");
const user = await sendHTTPCommand(baseUrl,LoginUserCommand({username:`foo`,password:`bar`}))
await sendHTTPCommand(baseUrl,AddUserPropertyCommand(user.accessToken,{parent_id:user._id,name:"hello",value:"world"}))

Paginate Listing, example using Listing

import {
  ListBotsCommand,
  sendHTTPCommand} from "saga-ts";

const baseURL=new URL("https://saga-api.com");
const accessToken="123213132";//from cache
const botsListing = await sendHTTPCommand(baseUrl,ListBotsCommand(accessToken))

//do we have more? nextCommand contains all the data needed for the call
if (botsListing.nextCommand) {
  const botsNext = await sendHTTPCommand(baseUrl, botsListing.nextCommand);
}

//OR

//do we have some previous? prevcommand contains all the data needed for the call
if (botsListing.prevCommand) {
  const botsPrev = await sendHTTPCommand(baseUrl, botsListing.prevCommand);

Handle HTTP Error

import {
  ListUserCommand,
  RegisterUserCommand,
  sendHTTPCommand} from "saga-ts";

const baseURL=new URL("https://saga-api.com");
const accessToken="89012y417114211";//from cache
try{
  await sendHTTPCommand(baseUrl,CreateBot(user.accessToken,{name:"ALREADY TAKEN"}))  
} catch(e){
  if(e.statusCode===422){
    //e.errors contains [fieldName:string]: message
    //handle the specific error messages
  }
  //...
}

Inspect Missing Fields in failed HTTP Call

import {
  ListUserCommand,
  RegisterUserCommand,
  sendHTTPCommand} from "saga-ts";

const baseURL=new URL("https://saga-api.com");
const user = await sendHTTPCommand(baseUrl,RegisterUserCommand({username:`foo`,password:`bar`}))
try{
  await sendHTTPCommand(baseUrl,ListUserCommand(user.accessToken,{parent_id:user._id,name:"hello",value:"world"}))  
} catch(e){
  //handle 401 and 403 for
}

Subscribe to Socket Bot Property Changes

import {
  Authentication,
  SocketSession} from "saga-ts";

const baseURL=new URL("https://saga-api.com");
const socketSession = new SocketSession(
  baseUrl,
  accessToken, //assumed existing
  (error)=>console.error //disconnect errors need to be handled asynchronously
)
socketSession.on("/properties", (property)=>{
  //do something with propterties
  if(property.name="location"){
    updateMapLocation(property);
  }//....
})
//join bot command
await socketSession.emitCommand(JoinBotCommand("ID OF BOT TO JOIN"))

Handle Socket Emit Comand Errors

import {
  Authentication,
  SocketSession} from "saga-ts";

const baseURL=new URL("https://saga-api.com");
const socketSession = new SocketSession(
  baseUrl,
  accessToken, //assumed existing
  (error)=>console.error //disconnect errors need to be handled asynchronously
)

try{
  await socketSession.emitCommand(JoinBotCommand("Not access to id"))  
} catch(e){
  //deal with API Error like 401,403,404 and 422 depending on the comand
}

Handle Socket Connection Error

import {SocketSession} from "saga-ts";
const baseURL=new URL("https://saga-api.com");
new SocketSession(
    baseUrl,
    "bad token",
    (err)=>{
      //handleError
    }
)