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

mysam-api

v0.0.9

Published

An API client for the mysam.fr cab service.

Downloads

2

Readme

An API client for MySAM

This is a TypeScript/Javascript API client for the MySAM API.

It features:

  • a simple yet exhaustive API mapping of the MySAM REST API
  • strong static typing checks using TypeScript for security
  • an easily composable structure, inspired from the Stripe client

Installation

The library is available using NPM or yarn:

$ npm install --save mysam-api
# or
$ yarn add mysam-api

Usage

You need to grab the adequate credentials to run the client, then pass your credentians and access the relevant methods:

import MySAMAPIClient from "mysam-api"

// add your subdomain and API key
const mysam = new MySAMAPIClient({
  subdomain: "api.demo",
  apiKey: "<YOU_API_KEY>",
})

// and use it adequately
async function process() {
  const existingClients = await mysam.clients.list()
  console.log(
    "Found clients:",
    JSON.stringify(existingClients.content, null, 2),
  )

  const newClient = await mysam.clients.registerClient({
    email: "[email protected]",
    firstName: "John",
    lastName: "Smith",
    mobilePhoneNumber: "555-5555-555",
    password: "somepassword",
  })
  console.log("Done creating new client with ID:", newClient.id)
}
process()

The library also offers a custom MySAMError type that wraps the error messages sent bu the API. It also offers a series of test functions to detect the common cases of errors: this is especially useful with TypesScript to use smart completion and validate exhaustivity of switch cases:

try {
  const newCoupon = await mysam.coupons.create({
    clientId: "<SOME_CLIENT_ID",
    couponCode: "TESTCOUPON",
  })
  console.log(newCoupon)
} catch (error) {
  // test if the error is a MySAMError with relevant .type values
  if (isCouponError(error)) {
    switch (error.type) {
      case "COUPON_ALREADY_ASSIGNED": // ⬅︎ completion works here !
        console.warn("Coupon is already assigned !")
        break
      case "COUPON_NOT_FOUND":
        console.warn("Coupon does not exist")
        break
    }
    console.warn("Unexpected error:", error)
  }
}

Supported API endpoints

addresses: geolocation search

Usage:

// to search an address using a location string
let address = await mysam.addresses.search("22 rue du Pont Neuf, 75001 Paris")

// to search an address using a GPS coordinate
let address = await mysam.addresses.search({
  latitude: 48.86016845703125,
  longitude: 2.3441596031188965,
})

Returns: an Address object:

{
  address: '22 Rue du Pont Neuf',
  zipCode: '75001',
  city: 'Paris',
  latitude: 48.860699,
  longitude: 2.34477
}

bills: download PDF invoices

NOTE: this API requires a Trip ID

Usage:

const pdfData = await mysam.bills.downloadInvoice(2199)

Returns: the RAW data as an ArrayBuffer

clients: register and manage Clients

Usage:

// register a new client into the system
let client = await mysam.clients.registerClient({
      email: "[email protected]",
      firstName: "James",
      lastName: "Smith",
      mobilePhoneNumber: "06050403302",
      password: "thisismypassword",
})

// update an existing client
let updatedClient = await mysam.clients.update(
  // the internal user ID for thie client
  "66c7b90b-7b10-4c22-b57f-4bb893157425",
  // the update parameters, typically a subset of the creation params
  {
    firstName: "John",
    mobilePhoneNumber: "0102030405,
    // ...

    // you can also change password and set opt-in for emails
    password: "mynewpassword",
    emailOptIn: false
  }
)

// list all the existing clients
let clients = await mysam.clients.list()

Returns: a (new or updated) Client

{
  userId: "d77055fc-8a3d-44cc-8db2-f1ee1ed8c437",
  firstName: "John",
  lastName: "Smith",
  email: "[email protected]",
  created: "2020-04-14T13:38:53.586Z",
  mobilePhoneNumber: "0102030405"
}

or in the case of list() a list of client embedded in a "list Result" object:

