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

@dodi-smart/ttlock-graphql-api

v1.3.0

Published

TTLock GraphQL API

Downloads

18

Readme

This package creates a TTLock GraphQL API, allowing for interaction with data at TTLock. It is unofficial TTLock GraphQL API generated based on documentation, mainly configured to be used as Hasura Remote Schema.

Here's an example of how to use the TTLock GraphQL API to get a list of smart locks of the configured TTLock user:

query MyLocks {
  ttlock {
    smartlocks {
      lockName
      lockId
      details {
        state {
          state
        }
        electricQuantity
        firmwareRevision
        hardwareRevision
      }
    }
  }
}

It's recommended to add the TTLock GraphQL API as a Remote Schema in Hasura and connect data from your database with data in TTLock. By doing so, it's possible to request data from your database and TTLock in a single GraphQL query.

Here's an example of how to use the TTLock GraphQL API to get a list of smart locks for a specific TTLock user. Note that the user data is fetched from your database and the TTLock user data is fetched trough the TTLock API:

query UsersLocks {
  users {
    id
    displayName
    ttlocks {
      # Remote schema relation in users table
      lockName
      lockId
      details {
        state {
          state
        }
        electricQuantity
        firmwareRevision
        hardwareRevision
      }
    }
  }
}

Supported APIs

APIs can be added upon request. PRs are welcome of course!

https://euopen.ttlock.com/document/doc?urlName=userGuide%2FekeyEn.html

| Api | Supported | Comment | | ----------------- | :-------: | ------- | | User | 🔴 | | | Lock | 🟠 | | | Ekey | 🔴 | | | Passcode | 🟢 | | | Gateway | 🟠 | | | AddressToken | 🔴 | | | IC Card | 🔴 | | | Fingerprint | 🔴 | | | Group | 🔴 | | | Unlock record | 🟠 | | | Lock upgrade | 🔴 | | | Wireless Keyboard | 🟢 | | | Remote | 🔴 | | | Door Sensor | 🔴 | | | NB-IoT | 🔴 | | | QR Code | 🔴 | | | WiFi Lock | 🔴 | |

🟢 - Supported 🟠 - Partial 🔴 - Not supported

Getting Started

Install the package:

pnpm add @dodi-smart/ttlock-graphql-api

Setup serverless function

Create a new Serverless Function: functions/graphql/ttlock.ts:

import { createTTlockGraphQLServer } from '@dodi-smart/ttlock-graphql-api'

const server = createTTlockGraphQLServer({
  graphiql: true,
  graphqlEndpoint: '/graphql/ttlock',
  healthCheckEndpoint: '/graphql/ttlock/health',
  provideAuth(context) {
    return {
      // Should provide authentication
    }
  },
  onUpdateSession(context, auth) {
    // Handle session update
  }
})

export default server

Setup TTLock Management

Go to TTLock Management and obtain OAuth2 API key and secret by creating an application and wait for approval.

  • Add TTLOCK_CLIENT_ID as an environment variable.
  • Add TTLOCK_CLIENT_SECRET as an environment variable.

If you're using Nhost, add TTLOCK_CLIENT_ID, TTLOCK_CLIENT_SECRET to .env.development like this:

TTLOCK_CLIENT_ID=6EYY••••
TTLOCK_CLIENT_SECRET=BPum••••

And add the production key values to environment variables in the Nhost dashboard.

Start Nhost

nhost up

Learn more about the Nhost CLI.

Test

Test the TTLock GraphQL API in the browser:

https://local.functions.nhost.run/v1/graphql/ttlock

Remote Schema

Add the TTLock GraphQL API as a Remote Schema in Hasura.

URL

{{NHOST_FUNCTIONS_URL}}/graphql/ttlock

Headers

x-nhost-webhook-secret: NHOST_WEBHOOK_SECRET (From env var)

The NHOST_WEBHOOK_SECRET is used to verify that the request is coming from Nhost. The environment variable is a system environment variable and is always available.

Authentication

You have several options to authentication your users agains TTLock using this library. All of them depends on the usecase:

Single user usecase (easy to setup)

When the system should work with the locks of a single user (administrator). Permissions and access to the locks are granted to others users via the administrator or using Hasura user roles.

Multi user usecase (advanced)

When system work with locks of multiple users. Each user can authenticate against TTLock using their own credentials via OAuth 2.0. This usecase can be used for multi tenant apps for example.

How to choose

| Use case | Using JWT Token (easy) | OAuth 2.0 (advanced) | | ----------- | :--------------------: | :------------------: | | Single user | 🟠 | 🟢 | | Multi user | 🔴 | 🟢 |

🟢 - Preferable way 🟠 - Supported 🔴 - Not supported

Using JWT Token

