Skip to content
This repository has been archived by the owner on Jan 21, 2022. It is now read-only.

Commit

Permalink
Merge pull request #14 from clerkinc/yourtallness/external_account_su…
Browse files Browse the repository at this point in the history
…pport

feat: abstract google & facebook account as external_accounts, fix (d…
  • Loading branch information
yourtallness authored Apr 2, 2021
2 parents 8771fd7 + 0a9d071 commit 9117769
Show file tree
Hide file tree
Showing 20 changed files with 426 additions and 2,393 deletions.
12 changes: 0 additions & 12 deletions .github/workflows/size.yml

This file was deleted.

130 changes: 75 additions & 55 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,60 +2,64 @@

Thank you for choosing [Clerk](https://clerk.dev/) for your authentication, session & user management needs!

This SDK allows you to call the Clerk server API from node / JS / TS code without having to implement the calls yourself.
This SDK allows you to call the Clerk server API from node / JS / TS code without having to implement the calls
yourself.

To gain a better understanding of the underlying API calls the SDK makes, feel free to consult the [official Clerk server API documentation](https://docs.clerk.dev/server-api/).
To gain a better understanding of the underlying API calls the SDK makes, feel free to consult
the [official Clerk server API documentation](https://docs.clerk.dev/server-api/).

## Table of contents

- [Internal implementation details](#internal-implementation-details)
- [Installation](#installation)
- [Resource types](#resource-types)
- [Usage](#usage)
- [Options & ENV vars available](#options--env-vars-available)
- [tl;dr](#tldr)
- [Full option reference](#full-option-reference)
- [httpOptions](#httpoptions)
- [Singleton](#singleton)
- [ESM](#esm)
- [CJS](#cjs)
- [Setters](#setters)
- [Custom instance](#custom-instance)
- [ESM](#esm-1)
- [CJS](#cjs-1)
- [Examples](#examples)
- [Client operations](#client-operations)
- [getClientList()](#getclientlist)
- [getClient(clientId)](#getclientclientid)
- [verifyClient(sessionToken)](#verifyclientsessiontoken)
- [Session operations](#session-operations)
- [getSessionList({ clientId, userId })](#getsessionlist-clientid-userid-)
- [getSession(sessionId)](#getsessionsessionid)
- [revokeSession(sessionId)](#revokesessionsessionid)
- [verifySession(sessionId, sessionToken)](#verifysessionsessionid-sessiontoken)
- [User operations](#user-operations)
- [getUserList()](#getuserlist)
- [getUser(userId)](#getuseruserid)
- [updateUser(userId, params)](#updateuseruserid-params)
- [deleteUser(userId)](#deleteuseruserid)
- [Email operations](#email-operations)
- [createEmail({ fromEmailName, subject, body, emailAddressId })](#createemail-fromemailname-subject-body-emailaddressid-)
- [SMS Message operations](#sms-message-operations)
- [createSMSMessage({ message, phoneNumberId })](#createsmsmessage-message-phonenumberid-)
- [Options & ENV vars available](#options--env-vars-available)
- [tl;dr](#tldr)
- [Full option reference](#full-option-reference)
- [httpOptions](#httpoptions)
- [Singleton](#singleton)
- [ESM](#esm)
- [CJS](#cjs)
- [Setters](#setters)
- [Custom instance](#custom-instance)
- [ESM](#esm-1)
- [CJS](#cjs-1)
- [Examples](#examples)
- [Client operations](#client-operations)
- [getClientList()](#getclientlist)
- [getClient(clientId)](#getclientclientid)
- [verifyClient(sessionToken)](#verifyclientsessiontoken)
- [Session operations](#session-operations)
- [getSessionList({ clientId, userId })](#getsessionlist-clientid-userid-)
- [getSession(sessionId)](#getsessionsessionid)
- [revokeSession(sessionId)](#revokesessionsessionid)
- [verifySession(sessionId, sessionToken)](#verifysessionsessionid-sessiontoken)
- [User operations](#user-operations)
- [getUserList()](#getuserlist)
- [getUser(userId)](#getuseruserid)
- [updateUser(userId, params)](#updateuseruserid-params)
- [deleteUser(userId)](#deleteuseruserid)
- [Email operations](#email-operations)
- [createEmail({ fromEmailName, subject, body, emailAddressId })](#createemail-fromemailname-subject-body-emailaddressid-)
- [SMS Message operations](#sms-message-operations)
- [createSMSMessage({ message, phoneNumberId })](#createsmsmessage-message-phonenumberid-)
- [Error handling](#error-handling)
- [Express middleware](#express-middleware)
- [Next](#next)
- [Feedback / Issue reporting](#feedback--issue-reporting)

## Internal implementation details

This project is written in [TypeScript](https://www.typescriptlang.org/) and built with [tsdx](https://github.com/formium/tsdx).
This project is written in [TypeScript](https://www.typescriptlang.org/) and built
with [tsdx](https://github.com/formium/tsdx).

CJS, ESM, and UMD module builds are provided.

The http client used by the sdk is [got](https://github.com/sindresorhus/got).

All resource operations are mounted as sub-APIs on a `Clerk` class and return promises that either resolve with their expected resource types or reject with the error types described below.
All resource operations are mounted as sub-APIs on a `Clerk` class and return promises that either resolve with their
expected resource types or reject with the error types described below.

The sub-APIs are also importable directly if you don't want to go through the `Clerk` class.

Expand Down Expand Up @@ -100,7 +104,8 @@ If you set `CLERK_API_KEY` in your environment you are good to go.

The following options are available for you to customize the behaviour of the `Clerk` class.

Note that most options can also be set as ENV vars so that you don't need to pass anything to the constructor or set it via the available setters.
Note that most options can also be set as ENV vars so that you don't need to pass anything to the constructor or set it
via the available setters.

| Option | Description | Default | ENV variable |
| ------------ | ------------------------------------------------------------------ | ----------------------- | ------------------- |
Expand All @@ -117,7 +122,8 @@ For every option the resolution is as follows, in order of descending precedence

#### httpOptions

The SDK allows you to pass options to the underlying http client (got) by instantiating it with an additional `httpOptions` object.
The SDK allows you to pass options to the underlying http client (got) by instantiating it with an
additional `httpOptions` object.

e.g. to pass a custom header:

Expand All @@ -131,7 +137,8 @@ You can check the options the got client supports [here](https://github.com/sind

### Singleton

If you are comfortable with setting the `CLERK_API_KEY` ENV variable and be done with it, the default instance created by the SDK will suffice for your needs.
If you are comfortable with setting the `CLERK_API_KEY` ENV variable and be done with it, the default instance created
by the SDK will suffice for your needs.

#### ESM

Expand Down Expand Up @@ -172,7 +179,8 @@ clients.getClient(clientId)

#### Setters

The following setters are avaible for you to change the options even after you've obtained a handle on a `Clerk` or sub-api instance:
The following setters are avaible for you to change the options even after you've obtained a handle on a `Clerk` or
sub-api instance:

If you have a `clerk` handle:

Expand All @@ -190,7 +198,8 @@ If are using a sub-api handle and wish to change options on the (implicit) singl

### Custom instantiation

If you would like to use more than one `Clerk` instance, e.g. if you are using multiple api keys or simply prefer the warm fuzzy feeling of controlling instantiation yourself:
If you would like to use more than one `Clerk` instance, e.g. if you are using multiple api keys or simply prefer the
warm fuzzy feeling of controlling instantiation yourself:

#### ESM

Expand Down Expand Up @@ -218,7 +227,8 @@ clerk.smsMessages

### Examples

You also consult the [examples folder](https://github.com/clerkinc/clerk-sdk-node/tree/main/examples) for further hints on usage.
You also consult the [examples folder](https://github.com/clerkinc/clerk-sdk-node/tree/main/examples) for further hints
on usage.

### Client operations

Expand Down Expand Up @@ -330,13 +340,15 @@ const user = await clerk.users.update(userId, params)

Supported user attributes for update are:

| Attribute | Data type |
| --------------------- | --------- |
| firstName | string |
| lastName | string |
| password | string |
| primaryEmailAddressID | string |
| primaryPhoneNumberID | string |
| Attribute | Data type |
| :-------------------: | :---------------------: |
| firstName | string |
| lastName | string |
| password | string |
| primaryEmailAddressID | string |
| primaryPhoneNumberID | string |
| publicMetadata | Record<string, unknown> |
| privateMetadata | Record<string, unknown> |

#### deleteUser(userId)

Expand Down Expand Up @@ -383,7 +395,8 @@ The error handling is pretty generic at the moment but more fine grained errors

## Express middleware

For usage with [Express](https://github.com/expressjs/express), this package also exports a `ClerkExpressMiddleware` function that can be used in the standard manner:
For usage with [Express](https://github.com/expressjs/express), this package also exports a `ClerkExpressMiddleware`
function that can be used in the standard manner:

```
import { ClerkExpressMiddleware } from 'sdk-server-node';
Expand All @@ -399,7 +412,8 @@ app.use(ClerkExpressMiddleware(options));

The middleware will set the Clerk session on the request object as `req.session` and simply call the next middleware.

You can then implement your own logic for handling a logged in or logged out user in your express endpoints or custom middleware, depending on whether they are trying to access a public or protected resource.
You can then implement your own logic for handling a logged in or logged out user in your express endpoints or custom
middleware, depending on whether they are trying to access a public or protected resource.

If you want to use the express middleware of your custom `Clerk` instance, you can use:

Expand All @@ -411,9 +425,11 @@ Where `clerk` is your own instance.

## Next

The current package also offers a way of making your [Next.js api middleware](https://nextjs.org/docs/api-routes/api-middlewares) aware of the Clerk Session.
The current package also offers a way of making
your [Next.js api middleware](https://nextjs.org/docs/api-routes/api-middlewares) aware of the Clerk Session.

You can define your handler function with the usual signature (`function handler(req, res) {}`) then wrap it with `withSession`:
You can define your handler function with the usual signature (`function handler(req, res) {}`) then wrap it
with `withSession`:

```
import { withSession, WithSessionProp } from '@clerk/clerk-sdk-node';
Expand All @@ -439,13 +455,15 @@ You can also pass an `onError` handler to the underlying Express middleware that
export withSession(handler, { clerk, onError: error => console.log(error) });
```

In case you would like the request to be rejected with a 401 (Unauthorized) automatically when no session exists, without having to implement such logic yourself, you can opt for the stricter variant:
In case you would like the request to be rejected with a 401 (Unauthorized) automatically when no session exists,
without having to implement such logic yourself, you can opt for the stricter variant:

```
import clerk, { requireSession, RequireSessionProp } from '@clerk/clerk-sdk-node';
```

In this case your handler can be even simpler because the existence of the session can be assumed, otherwise the execution will never reach your handler:
In this case your handler can be even simpler because the existence of the session can be assumed, otherwise the
execution will never reach your handler:

```
function handler(req RequireSessionProp<NextApiRequest>, res: NextApiResponse) {
Expand All @@ -455,7 +473,8 @@ function handler(req RequireSessionProp<NextApiRequest>, res: NextApiResponse) {
export requireSession(handler, { clerk, onError });
```

The aforementioned usage pertains to the singleton case. If you would like to use a `Clerk` instance you instantiated yourself (e.g. named `clerk`), you can use the following syntax instead:
The aforementioned usage pertains to the singleton case. If you would like to use a `Clerk` instance you instantiated
yourself (e.g. named `clerk`), you can use the following syntax instead:

```
export clerk.withSession(handler);
Expand All @@ -465,4 +484,5 @@ export clerk.requireSession(handler);

## Feedback / Issue reporting

Please report issues or open feauture request in the [github issue section](https://github.com/clerkinc/clerk-sdk-node/issues).
Please report issues or open feauture request in
the [github issue section](https://github.com/clerkinc/clerk-sdk-node/issues).
4 changes: 4 additions & 0 deletions examples/node/src/users.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@ try {
let updatedUser = await users.updateUser(userId, {
firstName: 'Kyle',
lastName: 'Reese',
publicMetadata: {
zodiac_sign: 'leo',
ascendant: 'scorpio',
},
});

// let updatedUser = await users.updateUser(userId, { firstName: 'John', lastName: 'Connor' });
Expand Down
16 changes: 1 addition & 15 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,7 @@
"build": "tsdx build",
"test": "tsdx test",
"lint": "tsdx lint",
"prepare": "tsdx build",
"size": "size-limit",
"analyze": "size-limit --why"
"prepare": "tsdx build"
},
"prettier": {
"printWidth": 80,
Expand All @@ -32,25 +30,13 @@
"url": "https://github.com/clerkinc/clerk-sdk-node"
},
"module": "dist/clerk-sdk-node.esm.js",
"size-limit": [
{
"path": "dist/clerk-sdk-node.cjs.production.min.js",
"limit": "10 KB"
},
{
"path": "dist/clerk-sdk-node.esm.js",
"limit": "10 KB"
}
],
"devDependencies": {
"@size-limit/preset-small-lib": "^4.9.1",
"@types/express": "^4.17.11",
"@types/jest": "^26.0.20",
"husky": "^4.3.7",
"jest": "^26.6.3",
"next": "^10.0.7",
"nock": "^13.0.7",
"size-limit": "^4.9.1",
"ts-jest": "^26.5.0",
"tsdx": "^0.14.1",
"tslib": "^2.1.0",
Expand Down
11 changes: 9 additions & 2 deletions src/__tests__/apis/UserApi.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ test('getUserList() with limit returns a list of users', async () => {
'Content-Type': 'application/x-www-form-urlencoded',
});

const userList = await users.getUserList({limit: 1});
const userList = await users.getUserList({ limit: 1 });

expect(userList).toBeInstanceOf(Array);
expect(userList.length).toEqual(1);
Expand All @@ -46,7 +46,7 @@ test('getUserList() with limit returns a list of users', async () => {
'Content-Type': 'application/x-www-form-urlencoded',
});

const userList = await users.getUserList({limit: 1, offset: 1});
const userList = await users.getUserList({ limit: 1, offset: 1 });

expect(userList).toBeInstanceOf(Array);
expect(userList.length).toEqual(1);
Expand Down Expand Up @@ -74,4 +74,11 @@ test('getUser() returns a single user', async () => {
// expect(user).toMatchObject(expected);

expect(user).toBeInstanceOf(User);

expect(user.externalAccounts.length).toEqual(2);
expect(user.externalAccounts[0].provider).toEqual('google');
expect(user.externalAccounts[1].provider).toEqual('facebook');

const expectedPublicMetadata = { zodiac_sign: 'leo', ascendant: 'scorpio' };
expect(user.publicMetadata).toEqual(expectedPublicMetadata);
});
Loading

0 comments on commit 9117769

Please sign in to comment.