{
  size: 20, // ⬅︎ results per page
  number: 0, // ⬅︎ current page
  first: true, // ⬅︎ this is the first page
  totalPages: 1, // ⬅︎ results span 1 page
  totalElements: 2, // ⬅︎ the whole list (without paging) contains 2 elements
  last: true, // ⬅︎ this is the last page
  numberOfElements: 2, // ⬅︎ the "content" array holds 2 elements
  // the actual "Clients" are embedded into the "content" array:
  content: [
    {
      userId: 'd77055fc-8a3d-44cc-8db2-f1ee1ed8c437',
      firstName: 'Josn',
      lastName: 'Smith',
      email: '[email protected]',
      created: "2020-04-14T13:38:53.586Z",
      mobilePhoneNumber: "0102030405",
    },
    {
      userId: '66c7b90b-7b10-4c22-b57f-4bb893157425',
      firstName: 'Jane',
      lastName: 'Smith',
      email: '[email protected]',
      created: "2020-04-14T13:38:53.586Z",
      mobilePhoneNumber: "0102030405",
    }
  ]
}

NOTE: the list() methods offers options to control the paging:

let clients = await mysam.clients.list({
  page: 2, // ⬅︎ shows results in page 2
  size: 50, // ⬅︎ no more than 50 results per page
})

coupons: apply pre-registered Coupons to a Client

Usage:

// Apply the TESTCOUPON coupon to a given client
const appliedCoupon = await mysam.coupons.create({
  clientId: "d77055fc-8a3d-44cc-8db2-f1ee1ed8c437",
  couponCode: "TESTCOUPON",
})

Returns: a Coupon result

{
  code: 'TESTCOUPON',
  unit: 'CURRENCY',
  zeroDecimalAmount: 500,
  active: true,
  combinable: false,
  used: false
}

estimation: estimate the price of a Trip

Usage:

// estimate approach time of the driver, in seconds
const approachTimeInSecs = await mysam.estimation.approachTime({
  // GPS location
  latitude: 48.880931,
  longitude: 2.355323,
  // type of vehicle
  vehicleType: "CAR", // ⬅︎ either CAR or VAN or LUXE
})
console.log(approachTimeInSecs) // for eg. 600 for 10 minute wait

// complete estimation of a trip
const estimation = await mysam.estimation.estimate({
  clientId: "d77055fc-8a3d-44cc-8db2-f1ee1ed8c437",
  // start location
  fromLatitude: 48.86016845703125,
  fromLongitude: 2.3441596031188965,
  // end location
  toLatitude: 48.880931,
  toLongitude: 2.355323,
  // type of vehicle
  vehicleType: "CAR", // ⬅︎ either CAR or VAN or LUXE
})

Returns: an Estimation object

{
  id: 10730,
  distance: 3382, // ⬅ ︎distance in meters
  duration: 739, // ⬅︎ trip duration in seconds
  isPriceIncreased: false,
  tripType: 'IMMEDIATE',
  vehicleType: 'CAR',
  startDate: Date("2020-04-14T15:10:20.748Z")
  price: 8 // estimated price in €
}

flat-fees: list the pre-defined fees.

Usage:

const flatFees = await mysam.flatFees.list()

Returns: a list of FlatFee objects

NOTE: this method accepts the same paging options as the clients.list() method NOTE: the returned flatFeeId can be provided to the estimation endpoint for pricing

trips: manage Trips

NOTE: these API are much easier to use with TypeScript, due to the checks the compiler is able to do on the arguments

Basic Trip management

Usage:

// Create a new trip for this client
let trip = await mysam.trips.create({
  clientId: "d77055fc-8a3d-44cc-8db2-f1ee1ed8c437",
  fromAddress: {
    address: "22 rue du pont neuf",
    city: "Paris",
    country: "FR",
    zipCode: "75001",
    latitude: 48.86016845703125,
    longitude: 2.3441596031188965,
  },
  toAddress: {
    address: "93 avenue Denfert-Rochereau",
    city: "Paris",
    country: "FR",
    zipCode: "75014",
    latitude: 48.836177825927734,
    longitude: 2.3342578411102295,
  },
  type: "IMMEDIATE",
  vehicleType: "CAR",
  nbPassengers: 2,
  paymentMethod: "DEFERRED",
  autoAssignToDriver: true,
})

