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

@vaultys/smartlink-sdk

v1.0.3

Published

SDK for SmartLink API and webhooks

Downloads

217

Readme

SmartLink SDK

Table of Contents

Introduction

The SmartLink SDK allows you to make requests to the SmartLink API. To use the SDK, you need to obtain an API key from your SmartLink account via the Workflow administrator menu.

Examples

Example 1: Init client locally

import { createClient } from "@hey-api/client-fetch";
import { getApps } from "@vaultys/smartlink-sdk";

const fetch = async () => {
  const client = createClient({
    baseUrl: "https://<your_smartlink_url>/api/workflow",
    headers: {
      "x-api-key": "<your_secret_api_key>",
    },
  });
  const apps = await getApps({ client });
  console.log("apps", apps.data);
};

fetch();

Example 2: Configure client globally

import { client, getApps } from "@vaultys/smartlink-sdk";

client.setConfig({
  baseUrl: "https://<your_smartlink_url>/api/workflow",
  headers: {
    "x-api-key": "<your_secret_api_key>",
  },
});

const fetch = async () => {
  const apps = await getApps();
  console.log("apps", apps.data);
};

fetch();

SDK Functions

getAppByClientId

Fetches an app by its unique ID.

await getAppByClientId({
  path: {
    clientId: "app_id",
  },
});

Parameters

| Parameters | type | required | default | | ---------- | ------ | -------- | ------- | | clientId | string | true | |

Response

200: { data: The App }

401: { error: "Not authorized" }

404: { error: "App not found" }

500: { error: "Internal server error" }

postApp

Creates a new app for your organization

await postApp({
  body: {
    title: "App title",
    url: "https://app.com",
    iconUrl: "https://app.com/icon.png",
    description: "App description",
    slug: "my_unique_slug",
  },
});

Body

| Parameters | type | required | default | | ----------- | ------ | -------- | ----------------------------------------------------- | | title | string | true | | | url | string | false | null | | iconUrl | string | false | null (icons are automatically retrieved by smartlink) | | description | string | false | null | | slug | string | false | auto generated (randomUUID) |

Response

200: { data: The added App }

401: { error: "Not authorized" }

500: { error: "Internal server error" }

putAppByClientId

Updates an app by its client ID.

await putAppByClientId({
  path: {
    clientId: "your_client_id",
  },
  body: {
    title: "Updated title",
    url: "https://updated-url.com",
    iconUrl: "https://updated-url.com/icon.png",
    description: "Updated description",
    slug: "updated_slug",
  },
});

Parameters

| Parameters | type | required | default | | ---------- | ------ | -------- | ------- | | clientId | string | true | |

Body

| Parameters | type | required | default | | ----------- | ------ | -------- | ------- | | title | string | true | | | url | string | false | null | | iconUrl | string | false | null | | description | string | false | null | | slug | string | false | null |

Response

200: { data: The updated App }

401: { error: "Not authorized" }

404: { error: "App not found" }

500: { error: "Internal server error" }

deleteAppByClientId

Deletes an app by its client ID.

await deleteAppByClientId({
  path: {
    clientId: "your_client_id",
  },
});

Parameters

| Parameters | type | required | default | | ---------- | ------ | -------- | ------- | | clientId | string | true | |

Response

200: { data: The deleted App }

401: { error: "Not authorized" }

404: { error: "App not found" }

500: { error: "Internal server error" }

getApps

Get all apps of your organization.

const apps = await getApps();

Response

200: { data: Array of created Apps }

401: { error: "Not authorized" }

500: { error: "Internal server error" }

postApps

Creates multiple apps for your organization.

await postApps({
  body: [
    {
      title: "App title 1",
      url: "https://app1.com",
      iconUrl: "https://app1.com/icon.png",
      description: "App description 1",
      slug: "unique_slug_1",
    },
    {
      title: "App title 2",
      url: "https://app2.com",
      iconUrl: "https://app2.com/icon.png",
      description: "App description 2",
      slug: "unique_slug_2",
    },
  ],
});

Body

Array of:

| Parameters | type | required | default | | ----------- | ------ | -------- | ------- | | title | string | true | | | url | string | false | null | | iconUrl | string | false | null | | description | string | false | null | | slug | string | false | null |

Response

200: { data: Array of created Apps }

401: { error: "Not authorized" }

500: { error: "Internal server error" }

getEvents

Retrieve log events with various filters.

const events = await getEvents({
  query: {
    fromDate: 1733995830,
    toDate: 1733995840,
    type: 0,
    membershipId: 1,
    folderId: 1,
    userId: 1,
    deviceId: 1,
    appClientId: "1",
  },
});

Query

| Parameters | type | required | default | | ------------ | ------------------------- | -------- | ------- | | fromDate | integer | false | null | | toDate | integer | false | null | | type | integer (see Events type) | false | null | | membershipId | integer | false | null | | folderId | integer | false | null | | userId | integer | false | null | | deviceId | integer | false | null | | appClientId | string | false | null |

### Events type

