Thanks to visit codestin.com
Credit goes to github.com

Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 47 additions & 0 deletions .github/workflows/tests.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -304,3 +304,50 @@ jobs:
echo "assertEqualsed response to contain 'Counter: 2', got $(cat response.html)"
exit 1
fi



example-nodejs:
needs:
- test
env:
UPSTASH_REDIS_REST_URL: http://127.0.0.1:6379
UPSTASH_REDIS_REST_TOKEN: ${{ secrets.UPSTASH_AUTH_TOKEN }}
runs-on: ubuntu-latest
steps:
- name: Setup repo
uses: actions/checkout@v2
- uses: denoland/setup-deno@v1
with:
deno-version: v1.x
- name: Cache pnpm modules
uses: actions/cache@v2
with:
path: ~/.pnpm-store
key: ${{ runner.os }}-${{ hashFiles('**/pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-

- uses: pnpm/action-setup@v2
with:
version: 6

- name: Build
run: deno run -A ./cmd/build.ts

- name: Start redis server
uses: ./.github/actions/redis
with:
UPSTASH_REDIS_REST_URL: http://127.0.0.1:6379
UPSTASH_REDIS_REST_TOKEN: ${{ secrets.UPSTASH_AUTH_TOKEN }}
UPSTASH_REPO_ACCESS_TOKEN: ${{ secrets.UPSTASH_REPO_ACCESS_TOKEN }}
REDIS_SERVER_CONFIG: ${{ secrets.REDIS_SERVER_CONFIG }}

- name: Install example
run: |
pnpm install
working-directory: examples/nodejs

- name: Run example
run: node ./index.js
working-directory: examples/nodejs
25 changes: 14 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,21 +25,15 @@ supported.

## Upgrading to v1.4.0 **(ReferenceError: fetch is not defined)**

If you are running on nodejs v17 and earlier, you need to manually provide a
`fetch` polyfill. The simplest way is using `isomorphic-fetch`

```bash
npm install isomorphic-fetch
```
If you are running on nodejs v17 and earlier, `fetch` will not be natively
supported. Platforms like Vercel, Netlify, Deno, Fastly etc. provide a polyfill
for you. But if you are running on bare node, you need to either specify a
polyfill yourself or change the import path to:

```typescript
import "isomorphic-fetch";
import { Redis } from "@upstash/redis";
import { Redis } from "@upstash/redis/with-fetch";
```

`fetch` is natively supported in node18 as well as all major platforms: Vercel,
Netlify, Deno, Fastly etc. and you do not need to do anything.

## Upgrading from v0.2.0?

Please read the
Expand Down Expand Up @@ -93,6 +87,15 @@ const redis = new Redis({
const redis = Redis.fromEnv()
```

If you are running on nodejs v17 and earlier, `fetch` will not be natively
supported. Platforms like Vercel, Netlify, Deno, Fastly etc. provide a polyfill
for you. But if you are running on bare node, you need to either specify a
polyfill yourself or change the import path to:

```typescript
import { Redis } from "@upstash/redis/with-fetch";
```

- [Code example](https://github.com/upstash/upstash-redis/blob/main/examples/nodejs)

#### Cloudflare Workers
Expand Down
12 changes: 12 additions & 0 deletions cmd/build.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,10 @@ await build({
name: "./fastly",
path: "./platforms/fastly.ts",
},
{
name: "./with-fetch",
path: "./platforms/node_with_fetch.ts",
},
],
outDir,
shims: {
Expand All @@ -36,6 +40,11 @@ await build({
typesPackage: { name: "@types/node", version: "latest" },
globalNames: [],
},
{
package: { name: "@types/node", version: "latest" },
typesPackage: { name: "@types/node", version: "latest" },
globalNames: [],
},
],
},
typeCheck: true,
Expand All @@ -56,6 +65,9 @@ await build({
bugs: {
url: "https://github.com/upstash/upstash-redis/issues",
},
dependencies: {
"isomorphic-fetch": "^3.0.0",
},
homepage: "https://github.com/upstash/upstash-redis#readme",
browser: {
"isomorphic-fetch": false,
Expand Down
2 changes: 1 addition & 1 deletion examples/aws-lambda/index.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
const { Redis } = require("@upstash/redis");
const { Redis } = require("@upstash/redis/with-fetch");

exports.handler = async (_event, _context) => {
let response;
Expand Down
9 changes: 7 additions & 2 deletions examples/nodejs/index.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,19 @@
const { Redis } = require("@upstash/redis");
import { Redis } from "@upstash/redis/with-fetch";

const redis = Redis.fromEnv();
async function run() {
const key = "key";
const value = { hello: "world" };

const res1 = await redis.set(key, '{"hello":"world"}');
const res1 = await redis.set(key, value);
console.log(res1);

const res2 = await redis.get(key);
console.log(typeof res2, res2);

if (JSON.stringify(value) != JSON.stringify(res2)) {
throw new Error("value not equal");
}
}

run();
179 changes: 179 additions & 0 deletions platforms/node_with_fetch.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
// deno-lint-ignore-file

import * as core from "../pkg/redis.ts";
import { Requester, UpstashRequest, UpstashResponse } from "../pkg/http.ts";
import { UpstashError } from "../pkg/error.ts";
import "isomorphic-fetch";
// @ts-ignore Deno can't compile
// import https from "https";
// @ts-ignore Deno can't compile
// import http from "http";
// import "isomorphic-fetch";

export type { Requester, UpstashRequest, UpstashResponse };

/**
* Connection credentials for upstash redis.
* Get them from https://console.upstash.com/redis/<uuid>
*/
export type RedisConfigNodejs = {
/**
* UPSTASH_REDIS_REST_URL
*/
url: string;
/**
* UPSTASH_REDIS_REST_TOKEN
*/
token: string;
/**
* An agent allows you to reuse connections to reduce latency for multiple sequential requests.
*
* This is a node specific implementation and is not supported in various runtimes like Vercel
* edge functions.
*
* @example
* ```ts
* import https from "https"
*
* const options: RedisConfigNodejs = {
* agent: new https.Agent({ keepAlive: true })
* }
* ```
*/
// agent?: http.Agent | https.Agent;
} & core.RedisOptions;

/**
* Serverless redis client for upstash.
*/
export class Redis extends core.Redis {
/**
* Create a new redis client by providing the url and token
*
* @example
* ```typescript
* const redis = new Redis({
* url: "<UPSTASH_REDIS_REST_URL>",
* token: "<UPSTASH_REDIS_REST_TOKEN>",
* });
* ```
*/
constructor(config: RedisConfigNodejs);

/**
* Create a new redis client by providing a custom `Requester` implementation
*
* @example
* ```ts
*
* import { UpstashRequest, Requester, UpstashResponse, Redis } from "@upstash/redis"
*
* const requester: Requester = {
* request: <TResult>(req: UpstashRequest): Promise<UpstashResponse<TResult>> => {
* // ...
* }
* }
*
* const redis = new Redis(requester)
* ```
*/
constructor(requesters: Requester);
constructor(configOrRequester: RedisConfigNodejs | Requester) {
if ("request" in configOrRequester) {
super(configOrRequester);
return;
}
if (
configOrRequester.url.startsWith(" ") ||
configOrRequester.url.endsWith(" ") ||
/\r|\n/.test(configOrRequester.url)
) {
console.warn(
"The redis url contains whitespace or newline, which can cause errors!",
);
}
if (
configOrRequester.token.startsWith(" ") ||
configOrRequester.token.endsWith(" ") ||
/\r|\n/.test(configOrRequester.token)
) {
console.warn(
"The redis token contains whitespace or newline, which can cause errors!",
);
}

const client = defaultRequester({
baseUrl: configOrRequester.url,
headers: { authorization: `Bearer ${configOrRequester.token}` },
// agent: configOrRequester.agent,
});

super(client, {
automaticDeserialization: configOrRequester.automaticDeserialization,
});
}

/**
* Create a new Upstash Redis instance from environment variables.
*
* Use this to automatically load connection secrets from your environment
* variables. For instance when using the Vercel integration.
*
* This tries to load `UPSTASH_REDIS_REST_URL` and `UPSTASH_REDIS_REST_TOKEN` from
* your environment using `process.env`.
*/
static fromEnv(config?: Omit<RedisConfigNodejs, "url" | "token">): Redis {
// @ts-ignore process will be defined in node
if (typeof process?.env === "undefined") {
throw new Error(
'Unable to get environment variables, `process.env` is undefined. If you are deploying to cloudflare, please import from "@upstash/redis/cloudflare" instead',
);
}
// @ts-ignore process will be defined in node
const url = process?.env["UPSTASH_REDIS_REST_URL"];
if (!url) {
throw new Error(
"Unable to find environment variable: `UPSTASH_REDIS_REST_URL`",
);
}
// @ts-ignore process will be defined in node
const token = process?.env["UPSTASH_REDIS_REST_TOKEN"];
if (!token) {
throw new Error(
"Unable to find environment variable: `UPSTASH_REDIS_REST_TOKEN`",
);
}
return new Redis({ url, token, ...config });
}
}

function defaultRequester(config: {
headers?: Record<string, string>;
baseUrl: string;
// agent?: http.Agent | https.Agent;
}): Requester {
return {
request: async function <TResult>(
req: UpstashRequest,
): Promise<UpstashResponse<TResult>> {
if (!req.path) {
req.path = [];
}

const res = await fetch([config.baseUrl, ...req.path].join("/"), {
method: "POST",
headers: { "Content-Type": "application/json", ...config.headers },
body: JSON.stringify(req.body),
keepalive: true,
// @ts-ignore
agent: config.agent,
});
const body = (await res.json()) as UpstashResponse<TResult>;
if (!res.ok) {
throw new UpstashError(body.error!);
}

return body;
},
};
}