// retrieve trip info, by ID
let existingTrip = await mysam.trips.get(2199)

// cancel a trip
let canceledTrip = await mysam.trips.cancel(2199)

// compute the price due in case of a cancelation
let cancelationPrice = await mysam.trips.esimateCancelationPrice(2199)
console.log(cancelationPrice) // ⬅︎ eg. 5 for 5€

// update the price of the course (dicounted price must be < current price !)
let updatedTrip = await mysam.trips.createDiscount(
  2199, // ⬅ ︎the trip ID
  5, // ⬅︎ the new price in €
)

Returns: a Trip object

{
  fromAddress: {
    address: '22 rue du pont neuf',
    zipCode: '75001',
    city: 'Paris',
    country: 'FR',
    latitude: 48.86016845703125,
    longitude: 2.3441596031188965
  },
  toAddress: {
    address: '93 avenue Denfert-Rochereau',
    zipCode: '75014',
    city: 'Paris',
    country: 'FR',
    latitude: 48.836177825927734,
    longitude: 2.3342578411102295
  },
  client: {
    userId: 'd77055fc-8a3d-44cc-8db2-f1ee1ed8c437',
    firstName: 'John',
    lastName: 'Smith',
    email: '[email protected]',
    created: 2020-04-07T15:11:34.413Z,
    mobilePhoneNumber: '0102030405'
  },
  status: 'NO_DRIVER_AVAILABLE', // ⬅︎ ou "WAITING" ou "ASSIGNED" ou "STARTED" ou "CANCELED" ou "FINISHED"
  startDate: 2020-04-14T13:29:46.956Z,
  endDate: 2020-04-14T13:34:58.026Z, // ⬅︎ date de fin, non présent en "WAITING" ou "ASSIGNED"
  id: 2199,
  eurosDiscountedPrice: 12,
  estimatedPrice: 12 // ⬅︎ le prix à afficher au client
}

Trip lookup

Usage:

// search all the trips between two dates
const trips = await mysam.trips.search({
  stardDate: new Date("2020-03-14T13:29:46.956Z"),
  endDate: new Date("2020-04-14T13:29:46.956Z"),
})

// search can be scoped to:
// • all the trips (default) with the "all" filter
// • only the trips created through the MySAM interface using the "mysam" filter
// • only a given client using the "client" filter
// ex:
const tripsCreatedInMySAM = await mysam.trips.search(
  {
    stardDate: new Date("2020-03-14T13:29:46.956Z"),
    endDate: new Date("2020-04-14T13:29:46.956Z"),
  },
  {
    filter: "mysam",
  },
)

const tripForJohn = await mysam.trips.search(
  {
    stardDate: new Date("2020-03-14T13:29:46.956Z"),
    endDate: new Date("2020-04-14T13:29:46.956Z"),
  },
  {
    filter: "client",
    clientID: "d77055fc-8a3d-44cc-8db2-f1ee1ed8c437",
  },
)

Returns: a "List Result" of Trips

NOTE: this method accepts the same paging options as the clients.list() or flatFees.list() methods

trip-driver: manage live info on Drivers

NOTE: these API only work then the underlying Trip is in ASSIGNED or STARTED state !

Get the current location (DriverLocation) of the vehicle

const tripId = 1234 // ⬅︎ the active trip ID
const driverLocation = await mysam.tripDriver.getDriverLocation(tripId)
console.log(`Driver is at: ${driverLocation.latitude}, ${driverLocation.longitude})

Estimate the delay for the driver to arrive on site

const tripId = 1234 // ⬅︎ the active trip ID
const timeToPickUp = await mysam.tripDriver.estimateTimeToPickUpLocation(tripId)
console.log(
  `Vehicle will arrive in: ${timeToPickUp.duration}s (${timeToPiclUp.distance}m)`,
)

Contributing

PRs are welcomed 😀

License

This project is licensed under the MIT License - see the LICENSE file for details

Additional tooling

The project written in TypeScript, but it's also available to Javascript using NPM

TODO

  • [ ] Complete the API with the remaning calls
  • [ ] Add comments & docs
  • [ ] Add some testing