| type | description | | ---- | --------------------------------------------------- | | 0 | An app was opened | | 1 | Someone is successfully connected on SmartLink | | 2 | A connection has failed on SmartLink | | 3 | A connection was denied on SmartLink | | 4 | Someone is successfully connected from an extension | | 5 | A connection from an extension has failed | | 6 | A connection from an extension was denied | | 7 | A new password was set | | 8 | A login from was blocked by anti-phishing feature |

Response

200: { data: Array of events }

401: { error: "Not authorized" }

500: { error: "Internal server error" }

getFolderById

Fetches a folder by its ID.

await getFolderById({
  path: {
    id: "your_folder_id",
  },
});

Parameters

| Parameters | type | required | default | | ---------- | ------ | -------- | ------- | | id | string | true | |

Response

200: { data: The Folder }

401: { error: "Not authorized" }

404: { error: "Folder not found" }

500: { error: "Internal server error" }

deleteFolderById

Deletes a folder resource identified by the given ID.

await deleteFolderById({
  path: {
    id: "your_folder_id",
  },
});

Parameters

| Parameters | type | required | default | | ---------- | ------ | -------- | ------- | | id | string | true | |

Response

200: { data: The deleted Folder }

401: { error: "Not authorized" }

404: { error: "Folder not found" }

500: { error: "Internal server error" }

postFolder

Creates a new folder within your organization.

await postFolder({
  body: {
    name: "Folder name",
    parentId: 2,
  },
});

Body

| Parameters | type | required | default | | ---------- | ------- | -------- | ------- | | name | string | true | | | parentId | integer | false | null |

Response

200: { data: The created Folder }

401: { error: "Not authorized" }

500: { error: "Internal server error" }

getFolders

Get all folders of your organization.

const folders = await getFolders();

Response

200: { data: Array of Folder }

401: { error: "Not authorized" }

500: { error: "Internal server error" }

postMembershipByIdDeactivate

Updates a membership's status to "INACTIVE" by its ID.

await postMembershipByIdDeactivate({
  path: {
    id: "your_membership_id",
  },
});

Parameters

| Parameters | type | required | default | | ---------- | ------ | -------- | ------- | | id | string | true | |

Response

200: { data: The updated User }

401: { error: "Not authorized" }

404: { error: "User not found" }

500: { error: "Internal server error" }

getMembershipById

Fetches a membership by its ID.

await getMembershipById({
  path: {
    id: "your_membership_id",
  },
});

Parameters

| Parameters | type | required | default | | ---------- | ------ | -------- | ------- | | id | string | true | |

Response

200: { data: The User }

401: { error: "Not authorized" }

404: { error: "User not found" }

500: { error: "Internal server error" }

putMembershipById

Updates a membership by its ID.

await putMembershipById({
  path: {
    id: <your_membership_id>,
  },
  body: {
    firstName: "John",
    name: "Doe",
    phone: "+336...",
    email: "[email protected]",
    role: "ADMIN" | "USER",
    status: "ACTIVE" | "INACTIVE",
    language: "fr",
  },
});

Parameters

| Parameters | type | required | default | | ---------- | ------ | -------- | ------- | | id | string | true | |

Body

| Parameters | type | required | default | | ---------- | ------------------------------------- | -------- | ----------------- | | firstName | string | false | keep actual value | | name | string | false | keep actual value | | phone | string | false | keep actual value | | email | string | false | keep actual value | | role | "ADMIN" or "USER" | false | keep actual value | | status | "ACTIVE" or "INACTIVE" | false | keep actual value | | language | string ("fr", "en", "es", "zh", "de") | false | keep actual value |

Response

200: { data: The updated User }

401: { error: "Not authorized" }

404: { error: "User not found" }

500: { error: "Internal server error" }

deleteMembershipById

Deletes a membership resource identified by the given ID.

await deleteMembershipById({
  path: {
    id: <your_membership_id>,
  },
});

Parameters

| Parameters | type | required | default | | ---------- | ------- | -------- | ------- | | id | integer | true | |

Response

200: { data: The deleted User }

401: { error: "Not authorized" }

404: { error: "User not found" }

500: { error: "Internal server error" }

postMembership

Creates a new membership for your organization.

await postMembership({
  body: {
    firstName: "John",
    name: "Doe",
    phone: "+336...",
    email: "[email protected]",
    sendMail: true, // invite user by email
    sender: {
      // sender will be displayed in the invitation email
      firstName: "Admin",
      name: "istrator",
    },
    isAdmin: false, // administrator membership ?
  },
});

Body

| Parameters | type | required | default | | ---------- | -------------------------------- | -------- | ------- | | firstName | string | true | | | name | string | true | | | email | string | true | | | phone | string | true | null | | sendMail | boolean | false | false | | sender | {firsName: string; name: string} | false | null | | isAdmin | boolean | false | false |

Response

200: { data: The created User }

401: { error: "Not authorized" }

500: { error: "Internal server error" }

getMemberships

Get all memberships of your organization.

const memberships = await getMemberships();

Response

200: { data: Array of User }

401: { error: "Not authorized" }

500: { error: "Internal server error" }

postMemberships