Obtain a JWT token by logging the user via curl, paw or postman. The Refresh token is valid for 10 years.

  • Add TTLOCK_ACCESS_TOKEN as an environment variable.
  • Add TTLOCK_REFRESH_TOKEN as an environment variable.

If you're using Nhost, add TTLOCK_ACCESS_TOKEN and TTLOCK_REFRESH_TOKEN to .env.development like this:

TTLOCK_ACCESS_TOKEN=59f6d••••
TTLOCK_REFRESH_TOKEN=BPum••••

And add the production key values to environment variables in the Nhost dashboard.

Configure the TTLock GraphQL API

import { createTTLockGraphQLServer } from '@dodi-smart/ttlock-graphql-api'

const server = createTTLockGraphQLServer({
  graphqlEndpoint: '/graphql/ttlock',
  healthCheckEndpoint: '/graphql/ttlock/health',
  provideAuth(context) {
    const { request } = context
    return {
      accessToken: process.env["TTLOCK_ACCESS_TOKEN"]
      refreshToken: process.env["TTLOCK_REFRESH_TOKEN"]
    }
  },
  onUpdateSession(context, auth) {
    // Can be empty as TTLOCK_REFRESH_TOKEN is valid for 10 years
  }
})

export default server

OAuth 2.0

From the TTLock Management page get client id and secret.

  • Add TTLOCK_CLIENT_ID as an environment variable.
  • Add TTLOCK_CLIENT_SECRET as an environment variable.

If you're using Nhost, add TTLOCK_CLIENT_ID and TTLOCK_CLIENT_SECRET to .env.development like this:

TTLOCK_CLIENT_ID=59f6d••••
TTLOCK_CLIENT_SECRET=BPum••••

Configure the TTLock GraphQL API

import { createTTLockGraphQLServer } from '@dodi-smart/ttlock-graphql-api'

const server = createTTLockGraphQLServer({
  graphqlEndpoint: '/graphql/ttlock',
  healthCheckEndpoint: '/graphql/ttlock/health',
  provideAuth(context) {
    const { userClaims } = context

    const { user } = await gqlSDK.getUser({
      id: userId
    })

    return {
      // Example if ttlock creds are saved in user's metadata, can differ
      accessToken: user.metadata.ttlockAccessToken,
      refreshToken: user.metadata.ttlockRefreshToken,
    }
  },
  onUpdateSession(context, auth) {
    const { userClaims } = context
    const { accessToken, refreshToken } = auth

    await gqlSDK.updateUserTTLockAuth({
      id: userId,
      accessToken,
      refreshToken
    })
  }
})

export default server

Permissions

Here's a minimal example without any custom permissions. Only requests using the x-hasura-admin-secret header will work:

import { createTTLockGraphQLServer } from '@dodi-smart/ttlock-graphql-api'

const server = createTTLockGraphQLServer({
  graphqlEndpoint: '/graphql/ttlock',
  healthCheckEndpoint: '/graphql/ttlock/health',
  provideAuth(context) {
    /* ... */
  },
  onUpdateSession(context, auth) {
    /* ... */
  }
})

export default server

For more granular permissions, you can pass an isAllowed function to the createTTLockGraphQLServer. The isAllowed function takes a context as parameter and runs every time the GraphQL server makes a request to TTLock to get or modify data for a specific TTLock user.

Here is an example of an isAllowed function:

import { createTTLockGraphQLServer } from '@dodi-smart/ttlock-graphql-api';

const isAllowed = (context: Context) => {
  const { isAdmin, userClaims } = context

  // allow all requests if they have a valid `x-hasura-admin-secret`
  if (isAdmin) {
    return true
  }

  // get user id
  const userId = userClaims['x-hasura-user-id']

  // check if the user is signed in
  if (!userId) {
    return false
  }

  // get more user information from the database
  const { user } = await gqlSDK.getUser({
    id: userId
  })

  if (!user) {
    return false
  }

  // other checks
}

const server = createTTLockGraphQLServer({
  graphqlEndpoint: '/graphql/ttlock',
  healthCheckEndpoint: '/graphql/ttlock/health',
  isAllowed,
  provideAuth(context) {
    /* ... */
  },
  onUpdateSession(context, auth) {
    /* ... */
  }
});

export default server;

Context

The context object contains:

  • userClaims - verified JWT claims from the user's access token.
  • isAdmin - true if the request was made using a valid x-hasura-admin-secret header.
  • request - Fetch API Request object that represents the incoming HTTP request in platform-independent way. It can be useful for accessing headers to authenticate a user
  • query - the DocumentNode that was parsed from the GraphQL query string
  • operationName - the operation name selected from the incoming query
  • variables - the variables that were defined in the query
  • extensions - the extensions that were received from the client

Read more about the default context from GraphQL Yoga.