Skip to content

Commit

Permalink
Merge pull request #55 from msywulak/header-forward
Browse files Browse the repository at this point in the history
Handle custom header additions without requiring "Upstash-Forward-*" as a prefix.
  • Loading branch information
ogzhanolguncu authored Nov 21, 2023
2 parents 4b93fa1 + 2246c80 commit 64573cd
Show file tree
Hide file tree
Showing 4 changed files with 81 additions and 8 deletions.
40 changes: 40 additions & 0 deletions examples/nodejs/customHeaders.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
const { Client, Receiver } = require("@upstash/qstash");
require("isomorphic-fetch");

async function main() {
const q = new Client({
token: "",
});

const res = await q.publish({
url: "https://qstash-prod-andreas.requestcatcher.com/test",
body: "Hello World",
headers: {
"Upstash-Forward-Custom-Header-1": "Value 1", // Handle already prefixed headers
"Custom-Header-2": "Value 2", // Handle non-prefixed headers
},
});
console.log(res);

// Validating a signature
const receiver = new Receiver({
currentSigningKey: "sig_3nj4aiyJ2JojDnQ1RRodpYubZAZxAJxNfQcRSKPwVUNbueYk2o",
nextSigningKey: "sig_31zVqmL3s7Eo1vpu1jRSMpaetJXvAT3RvNcfoGUp1Toii8fsQEE",
});

const isValid = await receiver
.verify({
signature:
"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOiIiLCJib2R5IjoicFpHbTFBdjBJRUJLQVJjeno3ZXhrTllzWmI4THphTXJWN0ozMmEyZkZHND0iLCJleHAiOjE2NTc1MzA3NTYsImlhdCI6MTY1NzUzMDQ1NiwiaXNzIjoiVXBzdGFzaCIsImp0aSI6Imp3dF83QXFHbkRLV3dLTmY2dEdUNExnRjhqdENEQjhqIiwibmJmIjoxNjU3NTMwNDU2LCJzdWIiOiJodHRwczovL3FzdGFzaC1wcm9kLWFuZHJlYXMucmVxdWVzdGNhdGNoZXIuY29tL3Rlc3QifQ.GzDXaBRUAqx0KPE-WxfZVVceJll3T1RgxdTRbWPZw8s",
body: "Hello World",
url: "https://qstash-prod-andreas.requestcatcher.com/test",
})
.catch((err) => {
console.log(err);
return false;
});

console.log({ isValid });
}

main();
17 changes: 11 additions & 6 deletions src/client/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { Messages } from "./messages";
import { Schedules } from "./schedules";
import { Topics } from "./topics";
import { Event } from "./types";
import { prefixHeaders } from "./utils";
type ClientConfig = {
/**
* Url of the qstash api server.
Expand Down Expand Up @@ -168,7 +169,9 @@ export class Client {
public constructor(config: ClientConfig) {
this.http = new HttpClient({
retry: config.retry,
baseUrl: config.baseUrl ? config.baseUrl.replace(/\/$/, "") : "https://qstash.upstash.io",
baseUrl: config.baseUrl
? config.baseUrl.replace(/\/$/, "")
: "https://qstash.upstash.io",
authorization: `Bearer ${config.token}`,
});
}
Expand Down Expand Up @@ -209,9 +212,9 @@ export class Client {
return new Schedules(this.http);
}
public async publish<TRequest extends PublishRequest>(
req: TRequest,
req: TRequest
): Promise<PublishResponse<TRequest>> {
const headers = new Headers(req.headers);
const headers = prefixHeaders(new Headers(req.headers));

headers.set("Upstash-Method", req.method ?? "POST");

Expand Down Expand Up @@ -258,9 +261,9 @@ export class Client {
*/
public async publishJSON<
TBody = unknown,
TRequest extends PublishRequest<TBody> = PublishRequest<TBody>,
TRequest extends PublishRequest<TBody> = PublishRequest<TBody>
>(req: TRequest): Promise<PublishResponse<TRequest>> {
const headers = new Headers(req.headers);
const headers = prefixHeaders(new Headers(req.headers));
headers.set("Content-Type", "application/json");

// @ts-ignore it's just internal
Expand Down Expand Up @@ -312,4 +315,6 @@ type PublishToUrlResponse = {

type PublishToTopicResponse = PublishToUrlResponse[];

type PublishResponse<R> = R extends { url: string } ? PublishToUrlResponse : PublishToTopicResponse;
type PublishResponse<R> = R extends { url: string }
? PublishToUrlResponse
: PublishToTopicResponse;
7 changes: 5 additions & 2 deletions src/client/schedules.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { prefixHeaders } from "./utils";
import { Requester } from "./http";

export type Schedule = {
Expand Down Expand Up @@ -98,8 +99,10 @@ export class Schedules {
/**
* Create a schedule
*/
public async create(req: CreateScheduleRequest): Promise<{ scheduleId: string }> {
const headers = new Headers(req.headers);
public async create(
req: CreateScheduleRequest
): Promise<{ scheduleId: string }> {
const headers = prefixHeaders(new Headers(req.headers));

if (!headers.has("Content-Type")) {
headers.set("Content-Type", "application/json");
Expand Down
25 changes: 25 additions & 0 deletions src/client/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
export function prefixHeaders(headers: Headers) {
const isIgnoredHeader = (header: string) => {
const lowerCaseHeader = header.toLowerCase();
return (
lowerCaseHeader.startsWith("content-type") ||
lowerCaseHeader.startsWith("upstash-")
);
};

// Get keys of headers that need to be prefixed
const keysToBePrefixed = Array.from(headers.keys()).filter(
(key) => !isIgnoredHeader(key)
);

// Add the prefixed headers
for (const key of keysToBePrefixed) {
const value = headers.get(key);
if (value !== null) {
headers.set(`Upstash-Forward-${key}`, value);
}
headers.delete(key); // clean up non-prefixed headers
}

return headers;
}

0 comments on commit 64573cd

Please sign in to comment.