Creates multiple memberships for your organization.

await postMemberships({
  body: [
    {
      firstName: "John",
      name: "Doe",
      phone: "+336...",
      email: "[email protected]",
      sendMail: true, // invite user by email
      sender: {
        // sender will be displayed in the invitation email
        firstName: "Admin",
        name: "istrator",
      },
      isAdmin: false, // administrator membership ?,
    },
    {
      firstName: "Jane",
      name: "Doe",
      phone: "+336...",
      email: "[email protected]",
      sendMail: false,
      isAdmin: true, // administrator membership ?
    },
  ],
});

Body

Array of:

| Parameters | type | required | default | | ---------- | -------------------------------- | -------- | ------- | | firstName | string | true | | | name | string | true | | | email | string | true | | | phone | string | true | null | | sendMail | boolean | false | false | | sender | {firsName: string; name: string} | false | null | | isAdmin | boolean | false | false |

Response

200: { data: {memberships: Array of created Users, count: number (total of users for this search)} }

401: { error: "Not authorized" }

500: { error: "Internal server error" }

getMembershipsSearch

Search memberships with various filters. Responses are paginated so you need to specify the page you want.

const memberships = await getMembershipsSearch({
  query: {
    page: 1,
    pageSize: 10,
    roles: "ADMIN,USER",
    search: "john", // search in names, firstNames, emails and phones
    statusFilter: "all",
  },
});

Query

| Parameters | type | required | default | | ------------ | ---------------------------------------------- | -------- | ---------------- | | page | integer | true | | | pageSize | integer | false | 10 | | roles | string (comma separated ) | false | null (all roles) | | search | string | false | null | | statusFilter | string ("all", "registered" or "unregistered") | false | all |

Response

200: { data: Array of User }

401: { error: "Not authorized" }

500: { error: "Internal server error" }

Schemas

User

| Field | type | description | | -------------- | ------- | ------------------------------------ | | id | integer | Membership unique ID | | role | string | Membership role (OWNER, USER, ADMIN) | | organizationId | integer | Unique ID of the organization | | userId | integer | Unique ID of the user | | createdAt | Date | Creation date | | updatedAt | Date | Last update date | | status | string | Membership status (ACTIVE, INACTIVE) | | language | string | Preferred language (ex 'en') | | name | string | User's name | | firstName | string | User's first name | | email | string | User's email address | | phone | string | User's phone number |

Folder

| Field | type | description | | -------------- | ------- | ------------------------------------- | | id | integer | Folder unique ID | | name | string | Folder name | | forAllUsers | boolean | Indicates if folder is for all users | | organizationId | integer | Unique ID of the organization | | parentId | integer | Unique ID of the parent folder | | path | string | Full path of the folder (/NewYork/HR) |

App

| Field | type | description | | -------------- | ------- | --------------------------------- | | clientId | string | App client ID | | type | string | App type (SMARTLINK, SAML2) | | title | string | App title | | url | string | App URL | | iconUrl | string | App icon URL | | ping | integer | How many times the app was opened | | slug | string | Unique slug for the app | | description | string | App description | | organizationId | integer | Unique ID of the organization |

Event

| Field | type | description | | -------------- | -------- | ---------------------------------------- | | id | integer | Log event unique ID | | createdAt | DateTime | Creation date of the log event | | message | string | Log event message | | type | integer | Log event type type | | organizationId | integer | Unique ID of the organization (nullable) | | membershipId | integer | Unique ID of the membership (nullable) | | folderId | integer | Unique ID of the folder (nullable) | | deviceId | integer | Unique ID of the device (nullable) | | userId | integer | Unique ID of the user (nullable) | | appClientId | string | Unique client ID of the app (nullable) |

Webhooks

Verify

const body = await request.json();
if (await Webhook.verify(body, <YOUR API KEY>)) {
  switch (body.event) {
    case "membership.created":
      // handle membership created webhook
      // ...
      break;

    // ....
  }
} else {
  // wrong signature or timestamp expired
}

Webhook Types

The following webhook types are available:

  • Membership Webhooks

    • membership.created: Triggered when a membership is created.
    • membership.deleted: Triggered when a membership is deleted.
    • membership.updated: Triggered when a membership is updated.
    • membership.connected: Triggered when a membership connection is established.
    • membership.connected.fail: Triggered when a membership connection fails.
    • membership.connected.denied: Triggered when a membership connection is denied.
    • membership.extension.connected: Triggered when a membership is connected from an extension.
    • membership.extension.connected.fail: Triggered when a membership connection fails from an extension.
    • membership.extension.connected.denied: Triggered when a membership connection is denied from an extension.
  • Folder Webhooks

    • folder.created: Triggered when a folder is created.
    • folder.deleted: Triggered when a folder is deleted.
    • folder.updated: Triggered when a folder is updated.
  • App Webhooks

    • app.created: Triggered when an app is created.
    • app.deleted: Triggered when an app is deleted.
    • app.updated: Triggered when an app is updated.
    • app.opened: Triggered when an app is opened.
  • Event Webhooks

    • event: Triggered when a log event occurs.