Skip to content

Commit

Permalink
feat: wip
Browse files Browse the repository at this point in the history
  • Loading branch information
chronark committed Jul 6, 2022
1 parent 7f1e901 commit e96f93b
Show file tree
Hide file tree
Showing 13 changed files with 150 additions and 42 deletions.
120 changes: 119 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1 +1,119 @@
# sdk-qstash-ts
# Upstash qStash SDK

[![Tests](https://github.com/upstash/upstash-redis/actions/workflows/tests.yaml/badge.svg)](https://github.com/upstash/upstash-redis/actions/workflows/tests.yaml)
![npm (scoped)](https://img.shields.io/npm/v/@upstash/redis)
![npm bundle size](https://img.shields.io/bundlephobia/minzip/@upstash/redis)

**qStash** is a serverless queueing / messaging system, designed to be used with
serverless functions to consume from the queue.

It is the only connectionless (HTTP based) Redis client and designed for:

- Serverless functions (AWS Lambda ...)
- Cloudflare Workers (see
[the example](https://github.com/upstash/upstash-redis/tree/main/examples/cloudflare-workers))
- Fastly Compute@Edge (see
[the example](https://github.com/upstash/upstash-redis/tree/main/examples/fastly))
- Next.js, Jamstack ...
- Client side web/mobile applications
- WebAssembly
- and other environments where HTTP is preferred over TCP.

See
[the list of APIs](https://docs.upstash.com/features/restapi#rest---redis-api-compatibility)
supported.

## How does qStash work?

qStash is the message broker between your serverless apps. You send a HTTP
request to qStash, that includes a destination, a payload and optional settings.
We store your message durable and will deliver it to the destination server via
HTTP. In case the destination is not ready to receive the message, we will retry
the message later, to guarentee at-least-once delivery.

## Quick Start

### Install

#### npm

```bash
npm install @upstash/qstash
```

#### Deno

```ts
import { Redis } from "https://deno.land/x/upstash_qstash/mod.ts";
```

### Activate qStash

Go to [upstash](https://console.upstash.com/qstash) and activate qStash.

## Basic Usage:

### Publishing a message

```ts
import { Client } from "@upstash/qstash"

const q = new Client({
token: <QSTASH_TOKEN>,
})

const res = await q.publishJSON({
body: { hello: "world" },
})

console.log(res.messageID)
```

### Consuming a message

How to consume a message depends on your http server. QStash does not receive
the http request directly, but should be called by you as the first step in your
handler function.

```ts
import { Consumer } from "@upstash/qstash";

const c = new Consumer({
currentSigningKey: "..",
nextSigningKey: "..",
});

const isValid = await c.verify({
/**
* The signature from the `upstash-signature` header.
*/
signature: "string";

/**
* The raw request body.
*/
body: "string";

/**
* URL of the endpoint where the request was sent to.
*/
url: "string";
})
```

## Docs

See [the documentation](https://docs.upstash.com/features/qstash) for details.

## Contributing

### [Install Deno](https://deno.land/#installation)

### Running tests

```sh
QSTASH_TOKEN=".." deno test -A
```

```
```
4 changes: 2 additions & 2 deletions examples/nextjs/pages/api/qstash.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ async function handler(
}

export default verifySignature(handler, {
"currentSigningKey": "sig_3XkV1SD5puLtBKyGAWHVfktnkaqwMQFV2qkYRXJNmSSDoyYysc",
"nextSigningKey": "sig_3coKFaxVLdU8sk8FiURFtJeePitgk19NSqMxZSnzXq2ckiCALJ",
"currentSigningKey": "sig_3xVnLBEC758CtJcqW8hfkRjhe7cj2XBANdeVRxta32P9zXZm9o",
"nextSigningKey": "sig_4dMSAQ1M4mmYGeSTPFX8ikFVbdq1k4bbknJKH8PoRsWy39kBWX",
});

export const config = {
Expand Down
33 changes: 0 additions & 33 deletions hmac.ts

This file was deleted.

5 changes: 0 additions & 5 deletions imports.json

This file was deleted.

2 changes: 2 additions & 0 deletions mod.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from "./consumer.ts";
export * from "./client.ts";
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
2 changes: 1 addition & 1 deletion types.ts → pkg/client/types.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
export type State =
| "created"
| "scheduled"
| "planned"
| "active"
| "delivered"
| "error"
Expand Down
26 changes: 26 additions & 0 deletions consumer.ts → pkg/consumer/consumer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,19 @@ export type ConsumerConfig = {
};

export type VerifyRequest = {
/**
* The signature from the `upstash-signature` header.
*/
signature: string;

/**
* The raw request body.
*/
body: string;

/**
* URL of the endpoint where the request was sent to.
*/
url: string;
};

Expand All @@ -18,6 +29,9 @@ export class SignatureError extends Error {
this.name = "SignatureError";
}
}
/**
* Consumer offers a simlpe way to verify the signature of a request.
*/
export class Consumer {
private readonly currentSigningKey: string;
private readonly nextSigningKey: string;
Expand All @@ -27,6 +41,15 @@ export class Consumer {
this.nextSigningKey = config.nextSigningKey;
}

/**
* Verify the signature of a request.
*
* Tries to verify the signature with the current signing key.
* If that fails, maybe because you have rotated the keys recently, it will
* try to verify the signature with the next signing key.
*
* If that fails, the signature is invalid and a `SignatureError` is thrown.
*/
public async verify(req: VerifyRequest): Promise<boolean> {
const isValid = await this.verifyWithKey(this.currentSigningKey, req);
if (isValid) {
Expand All @@ -35,6 +58,9 @@ export class Consumer {
return this.verifyWithKey(this.nextSigningKey, req);
}

/**
* Verify signature with a specific signing key
*/
private async verifyWithKey(
key: string,
req: VerifyRequest,
Expand Down
File renamed without changes.

0 comments on commit e96f93b

Please sign in to comment.