From 94138c553135d5a10c3426972f5d25cc445ec148 Mon Sep 17 00:00:00 2001 From: Deepjyoti Barman Date: Fri, 30 Aug 2024 11:09:03 +0530 Subject: [PATCH 01/32] Add support for polyfilling buffer and node for next --- lib/ts/nextjs.ts | 3 ++ lib/ts/polyfill.ts | 9 ++++ package-lock.json | 105 +++++++++++++++++++++++++++++++++++++-------- package.json | 2 + 4 files changed, 102 insertions(+), 17 deletions(-) create mode 100644 lib/ts/polyfill.ts diff --git a/lib/ts/nextjs.ts b/lib/ts/nextjs.ts index 59a4ed42e..9f9fb92ec 100644 --- a/lib/ts/nextjs.ts +++ b/lib/ts/nextjs.ts @@ -12,6 +12,9 @@ * License for the specific language governing permissions and limitations * under the License. */ + +import './polyfill' + import { serialize } from "cookie"; import { errorHandler } from "./framework/express"; import { getUserContext } from "./utils"; diff --git a/lib/ts/polyfill.ts b/lib/ts/polyfill.ts new file mode 100644 index 000000000..a3a474067 --- /dev/null +++ b/lib/ts/polyfill.ts @@ -0,0 +1,9 @@ +// Check if 'Buffer' is available, if not, polyfill it +if (typeof Buffer === 'undefined') { + global.Buffer = require('buffer').Buffer; +} + +// Check if 'process' is available, if not, polyfill it +if (typeof process === 'undefined') { + global.process = require('process'); +} diff --git a/package-lock.json b/package-lock.json index 96ecc1e07..d46f8bc47 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,6 +9,7 @@ "version": "20.0.3", "license": "Apache-2.0", "dependencies": { + "buffer": "^6.0.3", "content-type": "^1.0.5", "cookie": "0.4.0", "cross-fetch": "^3.1.6", @@ -18,6 +19,7 @@ "libphonenumber-js": "^1.9.44", "nodemailer": "^6.7.2", "pkce-challenge": "^3.0.0", + "process": "^0.11.10", "psl": "1.8.0", "supertokens-js-override": "^0.0.4", "twilio": "^4.19.3" @@ -2110,6 +2112,17 @@ "node": ">=8" } }, + "node_modules/aws-sdk/node_modules/buffer": { + "version": "4.9.2", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.2.tgz", + "integrity": "sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg==", + "dev": true, + "dependencies": { + "base64-js": "^1.0.2", + "ieee754": "^1.1.4", + "isarray": "^1.0.0" + } + }, "node_modules/aws-sdk/node_modules/uuid": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.0.0.tgz", @@ -2152,7 +2165,6 @@ "version": "1.5.1", "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", - "dev": true, "funding": [ { "type": "github", @@ -2366,14 +2378,26 @@ } }, "node_modules/buffer": { - "version": "4.9.2", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.2.tgz", - "integrity": "sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg==", - "dev": true, + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], "dependencies": { - "base64-js": "^1.0.2", - "ieee754": "^1.1.4", - "isarray": "^1.0.0" + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" } }, "node_modules/buffer-equal-constant-time": { @@ -2381,6 +2405,25 @@ "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==" }, + "node_modules/buffer/node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, "node_modules/busboy": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz", @@ -6481,6 +6524,14 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, + "node_modules/process": { + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", + "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==", + "engines": { + "node": ">= 0.6.0" + } + }, "node_modules/process-nextick-args": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", @@ -9817,6 +9868,17 @@ "xml2js": "0.6.2" }, "dependencies": { + "buffer": { + "version": "4.9.2", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.2.tgz", + "integrity": "sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg==", + "dev": true, + "requires": { + "base64-js": "^1.0.2", + "ieee754": "^1.1.4", + "isarray": "^1.0.0" + } + }, "uuid": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.0.0.tgz", @@ -9932,8 +9994,7 @@ "base64-js": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", - "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", - "dev": true + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==" }, "bcp47": { "version": "1.1.2", @@ -10092,14 +10153,19 @@ } }, "buffer": { - "version": "4.9.2", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.2.tgz", - "integrity": "sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg==", - "dev": true, + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", "requires": { - "base64-js": "^1.0.2", - "ieee754": "^1.1.4", - "isarray": "^1.0.0" + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + }, + "dependencies": { + "ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==" + } } }, "buffer-equal-constant-time": { @@ -13219,6 +13285,11 @@ } } }, + "process": { + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", + "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==" + }, "process-nextick-args": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", diff --git a/package.json b/package.json index 8ad8f18be..274df0335 100644 --- a/package.json +++ b/package.json @@ -113,6 +113,7 @@ }, "homepage": "https://github.com/supertokens/supertokens-node#readme", "dependencies": { + "buffer": "^6.0.3", "content-type": "^1.0.5", "cookie": "0.4.0", "cross-fetch": "^3.1.6", @@ -122,6 +123,7 @@ "libphonenumber-js": "^1.9.44", "nodemailer": "^6.7.2", "pkce-challenge": "^3.0.0", + "process": "^0.11.10", "psl": "1.8.0", "supertokens-js-override": "^0.0.4", "twilio": "^4.19.3" From 94300b9c6fb6c6fe4a72e068a8b7f83416316b48 Mon Sep 17 00:00:00 2001 From: Deepjyoti Barman Date: Fri, 30 Aug 2024 11:10:21 +0530 Subject: [PATCH 02/32] Use querystringify instead of querystring for edge compatibility --- lib/ts/framework/awsLambda/framework.ts | 8 ++++---- package-lock.json | 14 ++++++++++++++ package.json | 2 ++ 3 files changed, 20 insertions(+), 4 deletions(-) diff --git a/lib/ts/framework/awsLambda/framework.ts b/lib/ts/framework/awsLambda/framework.ts index ae9d247de..a4b992e3d 100644 --- a/lib/ts/framework/awsLambda/framework.ts +++ b/lib/ts/framework/awsLambda/framework.ts @@ -30,7 +30,7 @@ import { COOKIE_HEADER } from "../constants"; import { SessionContainerInterface } from "../../recipe/session/types"; import SuperTokens from "../../supertokens"; import { Framework } from "../types"; -import { parse } from "querystring"; +import queryString from "querystringify"; export class AWSRequest extends BaseRequest { private event: APIGatewayProxyEventV2 | APIGatewayProxyEvent; @@ -45,7 +45,7 @@ export class AWSRequest extends BaseRequest { if (this.event.body === null || this.event.body === undefined) { return {}; } else { - const parsedUrlEncodedFormData = parse(this.event.body); + const parsedUrlEncodedFormData = queryString.parse(this.event.body); return parsedUrlEncodedFormData === undefined ? {} : parsedUrlEncodedFormData; } }; @@ -229,8 +229,8 @@ export class AWSResponse extends BaseResponse { } let headers: | { - [header: string]: boolean | number | string; - } + [header: string]: boolean | number | string; + } | undefined = response.headers; if (headers === undefined) { headers = {}; diff --git a/package-lock.json b/package-lock.json index d46f8bc47..4d5663091 100644 --- a/package-lock.json +++ b/package-lock.json @@ -21,6 +21,7 @@ "pkce-challenge": "^3.0.0", "process": "^0.11.10", "psl": "1.8.0", + "querystringify": "^2.2.0", "supertokens-js-override": "^0.0.4", "twilio": "^4.19.3" }, @@ -41,6 +42,7 @@ "@types/koa-bodyparser": "^4.3.3", "@types/nodemailer": "^6.4.4", "@types/psl": "1.1.0", + "@types/querystringify": "^2.0.2", "@types/validator": "10.11.0", "aws-sdk-mock": "^5.4.0", "body-parser": "1.20.1", @@ -1689,6 +1691,12 @@ "integrity": "sha512-5khscbd3SwWMhFqylJBLQ0zIu7c1K6Vz0uBIt915BI3zV0q1nfjRQD3RqSBcPaO6PHEF4ov/t9y89fSiyThlPA==", "dev": true }, + "node_modules/@types/querystringify": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@types/querystringify/-/querystringify-2.0.2.tgz", + "integrity": "sha512-7d6OQK6pJ//zE32XLK3vI6GHYhBDcYooaRco9cKFGNu59GVatL5+u7rkiAViq44DxDTd/7QQNBWSDHfJGBz/Pw==", + "dev": true + }, "node_modules/@types/range-parser": { "version": "1.2.7", "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz", @@ -9593,6 +9601,12 @@ "integrity": "sha512-5khscbd3SwWMhFqylJBLQ0zIu7c1K6Vz0uBIt915BI3zV0q1nfjRQD3RqSBcPaO6PHEF4ov/t9y89fSiyThlPA==", "dev": true }, + "@types/querystringify": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@types/querystringify/-/querystringify-2.0.2.tgz", + "integrity": "sha512-7d6OQK6pJ//zE32XLK3vI6GHYhBDcYooaRco9cKFGNu59GVatL5+u7rkiAViq44DxDTd/7QQNBWSDHfJGBz/Pw==", + "dev": true + }, "@types/range-parser": { "version": "1.2.7", "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz", diff --git a/package.json b/package.json index 274df0335..f2da702bb 100644 --- a/package.json +++ b/package.json @@ -125,6 +125,7 @@ "pkce-challenge": "^3.0.0", "process": "^0.11.10", "psl": "1.8.0", + "querystringify": "^2.2.0", "supertokens-js-override": "^0.0.4", "twilio": "^4.19.3" }, @@ -145,6 +146,7 @@ "@types/koa-bodyparser": "^4.3.3", "@types/nodemailer": "^6.4.4", "@types/psl": "1.1.0", + "@types/querystringify": "^2.0.2", "@types/validator": "10.11.0", "aws-sdk-mock": "^5.4.0", "body-parser": "1.20.1", From 5262e6b8a2a17582e925dde466af8e316208c920 Mon Sep 17 00:00:00 2001 From: Deepjyoti Barman Date: Fri, 30 Aug 2024 15:19:21 +0530 Subject: [PATCH 03/32] Add support for parse implementation using URLSearchParams --- lib/ts/framework/awsLambda/framework.ts | 5 +- lib/ts/framework/utils.ts | 65 +++++++++++++++++-------- package-lock.json | 52 +++++++++----------- package.json | 5 +- 4 files changed, 73 insertions(+), 54 deletions(-) diff --git a/lib/ts/framework/awsLambda/framework.ts b/lib/ts/framework/awsLambda/framework.ts index a4b992e3d..5c29a4bdc 100644 --- a/lib/ts/framework/awsLambda/framework.ts +++ b/lib/ts/framework/awsLambda/framework.ts @@ -25,12 +25,11 @@ import { HTTPMethod } from "../../types"; import { getFromObjectCaseInsensitive, makeDefaultUserContextFromAPI, normaliseHttpMethod } from "../../utils"; import { BaseRequest } from "../request"; import { BaseResponse } from "../response"; -import { normalizeHeaderValue, getCookieValueFromHeaders, serializeCookieValue } from "../utils"; +import { normalizeHeaderValue, getCookieValueFromHeaders, serializeCookieValue, parseParams } from "../utils"; import { COOKIE_HEADER } from "../constants"; import { SessionContainerInterface } from "../../recipe/session/types"; import SuperTokens from "../../supertokens"; import { Framework } from "../types"; -import queryString from "querystringify"; export class AWSRequest extends BaseRequest { private event: APIGatewayProxyEventV2 | APIGatewayProxyEvent; @@ -45,7 +44,7 @@ export class AWSRequest extends BaseRequest { if (this.event.body === null || this.event.body === undefined) { return {}; } else { - const parsedUrlEncodedFormData = queryString.parse(this.event.body); + const parsedUrlEncodedFormData = parseParams(this.event.body); return parsedUrlEncodedFormData === undefined ? {} : parsedUrlEncodedFormData; } }; diff --git a/lib/ts/framework/utils.ts b/lib/ts/framework/utils.ts index 287a5db18..72c2502a0 100644 --- a/lib/ts/framework/utils.ts +++ b/lib/ts/framework/utils.ts @@ -13,7 +13,6 @@ * under the License. */ -import { Readable } from "stream"; import { parse, serialize } from "cookie"; import type { Request, Response } from "express"; import type { IncomingMessage } from "http"; @@ -23,7 +22,49 @@ import type { HTTPMethod } from "../types"; import { COOKIE_HEADER } from "./constants"; import { getFromObjectCaseInsensitive } from "../utils"; import contentType from "content-type"; -import inflate from "inflation"; +import pako from "pako"; + +async function inflate(stream: IncomingMessage): Promise { + if (!stream) { + throw new TypeError("argument stream is required"); + } + + const encoding = stream.headers && stream.headers["content-encoding"]; + + let i = new pako.Inflate(); + for await (const chunk of stream) { + i.push(Buffer.from(chunk)); + } + + if (typeof i.result === "string") { + return i.result; + } else { + return new TextDecoder(encoding).decode(i.result, { stream: true }); + } +} + +export function parseParams(string: string): object { + // Set up a new URLSearchParams object using the string. + const params = new URLSearchParams(string) + + // Get an iterator for the URLSearchParams object. + const entries = params.entries() + + const result: { [key: string]: any } = {} + + // Loop through the URLSearchParams object and add each key/value + for (const [key, value] of entries) { + // Split comma-separated values into an array. + result[key] = value.split(",") + + // If a key does not have a value, delete it. + if (!value) { + delete result[key] + } + } + + return result +} export function getCookieValueFromHeaders(headers: any, key: string): string | undefined { if (headers === undefined || headers === null) { @@ -123,8 +164,7 @@ export async function parseJSONBodyFromRequest(req: IncomingMessage) { if (!encoding.startsWith("utf-")) { throw new Error(`unsupported charset ${encoding.toUpperCase()}`); } - const buffer = await getBody(inflate(req)); - const str = buffer.toString(encoding as BufferEncoding); + const str = await inflate(req); if (str.length === 0) { return {}; @@ -137,8 +177,7 @@ export async function parseURLEncodedFormData(req: IncomingMessage) { if (!encoding.startsWith("utf-")) { throw new Error(`unsupported charset ${encoding.toUpperCase()}`); } - const buffer = await getBody(inflate(req)); - const str = buffer.toString(encoding as BufferEncoding); + const str = await inflate(req); let body: any = {}; for (const [key, val] of new URLSearchParams(str).entries()) { @@ -360,17 +399,3 @@ export function serializeCookieValue( return serialize(key, value, opts); } - -// based on https://nodejs.org/en/docs/guides/anatomy-of-an-http-transaction -function getBody(request: Readable) { - return new Promise((resolve) => { - const bodyParts: Uint8Array[] = []; - request - .on("data", (chunk) => { - bodyParts.push(chunk); - }) - .on("end", () => { - resolve(Buffer.concat(bodyParts)); - }); - }); -} diff --git a/package-lock.json b/package-lock.json index 4d5663091..c30f253ca 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,14 +14,13 @@ "cookie": "0.4.0", "cross-fetch": "^3.1.6", "debug": "^4.3.3", - "inflation": "^2.0.0", "jose": "^4.13.1", "libphonenumber-js": "^1.9.44", "nodemailer": "^6.7.2", + "pako": "^2.1.0", "pkce-challenge": "^3.0.0", "process": "^0.11.10", "psl": "1.8.0", - "querystringify": "^2.2.0", "supertokens-js-override": "^0.0.4", "twilio": "^4.19.3" }, @@ -41,8 +40,8 @@ "@types/koa": "^2.13.4", "@types/koa-bodyparser": "^4.3.3", "@types/nodemailer": "^6.4.4", + "@types/pako": "^2.0.3", "@types/psl": "1.1.0", - "@types/querystringify": "^2.0.2", "@types/validator": "10.11.0", "aws-sdk-mock": "^5.4.0", "body-parser": "1.20.1", @@ -1679,6 +1678,12 @@ "@types/node": "*" } }, + "node_modules/@types/pako": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@types/pako/-/pako-2.0.3.tgz", + "integrity": "sha512-bq0hMV9opAcrmE0Byyo0fY3Ew4tgOevJmQ9grUhpXQhYfyLJ1Kqg3P33JT5fdbT2AjeAjR51zqqVjAL/HMkx7Q==", + "dev": true + }, "node_modules/@types/psl": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@types/psl/-/psl-1.1.0.tgz", @@ -1691,12 +1696,6 @@ "integrity": "sha512-5khscbd3SwWMhFqylJBLQ0zIu7c1K6Vz0uBIt915BI3zV0q1nfjRQD3RqSBcPaO6PHEF4ov/t9y89fSiyThlPA==", "dev": true }, - "node_modules/@types/querystringify": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@types/querystringify/-/querystringify-2.0.2.tgz", - "integrity": "sha512-7d6OQK6pJ//zE32XLK3vI6GHYhBDcYooaRco9cKFGNu59GVatL5+u7rkiAViq44DxDTd/7QQNBWSDHfJGBz/Pw==", - "dev": true - }, "node_modules/@types/range-parser": { "version": "1.2.7", "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz", @@ -4150,14 +4149,6 @@ "node": ">=8" } }, - "node_modules/inflation": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/inflation/-/inflation-2.1.0.tgz", - "integrity": "sha512-t54PPJHG1Pp7VQvxyVCJ9mBbjG3Hqryges9bXoOO6GExCPa+//i/d5GSuFtpx3ALLd7lgIAur6zrIlBQyJuMlQ==", - "engines": { - "node": ">= 0.8.0" - } - }, "node_modules/inflection": { "version": "1.13.4", "resolved": "https://registry.npmjs.org/inflection/-/inflection-1.13.4.tgz", @@ -6200,6 +6191,11 @@ "node": ">=8" } }, + "node_modules/pako": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/pako/-/pako-2.1.0.tgz", + "integrity": "sha512-w+eufiZ1WuJYgPXbV/PO3NCMEc3xqylkKHzp8bxp1uW4qaSNQUkwmLLEc3kKsfz8lpV1F8Ht3U1Cm+9Srog2ug==" + }, "node_modules/param-case": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/param-case/-/param-case-3.0.4.tgz", @@ -9589,6 +9585,12 @@ "@types/node": "*" } }, + "@types/pako": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@types/pako/-/pako-2.0.3.tgz", + "integrity": "sha512-bq0hMV9opAcrmE0Byyo0fY3Ew4tgOevJmQ9grUhpXQhYfyLJ1Kqg3P33JT5fdbT2AjeAjR51zqqVjAL/HMkx7Q==", + "dev": true + }, "@types/psl": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@types/psl/-/psl-1.1.0.tgz", @@ -9601,12 +9603,6 @@ "integrity": "sha512-5khscbd3SwWMhFqylJBLQ0zIu7c1K6Vz0uBIt915BI3zV0q1nfjRQD3RqSBcPaO6PHEF4ov/t9y89fSiyThlPA==", "dev": true }, - "@types/querystringify": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@types/querystringify/-/querystringify-2.0.2.tgz", - "integrity": "sha512-7d6OQK6pJ//zE32XLK3vI6GHYhBDcYooaRco9cKFGNu59GVatL5+u7rkiAViq44DxDTd/7QQNBWSDHfJGBz/Pw==", - "dev": true - }, "@types/range-parser": { "version": "1.2.7", "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz", @@ -11490,11 +11486,6 @@ "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", "dev": true }, - "inflation": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/inflation/-/inflation-2.1.0.tgz", - "integrity": "sha512-t54PPJHG1Pp7VQvxyVCJ9mBbjG3Hqryges9bXoOO6GExCPa+//i/d5GSuFtpx3ALLd7lgIAur6zrIlBQyJuMlQ==" - }, "inflection": { "version": "1.13.4", "resolved": "https://registry.npmjs.org/inflection/-/inflection-1.13.4.tgz", @@ -13061,6 +13052,11 @@ "release-zalgo": "^1.0.0" } }, + "pako": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/pako/-/pako-2.1.0.tgz", + "integrity": "sha512-w+eufiZ1WuJYgPXbV/PO3NCMEc3xqylkKHzp8bxp1uW4qaSNQUkwmLLEc3kKsfz8lpV1F8Ht3U1Cm+9Srog2ug==" + }, "param-case": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/param-case/-/param-case-3.0.4.tgz", diff --git a/package.json b/package.json index f2da702bb..b3e830963 100644 --- a/package.json +++ b/package.json @@ -118,14 +118,13 @@ "cookie": "0.4.0", "cross-fetch": "^3.1.6", "debug": "^4.3.3", - "inflation": "^2.0.0", "jose": "^4.13.1", "libphonenumber-js": "^1.9.44", "nodemailer": "^6.7.2", + "pako": "^2.1.0", "pkce-challenge": "^3.0.0", "process": "^0.11.10", "psl": "1.8.0", - "querystringify": "^2.2.0", "supertokens-js-override": "^0.0.4", "twilio": "^4.19.3" }, @@ -145,8 +144,8 @@ "@types/koa": "^2.13.4", "@types/koa-bodyparser": "^4.3.3", "@types/nodemailer": "^6.4.4", + "@types/pako": "^2.0.3", "@types/psl": "1.1.0", - "@types/querystringify": "^2.0.2", "@types/validator": "10.11.0", "aws-sdk-mock": "^5.4.0", "body-parser": "1.20.1", From 7f9f61ec5222cf9d89c09eaa23b4156110e07731 Mon Sep 17 00:00:00 2001 From: Deepjyoti Barman Date: Fri, 30 Aug 2024 17:16:02 +0530 Subject: [PATCH 04/32] Add tests for parseParams --- lib/build/framework/awsLambda/framework.js | 81 ++++------ lib/build/framework/utils.d.ts | 42 +----- lib/build/framework/utils.js | 164 +++++++++++++-------- lib/build/nextjs.d.ts | 36 ++--- lib/build/nextjs.js | 126 ++++++++-------- lib/build/polyfill.d.ts | 1 + lib/build/polyfill.js | 9 ++ test/framework/utils.test.js | 14 ++ 8 files changed, 229 insertions(+), 244 deletions(-) create mode 100644 lib/build/polyfill.d.ts create mode 100644 lib/build/polyfill.js create mode 100644 test/framework/utils.test.js diff --git a/lib/build/framework/awsLambda/framework.js b/lib/build/framework/awsLambda/framework.js index 45b93076a..16489a7a0 100644 --- a/lib/build/framework/awsLambda/framework.js +++ b/lib/build/framework/awsLambda/framework.js @@ -1,9 +1,7 @@ "use strict"; -var __importDefault = - (this && this.__importDefault) || - function (mod) { - return mod && mod.__esModule ? mod : { default: mod }; - }; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; Object.defineProperty(exports, "__esModule", { value: true }); exports.AWSWrapper = exports.middleware = exports.AWSResponse = exports.AWSRequest = void 0; const utils_1 = require("../../utils"); @@ -12,22 +10,23 @@ const response_1 = require("../response"); const utils_2 = require("../utils"); const constants_1 = require("../constants"); const supertokens_1 = __importDefault(require("../../supertokens")); -const querystring_1 = require("querystring"); class AWSRequest extends request_1.BaseRequest { constructor(event) { super(); this.getFormDataFromRequestBody = async () => { if (this.event.body === null || this.event.body === undefined) { return {}; - } else { - const parsedUrlEncodedFormData = querystring_1.parse(this.event.body); + } + else { + const parsedUrlEncodedFormData = utils_2.parseParams(this.event.body); return parsedUrlEncodedFormData === undefined ? {} : parsedUrlEncodedFormData; } }; this.getJSONFromRequestBody = async () => { if (this.event.body === null || this.event.body === undefined) { return {}; - } else { + } + else { const parsedJSONBody = JSON.parse(this.event.body); return parsedJSONBody === undefined ? {} : parsedJSONBody; } @@ -51,20 +50,15 @@ class AWSRequest extends request_1.BaseRequest { }; this.getCookieValue = (key) => { let cookies = this.event.cookies; - if ( - (this.event.headers === undefined || this.event.headers === null) && - (cookies === undefined || cookies === null) - ) { + if ((this.event.headers === undefined || this.event.headers === null) && + (cookies === undefined || cookies === null)) { return undefined; } let value = utils_2.getCookieValueFromHeaders(this.event.headers, key); if (value === undefined && cookies !== undefined && cookies !== null) { - value = utils_2.getCookieValueFromHeaders( - { - cookie: cookies.join(";"), - }, - key - ); + value = utils_2.getCookieValueFromHeaders({ + cookie: cookies.join(";"), + }, key); } return value; }; @@ -115,21 +109,10 @@ class AWSResponse extends response_1.BaseResponse { }); }; this.removeHeader = (key) => { - this.event.supertokens.response.headers = this.event.supertokens.response.headers.filter( - (header) => header.key.toLowerCase() !== key.toLowerCase() - ); + this.event.supertokens.response.headers = this.event.supertokens.response.headers.filter((header) => header.key.toLowerCase() !== key.toLowerCase()); }; this.setCookie = (key, value, domain, secure, httpOnly, expires, path, sameSite) => { - let serialisedCookie = utils_2.serializeCookieValue( - key, - value, - domain, - secure, - httpOnly, - expires, - path, - sameSite - ); + let serialisedCookie = utils_2.serializeCookieValue(key, value, domain, secure, httpOnly, expires, path, sameSite); this.event.supertokens.response.cookies = [ ...this.event.supertokens.response.cookies.filter((c) => !c.startsWith(key + "=")), serialisedCookie, @@ -183,14 +166,13 @@ class AWSResponse extends response_1.BaseResponse { For example if the caller is trying to add front token to the access control exposed headers property we do not want to append if something else had already added it */ - if ( - typeof currentValue !== "string" || - !currentValue.includes(supertokensHeaders[i].value.toString()) - ) { + if (typeof currentValue !== "string" || + !currentValue.includes(supertokensHeaders[i].value.toString())) { let newValue = `${currentValue}, ${supertokensHeaders[i].value}`; headers[supertokensHeaders[i].key] = newValue; } - } else { + } + else { headers[supertokensHeaders[i].key] = supertokensHeaders[i].value; } } @@ -200,28 +182,26 @@ class AWSResponse extends response_1.BaseResponse { cookies = []; } cookies.push(...supertokensCookies); - let result = Object.assign(Object.assign({}, response), { cookies, body, statusCode, headers }); + let result = Object.assign(Object.assign({}, response), { cookies, + body, + statusCode, + headers }); return result; - } else { + } + else { let multiValueHeaders = response.multiValueHeaders; if (multiValueHeaders === undefined) { multiValueHeaders = {}; } let headsersInMultiValueHeaders = Object.keys(multiValueHeaders); - let cookieHeader = headsersInMultiValueHeaders.find( - (h) => h.toLowerCase() === constants_1.COOKIE_HEADER.toLowerCase() - ); + let cookieHeader = headsersInMultiValueHeaders.find((h) => h.toLowerCase() === constants_1.COOKIE_HEADER.toLowerCase()); if (cookieHeader === undefined) { multiValueHeaders[constants_1.COOKIE_HEADER] = supertokensCookies; - } else { + } + else { multiValueHeaders[cookieHeader].push(...supertokensCookies); } - let result = Object.assign(Object.assign({}, response), { - multiValueHeaders, - body: body, - statusCode: statusCode, - headers, - }); + let result = Object.assign(Object.assign({}, response), { multiValueHeaders, body: body, statusCode: statusCode, headers }); return result; } }; @@ -264,7 +244,8 @@ const middleware = (handler) => { error: `The middleware couldn't serve the API path ${request.getOriginalURL()}, method: ${request.getMethod()}. If this is an unexpected behaviour, please create an issue here: https://github.com/supertokens/supertokens-node/issues`, }); return response.sendResponse(); - } catch (err) { + } + catch (err) { await supertokens.errorHandler(err, request, response, userContext); if (response.responseSet) { return response.sendResponse(); diff --git a/lib/build/framework/utils.d.ts b/lib/build/framework/utils.d.ts index 9350de8b2..afd051456 100644 --- a/lib/build/framework/utils.d.ts +++ b/lib/build/framework/utils.d.ts @@ -4,23 +4,16 @@ import type { Request, Response } from "express"; import type { IncomingMessage } from "http"; import { ServerResponse } from "http"; import type { HTTPMethod } from "../types"; +export declare function parseParams(string: string): object; export declare function getCookieValueFromHeaders(headers: any, key: string): string | undefined; export declare function getCookieValueFromIncomingMessage(request: IncomingMessage, key: string): string | undefined; export declare function getHeaderValueFromIncomingMessage(request: IncomingMessage, key: string): string | undefined; export declare function normalizeHeaderValue(value: string | string[] | undefined): string | undefined; export declare function parseJSONBodyFromRequest(req: IncomingMessage): Promise; export declare function parseURLEncodedFormData(req: IncomingMessage): Promise; -export declare function assertThatBodyParserHasBeenUsedForExpressLikeRequest( - method: HTTPMethod, - request: Request -): Promise; +export declare function assertThatBodyParserHasBeenUsedForExpressLikeRequest(method: HTTPMethod, request: Request): Promise; export declare function assertFormDataBodyParserHasBeenUsedForExpressLikeRequest(request: Request): Promise; -export declare function setHeaderForExpressLikeResponse( - res: Response, - key: string, - value: string, - allowDuplicateKey: boolean -): void; +export declare function setHeaderForExpressLikeResponse(res: Response, key: string, value: string, allowDuplicateKey: boolean): void; /** * * @param res @@ -32,29 +25,6 @@ export declare function setHeaderForExpressLikeResponse( * @param expires * @param path */ -export declare function setCookieForServerResponse( - res: ServerResponse, - key: string, - value: string, - domain: string | undefined, - secure: boolean, - httpOnly: boolean, - expires: number, - path: string, - sameSite: "strict" | "lax" | "none" -): ServerResponse; -export declare function getCookieValueToSetInHeader( - prev: string | string[] | undefined, - val: string | string[], - key: string -): string | string[]; -export declare function serializeCookieValue( - key: string, - value: string, - domain: string | undefined, - secure: boolean, - httpOnly: boolean, - expires: number, - path: string, - sameSite: "strict" | "lax" | "none" -): string; +export declare function setCookieForServerResponse(res: ServerResponse, key: string, value: string, domain: string | undefined, secure: boolean, httpOnly: boolean, expires: number, path: string, sameSite: "strict" | "lax" | "none"): ServerResponse; +export declare function getCookieValueToSetInHeader(prev: string | string[] | undefined, val: string | string[], key: string): string | string[]; +export declare function serializeCookieValue(key: string, value: string, domain: string | undefined, secure: boolean, httpOnly: boolean, expires: number, path: string, sameSite: "strict" | "lax" | "none"): string; diff --git a/lib/build/framework/utils.js b/lib/build/framework/utils.js index 6607ae65f..6e3ef3c07 100644 --- a/lib/build/framework/utils.js +++ b/lib/build/framework/utils.js @@ -13,19 +13,69 @@ * License for the specific language governing permissions and limitations * under the License. */ -var __importDefault = - (this && this.__importDefault) || - function (mod) { - return mod && mod.__esModule ? mod : { default: mod }; - }; +var __asyncValues = (this && this.__asyncValues) || function (o) { + if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined."); + var m = o[Symbol.asyncIterator], i; + return m ? m.call(o) : (o = typeof __values === "function" ? __values(o) : o[Symbol.iterator](), i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i); + function verb(n) { i[n] = o[n] && function (v) { return new Promise(function (resolve, reject) { v = o[n](v), settle(resolve, reject, v.done, v.value); }); }; } + function settle(resolve, reject, d, v) { Promise.resolve(v).then(function(v) { resolve({ value: v, done: d }); }, reject); } +}; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; Object.defineProperty(exports, "__esModule", { value: true }); -exports.serializeCookieValue = exports.getCookieValueToSetInHeader = exports.setCookieForServerResponse = exports.setHeaderForExpressLikeResponse = exports.assertFormDataBodyParserHasBeenUsedForExpressLikeRequest = exports.assertThatBodyParserHasBeenUsedForExpressLikeRequest = exports.parseURLEncodedFormData = exports.parseJSONBodyFromRequest = exports.normalizeHeaderValue = exports.getHeaderValueFromIncomingMessage = exports.getCookieValueFromIncomingMessage = exports.getCookieValueFromHeaders = void 0; +exports.serializeCookieValue = exports.getCookieValueToSetInHeader = exports.setCookieForServerResponse = exports.setHeaderForExpressLikeResponse = exports.assertFormDataBodyParserHasBeenUsedForExpressLikeRequest = exports.assertThatBodyParserHasBeenUsedForExpressLikeRequest = exports.parseURLEncodedFormData = exports.parseJSONBodyFromRequest = exports.normalizeHeaderValue = exports.getHeaderValueFromIncomingMessage = exports.getCookieValueFromIncomingMessage = exports.getCookieValueFromHeaders = exports.parseParams = void 0; const cookie_1 = require("cookie"); const error_1 = __importDefault(require("../error")); const constants_1 = require("./constants"); const utils_1 = require("../utils"); const content_type_1 = __importDefault(require("content-type")); -const inflation_1 = __importDefault(require("inflation")); +const pako_1 = __importDefault(require("pako")); +async function inflate(stream) { + var e_1, _a; + if (!stream) { + throw new TypeError("argument stream is required"); + } + const encoding = stream.headers && stream.headers["content-encoding"]; + let i = new pako_1.default.Inflate(); + try { + for (var stream_1 = __asyncValues(stream), stream_1_1; stream_1_1 = await stream_1.next(), !stream_1_1.done;) { + const chunk = stream_1_1.value; + i.push(Buffer.from(chunk)); + } + } + catch (e_1_1) { e_1 = { error: e_1_1 }; } + finally { + try { + if (stream_1_1 && !stream_1_1.done && (_a = stream_1.return)) await _a.call(stream_1); + } + finally { if (e_1) throw e_1.error; } + } + if (typeof i.result === "string") { + return i.result; + } + else { + return new TextDecoder(encoding).decode(i.result, { stream: true }); + } +} +function parseParams(string) { + // Set up a new URLSearchParams object using the string. + const params = new URLSearchParams(string); + // Get an iterator for the URLSearchParams object. + const entries = params.entries(); + const result = {}; + // Loop through the URLSearchParams object and add each key/value + for (const [key, value] of entries) { + // Split comma-separated values into an array. + result[key] = value.split(","); + // If a key does not have a value, delete it. + if (!value) { + delete result[key]; + } + } + return result; +} +exports.parseParams = parseParams; function getCookieValueFromHeaders(headers, key) { if (headers === undefined || headers === null) { return undefined; @@ -74,7 +124,8 @@ function JSONCookie(str) { } try { return JSON.parse(str.slice(2)); - } catch (err) { + } + catch (err) { return undefined; } } @@ -101,7 +152,8 @@ function JSONCookies(obj) { function getCharset(req) { try { return (content_type_1.default.parse(req).parameters.charset || "").toLowerCase(); - } catch (e) { + } + catch (e) { return undefined; } } @@ -110,8 +162,7 @@ async function parseJSONBodyFromRequest(req) { if (!encoding.startsWith("utf-")) { throw new Error(`unsupported charset ${encoding.toUpperCase()}`); } - const buffer = await getBody(inflation_1.default(req)); - const str = buffer.toString(encoding); + const str = await inflate(req); if (str.length === 0) { return {}; } @@ -123,17 +174,18 @@ async function parseURLEncodedFormData(req) { if (!encoding.startsWith("utf-")) { throw new Error(`unsupported charset ${encoding.toUpperCase()}`); } - const buffer = await getBody(inflation_1.default(req)); - const str = buffer.toString(encoding); + const str = await inflate(req); let body = {}; for (const [key, val] of new URLSearchParams(str).entries()) { if (key in body) { if (body[key] instanceof Array) { body[key].push(val); - } else { + } + else { body[key] = [body[key], val]; } - } else { + } + else { body[key] = val; } } @@ -146,25 +198,27 @@ async function assertThatBodyParserHasBeenUsedForExpressLikeRequest(method, requ if (typeof request.body === "string") { try { request.body = JSON.parse(request.body); - } catch (err) { + } + catch (err) { if (request.body === "") { request.body = {}; - } else { + } + else { throw new error_1.default({ type: error_1.default.BAD_INPUT_ERROR, message: "API input error: Please make sure to pass a valid JSON input in the request body", }); } } - } else if ( - request.body === undefined || + } + else if (request.body === undefined || Buffer.isBuffer(request.body) || - (Object.keys(request.body).length === 0 && request.readable) - ) { + (Object.keys(request.body).length === 0 && request.readable)) { try { // parsing it again to make sure that the request is parsed atleast once by a json parser request.body = await parseJSONBodyFromRequest(request); - } catch (_a) { + } + catch (_a) { throw new error_1.default({ type: error_1.default.BAD_INPUT_ERROR, message: "API input error: Please make sure to pass a valid JSON input in the request body", @@ -178,25 +232,27 @@ async function assertFormDataBodyParserHasBeenUsedForExpressLikeRequest(request) if (typeof request.body === "string") { try { request.body = Object.fromEntries(new URLSearchParams(request.body).entries()); - } catch (err) { + } + catch (err) { if (request.body === "") { request.body = {}; - } else { + } + else { throw new error_1.default({ type: error_1.default.BAD_INPUT_ERROR, message: "API input error: Please make sure to pass valid url encoded form in the request body", }); } } - } else if ( - request.body === undefined || + } + else if (request.body === undefined || Buffer.isBuffer(request.body) || - (Object.keys(request.body).length === 0 && request.readable) - ) { + (Object.keys(request.body).length === 0 && request.readable)) { try { // parsing it again to make sure that the request is parsed atleast once by a form data parser request.body = await parseURLEncodedFormData(request); - } catch (_a) { + } + catch (_a) { throw new error_1.default({ type: error_1.default.BAD_INPUT_ERROR, message: "API input error: Please make sure to pass valid url encoded form in the request body", @@ -214,10 +270,12 @@ function setHeaderForExpressLikeResponse(res, key, value, allowDuplicateKey) { if (existingValue === undefined) { if (res.header !== undefined) { res.header(key, value); - } else { + } + else { res.setHeader(key, value); } - } else if (allowDuplicateKey) { + } + else if (allowDuplicateKey) { /** We only want to append if it does not already exist For example if the caller is trying to add front token to the access control exposed headers property @@ -226,27 +284,24 @@ function setHeaderForExpressLikeResponse(res, key, value, allowDuplicateKey) { if (typeof existingValue !== "string" || !existingValue.includes(value)) { if (res.header !== undefined) { res.header(key, existingValue + ", " + value); - } else { + } + else { res.setHeader(key, existingValue + ", " + value); } } - } else { + } + else { // we overwrite the current one with the new one if (res.header !== undefined) { res.header(key, value); - } else { + } + else { res.setHeader(key, value); } } - } catch (err) { - throw new Error( - "Error while setting header with key: " + - key + - " and value: " + - value + - "\nError: " + - ((_a = err.message) !== null && _a !== void 0 ? _a : err) - ); + } + catch (err) { + throw new Error("Error while setting header with key: " + key + " and value: " + value + "\nError: " + ((_a = err.message) !== null && _a !== void 0 ? _a : err)); } } exports.setHeaderForExpressLikeResponse = setHeaderForExpressLikeResponse; @@ -262,12 +317,7 @@ exports.setHeaderForExpressLikeResponse = setHeaderForExpressLikeResponse; * @param path */ function setCookieForServerResponse(res, key, value, domain, secure, httpOnly, expires, path, sameSite) { - return appendToServerResponse( - res, - constants_1.COOKIE_HEADER, - serializeCookieValue(key, value, domain, secure, httpOnly, expires, path, sameSite), - key - ); + return appendToServerResponse(res, constants_1.COOKIE_HEADER, serializeCookieValue(key, value, domain, secure, httpOnly, expires, path, sameSite), key); } exports.setCookieForServerResponse = setCookieForServerResponse; /** @@ -299,7 +349,8 @@ function getCookieValueToSetInHeader(prev, val, key) { } } prev = removedDuplicate; - } else { + } + else { if (prev.startsWith(key)) { prev = undefined; } @@ -324,16 +375,3 @@ function serializeCookieValue(key, value, domain, secure, httpOnly, expires, pat return cookie_1.serialize(key, value, opts); } exports.serializeCookieValue = serializeCookieValue; -// based on https://nodejs.org/en/docs/guides/anatomy-of-an-http-transaction -function getBody(request) { - return new Promise((resolve) => { - const bodyParts = []; - request - .on("data", (chunk) => { - bodyParts.push(chunk); - }) - .on("end", () => { - resolve(Buffer.concat(bodyParts)); - }); - }); -} diff --git a/lib/build/nextjs.d.ts b/lib/build/nextjs.d.ts index 7b06b2936..91f323e5e 100644 --- a/lib/build/nextjs.d.ts +++ b/lib/build/nextjs.d.ts @@ -1,4 +1,5 @@ // @ts-nocheck +import './polyfill'; import { CollectingResponse, PreParsedRequest } from "./framework/custom"; import { SessionContainer, VerifySessionOptions } from "./recipe/session"; declare type PartialNextRequest = { @@ -15,38 +16,19 @@ declare type PartialNextRequest = { }; }; export default class NextJS { - static superTokensNextWrapper( - middleware: (next: (middlewareError?: any) => void) => Promise, - request: any, - response: any - ): Promise; - static getAppDirRequestHandler( - NextResponse: typeof Response - ): (req: T) => Promise; + static superTokensNextWrapper(middleware: (next: (middlewareError?: any) => void) => Promise, request: any, response: any): Promise; + static getAppDirRequestHandler(NextResponse: typeof Response): (req: T) => Promise; private static commonSSRSession; - static getSSRSession( - cookies: Array<{ - name: string; - value: string; - }>, - headers: Headers, - options?: VerifySessionOptions, - userContext?: Record - ): Promise<{ + static getSSRSession(cookies: Array<{ + name: string; + value: string; + }>, headers: Headers, options?: VerifySessionOptions, userContext?: Record): Promise<{ session: SessionContainer | undefined; hasToken: boolean; hasInvalidClaims: boolean; }>; - static withSession( - req: NextRequest, - handler: (error: Error | undefined, session: SessionContainer | undefined) => Promise, - options?: VerifySessionOptions, - userContext?: Record - ): Promise; - static withPreParsedRequestResponse( - req: NextRequest, - handler: (baseRequest: PreParsedRequest, baseResponse: CollectingResponse) => Promise - ): Promise; + static withSession(req: NextRequest, handler: (error: Error | undefined, session: SessionContainer | undefined) => Promise, options?: VerifySessionOptions, userContext?: Record): Promise; + static withPreParsedRequestResponse(req: NextRequest, handler: (baseRequest: PreParsedRequest, baseResponse: CollectingResponse) => Promise): Promise; } export declare let superTokensNextWrapper: typeof NextJS.superTokensNextWrapper; export declare let getAppDirRequestHandler: typeof NextJS.getAppDirRequestHandler; diff --git a/lib/build/nextjs.js b/lib/build/nextjs.js index 1435b2cdd..9c36e4b20 100644 --- a/lib/build/nextjs.js +++ b/lib/build/nextjs.js @@ -1,22 +1,4 @@ "use strict"; -var __rest = - (this && this.__rest) || - function (s, e) { - var t = {}; - for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) t[p] = s[p]; - if (s != null && typeof Object.getOwnPropertySymbols === "function") - for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) { - if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i])) t[p[i]] = s[p[i]]; - } - return t; - }; -var __importDefault = - (this && this.__importDefault) || - function (mod) { - return mod && mod.__esModule ? mod : { default: mod }; - }; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.withPreParsedRequestResponse = exports.withSession = exports.getSSRSession = exports.getAppDirRequestHandler = exports.superTokensNextWrapper = void 0; /* Copyright (c) 2021, VRAI Labs and/or its affiliates. All rights reserved. * * This software is licensed under the Apache License, Version 2.0 (the @@ -31,6 +13,23 @@ exports.withPreParsedRequestResponse = exports.withSession = exports.getSSRSessi * License for the specific language governing permissions and limitations * under the License. */ +var __rest = (this && this.__rest) || function (s, e) { + var t = {}; + for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) + t[p] = s[p]; + if (s != null && typeof Object.getOwnPropertySymbols === "function") + for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) { + if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i])) + t[p[i]] = s[p[i]]; + } + return t; +}; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.withPreParsedRequestResponse = exports.withSession = exports.getSSRSession = exports.getAppDirRequestHandler = exports.superTokensNextWrapper = void 0; +require("./polyfill"); const cookie_1 = require("cookie"); const express_1 = require("./framework/express"); const utils_1 = require("./utils"); @@ -65,7 +64,8 @@ class NextJS { if (!callbackCalled && !response.finished && !response.headersSent) { return resolve(result); } - } catch (err) { + } + catch (err) { await express_1.errorHandler()(err, request, response, (errorHandlerError) => { if (errorHandlerError !== undefined) { return reject(errorHandlerError); @@ -99,17 +99,14 @@ class NextJS { return new NextResponse("Not found", { status: 404 }); } for (const respCookie of baseResponse.cookies) { - baseResponse.headers.append( - "Set-Cookie", - cookie_1.serialize(respCookie.key, respCookie.value, { - domain: respCookie.domain, - expires: new Date(respCookie.expires), - httpOnly: respCookie.httpOnly, - path: respCookie.path, - sameSite: respCookie.sameSite, - secure: respCookie.secure, - }) - ); + baseResponse.headers.append("Set-Cookie", cookie_1.serialize(respCookie.key, respCookie.value, { + domain: respCookie.domain, + expires: new Date(respCookie.expires), + httpOnly: respCookie.httpOnly, + path: respCookie.path, + sameSite: respCookie.sameSite, + secure: respCookie.secure, + })); } return new NextResponse(baseResponse.body, { headers: baseResponse.headers, @@ -125,8 +122,7 @@ class NextJS { forCreateNewSession: false, userContext, }); - const transferMethods = - tokenTransferMethod === "any" ? constants_1.availableTokenTransferMethods : [tokenTransferMethod]; + const transferMethods = tokenTransferMethod === "any" ? constants_1.availableTokenTransferMethods : [tokenTransferMethod]; const hasToken = transferMethods.some((transferMethod) => { const token = cookieAndHeaders_1.getToken(baseRequest, "access", transferMethod); if (!token) { @@ -135,7 +131,8 @@ class NextJS { try { jwt_1.parseJWTWithoutSignatureVerification(token); return true; - } catch (_a) { + } + catch (_a) { return false; } }); @@ -147,7 +144,8 @@ class NextJS { hasToken, baseResponse, }; - } catch (err) { + } + catch (err) { if (session_1.default.Error.isErrorFromSuperTokens(err)) { return { hasToken, @@ -158,7 +156,8 @@ class NextJS { status: err.type === session_1.default.Error.INVALID_CLAIMS ? 403 : 401, }), }; - } else { + } + else { throw err; } } @@ -174,9 +173,7 @@ class NextJS { getFormBody: async () => [], getJSONBody: async () => [], }); - const _a = await NextJS.commonSSRSession(baseRequest, options, utils_1.getUserContext(userContext)), - { baseResponse, nextResponse } = _a, - result = __rest(_a, ["baseResponse", "nextResponse"]); + const _a = await NextJS.commonSSRSession(baseRequest, options, utils_1.getUserContext(userContext)), { baseResponse, nextResponse } = _a, result = __rest(_a, ["baseResponse", "nextResponse"]); return result; } static async withSession(req, handler, options, userContext) { @@ -192,18 +189,15 @@ class NextJS { getFormBody: () => req.formData(), getJSONBody: () => req.json(), }); - const { session, nextResponse, baseResponse } = await NextJS.commonSSRSession( - baseRequest, - options, - utils_1.getUserContext(userContext) - ); + const { session, nextResponse, baseResponse } = await NextJS.commonSSRSession(baseRequest, options, utils_1.getUserContext(userContext)); if (nextResponse) { return nextResponse; } let userResponse; try { userResponse = await handler(undefined, session); - } catch (err) { + } + catch (err) { await custom_1.errorHandler()(err, baseRequest, baseResponse, (errorHandlerError) => { if (errorHandlerError) { throw errorHandlerError; @@ -219,17 +213,14 @@ class NextJS { let didAddHeaders = false; for (const respCookie of baseResponse.cookies) { didAddCookies = true; - userResponse.headers.append( - "Set-Cookie", - cookie_1.serialize(respCookie.key, respCookie.value, { - domain: respCookie.domain, - expires: new Date(respCookie.expires), - httpOnly: respCookie.httpOnly, - path: respCookie.path, - sameSite: respCookie.sameSite, - secure: respCookie.secure, - }) - ); + userResponse.headers.append("Set-Cookie", cookie_1.serialize(respCookie.key, respCookie.value, { + domain: respCookie.domain, + expires: new Date(respCookie.expires), + httpOnly: respCookie.httpOnly, + path: respCookie.path, + sameSite: respCookie.sameSite, + secure: respCookie.secure, + })); } baseResponse.headers.forEach((value, key) => { didAddHeaders = true; @@ -250,7 +241,8 @@ class NextJS { } } return userResponse; - } catch (error) { + } + catch (error) { return await handler(error, undefined); } } @@ -270,7 +262,8 @@ class NextJS { let userResponse; try { userResponse = await handler(baseRequest, baseResponse); - } catch (err) { + } + catch (err) { await custom_1.errorHandler()(err, baseRequest, baseResponse, (errorHandlerError) => { if (errorHandlerError) { throw errorHandlerError; @@ -286,17 +279,14 @@ class NextJS { let didAddHeaders = false; for (const respCookie of baseResponse.cookies) { didAddCookies = true; - userResponse.headers.append( - "Set-Cookie", - cookie_1.serialize(respCookie.key, respCookie.value, { - domain: respCookie.domain, - expires: new Date(respCookie.expires), - httpOnly: respCookie.httpOnly, - path: respCookie.path, - sameSite: respCookie.sameSite, - secure: respCookie.secure, - }) - ); + userResponse.headers.append("Set-Cookie", cookie_1.serialize(respCookie.key, respCookie.value, { + domain: respCookie.domain, + expires: new Date(respCookie.expires), + httpOnly: respCookie.httpOnly, + path: respCookie.path, + sameSite: respCookie.sameSite, + secure: respCookie.secure, + })); } baseResponse.headers.forEach((value, key) => { didAddHeaders = true; diff --git a/lib/build/polyfill.d.ts b/lib/build/polyfill.d.ts new file mode 100644 index 000000000..f6617924f --- /dev/null +++ b/lib/build/polyfill.d.ts @@ -0,0 +1 @@ +// @ts-nocheck diff --git a/lib/build/polyfill.js b/lib/build/polyfill.js new file mode 100644 index 000000000..fea70c2ba --- /dev/null +++ b/lib/build/polyfill.js @@ -0,0 +1,9 @@ +"use strict"; +// Check if 'Buffer' is available, if not, polyfill it +if (typeof Buffer === 'undefined') { + global.Buffer = require('buffer').Buffer; +} +// Check if 'process' is available, if not, polyfill it +if (typeof process === 'undefined') { + global.process = require('process'); +} diff --git a/test/framework/utils.test.js b/test/framework/utils.test.js new file mode 100644 index 000000000..91b82644a --- /dev/null +++ b/test/framework/utils.test.js @@ -0,0 +1,14 @@ +let assert = require("assert"); +const { parseParams } = require("../../lib/build/framework/utils"); + +describe("test framework related util functions", () => { + it("should be able to parse params", () => { + assert.deepEqual(parseParams("?a=1&b=secondValue&c="), { a: ["1"], b: ["secondValue"] }); + assert.deepEqual(parseParams("?a=1&b=first,second&c=third"), { + a: ["1"], + b: ["first", "second"], + c: ["third"], + }); + assert.deepEqual(parseParams(""), {}); + }); +}); From 97d723ee8f4131d1cb882a8318cc9124e4b2f651 Mon Sep 17 00:00:00 2001 From: Deepjyoti Barman Date: Fri, 30 Aug 2024 17:36:53 +0530 Subject: [PATCH 05/32] Run build-pretty on all files --- lib/build/framework/awsLambda/framework.js | 78 ++++++----- lib/build/framework/utils.d.ts | 41 +++++- lib/build/framework/utils.js | 146 ++++++++++++--------- lib/build/nextjs.d.ts | 37 ++++-- lib/build/nextjs.js | 121 +++++++++-------- lib/build/polyfill.js | 8 +- lib/ts/framework/awsLambda/framework.ts | 4 +- lib/ts/framework/utils.ts | 12 +- lib/ts/nextjs.ts | 2 +- lib/ts/polyfill.ts | 8 +- 10 files changed, 282 insertions(+), 175 deletions(-) diff --git a/lib/build/framework/awsLambda/framework.js b/lib/build/framework/awsLambda/framework.js index 16489a7a0..6df0f845b 100644 --- a/lib/build/framework/awsLambda/framework.js +++ b/lib/build/framework/awsLambda/framework.js @@ -1,7 +1,9 @@ "use strict"; -var __importDefault = (this && this.__importDefault) || function (mod) { - return (mod && mod.__esModule) ? mod : { "default": mod }; -}; +var __importDefault = + (this && this.__importDefault) || + function (mod) { + return mod && mod.__esModule ? mod : { default: mod }; + }; Object.defineProperty(exports, "__esModule", { value: true }); exports.AWSWrapper = exports.middleware = exports.AWSResponse = exports.AWSRequest = void 0; const utils_1 = require("../../utils"); @@ -16,8 +18,7 @@ class AWSRequest extends request_1.BaseRequest { this.getFormDataFromRequestBody = async () => { if (this.event.body === null || this.event.body === undefined) { return {}; - } - else { + } else { const parsedUrlEncodedFormData = utils_2.parseParams(this.event.body); return parsedUrlEncodedFormData === undefined ? {} : parsedUrlEncodedFormData; } @@ -25,8 +26,7 @@ class AWSRequest extends request_1.BaseRequest { this.getJSONFromRequestBody = async () => { if (this.event.body === null || this.event.body === undefined) { return {}; - } - else { + } else { const parsedJSONBody = JSON.parse(this.event.body); return parsedJSONBody === undefined ? {} : parsedJSONBody; } @@ -50,15 +50,20 @@ class AWSRequest extends request_1.BaseRequest { }; this.getCookieValue = (key) => { let cookies = this.event.cookies; - if ((this.event.headers === undefined || this.event.headers === null) && - (cookies === undefined || cookies === null)) { + if ( + (this.event.headers === undefined || this.event.headers === null) && + (cookies === undefined || cookies === null) + ) { return undefined; } let value = utils_2.getCookieValueFromHeaders(this.event.headers, key); if (value === undefined && cookies !== undefined && cookies !== null) { - value = utils_2.getCookieValueFromHeaders({ - cookie: cookies.join(";"), - }, key); + value = utils_2.getCookieValueFromHeaders( + { + cookie: cookies.join(";"), + }, + key + ); } return value; }; @@ -109,10 +114,21 @@ class AWSResponse extends response_1.BaseResponse { }); }; this.removeHeader = (key) => { - this.event.supertokens.response.headers = this.event.supertokens.response.headers.filter((header) => header.key.toLowerCase() !== key.toLowerCase()); + this.event.supertokens.response.headers = this.event.supertokens.response.headers.filter( + (header) => header.key.toLowerCase() !== key.toLowerCase() + ); }; this.setCookie = (key, value, domain, secure, httpOnly, expires, path, sameSite) => { - let serialisedCookie = utils_2.serializeCookieValue(key, value, domain, secure, httpOnly, expires, path, sameSite); + let serialisedCookie = utils_2.serializeCookieValue( + key, + value, + domain, + secure, + httpOnly, + expires, + path, + sameSite + ); this.event.supertokens.response.cookies = [ ...this.event.supertokens.response.cookies.filter((c) => !c.startsWith(key + "=")), serialisedCookie, @@ -166,13 +182,14 @@ class AWSResponse extends response_1.BaseResponse { For example if the caller is trying to add front token to the access control exposed headers property we do not want to append if something else had already added it */ - if (typeof currentValue !== "string" || - !currentValue.includes(supertokensHeaders[i].value.toString())) { + if ( + typeof currentValue !== "string" || + !currentValue.includes(supertokensHeaders[i].value.toString()) + ) { let newValue = `${currentValue}, ${supertokensHeaders[i].value}`; headers[supertokensHeaders[i].key] = newValue; } - } - else { + } else { headers[supertokensHeaders[i].key] = supertokensHeaders[i].value; } } @@ -182,26 +199,28 @@ class AWSResponse extends response_1.BaseResponse { cookies = []; } cookies.push(...supertokensCookies); - let result = Object.assign(Object.assign({}, response), { cookies, - body, - statusCode, - headers }); + let result = Object.assign(Object.assign({}, response), { cookies, body, statusCode, headers }); return result; - } - else { + } else { let multiValueHeaders = response.multiValueHeaders; if (multiValueHeaders === undefined) { multiValueHeaders = {}; } let headsersInMultiValueHeaders = Object.keys(multiValueHeaders); - let cookieHeader = headsersInMultiValueHeaders.find((h) => h.toLowerCase() === constants_1.COOKIE_HEADER.toLowerCase()); + let cookieHeader = headsersInMultiValueHeaders.find( + (h) => h.toLowerCase() === constants_1.COOKIE_HEADER.toLowerCase() + ); if (cookieHeader === undefined) { multiValueHeaders[constants_1.COOKIE_HEADER] = supertokensCookies; - } - else { + } else { multiValueHeaders[cookieHeader].push(...supertokensCookies); } - let result = Object.assign(Object.assign({}, response), { multiValueHeaders, body: body, statusCode: statusCode, headers }); + let result = Object.assign(Object.assign({}, response), { + multiValueHeaders, + body: body, + statusCode: statusCode, + headers, + }); return result; } }; @@ -244,8 +263,7 @@ const middleware = (handler) => { error: `The middleware couldn't serve the API path ${request.getOriginalURL()}, method: ${request.getMethod()}. If this is an unexpected behaviour, please create an issue here: https://github.com/supertokens/supertokens-node/issues`, }); return response.sendResponse(); - } - catch (err) { + } catch (err) { await supertokens.errorHandler(err, request, response, userContext); if (response.responseSet) { return response.sendResponse(); diff --git a/lib/build/framework/utils.d.ts b/lib/build/framework/utils.d.ts index afd051456..e9e4a1132 100644 --- a/lib/build/framework/utils.d.ts +++ b/lib/build/framework/utils.d.ts @@ -11,9 +11,17 @@ export declare function getHeaderValueFromIncomingMessage(request: IncomingMessa export declare function normalizeHeaderValue(value: string | string[] | undefined): string | undefined; export declare function parseJSONBodyFromRequest(req: IncomingMessage): Promise; export declare function parseURLEncodedFormData(req: IncomingMessage): Promise; -export declare function assertThatBodyParserHasBeenUsedForExpressLikeRequest(method: HTTPMethod, request: Request): Promise; +export declare function assertThatBodyParserHasBeenUsedForExpressLikeRequest( + method: HTTPMethod, + request: Request +): Promise; export declare function assertFormDataBodyParserHasBeenUsedForExpressLikeRequest(request: Request): Promise; -export declare function setHeaderForExpressLikeResponse(res: Response, key: string, value: string, allowDuplicateKey: boolean): void; +export declare function setHeaderForExpressLikeResponse( + res: Response, + key: string, + value: string, + allowDuplicateKey: boolean +): void; /** * * @param res @@ -25,6 +33,29 @@ export declare function setHeaderForExpressLikeResponse(res: Response, key: stri * @param expires * @param path */ -export declare function setCookieForServerResponse(res: ServerResponse, key: string, value: string, domain: string | undefined, secure: boolean, httpOnly: boolean, expires: number, path: string, sameSite: "strict" | "lax" | "none"): ServerResponse; -export declare function getCookieValueToSetInHeader(prev: string | string[] | undefined, val: string | string[], key: string): string | string[]; -export declare function serializeCookieValue(key: string, value: string, domain: string | undefined, secure: boolean, httpOnly: boolean, expires: number, path: string, sameSite: "strict" | "lax" | "none"): string; +export declare function setCookieForServerResponse( + res: ServerResponse, + key: string, + value: string, + domain: string | undefined, + secure: boolean, + httpOnly: boolean, + expires: number, + path: string, + sameSite: "strict" | "lax" | "none" +): ServerResponse; +export declare function getCookieValueToSetInHeader( + prev: string | string[] | undefined, + val: string | string[], + key: string +): string | string[]; +export declare function serializeCookieValue( + key: string, + value: string, + domain: string | undefined, + secure: boolean, + httpOnly: boolean, + expires: number, + path: string, + sameSite: "strict" | "lax" | "none" +): string; diff --git a/lib/build/framework/utils.js b/lib/build/framework/utils.js index 6e3ef3c07..00bda6edd 100644 --- a/lib/build/framework/utils.js +++ b/lib/build/framework/utils.js @@ -13,16 +13,43 @@ * License for the specific language governing permissions and limitations * under the License. */ -var __asyncValues = (this && this.__asyncValues) || function (o) { - if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined."); - var m = o[Symbol.asyncIterator], i; - return m ? m.call(o) : (o = typeof __values === "function" ? __values(o) : o[Symbol.iterator](), i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i); - function verb(n) { i[n] = o[n] && function (v) { return new Promise(function (resolve, reject) { v = o[n](v), settle(resolve, reject, v.done, v.value); }); }; } - function settle(resolve, reject, d, v) { Promise.resolve(v).then(function(v) { resolve({ value: v, done: d }); }, reject); } -}; -var __importDefault = (this && this.__importDefault) || function (mod) { - return (mod && mod.__esModule) ? mod : { "default": mod }; -}; +var __asyncValues = + (this && this.__asyncValues) || + function (o) { + if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined."); + var m = o[Symbol.asyncIterator], + i; + return m + ? m.call(o) + : ((o = typeof __values === "function" ? __values(o) : o[Symbol.iterator]()), + (i = {}), + verb("next"), + verb("throw"), + verb("return"), + (i[Symbol.asyncIterator] = function () { + return this; + }), + i); + function verb(n) { + i[n] = + o[n] && + function (v) { + return new Promise(function (resolve, reject) { + (v = o[n](v)), settle(resolve, reject, v.done, v.value); + }); + }; + } + function settle(resolve, reject, d, v) { + Promise.resolve(v).then(function (v) { + resolve({ value: v, done: d }); + }, reject); + } + }; +var __importDefault = + (this && this.__importDefault) || + function (mod) { + return mod && mod.__esModule ? mod : { default: mod }; + }; Object.defineProperty(exports, "__esModule", { value: true }); exports.serializeCookieValue = exports.getCookieValueToSetInHeader = exports.setCookieForServerResponse = exports.setHeaderForExpressLikeResponse = exports.assertFormDataBodyParserHasBeenUsedForExpressLikeRequest = exports.assertThatBodyParserHasBeenUsedForExpressLikeRequest = exports.parseURLEncodedFormData = exports.parseJSONBodyFromRequest = exports.normalizeHeaderValue = exports.getHeaderValueFromIncomingMessage = exports.getCookieValueFromIncomingMessage = exports.getCookieValueFromHeaders = exports.parseParams = void 0; const cookie_1 = require("cookie"); @@ -39,22 +66,26 @@ async function inflate(stream) { const encoding = stream.headers && stream.headers["content-encoding"]; let i = new pako_1.default.Inflate(); try { - for (var stream_1 = __asyncValues(stream), stream_1_1; stream_1_1 = await stream_1.next(), !stream_1_1.done;) { + for ( + var stream_1 = __asyncValues(stream), stream_1_1; + (stream_1_1 = await stream_1.next()), !stream_1_1.done; + + ) { const chunk = stream_1_1.value; i.push(Buffer.from(chunk)); } - } - catch (e_1_1) { e_1 = { error: e_1_1 }; } - finally { + } catch (e_1_1) { + e_1 = { error: e_1_1 }; + } finally { try { if (stream_1_1 && !stream_1_1.done && (_a = stream_1.return)) await _a.call(stream_1); + } finally { + if (e_1) throw e_1.error; } - finally { if (e_1) throw e_1.error; } } if (typeof i.result === "string") { return i.result; - } - else { + } else { return new TextDecoder(encoding).decode(i.result, { stream: true }); } } @@ -124,8 +155,7 @@ function JSONCookie(str) { } try { return JSON.parse(str.slice(2)); - } - catch (err) { + } catch (err) { return undefined; } } @@ -152,8 +182,7 @@ function JSONCookies(obj) { function getCharset(req) { try { return (content_type_1.default.parse(req).parameters.charset || "").toLowerCase(); - } - catch (e) { + } catch (e) { return undefined; } } @@ -180,12 +209,10 @@ async function parseURLEncodedFormData(req) { if (key in body) { if (body[key] instanceof Array) { body[key].push(val); - } - else { + } else { body[key] = [body[key], val]; } - } - else { + } else { body[key] = val; } } @@ -198,27 +225,25 @@ async function assertThatBodyParserHasBeenUsedForExpressLikeRequest(method, requ if (typeof request.body === "string") { try { request.body = JSON.parse(request.body); - } - catch (err) { + } catch (err) { if (request.body === "") { request.body = {}; - } - else { + } else { throw new error_1.default({ type: error_1.default.BAD_INPUT_ERROR, message: "API input error: Please make sure to pass a valid JSON input in the request body", }); } } - } - else if (request.body === undefined || + } else if ( + request.body === undefined || Buffer.isBuffer(request.body) || - (Object.keys(request.body).length === 0 && request.readable)) { + (Object.keys(request.body).length === 0 && request.readable) + ) { try { // parsing it again to make sure that the request is parsed atleast once by a json parser request.body = await parseJSONBodyFromRequest(request); - } - catch (_a) { + } catch (_a) { throw new error_1.default({ type: error_1.default.BAD_INPUT_ERROR, message: "API input error: Please make sure to pass a valid JSON input in the request body", @@ -232,27 +257,25 @@ async function assertFormDataBodyParserHasBeenUsedForExpressLikeRequest(request) if (typeof request.body === "string") { try { request.body = Object.fromEntries(new URLSearchParams(request.body).entries()); - } - catch (err) { + } catch (err) { if (request.body === "") { request.body = {}; - } - else { + } else { throw new error_1.default({ type: error_1.default.BAD_INPUT_ERROR, message: "API input error: Please make sure to pass valid url encoded form in the request body", }); } } - } - else if (request.body === undefined || + } else if ( + request.body === undefined || Buffer.isBuffer(request.body) || - (Object.keys(request.body).length === 0 && request.readable)) { + (Object.keys(request.body).length === 0 && request.readable) + ) { try { // parsing it again to make sure that the request is parsed atleast once by a form data parser request.body = await parseURLEncodedFormData(request); - } - catch (_a) { + } catch (_a) { throw new error_1.default({ type: error_1.default.BAD_INPUT_ERROR, message: "API input error: Please make sure to pass valid url encoded form in the request body", @@ -270,12 +293,10 @@ function setHeaderForExpressLikeResponse(res, key, value, allowDuplicateKey) { if (existingValue === undefined) { if (res.header !== undefined) { res.header(key, value); - } - else { + } else { res.setHeader(key, value); } - } - else if (allowDuplicateKey) { + } else if (allowDuplicateKey) { /** We only want to append if it does not already exist For example if the caller is trying to add front token to the access control exposed headers property @@ -284,24 +305,27 @@ function setHeaderForExpressLikeResponse(res, key, value, allowDuplicateKey) { if (typeof existingValue !== "string" || !existingValue.includes(value)) { if (res.header !== undefined) { res.header(key, existingValue + ", " + value); - } - else { + } else { res.setHeader(key, existingValue + ", " + value); } } - } - else { + } else { // we overwrite the current one with the new one if (res.header !== undefined) { res.header(key, value); - } - else { + } else { res.setHeader(key, value); } } - } - catch (err) { - throw new Error("Error while setting header with key: " + key + " and value: " + value + "\nError: " + ((_a = err.message) !== null && _a !== void 0 ? _a : err)); + } catch (err) { + throw new Error( + "Error while setting header with key: " + + key + + " and value: " + + value + + "\nError: " + + ((_a = err.message) !== null && _a !== void 0 ? _a : err) + ); } } exports.setHeaderForExpressLikeResponse = setHeaderForExpressLikeResponse; @@ -317,7 +341,12 @@ exports.setHeaderForExpressLikeResponse = setHeaderForExpressLikeResponse; * @param path */ function setCookieForServerResponse(res, key, value, domain, secure, httpOnly, expires, path, sameSite) { - return appendToServerResponse(res, constants_1.COOKIE_HEADER, serializeCookieValue(key, value, domain, secure, httpOnly, expires, path, sameSite), key); + return appendToServerResponse( + res, + constants_1.COOKIE_HEADER, + serializeCookieValue(key, value, domain, secure, httpOnly, expires, path, sameSite), + key + ); } exports.setCookieForServerResponse = setCookieForServerResponse; /** @@ -349,8 +378,7 @@ function getCookieValueToSetInHeader(prev, val, key) { } } prev = removedDuplicate; - } - else { + } else { if (prev.startsWith(key)) { prev = undefined; } diff --git a/lib/build/nextjs.d.ts b/lib/build/nextjs.d.ts index 91f323e5e..3493fd9ee 100644 --- a/lib/build/nextjs.d.ts +++ b/lib/build/nextjs.d.ts @@ -1,5 +1,5 @@ // @ts-nocheck -import './polyfill'; +import "./polyfill"; import { CollectingResponse, PreParsedRequest } from "./framework/custom"; import { SessionContainer, VerifySessionOptions } from "./recipe/session"; declare type PartialNextRequest = { @@ -16,19 +16,38 @@ declare type PartialNextRequest = { }; }; export default class NextJS { - static superTokensNextWrapper(middleware: (next: (middlewareError?: any) => void) => Promise, request: any, response: any): Promise; - static getAppDirRequestHandler(NextResponse: typeof Response): (req: T) => Promise; + static superTokensNextWrapper( + middleware: (next: (middlewareError?: any) => void) => Promise, + request: any, + response: any + ): Promise; + static getAppDirRequestHandler( + NextResponse: typeof Response + ): (req: T) => Promise; private static commonSSRSession; - static getSSRSession(cookies: Array<{ - name: string; - value: string; - }>, headers: Headers, options?: VerifySessionOptions, userContext?: Record): Promise<{ + static getSSRSession( + cookies: Array<{ + name: string; + value: string; + }>, + headers: Headers, + options?: VerifySessionOptions, + userContext?: Record + ): Promise<{ session: SessionContainer | undefined; hasToken: boolean; hasInvalidClaims: boolean; }>; - static withSession(req: NextRequest, handler: (error: Error | undefined, session: SessionContainer | undefined) => Promise, options?: VerifySessionOptions, userContext?: Record): Promise; - static withPreParsedRequestResponse(req: NextRequest, handler: (baseRequest: PreParsedRequest, baseResponse: CollectingResponse) => Promise): Promise; + static withSession( + req: NextRequest, + handler: (error: Error | undefined, session: SessionContainer | undefined) => Promise, + options?: VerifySessionOptions, + userContext?: Record + ): Promise; + static withPreParsedRequestResponse( + req: NextRequest, + handler: (baseRequest: PreParsedRequest, baseResponse: CollectingResponse) => Promise + ): Promise; } export declare let superTokensNextWrapper: typeof NextJS.superTokensNextWrapper; export declare let getAppDirRequestHandler: typeof NextJS.getAppDirRequestHandler; diff --git a/lib/build/nextjs.js b/lib/build/nextjs.js index 9c36e4b20..7e6f35e90 100644 --- a/lib/build/nextjs.js +++ b/lib/build/nextjs.js @@ -13,20 +13,22 @@ * License for the specific language governing permissions and limitations * under the License. */ -var __rest = (this && this.__rest) || function (s, e) { - var t = {}; - for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) - t[p] = s[p]; - if (s != null && typeof Object.getOwnPropertySymbols === "function") - for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) { - if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i])) - t[p[i]] = s[p[i]]; - } - return t; -}; -var __importDefault = (this && this.__importDefault) || function (mod) { - return (mod && mod.__esModule) ? mod : { "default": mod }; -}; +var __rest = + (this && this.__rest) || + function (s, e) { + var t = {}; + for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) t[p] = s[p]; + if (s != null && typeof Object.getOwnPropertySymbols === "function") + for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) { + if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i])) t[p[i]] = s[p[i]]; + } + return t; + }; +var __importDefault = + (this && this.__importDefault) || + function (mod) { + return mod && mod.__esModule ? mod : { default: mod }; + }; Object.defineProperty(exports, "__esModule", { value: true }); exports.withPreParsedRequestResponse = exports.withSession = exports.getSSRSession = exports.getAppDirRequestHandler = exports.superTokensNextWrapper = void 0; require("./polyfill"); @@ -64,8 +66,7 @@ class NextJS { if (!callbackCalled && !response.finished && !response.headersSent) { return resolve(result); } - } - catch (err) { + } catch (err) { await express_1.errorHandler()(err, request, response, (errorHandlerError) => { if (errorHandlerError !== undefined) { return reject(errorHandlerError); @@ -99,14 +100,17 @@ class NextJS { return new NextResponse("Not found", { status: 404 }); } for (const respCookie of baseResponse.cookies) { - baseResponse.headers.append("Set-Cookie", cookie_1.serialize(respCookie.key, respCookie.value, { - domain: respCookie.domain, - expires: new Date(respCookie.expires), - httpOnly: respCookie.httpOnly, - path: respCookie.path, - sameSite: respCookie.sameSite, - secure: respCookie.secure, - })); + baseResponse.headers.append( + "Set-Cookie", + cookie_1.serialize(respCookie.key, respCookie.value, { + domain: respCookie.domain, + expires: new Date(respCookie.expires), + httpOnly: respCookie.httpOnly, + path: respCookie.path, + sameSite: respCookie.sameSite, + secure: respCookie.secure, + }) + ); } return new NextResponse(baseResponse.body, { headers: baseResponse.headers, @@ -122,7 +126,8 @@ class NextJS { forCreateNewSession: false, userContext, }); - const transferMethods = tokenTransferMethod === "any" ? constants_1.availableTokenTransferMethods : [tokenTransferMethod]; + const transferMethods = + tokenTransferMethod === "any" ? constants_1.availableTokenTransferMethods : [tokenTransferMethod]; const hasToken = transferMethods.some((transferMethod) => { const token = cookieAndHeaders_1.getToken(baseRequest, "access", transferMethod); if (!token) { @@ -131,8 +136,7 @@ class NextJS { try { jwt_1.parseJWTWithoutSignatureVerification(token); return true; - } - catch (_a) { + } catch (_a) { return false; } }); @@ -144,8 +148,7 @@ class NextJS { hasToken, baseResponse, }; - } - catch (err) { + } catch (err) { if (session_1.default.Error.isErrorFromSuperTokens(err)) { return { hasToken, @@ -156,8 +159,7 @@ class NextJS { status: err.type === session_1.default.Error.INVALID_CLAIMS ? 403 : 401, }), }; - } - else { + } else { throw err; } } @@ -173,7 +175,9 @@ class NextJS { getFormBody: async () => [], getJSONBody: async () => [], }); - const _a = await NextJS.commonSSRSession(baseRequest, options, utils_1.getUserContext(userContext)), { baseResponse, nextResponse } = _a, result = __rest(_a, ["baseResponse", "nextResponse"]); + const _a = await NextJS.commonSSRSession(baseRequest, options, utils_1.getUserContext(userContext)), + { baseResponse, nextResponse } = _a, + result = __rest(_a, ["baseResponse", "nextResponse"]); return result; } static async withSession(req, handler, options, userContext) { @@ -189,15 +193,18 @@ class NextJS { getFormBody: () => req.formData(), getJSONBody: () => req.json(), }); - const { session, nextResponse, baseResponse } = await NextJS.commonSSRSession(baseRequest, options, utils_1.getUserContext(userContext)); + const { session, nextResponse, baseResponse } = await NextJS.commonSSRSession( + baseRequest, + options, + utils_1.getUserContext(userContext) + ); if (nextResponse) { return nextResponse; } let userResponse; try { userResponse = await handler(undefined, session); - } - catch (err) { + } catch (err) { await custom_1.errorHandler()(err, baseRequest, baseResponse, (errorHandlerError) => { if (errorHandlerError) { throw errorHandlerError; @@ -213,14 +220,17 @@ class NextJS { let didAddHeaders = false; for (const respCookie of baseResponse.cookies) { didAddCookies = true; - userResponse.headers.append("Set-Cookie", cookie_1.serialize(respCookie.key, respCookie.value, { - domain: respCookie.domain, - expires: new Date(respCookie.expires), - httpOnly: respCookie.httpOnly, - path: respCookie.path, - sameSite: respCookie.sameSite, - secure: respCookie.secure, - })); + userResponse.headers.append( + "Set-Cookie", + cookie_1.serialize(respCookie.key, respCookie.value, { + domain: respCookie.domain, + expires: new Date(respCookie.expires), + httpOnly: respCookie.httpOnly, + path: respCookie.path, + sameSite: respCookie.sameSite, + secure: respCookie.secure, + }) + ); } baseResponse.headers.forEach((value, key) => { didAddHeaders = true; @@ -241,8 +251,7 @@ class NextJS { } } return userResponse; - } - catch (error) { + } catch (error) { return await handler(error, undefined); } } @@ -262,8 +271,7 @@ class NextJS { let userResponse; try { userResponse = await handler(baseRequest, baseResponse); - } - catch (err) { + } catch (err) { await custom_1.errorHandler()(err, baseRequest, baseResponse, (errorHandlerError) => { if (errorHandlerError) { throw errorHandlerError; @@ -279,14 +287,17 @@ class NextJS { let didAddHeaders = false; for (const respCookie of baseResponse.cookies) { didAddCookies = true; - userResponse.headers.append("Set-Cookie", cookie_1.serialize(respCookie.key, respCookie.value, { - domain: respCookie.domain, - expires: new Date(respCookie.expires), - httpOnly: respCookie.httpOnly, - path: respCookie.path, - sameSite: respCookie.sameSite, - secure: respCookie.secure, - })); + userResponse.headers.append( + "Set-Cookie", + cookie_1.serialize(respCookie.key, respCookie.value, { + domain: respCookie.domain, + expires: new Date(respCookie.expires), + httpOnly: respCookie.httpOnly, + path: respCookie.path, + sameSite: respCookie.sameSite, + secure: respCookie.secure, + }) + ); } baseResponse.headers.forEach((value, key) => { didAddHeaders = true; diff --git a/lib/build/polyfill.js b/lib/build/polyfill.js index fea70c2ba..26b21b34e 100644 --- a/lib/build/polyfill.js +++ b/lib/build/polyfill.js @@ -1,9 +1,9 @@ "use strict"; // Check if 'Buffer' is available, if not, polyfill it -if (typeof Buffer === 'undefined') { - global.Buffer = require('buffer').Buffer; +if (typeof Buffer === "undefined") { + global.Buffer = require("buffer").Buffer; } // Check if 'process' is available, if not, polyfill it -if (typeof process === 'undefined') { - global.process = require('process'); +if (typeof process === "undefined") { + global.process = require("process"); } diff --git a/lib/ts/framework/awsLambda/framework.ts b/lib/ts/framework/awsLambda/framework.ts index 5c29a4bdc..202fe2b81 100644 --- a/lib/ts/framework/awsLambda/framework.ts +++ b/lib/ts/framework/awsLambda/framework.ts @@ -228,8 +228,8 @@ export class AWSResponse extends BaseResponse { } let headers: | { - [header: string]: boolean | number | string; - } + [header: string]: boolean | number | string; + } | undefined = response.headers; if (headers === undefined) { headers = {}; diff --git a/lib/ts/framework/utils.ts b/lib/ts/framework/utils.ts index 72c2502a0..989eaf1fb 100644 --- a/lib/ts/framework/utils.ts +++ b/lib/ts/framework/utils.ts @@ -45,25 +45,25 @@ async function inflate(stream: IncomingMessage): Promise { export function parseParams(string: string): object { // Set up a new URLSearchParams object using the string. - const params = new URLSearchParams(string) + const params = new URLSearchParams(string); // Get an iterator for the URLSearchParams object. - const entries = params.entries() + const entries = params.entries(); - const result: { [key: string]: any } = {} + const result: { [key: string]: any } = {}; // Loop through the URLSearchParams object and add each key/value for (const [key, value] of entries) { // Split comma-separated values into an array. - result[key] = value.split(",") + result[key] = value.split(","); // If a key does not have a value, delete it. if (!value) { - delete result[key] + delete result[key]; } } - return result + return result; } export function getCookieValueFromHeaders(headers: any, key: string): string | undefined { diff --git a/lib/ts/nextjs.ts b/lib/ts/nextjs.ts index 9f9fb92ec..b9668f31b 100644 --- a/lib/ts/nextjs.ts +++ b/lib/ts/nextjs.ts @@ -13,7 +13,7 @@ * under the License. */ -import './polyfill' +import "./polyfill"; import { serialize } from "cookie"; import { errorHandler } from "./framework/express"; diff --git a/lib/ts/polyfill.ts b/lib/ts/polyfill.ts index a3a474067..3f39afdb5 100644 --- a/lib/ts/polyfill.ts +++ b/lib/ts/polyfill.ts @@ -1,9 +1,9 @@ // Check if 'Buffer' is available, if not, polyfill it -if (typeof Buffer === 'undefined') { - global.Buffer = require('buffer').Buffer; +if (typeof Buffer === "undefined") { + global.Buffer = require("buffer").Buffer; } // Check if 'process' is available, if not, polyfill it -if (typeof process === 'undefined') { - global.process = require('process'); +if (typeof process === "undefined") { + global.process = require("process"); } From ab4f5f98caba5be344fd3bbbb6b07559b34a9aeb Mon Sep 17 00:00:00 2001 From: Deepjyoti Barman Date: Fri, 30 Aug 2024 17:46:22 +0530 Subject: [PATCH 06/32] Add a workflow for testing Next.JS with edge runtime --- .github/workflows/test-edge-function-next.yml | 40 +++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 .github/workflows/test-edge-function-next.yml diff --git a/.github/workflows/test-edge-function-next.yml b/.github/workflows/test-edge-function-next.yml new file mode 100644 index 000000000..0f8501a94 --- /dev/null +++ b/.github/workflows/test-edge-function-next.yml @@ -0,0 +1,40 @@ +name: "Test edge function compatibility for NextJS" +on: push +jobs: + test: + runs-on: ubuntu-latest + env: + NETLIFY_AUTH_TOKEN: ${{ secrets.netlify_auth_token }} + NETLIFY_SITE_ID: ${{ secrets.netlify_site_id }} + TEST_DEPLOYED_VERSION: true + defaults: + run: + working-directory: examples/next/with-emailpassword + steps: + - uses: actions/checkout@v2 + - run: echo $GITHUB_SHA + - run: npm install git+https://github.com:supertokens/supertokens-node.git#$GITHUB_SHA + - run: npm install + - run: npm install mocha@6.1.4 jsdom-global@3.0.2 puppeteer@^11.0.0 isomorphic-fetch@^3.0.0 + + # Step to update the runtime to edge to all files in app/api/ and pages/api/ + - name: Add runtime export to API files + run: | + find app/api -type f -name "*.js" -exec sed -i '1s/^/export const runtime = "edge";\n/' {} + + find pages/api -type f -name "*.js" -exec sed -i '1s/^/export const runtime = "edge";\n/' {} + + + - run: netlify deploy --alias 0 --build --json --auth=$NETLIFY_AUTH_TOKEN > deployInfo.json + - run: cat deployInfo.json + - run: | + ( \ + (echo "=========== Test attempt 1 ===========" && npx mocha --no-config --timeout 80000 test/**/*.test.js) || \ + (echo "=========== Test attempt 2 ===========" && npx mocha --no-config --timeout 80000 test/**/*.test.js) || \ + (echo "=========== Test attempt 3 ===========" && npx mocha --no-config --timeout 80000 test/**/*.test.js) \ + ) + - name: The job has failed + if: ${{ failure() }} + uses: actions/upload-artifact@v3 + with: + name: screenshots + path: | + ./**/*screenshot.jpeg From a0145dc295ff82b764572382f608c9242aef0d77 Mon Sep 17 00:00:00 2001 From: Deepjyoti Barman Date: Fri, 30 Aug 2024 18:46:59 +0530 Subject: [PATCH 07/32] Add support for gzip compression --- lib/build/framework/utils.js | 71 +++++++++++++++++++++++++----------- lib/ts/framework/utils.ts | 32 ++++++++++++---- 2 files changed, 74 insertions(+), 29 deletions(-) diff --git a/lib/build/framework/utils.js b/lib/build/framework/utils.js index 00bda6edd..0f2ad4b49 100644 --- a/lib/build/framework/utils.js +++ b/lib/build/framework/utils.js @@ -59,35 +59,60 @@ const utils_1 = require("../utils"); const content_type_1 = __importDefault(require("content-type")); const pako_1 = __importDefault(require("pako")); async function inflate(stream) { - var e_1, _a; + var e_1, _a, e_2, _b; if (!stream) { throw new TypeError("argument stream is required"); } - const encoding = stream.headers && stream.headers["content-encoding"]; - let i = new pako_1.default.Inflate(); - try { - for ( - var stream_1 = __asyncValues(stream), stream_1_1; - (stream_1_1 = await stream_1.next()), !stream_1_1.done; + const encoding = (stream.headers && stream.headers["content-encoding"]) || "identity"; + let decompressedData; + if (encoding === "gzip" || encoding === "deflate") { + const inflator = new pako_1.default.Inflate(); + try { + for ( + var stream_1 = __asyncValues(stream), stream_1_1; + (stream_1_1 = await stream_1.next()), !stream_1_1.done; - ) { - const chunk = stream_1_1.value; - i.push(Buffer.from(chunk)); + ) { + const chunk = stream_1_1.value; + inflator.push(chunk, false); + } + } catch (e_1_1) { + e_1 = { error: e_1_1 }; + } finally { + try { + if (stream_1_1 && !stream_1_1.done && (_a = stream_1.return)) await _a.call(stream_1); + } finally { + if (e_1) throw e_1.error; + } + } + if (inflator.err) { + throw new Error(`Decompression error: ${inflator.msg}`); } - } catch (e_1_1) { - e_1 = { error: e_1_1 }; - } finally { + decompressedData = inflator.result; + } else { + // Handle identity or unsupported encoding + decompressedData = Buffer.concat([]); try { - if (stream_1_1 && !stream_1_1.done && (_a = stream_1.return)) await _a.call(stream_1); + for ( + var stream_2 = __asyncValues(stream), stream_2_1; + (stream_2_1 = await stream_2.next()), !stream_2_1.done; + + ) { + const chunk = stream_2_1.value; + decompressedData = Buffer.concat([decompressedData, chunk]); + } + } catch (e_2_1) { + e_2 = { error: e_2_1 }; } finally { - if (e_1) throw e_1.error; + try { + if (stream_2_1 && !stream_2_1.done && (_b = stream_2.return)) await _b.call(stream_2); + } finally { + if (e_2) throw e_2.error; + } } } - if (typeof i.result === "string") { - return i.result; - } else { - return new TextDecoder(encoding).decode(i.result, { stream: true }); - } + if (typeof decompressedData === "string") return decompressedData; + return new TextDecoder().decode(decompressedData); } function parseParams(string) { // Set up a new URLSearchParams object using the string. @@ -220,6 +245,7 @@ async function parseURLEncodedFormData(req) { } exports.parseURLEncodedFormData = parseURLEncodedFormData; async function assertThatBodyParserHasBeenUsedForExpressLikeRequest(method, request) { + console.log("Entering assert 1"); // according to https://github.com/supertokens/supertokens-node/issues/33 if (method === "post" || method === "put") { if (typeof request.body === "string") { @@ -240,10 +266,12 @@ async function assertThatBodyParserHasBeenUsedForExpressLikeRequest(method, requ Buffer.isBuffer(request.body) || (Object.keys(request.body).length === 0 && request.readable) ) { + console.log("buffer detected"); try { // parsing it again to make sure that the request is parsed atleast once by a json parser request.body = await parseJSONBodyFromRequest(request); - } catch (_a) { + } catch (err) { + console.log("Err: ", err); throw new error_1.default({ type: error_1.default.BAD_INPUT_ERROR, message: "API input error: Please make sure to pass a valid JSON input in the request body", @@ -254,6 +282,7 @@ async function assertThatBodyParserHasBeenUsedForExpressLikeRequest(method, requ } exports.assertThatBodyParserHasBeenUsedForExpressLikeRequest = assertThatBodyParserHasBeenUsedForExpressLikeRequest; async function assertFormDataBodyParserHasBeenUsedForExpressLikeRequest(request) { + console.log("Entering assert 2"); if (typeof request.body === "string") { try { request.body = Object.fromEntries(new URLSearchParams(request.body).entries()); diff --git a/lib/ts/framework/utils.ts b/lib/ts/framework/utils.ts index 989eaf1fb..3d99688e1 100644 --- a/lib/ts/framework/utils.ts +++ b/lib/ts/framework/utils.ts @@ -29,18 +29,33 @@ async function inflate(stream: IncomingMessage): Promise { throw new TypeError("argument stream is required"); } - const encoding = stream.headers && stream.headers["content-encoding"]; + const encoding = (stream.headers && stream.headers["content-encoding"]) || "identity"; - let i = new pako.Inflate(); - for await (const chunk of stream) { - i.push(Buffer.from(chunk)); - } + let decompressedData: Uint8Array | string; + + if (encoding === "gzip" || encoding === "deflate") { + const inflator = new pako.Inflate(); - if (typeof i.result === "string") { - return i.result; + for await (const chunk of stream) { + inflator.push(chunk, false); + } + + if (inflator.err) { + throw new Error(`Decompression error: ${inflator.msg}`); + } + + decompressedData = inflator.result; } else { - return new TextDecoder(encoding).decode(i.result, { stream: true }); + // Handle identity or unsupported encoding + decompressedData = Buffer.concat([]); + for await (const chunk of stream) { + decompressedData = Buffer.concat([decompressedData, chunk]); + } } + + if (typeof decompressedData === "string") return decompressedData; + + return new TextDecoder().decode(decompressedData); } export function parseParams(string: string): object { @@ -229,6 +244,7 @@ export async function assertThatBodyParserHasBeenUsedForExpressLikeRequest(metho } export async function assertFormDataBodyParserHasBeenUsedForExpressLikeRequest(request: Request) { + console.log("Entering assert 2"); if (typeof request.body === "string") { try { request.body = Object.fromEntries(new URLSearchParams(request.body).entries()); From aad18adadd84e45b52978e7977753aedecb89319 Mon Sep 17 00:00:00 2001 From: Deepjyoti Barman Date: Fri, 30 Aug 2024 18:55:04 +0530 Subject: [PATCH 08/32] Add support for br compression --- lib/build/framework/utils.js | 37 ++++++++++++++++++++++++++++-------- lib/ts/framework/utils.ts | 11 ++++++++++- package-lock.json | 36 +++++++++++++++++++++++++++++++++++ package.json | 2 ++ 4 files changed, 77 insertions(+), 9 deletions(-) diff --git a/lib/build/framework/utils.js b/lib/build/framework/utils.js index 0f2ad4b49..52b688fd0 100644 --- a/lib/build/framework/utils.js +++ b/lib/build/framework/utils.js @@ -58,8 +58,9 @@ const constants_1 = require("./constants"); const utils_1 = require("../utils"); const content_type_1 = __importDefault(require("content-type")); const pako_1 = __importDefault(require("pako")); +const brotli_1 = require("brotli"); async function inflate(stream) { - var e_1, _a, e_2, _b; + var e_1, _a, e_2, _b, e_3, _c; if (!stream) { throw new TypeError("argument stream is required"); } @@ -89,9 +90,8 @@ async function inflate(stream) { throw new Error(`Decompression error: ${inflator.msg}`); } decompressedData = inflator.result; - } else { - // Handle identity or unsupported encoding - decompressedData = Buffer.concat([]); + } else if (encoding === "br") { + const chunks = []; try { for ( var stream_2 = __asyncValues(stream), stream_2_1; @@ -99,7 +99,7 @@ async function inflate(stream) { ) { const chunk = stream_2_1.value; - decompressedData = Buffer.concat([decompressedData, chunk]); + chunks.push(chunk); } } catch (e_2_1) { e_2 = { error: e_2_1 }; @@ -110,6 +110,29 @@ async function inflate(stream) { if (e_2) throw e_2.error; } } + const compressedData = Buffer.concat(chunks); + decompressedData = brotli_1.decompress(compressedData); + } else { + // Handle identity or unsupported encoding + decompressedData = Buffer.concat([]); + try { + for ( + var stream_3 = __asyncValues(stream), stream_3_1; + (stream_3_1 = await stream_3.next()), !stream_3_1.done; + + ) { + const chunk = stream_3_1.value; + decompressedData = Buffer.concat([decompressedData, chunk]); + } + } catch (e_3_1) { + e_3 = { error: e_3_1 }; + } finally { + try { + if (stream_3_1 && !stream_3_1.done && (_c = stream_3.return)) await _c.call(stream_3); + } finally { + if (e_3) throw e_3.error; + } + } } if (typeof decompressedData === "string") return decompressedData; return new TextDecoder().decode(decompressedData); @@ -245,7 +268,6 @@ async function parseURLEncodedFormData(req) { } exports.parseURLEncodedFormData = parseURLEncodedFormData; async function assertThatBodyParserHasBeenUsedForExpressLikeRequest(method, request) { - console.log("Entering assert 1"); // according to https://github.com/supertokens/supertokens-node/issues/33 if (method === "post" || method === "put") { if (typeof request.body === "string") { @@ -266,12 +288,11 @@ async function assertThatBodyParserHasBeenUsedForExpressLikeRequest(method, requ Buffer.isBuffer(request.body) || (Object.keys(request.body).length === 0 && request.readable) ) { - console.log("buffer detected"); try { // parsing it again to make sure that the request is parsed atleast once by a json parser request.body = await parseJSONBodyFromRequest(request); } catch (err) { - console.log("Err: ", err); + console.log("err:", err); throw new error_1.default({ type: error_1.default.BAD_INPUT_ERROR, message: "API input error: Please make sure to pass a valid JSON input in the request body", diff --git a/lib/ts/framework/utils.ts b/lib/ts/framework/utils.ts index 3d99688e1..d0b801918 100644 --- a/lib/ts/framework/utils.ts +++ b/lib/ts/framework/utils.ts @@ -23,6 +23,7 @@ import { COOKIE_HEADER } from "./constants"; import { getFromObjectCaseInsensitive } from "../utils"; import contentType from "content-type"; import pako from "pako"; +import { decompress as brotliDecompress } from "brotli"; async function inflate(stream: IncomingMessage): Promise { if (!stream) { @@ -45,6 +46,13 @@ async function inflate(stream: IncomingMessage): Promise { } decompressedData = inflator.result; + } else if (encoding === "br") { + const chunks: Buffer[] = []; + for await (const chunk of stream) { + chunks.push(chunk); + } + const compressedData = Buffer.concat(chunks); + decompressedData = brotliDecompress(compressedData); } else { // Handle identity or unsupported encoding decompressedData = Buffer.concat([]); @@ -233,7 +241,8 @@ export async function assertThatBodyParserHasBeenUsedForExpressLikeRequest(metho try { // parsing it again to make sure that the request is parsed atleast once by a json parser request.body = await parseJSONBodyFromRequest(request); - } catch { + } catch (err) { + console.log("err:", err); throw new STError({ type: STError.BAD_INPUT_ERROR, message: "API input error: Please make sure to pass a valid JSON input in the request body", diff --git a/package-lock.json b/package-lock.json index c30f253ca..bdd877b9c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,6 +9,7 @@ "version": "20.0.3", "license": "Apache-2.0", "dependencies": { + "brotli": "^1.3.3", "buffer": "^6.0.3", "content-type": "^1.0.5", "cookie": "0.4.0", @@ -31,6 +32,7 @@ "@loopback/repository": "3.7.1", "@loopback/rest": "9.3.0", "@types/aws-lambda": "8.10.77", + "@types/brotli": "^1.3.4", "@types/co-body": "^5.1.1", "@types/content-type": "^1.1.5", "@types/cookie": "0.3.3", @@ -1436,6 +1438,15 @@ "@types/node": "*" } }, + "node_modules/@types/brotli": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/@types/brotli/-/brotli-1.3.4.tgz", + "integrity": "sha512-cKYjgaS2DMdCKF7R0F5cgx1nfBYObN2ihIuPGQ4/dlIY6RpV7OWNwe9L8V4tTVKL2eZqOkNM9FM/rgTvLf4oXw==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/co-body": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/@types/co-body/-/co-body-5.1.1.tgz", @@ -2346,6 +2357,14 @@ "node": ">=8" } }, + "node_modules/brotli": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/brotli/-/brotli-1.3.3.tgz", + "integrity": "sha512-oTKjJdShmDuGW94SyyaoQvAjf30dZaHnjJ8uAF+u2/vGJkJbJPJAT1gDiOJP5v1Zb6f9KEyW/1HpuaWIXtGHPg==", + "dependencies": { + "base64-js": "^1.1.2" + } + }, "node_modules/browser-stdout": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", @@ -9343,6 +9362,15 @@ "@types/node": "*" } }, + "@types/brotli": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/@types/brotli/-/brotli-1.3.4.tgz", + "integrity": "sha512-cKYjgaS2DMdCKF7R0F5cgx1nfBYObN2ihIuPGQ4/dlIY6RpV7OWNwe9L8V4tTVKL2eZqOkNM9FM/rgTvLf4oXw==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, "@types/co-body": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/@types/co-body/-/co-body-5.1.1.tgz", @@ -10144,6 +10172,14 @@ "fill-range": "^7.0.1" } }, + "brotli": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/brotli/-/brotli-1.3.3.tgz", + "integrity": "sha512-oTKjJdShmDuGW94SyyaoQvAjf30dZaHnjJ8uAF+u2/vGJkJbJPJAT1gDiOJP5v1Zb6f9KEyW/1HpuaWIXtGHPg==", + "requires": { + "base64-js": "^1.1.2" + } + }, "browser-stdout": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", diff --git a/package.json b/package.json index b3e830963..d0e6f338b 100644 --- a/package.json +++ b/package.json @@ -113,6 +113,7 @@ }, "homepage": "https://github.com/supertokens/supertokens-node#readme", "dependencies": { + "brotli": "^1.3.3", "buffer": "^6.0.3", "content-type": "^1.0.5", "cookie": "0.4.0", @@ -135,6 +136,7 @@ "@loopback/repository": "3.7.1", "@loopback/rest": "9.3.0", "@types/aws-lambda": "8.10.77", + "@types/brotli": "^1.3.4", "@types/co-body": "^5.1.1", "@types/content-type": "^1.1.5", "@types/cookie": "0.3.3", From 028edd8409937a2e177e80e90292bc9d578ae795 Mon Sep 17 00:00:00 2001 From: Deepjyoti Barman Date: Fri, 30 Aug 2024 19:21:53 +0530 Subject: [PATCH 09/32] Disable brotli compression in edge --- lib/build/framework/utils.js | 11 +++++++++-- lib/ts/framework/utils.ts | 12 +++++++++++- 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/lib/build/framework/utils.js b/lib/build/framework/utils.js index 52b688fd0..2f592ca32 100644 --- a/lib/build/framework/utils.js +++ b/lib/build/framework/utils.js @@ -58,7 +58,13 @@ const constants_1 = require("./constants"); const utils_1 = require("../utils"); const content_type_1 = __importDefault(require("content-type")); const pako_1 = __importDefault(require("pako")); -const brotli_1 = require("brotli"); +let brotliDecompress = null; +try { + // @ts-ignore + if (typeof EdgeRuntime === "undefined") brotliDecompress = require("brotli").decompress; +} catch (error) { + brotliDecompress = null; +} async function inflate(stream) { var e_1, _a, e_2, _b, e_3, _c; if (!stream) { @@ -91,6 +97,7 @@ async function inflate(stream) { } decompressedData = inflator.result; } else if (encoding === "br") { + if (!brotliDecompress) throw new Error("Brotli decompression not supported on the platform"); const chunks = []; try { for ( @@ -111,7 +118,7 @@ async function inflate(stream) { } } const compressedData = Buffer.concat(chunks); - decompressedData = brotli_1.decompress(compressedData); + decompressedData = brotliDecompress(compressedData); } else { // Handle identity or unsupported encoding decompressedData = Buffer.concat([]); diff --git a/lib/ts/framework/utils.ts b/lib/ts/framework/utils.ts index d0b801918..bc81e7712 100644 --- a/lib/ts/framework/utils.ts +++ b/lib/ts/framework/utils.ts @@ -23,7 +23,15 @@ import { COOKIE_HEADER } from "./constants"; import { getFromObjectCaseInsensitive } from "../utils"; import contentType from "content-type"; import pako from "pako"; -import { decompress as brotliDecompress } from "brotli"; + +let brotliDecompress: ((input: Buffer) => Buffer) | null = null; + +try { + // @ts-ignore + if (typeof EdgeRuntime === "undefined") brotliDecompress = require("brotli").decompress; +} catch (error) { + brotliDecompress = null; +} async function inflate(stream: IncomingMessage): Promise { if (!stream) { @@ -47,6 +55,8 @@ async function inflate(stream: IncomingMessage): Promise { decompressedData = inflator.result; } else if (encoding === "br") { + if (!brotliDecompress) throw new Error("Brotli decompression not supported on the platform"); + const chunks: Buffer[] = []; for await (const chunk of stream) { chunks.push(chunk); From 15ac6244441886d9d5dbf7a9ac21f14593f87d09 Mon Sep 17 00:00:00 2001 From: Deepjyoti Barman Date: Sat, 31 Aug 2024 09:55:54 +0530 Subject: [PATCH 10/32] Remove unnecessary log --- lib/build/framework/utils.js | 4 +--- lib/ts/framework/utils.ts | 4 +--- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/lib/build/framework/utils.js b/lib/build/framework/utils.js index 2f592ca32..c3e906c67 100644 --- a/lib/build/framework/utils.js +++ b/lib/build/framework/utils.js @@ -298,8 +298,7 @@ async function assertThatBodyParserHasBeenUsedForExpressLikeRequest(method, requ try { // parsing it again to make sure that the request is parsed atleast once by a json parser request.body = await parseJSONBodyFromRequest(request); - } catch (err) { - console.log("err:", err); + } catch (_a) { throw new error_1.default({ type: error_1.default.BAD_INPUT_ERROR, message: "API input error: Please make sure to pass a valid JSON input in the request body", @@ -310,7 +309,6 @@ async function assertThatBodyParserHasBeenUsedForExpressLikeRequest(method, requ } exports.assertThatBodyParserHasBeenUsedForExpressLikeRequest = assertThatBodyParserHasBeenUsedForExpressLikeRequest; async function assertFormDataBodyParserHasBeenUsedForExpressLikeRequest(request) { - console.log("Entering assert 2"); if (typeof request.body === "string") { try { request.body = Object.fromEntries(new URLSearchParams(request.body).entries()); diff --git a/lib/ts/framework/utils.ts b/lib/ts/framework/utils.ts index bc81e7712..2b6668d63 100644 --- a/lib/ts/framework/utils.ts +++ b/lib/ts/framework/utils.ts @@ -251,8 +251,7 @@ export async function assertThatBodyParserHasBeenUsedForExpressLikeRequest(metho try { // parsing it again to make sure that the request is parsed atleast once by a json parser request.body = await parseJSONBodyFromRequest(request); - } catch (err) { - console.log("err:", err); + } catch { throw new STError({ type: STError.BAD_INPUT_ERROR, message: "API input error: Please make sure to pass a valid JSON input in the request body", @@ -263,7 +262,6 @@ export async function assertThatBodyParserHasBeenUsedForExpressLikeRequest(metho } export async function assertFormDataBodyParserHasBeenUsedForExpressLikeRequest(request: Request) { - console.log("Entering assert 2"); if (typeof request.body === "string") { try { request.body = Object.fromEntries(new URLSearchParams(request.body).entries()); From 5a9649d4f5c07224727dd18648895cb1a2896355 Mon Sep 17 00:00:00 2001 From: Deepjyoti Barman Date: Mon, 2 Sep 2024 17:10:31 +0530 Subject: [PATCH 11/32] Replace parseParams with one URLSearchParams alternative --- lib/build/framework/awsLambda/framework.js | 2 +- lib/build/framework/utils.d.ts | 1 - lib/build/framework/utils.js | 20 +------------------ lib/ts/framework/awsLambda/framework.ts | 4 ++-- lib/ts/framework/utils.ts | 23 ---------------------- 5 files changed, 4 insertions(+), 46 deletions(-) diff --git a/lib/build/framework/awsLambda/framework.js b/lib/build/framework/awsLambda/framework.js index 6df0f845b..8c2679cfc 100644 --- a/lib/build/framework/awsLambda/framework.js +++ b/lib/build/framework/awsLambda/framework.js @@ -19,7 +19,7 @@ class AWSRequest extends request_1.BaseRequest { if (this.event.body === null || this.event.body === undefined) { return {}; } else { - const parsedUrlEncodedFormData = utils_2.parseParams(this.event.body); + const parsedUrlEncodedFormData = Object.fromEntries(new URLSearchParams(this.event.body).entries()); return parsedUrlEncodedFormData === undefined ? {} : parsedUrlEncodedFormData; } }; diff --git a/lib/build/framework/utils.d.ts b/lib/build/framework/utils.d.ts index e9e4a1132..9350de8b2 100644 --- a/lib/build/framework/utils.d.ts +++ b/lib/build/framework/utils.d.ts @@ -4,7 +4,6 @@ import type { Request, Response } from "express"; import type { IncomingMessage } from "http"; import { ServerResponse } from "http"; import type { HTTPMethod } from "../types"; -export declare function parseParams(string: string): object; export declare function getCookieValueFromHeaders(headers: any, key: string): string | undefined; export declare function getCookieValueFromIncomingMessage(request: IncomingMessage, key: string): string | undefined; export declare function getHeaderValueFromIncomingMessage(request: IncomingMessage, key: string): string | undefined; diff --git a/lib/build/framework/utils.js b/lib/build/framework/utils.js index c3e906c67..1917088ed 100644 --- a/lib/build/framework/utils.js +++ b/lib/build/framework/utils.js @@ -51,7 +51,7 @@ var __importDefault = return mod && mod.__esModule ? mod : { default: mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); -exports.serializeCookieValue = exports.getCookieValueToSetInHeader = exports.setCookieForServerResponse = exports.setHeaderForExpressLikeResponse = exports.assertFormDataBodyParserHasBeenUsedForExpressLikeRequest = exports.assertThatBodyParserHasBeenUsedForExpressLikeRequest = exports.parseURLEncodedFormData = exports.parseJSONBodyFromRequest = exports.normalizeHeaderValue = exports.getHeaderValueFromIncomingMessage = exports.getCookieValueFromIncomingMessage = exports.getCookieValueFromHeaders = exports.parseParams = void 0; +exports.serializeCookieValue = exports.getCookieValueToSetInHeader = exports.setCookieForServerResponse = exports.setHeaderForExpressLikeResponse = exports.assertFormDataBodyParserHasBeenUsedForExpressLikeRequest = exports.assertThatBodyParserHasBeenUsedForExpressLikeRequest = exports.parseURLEncodedFormData = exports.parseJSONBodyFromRequest = exports.normalizeHeaderValue = exports.getHeaderValueFromIncomingMessage = exports.getCookieValueFromIncomingMessage = exports.getCookieValueFromHeaders = void 0; const cookie_1 = require("cookie"); const error_1 = __importDefault(require("../error")); const constants_1 = require("./constants"); @@ -144,24 +144,6 @@ async function inflate(stream) { if (typeof decompressedData === "string") return decompressedData; return new TextDecoder().decode(decompressedData); } -function parseParams(string) { - // Set up a new URLSearchParams object using the string. - const params = new URLSearchParams(string); - // Get an iterator for the URLSearchParams object. - const entries = params.entries(); - const result = {}; - // Loop through the URLSearchParams object and add each key/value - for (const [key, value] of entries) { - // Split comma-separated values into an array. - result[key] = value.split(","); - // If a key does not have a value, delete it. - if (!value) { - delete result[key]; - } - } - return result; -} -exports.parseParams = parseParams; function getCookieValueFromHeaders(headers, key) { if (headers === undefined || headers === null) { return undefined; diff --git a/lib/ts/framework/awsLambda/framework.ts b/lib/ts/framework/awsLambda/framework.ts index 202fe2b81..12b912fdc 100644 --- a/lib/ts/framework/awsLambda/framework.ts +++ b/lib/ts/framework/awsLambda/framework.ts @@ -25,7 +25,7 @@ import { HTTPMethod } from "../../types"; import { getFromObjectCaseInsensitive, makeDefaultUserContextFromAPI, normaliseHttpMethod } from "../../utils"; import { BaseRequest } from "../request"; import { BaseResponse } from "../response"; -import { normalizeHeaderValue, getCookieValueFromHeaders, serializeCookieValue, parseParams } from "../utils"; +import { normalizeHeaderValue, getCookieValueFromHeaders, serializeCookieValue } from "../utils"; import { COOKIE_HEADER } from "../constants"; import { SessionContainerInterface } from "../../recipe/session/types"; import SuperTokens from "../../supertokens"; @@ -44,7 +44,7 @@ export class AWSRequest extends BaseRequest { if (this.event.body === null || this.event.body === undefined) { return {}; } else { - const parsedUrlEncodedFormData = parseParams(this.event.body); + const parsedUrlEncodedFormData = Object.fromEntries(new URLSearchParams(this.event.body).entries()); return parsedUrlEncodedFormData === undefined ? {} : parsedUrlEncodedFormData; } }; diff --git a/lib/ts/framework/utils.ts b/lib/ts/framework/utils.ts index 2b6668d63..fc4d28e60 100644 --- a/lib/ts/framework/utils.ts +++ b/lib/ts/framework/utils.ts @@ -76,29 +76,6 @@ async function inflate(stream: IncomingMessage): Promise { return new TextDecoder().decode(decompressedData); } -export function parseParams(string: string): object { - // Set up a new URLSearchParams object using the string. - const params = new URLSearchParams(string); - - // Get an iterator for the URLSearchParams object. - const entries = params.entries(); - - const result: { [key: string]: any } = {}; - - // Loop through the URLSearchParams object and add each key/value - for (const [key, value] of entries) { - // Split comma-separated values into an array. - result[key] = value.split(","); - - // If a key does not have a value, delete it. - if (!value) { - delete result[key]; - } - } - - return result; -} - export function getCookieValueFromHeaders(headers: any, key: string): string | undefined { if (headers === undefined || headers === null) { return undefined; From a9d65358f4dad420629c8042a2560dc04713e3bd Mon Sep 17 00:00:00 2001 From: Deepjyoti Barman Date: Mon, 2 Sep 2024 17:32:03 +0530 Subject: [PATCH 12/32] Add support for throwing a proper error when brotli doesn't work --- lib/build/framework/constants.d.ts | 1 + lib/build/framework/constants.js | 4 +++- lib/build/framework/utils.js | 12 ++++++++++-- lib/ts/framework/constants.ts | 3 +++ lib/ts/framework/utils.ts | 15 ++++++++++++--- 5 files changed, 29 insertions(+), 6 deletions(-) diff --git a/lib/build/framework/constants.d.ts b/lib/build/framework/constants.d.ts index eb751247f..2dd4989bd 100644 --- a/lib/build/framework/constants.d.ts +++ b/lib/build/framework/constants.d.ts @@ -1,2 +1,3 @@ // @ts-nocheck export declare const COOKIE_HEADER = "Set-Cookie"; +export declare const BROTLI_DECOMPRESSION_ERROR_MESSAGE = "Brotli decompression not supported on the platform"; diff --git a/lib/build/framework/constants.js b/lib/build/framework/constants.js index 8a7a8ea6c..d5f167a4c 100644 --- a/lib/build/framework/constants.js +++ b/lib/build/framework/constants.js @@ -1,6 +1,6 @@ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -exports.COOKIE_HEADER = void 0; +exports.BROTLI_DECOMPRESSION_ERROR_MESSAGE = exports.COOKIE_HEADER = void 0; /* Copyright (c) 2021, VRAI Labs and/or its affiliates. All rights reserved. * * This software is licensed under the Apache License, Version 2.0 (the @@ -16,3 +16,5 @@ exports.COOKIE_HEADER = void 0; * under the License. */ exports.COOKIE_HEADER = "Set-Cookie"; +// Define error message for brotli decompression not being supported +exports.BROTLI_DECOMPRESSION_ERROR_MESSAGE = "Brotli decompression not supported on the platform"; diff --git a/lib/build/framework/utils.js b/lib/build/framework/utils.js index 1917088ed..b57b5fd0d 100644 --- a/lib/build/framework/utils.js +++ b/lib/build/framework/utils.js @@ -97,7 +97,7 @@ async function inflate(stream) { } decompressedData = inflator.result; } else if (encoding === "br") { - if (!brotliDecompress) throw new Error("Brotli decompression not supported on the platform"); + if (!brotliDecompress) throw new Error(constants_1.BROTLI_DECOMPRESSION_ERROR_MESSAGE); const chunks = []; try { for ( @@ -280,7 +280,15 @@ async function assertThatBodyParserHasBeenUsedForExpressLikeRequest(method, requ try { // parsing it again to make sure that the request is parsed atleast once by a json parser request.body = await parseJSONBodyFromRequest(request); - } catch (_a) { + } catch (err) { + // If the error message matches the brotli decompression + // related error, then throw that error. + if (err.message === constants_1.BROTLI_DECOMPRESSION_ERROR_MESSAGE) { + throw new error_1.default({ + type: error_1.default.BAD_INPUT_ERROR, + message: `API input error: ${constants_1.BROTLI_DECOMPRESSION_ERROR_MESSAGE}`, + }); + } throw new error_1.default({ type: error_1.default.BAD_INPUT_ERROR, message: "API input error: Please make sure to pass a valid JSON input in the request body", diff --git a/lib/ts/framework/constants.ts b/lib/ts/framework/constants.ts index 603783285..c194e19f5 100644 --- a/lib/ts/framework/constants.ts +++ b/lib/ts/framework/constants.ts @@ -13,3 +13,6 @@ * under the License. */ export const COOKIE_HEADER = "Set-Cookie"; + +// Define error message for brotli decompression not being supported +export const BROTLI_DECOMPRESSION_ERROR_MESSAGE = "Brotli decompression not supported on the platform"; diff --git a/lib/ts/framework/utils.ts b/lib/ts/framework/utils.ts index fc4d28e60..90f52efa7 100644 --- a/lib/ts/framework/utils.ts +++ b/lib/ts/framework/utils.ts @@ -19,7 +19,7 @@ import type { IncomingMessage } from "http"; import { ServerResponse } from "http"; import STError from "../error"; import type { HTTPMethod } from "../types"; -import { COOKIE_HEADER } from "./constants"; +import { BROTLI_DECOMPRESSION_ERROR_MESSAGE, COOKIE_HEADER } from "./constants"; import { getFromObjectCaseInsensitive } from "../utils"; import contentType from "content-type"; import pako from "pako"; @@ -55,7 +55,7 @@ async function inflate(stream: IncomingMessage): Promise { decompressedData = inflator.result; } else if (encoding === "br") { - if (!brotliDecompress) throw new Error("Brotli decompression not supported on the platform"); + if (!brotliDecompress) throw new Error(BROTLI_DECOMPRESSION_ERROR_MESSAGE); const chunks: Buffer[] = []; for await (const chunk of stream) { @@ -228,7 +228,16 @@ export async function assertThatBodyParserHasBeenUsedForExpressLikeRequest(metho try { // parsing it again to make sure that the request is parsed atleast once by a json parser request.body = await parseJSONBodyFromRequest(request); - } catch { + } catch (err) { + // If the error message matches the brotli decompression + // related error, then throw that error. + if (err.message === BROTLI_DECOMPRESSION_ERROR_MESSAGE) { + throw new STError({ + type: STError.BAD_INPUT_ERROR, + message: `API input error: ${BROTLI_DECOMPRESSION_ERROR_MESSAGE}`, + }); + } + throw new STError({ type: STError.BAD_INPUT_ERROR, message: "API input error: Please make sure to pass a valid JSON input in the request body", From 7cd8d97cb0dec3ebfe547f9abf3bcb41a41d862f Mon Sep 17 00:00:00 2001 From: Deepjyoti Barman Date: Tue, 3 Sep 2024 12:38:17 +0530 Subject: [PATCH 13/32] Add support for CF workflow to test edge function compatibility --- .github/workflows/test-cf-worker-next.yml | 73 +++++++++++++++++++ .../app/api/auth/[...auth]/route.ts | 37 ++++++++++ 2 files changed, 110 insertions(+) create mode 100644 .github/workflows/test-cf-worker-next.yml create mode 100644 examples/next/with-emailpassword/app/api/auth/[...auth]/route.ts diff --git a/.github/workflows/test-cf-worker-next.yml b/.github/workflows/test-cf-worker-next.yml new file mode 100644 index 000000000..3b9f9a513 --- /dev/null +++ b/.github/workflows/test-cf-worker-next.yml @@ -0,0 +1,73 @@ +name: "Test edge function compatibility for Next.js on Cloudflare Workers" +on: push +jobs: + test: + runs-on: ubuntu-latest + env: + CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }} + CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }} + APP_URL: supertokens-node-b95.pages.dev + TEST_DEPLOYED_VERSION: true + defaults: + run: + working-directory: examples/next/with-emailpassword + steps: + - uses: actions/checkout@v2 + - run: echo $GITHUB_SHA + - run: npm install git+https://github.com:supertokens/supertokens-node.git#$GITHUB_SHA + - run: npm install + - run: npm install mocha@6.1.4 jsdom-global@3.0.2 puppeteer@^11.0.0 isomorphic-fetch@^3.0.0 + + # Step to update the runtime to edge to all files in app/api/ and remove pages path + # to avoid conflicts + - name: Add runtime export to API files + run: | + rm -rf pages + find app/api -type f \( -name "*.js" -o -name "*.ts" \) -exec sed -i '1s/^/export const runtime = "edge";\n/' {} + + echo 'export const runtime = "edge";' >> app/auth/[[...path]]/page.tsx + + # Install next on pages to build the app + - name: Install next-on-pages + run: npm install --save-dev @cloudflare/next-on-pages + + # Setup the compatibility flag to make non edge functions run + - name: Create a wrangler.toml + run: echo "compatibility_flags = [ "nodejs_compat" ]" >> wrangler.toml + + - name: Replace APP_URL with deployed URL value + run: | + sed -i "s|process.env.APP_URL|\"${{ env.APP_URL }}\"|" config/appInfo.ts + - name: Build using next-on-pages + run: npx next-on-pages + + - name: Publish to Cloudflare Pages + id: deploy + uses: cloudflare/pages-action@v1 + with: + apiToken: ${{ env.CLOUDFLARE_API_TOKEN }} + accountId: ${{ env.CLOUDFLARE_ACCOUNT_ID }} + projectName: "supertokens-node-pr-check-for-edge-function-compat" + directory: "./examples/next/with-emailpassword/.vercel/output/static" + wranglerVersion: "3" + branch: "master" + + - name: Extract deployment info and save to JSON + id: extract_deploy_info + run: | + DEPLOY_ID=${{ steps.deploy.outputs.id }} + DEPLOY_URL=${{ steps.deploy.outputs.url }} + echo "{\"deploy_url\": \"$DEPLOY_URL\", \"deploy_id\": \"$DEPLOY_ID\"}" > deployInfo.json + - name: Run tests + run: | + ( \ + (echo "=========== Test attempt 1 ===========" && npx mocha --no-config --timeout 80000 test/**/*.test.js) || \ + (echo "=========== Test attempt 2 ===========" && npx mocha --no-config --timeout 80000 test/**/*.test.js) || \ + (echo "=========== Test attempt 3 ===========" && npx mocha --no-config --timeout 80000 test/**/*.test.js) \ + ) + - name: The job has failed + if: ${{ failure() }} + uses: actions/upload-artifact@v3 + with: + name: screenshots + path: | + ./**/*screenshot.jpeg diff --git a/examples/next/with-emailpassword/app/api/auth/[...auth]/route.ts b/examples/next/with-emailpassword/app/api/auth/[...auth]/route.ts new file mode 100644 index 000000000..4385f250f --- /dev/null +++ b/examples/next/with-emailpassword/app/api/auth/[...auth]/route.ts @@ -0,0 +1,37 @@ +import { getAppDirRequestHandler } from "supertokens-node/nextjs"; +import { NextRequest, NextResponse } from "next/server"; +import supertokens from "supertokens-node"; +import { backendConfig } from "../../../../config/backendConfig"; + +supertokens.init(backendConfig()); + +const handleCall = getAppDirRequestHandler(NextResponse); + +export async function GET(request: NextRequest) { + const res = await handleCall(request); + if (!res.headers.has("Cache-Control")) { + // This is needed for production deployments with Vercel + res.headers.set("Cache-Control", "no-cache, no-store, max-age=0, must-revalidate"); + } + return res; +} + +export async function POST(request: NextRequest) { + return handleCall(request); +} + +export async function DELETE(request: NextRequest) { + return handleCall(request); +} + +export async function PUT(request: NextRequest) { + return handleCall(request); +} + +export async function PATCH(request: NextRequest) { + return handleCall(request); +} + +export async function HEAD(request: NextRequest) { + return handleCall(request); +} From cbfbc633a7c4e5680b7ab27341e69bd4e7041ff2 Mon Sep 17 00:00:00 2001 From: Deepjyoti Barman Date: Tue, 3 Sep 2024 12:38:57 +0530 Subject: [PATCH 14/32] Get rid of netflify edge test function --- .github/workflows/test-edge-function-next.yml | 40 ------------------- 1 file changed, 40 deletions(-) delete mode 100644 .github/workflows/test-edge-function-next.yml diff --git a/.github/workflows/test-edge-function-next.yml b/.github/workflows/test-edge-function-next.yml deleted file mode 100644 index 0f8501a94..000000000 --- a/.github/workflows/test-edge-function-next.yml +++ /dev/null @@ -1,40 +0,0 @@ -name: "Test edge function compatibility for NextJS" -on: push -jobs: - test: - runs-on: ubuntu-latest - env: - NETLIFY_AUTH_TOKEN: ${{ secrets.netlify_auth_token }} - NETLIFY_SITE_ID: ${{ secrets.netlify_site_id }} - TEST_DEPLOYED_VERSION: true - defaults: - run: - working-directory: examples/next/with-emailpassword - steps: - - uses: actions/checkout@v2 - - run: echo $GITHUB_SHA - - run: npm install git+https://github.com:supertokens/supertokens-node.git#$GITHUB_SHA - - run: npm install - - run: npm install mocha@6.1.4 jsdom-global@3.0.2 puppeteer@^11.0.0 isomorphic-fetch@^3.0.0 - - # Step to update the runtime to edge to all files in app/api/ and pages/api/ - - name: Add runtime export to API files - run: | - find app/api -type f -name "*.js" -exec sed -i '1s/^/export const runtime = "edge";\n/' {} + - find pages/api -type f -name "*.js" -exec sed -i '1s/^/export const runtime = "edge";\n/' {} + - - - run: netlify deploy --alias 0 --build --json --auth=$NETLIFY_AUTH_TOKEN > deployInfo.json - - run: cat deployInfo.json - - run: | - ( \ - (echo "=========== Test attempt 1 ===========" && npx mocha --no-config --timeout 80000 test/**/*.test.js) || \ - (echo "=========== Test attempt 2 ===========" && npx mocha --no-config --timeout 80000 test/**/*.test.js) || \ - (echo "=========== Test attempt 3 ===========" && npx mocha --no-config --timeout 80000 test/**/*.test.js) \ - ) - - name: The job has failed - if: ${{ failure() }} - uses: actions/upload-artifact@v3 - with: - name: screenshots - path: | - ./**/*screenshot.jpeg From 4a0b2c355e8e7040f739977fc268d1de0ccfb6f2 Mon Sep 17 00:00:00 2001 From: Deepjyoti Barman Date: Tue, 3 Sep 2024 12:40:54 +0530 Subject: [PATCH 15/32] Remove newly added conflicting route from netlify next test wf --- .github/workflows/test-edge-function.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.github/workflows/test-edge-function.yml b/.github/workflows/test-edge-function.yml index a6824b9dc..54029da46 100644 --- a/.github/workflows/test-edge-function.yml +++ b/.github/workflows/test-edge-function.yml @@ -16,6 +16,12 @@ jobs: - run: npm install git+https://github.com:supertokens/supertokens-node.git#$GITHUB_SHA - run: npm install - run: npm install mocha@6.1.4 jsdom-global@3.0.2 puppeteer@^11.0.0 isomorphic-fetch@^3.0.0 + + # Remove the `/app/api/auth` directory as it will conflict with the `pages` routes + # which were added for compatibility with edge in Cloudflare. + - name: Remove possibly conflicting directory. + run: rm -rf app/api/auth + - run: netlify deploy --alias 0 --build --json --auth=$NETLIFY_AUTH_TOKEN > deployInfo.json - run: cat deployInfo.json - run: | From fcc69f4dfccc2c44d78968a0ff6ad704744ff74b Mon Sep 17 00:00:00 2001 From: Deepjyoti Barman Date: Tue, 3 Sep 2024 12:41:25 +0530 Subject: [PATCH 16/32] Rename api/auth dynamic variable in next app router --- .../app/api/auth/{[...auth] => [...path]}/route.ts | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename examples/next/with-emailpassword/app/api/auth/{[...auth] => [...path]}/route.ts (100%) diff --git a/examples/next/with-emailpassword/app/api/auth/[...auth]/route.ts b/examples/next/with-emailpassword/app/api/auth/[...path]/route.ts similarity index 100% rename from examples/next/with-emailpassword/app/api/auth/[...auth]/route.ts rename to examples/next/with-emailpassword/app/api/auth/[...path]/route.ts From 39aaca4a494b6556c16bbf7a958ef7277d6aad81 Mon Sep 17 00:00:00 2001 From: Deepjyoti Barman Date: Tue, 3 Sep 2024 13:03:29 +0530 Subject: [PATCH 17/32] Use ponyfilled process to refactor checking for test env --- lib/build/processState.js | 3 ++- lib/build/querier.js | 6 +++--- lib/build/recipe/accountlinking/recipe.js | 3 ++- lib/build/recipe/dashboard/recipe.js | 3 ++- .../recipe/emailpassword/passwordResetFunctions.js | 2 +- lib/build/recipe/emailpassword/recipe.js | 2 +- .../emailverification/emailVerificationFunctions.js | 2 +- lib/build/recipe/emailverification/recipe.js | 3 ++- lib/build/recipe/jwt/recipe.js | 7 ++++--- lib/build/recipe/multifactorauth/recipe.js | 3 ++- lib/build/recipe/multitenancy/recipe.js | 3 ++- lib/build/recipe/openid/recipe.js | 3 ++- .../services/backwardCompatibility/index.js | 2 +- lib/build/recipe/passwordless/recipe.js | 3 ++- lib/build/recipe/session/recipe.js | 3 ++- lib/build/recipe/session/recipeImplementation.js | 3 ++- lib/build/recipe/thirdparty/recipe.js | 3 ++- lib/build/recipe/totp/recipe.js | 3 ++- lib/build/recipe/usermetadata/recipe.js | 7 ++++--- lib/build/recipe/userroles/recipe.js | 3 ++- lib/build/supertokens.js | 4 ++-- lib/build/utils.d.ts | 1 + lib/build/utils.js | 13 ++++++++++++- lib/ts/processState.ts | 4 +++- lib/ts/querier.ts | 8 ++++---- lib/ts/recipe/accountlinking/recipe.ts | 3 ++- lib/ts/recipe/dashboard/recipe.ts | 3 ++- .../recipe/emailpassword/passwordResetFunctions.ts | 4 ++-- lib/ts/recipe/emailpassword/recipe.ts | 4 ++-- .../emailverification/emailVerificationFunctions.ts | 4 ++-- lib/ts/recipe/emailverification/recipe.ts | 3 ++- lib/ts/recipe/jwt/recipe.ts | 3 ++- lib/ts/recipe/multifactorauth/recipe.ts | 3 ++- lib/ts/recipe/multitenancy/recipe.ts | 3 ++- lib/ts/recipe/openid/recipe.ts | 3 ++- .../services/backwardCompatibility/index.ts | 4 ++-- lib/ts/recipe/passwordless/recipe.ts | 3 ++- lib/ts/recipe/session/recipe.ts | 3 ++- lib/ts/recipe/session/recipeImplementation.ts | 3 ++- lib/ts/recipe/thirdparty/recipe.ts | 3 ++- lib/ts/recipe/totp/recipe.ts | 3 ++- lib/ts/recipe/usermetadata/recipe.ts | 3 ++- lib/ts/recipe/userroles/recipe.ts | 3 ++- lib/ts/supertokens.ts | 5 +++-- lib/ts/utils.ts | 12 ++++++++++++ 45 files changed, 114 insertions(+), 58 deletions(-) diff --git a/lib/build/processState.js b/lib/build/processState.js index 45d1bcd92..9dd483422 100644 --- a/lib/build/processState.js +++ b/lib/build/processState.js @@ -15,6 +15,7 @@ */ Object.defineProperty(exports, "__esModule", { value: true }); exports.ProcessState = exports.PROCESS_STATE = void 0; +const utils_1 = require("./utils"); var PROCESS_STATE; (function (PROCESS_STATE) { PROCESS_STATE[(PROCESS_STATE["CALLING_SERVICE_IN_VERIFY"] = 0)] = "CALLING_SERVICE_IN_VERIFY"; @@ -32,7 +33,7 @@ class ProcessState { constructor() { this.history = []; this.addState = (state) => { - if (process.env.TEST_MODE === "testing") { + if (utils_1.isTestEnv()) { this.history.push(state); } }; diff --git a/lib/build/querier.js b/lib/build/querier.js index e90a3d875..7803b6cc6 100644 --- a/lib/build/querier.js +++ b/lib/build/querier.js @@ -92,7 +92,7 @@ class Querier { return Querier.apiVersion; }; this.getHostsAliveForTesting = () => { - if (process.env.TEST_MODE !== "testing") { + if (!utils_1.isTestEnv()) { throw Error("calling testing function in non testing env"); } return Querier.hostsAliveForTesting; @@ -411,7 +411,7 @@ class Querier { ); logger_1.logDebugMessage(`core-call: ${method} ${url}`); let response = await requestFunc(url); - if (process.env.TEST_MODE === "testing") { + if (utils_1.isTestEnv()) { Querier.hostsAliveForTesting.add(currentDomain + currentBasePath); } if (response.status !== 200) { @@ -464,7 +464,7 @@ class Querier { this.rIdToCore = rIdToCore; } static reset() { - if (process.env.TEST_MODE !== "testing") { + if (!utils_1.isTestEnv()) { throw Error("calling testing function in non testing env"); } Querier.initCalled = false; diff --git a/lib/build/recipe/accountlinking/recipe.js b/lib/build/recipe/accountlinking/recipe.js index e9eeeb363..a5faf204f 100644 --- a/lib/build/recipe/accountlinking/recipe.js +++ b/lib/build/recipe/accountlinking/recipe.js @@ -29,6 +29,7 @@ const supertokens_1 = __importDefault(require("../../supertokens")); const processState_1 = require("../../processState"); const logger_1 = require("../../logger"); const recipe_1 = __importDefault(require("../emailverification/recipe")); +const utils_2 = require("../../utils"); class Recipe extends recipeModule_1.default { constructor(recipeId, appInfo, config, _recipes, _ingredients) { super(recipeId, appInfo); @@ -623,7 +624,7 @@ class Recipe extends recipeModule_1.default { return error_1.default.isErrorFromSuperTokens(err) && err.fromRecipe === Recipe.RECIPE_ID; } static reset() { - if (process.env.TEST_MODE !== "testing") { + if (!utils_2.isTestEnv()) { throw new Error("calling testing function in non testing env"); } Recipe.instance = undefined; diff --git a/lib/build/recipe/dashboard/recipe.js b/lib/build/recipe/dashboard/recipe.js index 17c4a4e8c..5f68a6add 100644 --- a/lib/build/recipe/dashboard/recipe.js +++ b/lib/build/recipe/dashboard/recipe.js @@ -68,6 +68,7 @@ const updateTenantFirstFactor_1 = __importDefault(require("./api/multitenancy/up const updateTenantSecondaryFactor_1 = __importDefault(require("./api/multitenancy/updateTenantSecondaryFactor")); const updateTenantCoreConfig_1 = __importDefault(require("./api/multitenancy/updateTenantCoreConfig")); const getThirdPartyConfig_1 = __importDefault(require("./api/multitenancy/getThirdPartyConfig")); +const utils_2 = require("../../utils"); class Recipe extends recipeModule_1.default { constructor(recipeId, appInfo, isInServerlessEnv, config) { super(recipeId, appInfo); @@ -602,7 +603,7 @@ class Recipe extends recipeModule_1.default { }; } static reset() { - if (process.env.TEST_MODE !== "testing") { + if (!utils_2.isTestEnv()) { throw new Error("calling testing function in non testing env"); } Recipe.instance = undefined; diff --git a/lib/build/recipe/emailpassword/passwordResetFunctions.js b/lib/build/recipe/emailpassword/passwordResetFunctions.js index 04a611730..23ec9186f 100644 --- a/lib/build/recipe/emailpassword/passwordResetFunctions.js +++ b/lib/build/recipe/emailpassword/passwordResetFunctions.js @@ -18,7 +18,7 @@ exports.createAndSendEmailUsingSupertokensService = void 0; const utils_1 = require("../../utils"); async function createAndSendEmailUsingSupertokensService(appInfo, user, passwordResetURLWithToken) { // related issue: https://github.com/supertokens/supertokens-node/issues/38 - if (process.env.TEST_MODE === "testing") { + if (utils_1.isTestEnv()) { return; } await utils_1.postWithFetch( diff --git a/lib/build/recipe/emailpassword/recipe.js b/lib/build/recipe/emailpassword/recipe.js index 901741090..dc968c536 100644 --- a/lib/build/recipe/emailpassword/recipe.js +++ b/lib/build/recipe/emailpassword/recipe.js @@ -291,7 +291,7 @@ class Recipe extends recipeModule_1.default { }; } static reset() { - if (process.env.TEST_MODE !== "testing") { + if (!utils_2.isTestEnv()) { throw new Error("calling testing function in non testing env"); } Recipe.instance = undefined; diff --git a/lib/build/recipe/emailverification/emailVerificationFunctions.js b/lib/build/recipe/emailverification/emailVerificationFunctions.js index ded4afd5a..fb6b03bfc 100644 --- a/lib/build/recipe/emailverification/emailVerificationFunctions.js +++ b/lib/build/recipe/emailverification/emailVerificationFunctions.js @@ -17,7 +17,7 @@ Object.defineProperty(exports, "__esModule", { value: true }); exports.createAndSendEmailUsingSupertokensService = void 0; const utils_1 = require("../../utils"); async function createAndSendEmailUsingSupertokensService(appInfo, user, emailVerifyURLWithToken) { - if (process.env.TEST_MODE === "testing") { + if (utils_1.isTestEnv()) { return; } await utils_1.postWithFetch( diff --git a/lib/build/recipe/emailverification/recipe.js b/lib/build/recipe/emailverification/recipe.js index 9c0703a91..9f22a9552 100644 --- a/lib/build/recipe/emailverification/recipe.js +++ b/lib/build/recipe/emailverification/recipe.js @@ -38,6 +38,7 @@ const error_2 = __importDefault(require("../session/error")); const session_1 = __importDefault(require("../session")); const __1 = require("../.."); const logger_1 = require("../../logger"); +const utils_2 = require("../../utils"); class Recipe extends recipeModule_1.default { constructor(recipeId, appInfo, isInServerlessEnv, config, ingredients) { super(recipeId, appInfo); @@ -314,7 +315,7 @@ class Recipe extends recipeModule_1.default { }; } static reset() { - if (process.env.TEST_MODE !== "testing") { + if (!utils_2.isTestEnv()) { throw new Error("calling testing function in non testing env"); } Recipe.instance = undefined; diff --git a/lib/build/recipe/jwt/recipe.js b/lib/build/recipe/jwt/recipe.js index d95d074b0..bb92d24a8 100644 --- a/lib/build/recipe/jwt/recipe.js +++ b/lib/build/recipe/jwt/recipe.js @@ -23,11 +23,12 @@ const error_1 = __importDefault(require("../../error")); const normalisedURLPath_1 = __importDefault(require("../../normalisedURLPath")); const querier_1 = require("../../querier"); const recipeModule_1 = __importDefault(require("../../recipeModule")); +const utils_1 = require("../../utils"); const getJWKS_1 = __importDefault(require("./api/getJWKS")); const implementation_1 = __importDefault(require("./api/implementation")); const constants_1 = require("./constants"); const recipeImplementation_1 = __importDefault(require("./recipeImplementation")); -const utils_1 = require("./utils"); +const utils_2 = require("./utils"); const supertokens_js_override_1 = __importDefault(require("supertokens-js-override")); class Recipe extends recipeModule_1.default { constructor(recipeId, appInfo, isInServerlessEnv, config) { @@ -43,7 +44,7 @@ class Recipe extends recipeModule_1.default { }; return await getJWKS_1.default(this.apiImpl, options, userContext); }; - this.config = utils_1.validateAndNormaliseUserInput(this, appInfo, config); + this.config = utils_2.validateAndNormaliseUserInput(this, appInfo, config); this.isInServerlessEnv = isInServerlessEnv; { let builder = new supertokens_js_override_1.default( @@ -78,7 +79,7 @@ class Recipe extends recipeModule_1.default { }; } static reset() { - if (process.env.TEST_MODE !== "testing") { + if (!utils_1.isTestEnv()) { throw new Error("calling testing function in non testing env"); } Recipe.instance = undefined; diff --git a/lib/build/recipe/multifactorauth/recipe.js b/lib/build/recipe/multifactorauth/recipe.js index c1b433469..31b8241a8 100644 --- a/lib/build/recipe/multifactorauth/recipe.js +++ b/lib/build/recipe/multifactorauth/recipe.js @@ -33,6 +33,7 @@ const recipe_1 = __importDefault(require("../session/recipe")); const postSuperTokensInitCallbacks_1 = require("../../postSuperTokensInitCallbacks"); const recipe_2 = __importDefault(require("../multitenancy/recipe")); const querier_1 = require("../../querier"); +const utils_2 = require("../../utils"); class Recipe extends recipeModule_1.default { constructor(recipeId, appInfo, isInServerlessEnv, config) { var _a; @@ -197,7 +198,7 @@ class Recipe extends recipeModule_1.default { }; } static reset() { - if (process.env.TEST_MODE !== "testing") { + if (!utils_2.isTestEnv()) { throw new Error("calling testing function in non testing env"); } Recipe.instance = undefined; diff --git a/lib/build/recipe/multitenancy/recipe.js b/lib/build/recipe/multitenancy/recipe.js index b6070232e..20f9c22be 100644 --- a/lib/build/recipe/multitenancy/recipe.js +++ b/lib/build/recipe/multitenancy/recipe.js @@ -32,6 +32,7 @@ const constants_1 = require("./constants"); const allowedDomainsClaim_1 = require("./allowedDomainsClaim"); const utils_1 = require("./utils"); const loginMethods_1 = __importDefault(require("./api/loginMethods")); +const utils_2 = require("../../utils"); class Recipe extends recipeModule_1.default { constructor(recipeId, appInfo, isInServerlessEnv, config) { super(recipeId, appInfo); @@ -120,7 +121,7 @@ class Recipe extends recipeModule_1.default { }; } static reset() { - if (process.env.TEST_MODE !== "testing") { + if (!utils_2.isTestEnv()) { throw new Error("calling testing function in non testing env"); } Recipe.instance = undefined; diff --git a/lib/build/recipe/openid/recipe.js b/lib/build/recipe/openid/recipe.js index fd7a67398..4dc74fd25 100644 --- a/lib/build/recipe/openid/recipe.js +++ b/lib/build/recipe/openid/recipe.js @@ -29,6 +29,7 @@ const implementation_1 = __importDefault(require("./api/implementation")); const normalisedURLPath_1 = __importDefault(require("../../normalisedURLPath")); const constants_1 = require("./constants"); const getOpenIdDiscoveryConfiguration_1 = __importDefault(require("./api/getOpenIdDiscoveryConfiguration")); +const utils_2 = require("../../utils"); class OpenIdRecipe extends recipeModule_1.default { constructor(recipeId, appInfo, isInServerlessEnv, config) { super(recipeId, appInfo); @@ -102,7 +103,7 @@ class OpenIdRecipe extends recipeModule_1.default { }; } static reset() { - if (process.env.TEST_MODE !== "testing") { + if (!utils_2.isTestEnv()) { throw new Error("calling testing function in non testing env"); } OpenIdRecipe.instance = undefined; diff --git a/lib/build/recipe/passwordless/emaildelivery/services/backwardCompatibility/index.js b/lib/build/recipe/passwordless/emaildelivery/services/backwardCompatibility/index.js index c901bd9b3..aacff4c5d 100644 --- a/lib/build/recipe/passwordless/emaildelivery/services/backwardCompatibility/index.js +++ b/lib/build/recipe/passwordless/emaildelivery/services/backwardCompatibility/index.js @@ -2,7 +2,7 @@ Object.defineProperty(exports, "__esModule", { value: true }); const utils_1 = require("../../../../../utils"); async function createAndSendEmailUsingSupertokensService(input) { - if (process.env.TEST_MODE === "testing") { + if (utils_1.isTestEnv()) { return; } const result = await utils_1.postWithFetch( diff --git a/lib/build/recipe/passwordless/recipe.js b/lib/build/recipe/passwordless/recipe.js index a18ca5fc2..09294ae9f 100644 --- a/lib/build/recipe/passwordless/recipe.js +++ b/lib/build/recipe/passwordless/recipe.js @@ -40,6 +40,7 @@ const recipe_1 = __importDefault(require("../multifactorauth/recipe")); const recipe_2 = __importDefault(require("../multitenancy/recipe")); const utils_2 = require("../thirdparty/utils"); const multifactorauth_1 = require("../multifactorauth"); +const utils_3 = require("../../utils"); class Recipe extends recipeModule_1.default { constructor(recipeId, appInfo, isInServerlessEnv, config, ingredients) { super(recipeId, appInfo); @@ -564,7 +565,7 @@ class Recipe extends recipeModule_1.default { }; } static reset() { - if (process.env.TEST_MODE !== "testing") { + if (!utils_3.isTestEnv()) { throw new Error("calling testing function in non testing env"); } Recipe.instance = undefined; diff --git a/lib/build/recipe/session/recipe.js b/lib/build/recipe/session/recipe.js index 77afe511a..429fbb415 100644 --- a/lib/build/recipe/session/recipe.js +++ b/lib/build/recipe/session/recipe.js @@ -33,6 +33,7 @@ const implementation_1 = __importDefault(require("./api/implementation")); const supertokens_js_override_1 = __importDefault(require("supertokens-js-override")); const recipe_1 = __importDefault(require("../openid/recipe")); const logger_1 = require("../../logger"); +const utils_2 = require("../../utils"); // For Express class SessionRecipe extends recipeModule_1.default { constructor(recipeId, appInfo, isInServerlessEnv, config) { @@ -234,7 +235,7 @@ class SessionRecipe extends recipeModule_1.default { }; } static reset() { - if (process.env.TEST_MODE !== "testing") { + if (!utils_2.isTestEnv()) { throw new Error("calling testing function in non testing env"); } SessionRecipe.instance = undefined; diff --git a/lib/build/recipe/session/recipeImplementation.js b/lib/build/recipe/session/recipeImplementation.js index 39c601791..0250d0376 100644 --- a/lib/build/recipe/session/recipeImplementation.js +++ b/lib/build/recipe/session/recipeImplementation.js @@ -54,6 +54,7 @@ const error_1 = __importDefault(require("./error")); const recipeUserId_1 = __importDefault(require("../../recipeUserId")); const constants_1 = require("../multitenancy/constants"); const constants_2 = require("./constants"); +const utils_2 = require("../../utils"); function getRecipeInterface(querier, config, appInfo, getRecipeImplAfterOverrides) { const JWKS = querier.getAllCoreUrlsForPath("/.well-known/jwks.json").map((url) => jose_1.createRemoteJWKSet(new URL(url), { @@ -442,7 +443,7 @@ function getRecipeInterface(querier, config, appInfo, getRecipeImplAfterOverride appInfo, getRecipeImpl: getRecipeImplAfterOverrides, }; - if (process.env.TEST_MODE === "testing") { + if (utils_2.isTestEnv()) { // testing mode, we add some of the help functions to the obj obj.helpers = helpers; } diff --git a/lib/build/recipe/thirdparty/recipe.js b/lib/build/recipe/thirdparty/recipe.js index ef0908761..d9daed748 100644 --- a/lib/build/recipe/thirdparty/recipe.js +++ b/lib/build/recipe/thirdparty/recipe.js @@ -34,6 +34,7 @@ const appleRedirect_1 = __importDefault(require("./api/appleRedirect")); const supertokens_js_override_1 = __importDefault(require("supertokens-js-override")); const postSuperTokensInitCallbacks_1 = require("../../postSuperTokensInitCallbacks"); const multifactorauth_1 = require("../multifactorauth"); +const utils_2 = require("../../utils"); class Recipe extends recipeModule_1.default { constructor(recipeId, appInfo, isInServerlessEnv, config, _recipes, _ingredients) { super(recipeId, appInfo); @@ -135,7 +136,7 @@ class Recipe extends recipeModule_1.default { throw new Error("Initialisation not done. Did you forget to call the ThirdParty.init function?"); } static reset() { - if (process.env.TEST_MODE !== "testing") { + if (!utils_2.isTestEnv()) { throw new Error("calling testing function in non testing env"); } Recipe.instance = undefined; diff --git a/lib/build/recipe/totp/recipe.js b/lib/build/recipe/totp/recipe.js index e33e44030..fb146942b 100644 --- a/lib/build/recipe/totp/recipe.js +++ b/lib/build/recipe/totp/recipe.js @@ -35,6 +35,7 @@ const listDevices_1 = __importDefault(require("./api/listDevices")); const removeDevice_1 = __importDefault(require("./api/removeDevice")); const postSuperTokensInitCallbacks_1 = require("../../postSuperTokensInitCallbacks"); const recipe_1 = __importDefault(require("../multifactorauth/recipe")); +const utils_2 = require("../../utils"); class Recipe extends recipeModule_1.default { constructor(recipeId, appInfo, isInServerlessEnv, config) { super(recipeId, appInfo); @@ -157,7 +158,7 @@ class Recipe extends recipeModule_1.default { }; } static reset() { - if (process.env.TEST_MODE !== "testing") { + if (!utils_2.isTestEnv()) { throw new Error("calling testing function in non testing env"); } Recipe.instance = undefined; diff --git a/lib/build/recipe/usermetadata/recipe.js b/lib/build/recipe/usermetadata/recipe.js index 96b98096a..600238705 100644 --- a/lib/build/recipe/usermetadata/recipe.js +++ b/lib/build/recipe/usermetadata/recipe.js @@ -22,8 +22,9 @@ Object.defineProperty(exports, "__esModule", { value: true }); const error_1 = __importDefault(require("../../error")); const querier_1 = require("../../querier"); const recipeModule_1 = __importDefault(require("../../recipeModule")); +const utils_1 = require("../../utils"); const recipeImplementation_1 = __importDefault(require("./recipeImplementation")); -const utils_1 = require("./utils"); +const utils_2 = require("./utils"); const supertokens_js_override_1 = __importDefault(require("supertokens-js-override")); class Recipe extends recipeModule_1.default { constructor(recipeId, appInfo, isInServerlessEnv, config) { @@ -32,7 +33,7 @@ class Recipe extends recipeModule_1.default { this.handleAPIRequest = async (_, _tenantId, __, ___, ____, _____) => { throw new Error("Should never come here"); }; - this.config = utils_1.validateAndNormaliseUserInput(this, appInfo, config); + this.config = utils_2.validateAndNormaliseUserInput(this, appInfo, config); this.isInServerlessEnv = isInServerlessEnv; { let builder = new supertokens_js_override_1.default( @@ -61,7 +62,7 @@ class Recipe extends recipeModule_1.default { }; } static reset() { - if (process.env.TEST_MODE !== "testing") { + if (!utils_1.isTestEnv()) { throw new Error("calling testing function in non testing env"); } Recipe.instance = undefined; diff --git a/lib/build/recipe/userroles/recipe.js b/lib/build/recipe/userroles/recipe.js index 53f5d56b6..fec355e1e 100644 --- a/lib/build/recipe/userroles/recipe.js +++ b/lib/build/recipe/userroles/recipe.js @@ -29,6 +29,7 @@ const postSuperTokensInitCallbacks_1 = require("../../postSuperTokensInitCallbac const recipe_1 = __importDefault(require("../session/recipe")); const userRoleClaim_1 = require("./userRoleClaim"); const permissionClaim_1 = require("./permissionClaim"); +const utils_2 = require("../../utils"); class Recipe extends recipeModule_1.default { constructor(recipeId, appInfo, isInServerlessEnv, config) { super(recipeId, appInfo); @@ -73,7 +74,7 @@ class Recipe extends recipeModule_1.default { }; } static reset() { - if (process.env.TEST_MODE !== "testing") { + if (!utils_2.isTestEnv()) { throw new Error("calling testing function in non testing env"); } Recipe.instance = undefined; diff --git a/lib/build/supertokens.js b/lib/build/supertokens.js index 7ee945c3b..ddc2aafeb 100644 --- a/lib/build/supertokens.js +++ b/lib/build/supertokens.js @@ -390,7 +390,7 @@ class SuperTokens { // the app doesn't have to do that if they only use TOTP (which shouldn't be that uncommon) // To let those cases function without initializing account linking we do not check it here, but when // the authentication endpoints are called. - this.telemetryEnabled = config.telemetry === undefined ? process.env.TEST_MODE !== "testing" : config.telemetry; + this.telemetryEnabled = config.telemetry === undefined ? !utils_1.isTestEnv() : config.telemetry; } static init(config) { if (SuperTokens.instance === undefined) { @@ -399,7 +399,7 @@ class SuperTokens { } } static reset() { - if (process.env.TEST_MODE !== "testing") { + if (!utils_1.isTestEnv()) { throw new Error("calling testing function in non testing env"); } querier_1.Querier.reset(); diff --git a/lib/build/utils.d.ts b/lib/build/utils.d.ts index 0659b1aae..07e24e561 100644 --- a/lib/build/utils.d.ts +++ b/lib/build/utils.d.ts @@ -57,3 +57,4 @@ export declare function postWithFetch( } >; export declare function normaliseEmail(email: string): string; +export declare const isTestEnv: () => boolean; diff --git a/lib/build/utils.js b/lib/build/utils.js index 741fda01f..6e9c369b3 100644 --- a/lib/build/utils.js +++ b/lib/build/utils.js @@ -41,7 +41,7 @@ var __importDefault = return mod && mod.__esModule ? mod : { default: mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); -exports.normaliseEmail = exports.postWithFetch = exports.getFromObjectCaseInsensitive = exports.getTopLevelDomainForSameSiteResolution = exports.setRequestInUserContextIfNotDefined = exports.getUserContext = exports.makeDefaultUserContextFromAPI = exports.humaniseMilliseconds = exports.frontendHasInterceptor = exports.getRidFromHeader = exports.hasGreaterThanEqualToFDI = exports.getLatestFDIVersionFromFDIList = exports.getBackwardsCompatibleUserInfo = exports.isAnIpAddress = exports.send200Response = exports.sendNon200Response = exports.sendNon200ResponseWithMessage = exports.normaliseHttpMethod = exports.normaliseInputAppInfoOrThrowError = exports.maxVersion = exports.getLargestVersionFromIntersection = exports.doFetch = void 0; +exports.isTestEnv = exports.normaliseEmail = exports.postWithFetch = exports.getFromObjectCaseInsensitive = exports.getTopLevelDomainForSameSiteResolution = exports.setRequestInUserContextIfNotDefined = exports.getUserContext = exports.makeDefaultUserContextFromAPI = exports.humaniseMilliseconds = exports.frontendHasInterceptor = exports.getRidFromHeader = exports.hasGreaterThanEqualToFDI = exports.getLatestFDIVersionFromFDIList = exports.getBackwardsCompatibleUserInfo = exports.isAnIpAddress = exports.send200Response = exports.sendNon200Response = exports.sendNon200ResponseWithMessage = exports.normaliseHttpMethod = exports.normaliseInputAppInfoOrThrowError = exports.maxVersion = exports.getLargestVersionFromIntersection = exports.doFetch = void 0; const psl = __importStar(require("psl")); const normalisedURLDomain_1 = __importDefault(require("./normalisedURLDomain")); const normalisedURLPath_1 = __importDefault(require("./normalisedURLPath")); @@ -425,3 +425,14 @@ function normaliseEmail(email) { return email; } exports.normaliseEmail = normaliseEmail; +const isTestEnv = () => { + /** + * Check if test mode is enabled by reading the environment variable. + */ + if (typeof process !== undefined) return process.env.TEST_MODE === "testing"; + // Since `process` is not available, we will import and use it + // instead. + const ponyFilledProcess = require("process"); + return ponyFilledProcess.env.TEST_MODE === "testing"; +}; +exports.isTestEnv = isTestEnv; diff --git a/lib/ts/processState.ts b/lib/ts/processState.ts index 0cbbb0478..3216a268f 100644 --- a/lib/ts/processState.ts +++ b/lib/ts/processState.ts @@ -13,6 +13,8 @@ * under the License. */ +import { isTestEnv } from "./utils"; + export enum PROCESS_STATE { CALLING_SERVICE_IN_VERIFY, CALLING_SERVICE_IN_GET_API_VERSION, @@ -41,7 +43,7 @@ export class ProcessState { } addState = (state: PROCESS_STATE) => { - if (process.env.TEST_MODE === "testing") { + if (isTestEnv()) { this.history.push(state); } }; diff --git a/lib/ts/querier.ts b/lib/ts/querier.ts index 8cedfdbcb..21f872cd9 100644 --- a/lib/ts/querier.ts +++ b/lib/ts/querier.ts @@ -12,7 +12,7 @@ * License for the specific language governing permissions and limitations * under the License. */ -import { doFetch, getLargestVersionFromIntersection } from "./utils"; +import { doFetch, getLargestVersionFromIntersection, isTestEnv } from "./utils"; import { cdiSupported } from "./version"; import NormalisedURLDomain from "./normalisedURLDomain"; import NormalisedURLPath from "./normalisedURLPath"; @@ -112,7 +112,7 @@ export class Querier { }; static reset() { - if (process.env.TEST_MODE !== "testing") { + if (!isTestEnv()) { throw Error("calling testing function in non testing env"); } Querier.initCalled = false; @@ -120,7 +120,7 @@ export class Querier { } getHostsAliveForTesting = () => { - if (process.env.TEST_MODE !== "testing") { + if (!isTestEnv()) { throw Error("calling testing function in non testing env"); } return Querier.hostsAliveForTesting; @@ -535,7 +535,7 @@ export class Querier { ProcessState.getInstance().addState(PROCESS_STATE.CALLING_SERVICE_IN_REQUEST_HELPER); logDebugMessage(`core-call: ${method} ${url}`); let response = await requestFunc(url); - if (process.env.TEST_MODE === "testing") { + if (isTestEnv()) { Querier.hostsAliveForTesting.add(currentDomain + currentBasePath); } if (response.status !== 200) { diff --git a/lib/ts/recipe/accountlinking/recipe.ts b/lib/ts/recipe/accountlinking/recipe.ts index b57b9329a..177d61def 100644 --- a/lib/ts/recipe/accountlinking/recipe.ts +++ b/lib/ts/recipe/accountlinking/recipe.ts @@ -31,6 +31,7 @@ import { logDebugMessage } from "../../logger"; import EmailVerificationRecipe from "../emailverification/recipe"; import { LoginMethod } from "../../user"; import { SessionContainerInterface } from "../session/types"; +import { isTestEnv } from "../../utils"; export default class Recipe extends RecipeModule { private static instance: Recipe | undefined = undefined; @@ -125,7 +126,7 @@ export default class Recipe extends RecipeModule { } static reset() { - if (process.env.TEST_MODE !== "testing") { + if (!isTestEnv()) { throw new Error("calling testing function in non testing env"); } Recipe.instance = undefined; diff --git a/lib/ts/recipe/dashboard/recipe.ts b/lib/ts/recipe/dashboard/recipe.ts index 4552185ab..1d82f5753 100644 --- a/lib/ts/recipe/dashboard/recipe.ts +++ b/lib/ts/recipe/dashboard/recipe.ts @@ -94,6 +94,7 @@ import updateTenantFirstFactor from "./api/multitenancy/updateTenantFirstFactor" import updateTenantSecondaryFactor from "./api/multitenancy/updateTenantSecondaryFactor"; import updateTenantCoreConfig from "./api/multitenancy/updateTenantCoreConfig"; import getThirdPartyConfig from "./api/multitenancy/getThirdPartyConfig"; +import { isTestEnv } from "../../utils"; export default class Recipe extends RecipeModule { private static instance: Recipe | undefined = undefined; @@ -142,7 +143,7 @@ export default class Recipe extends RecipeModule { } static reset() { - if (process.env.TEST_MODE !== "testing") { + if (!isTestEnv()) { throw new Error("calling testing function in non testing env"); } Recipe.instance = undefined; diff --git a/lib/ts/recipe/emailpassword/passwordResetFunctions.ts b/lib/ts/recipe/emailpassword/passwordResetFunctions.ts index d935f07be..ca23af864 100644 --- a/lib/ts/recipe/emailpassword/passwordResetFunctions.ts +++ b/lib/ts/recipe/emailpassword/passwordResetFunctions.ts @@ -14,7 +14,7 @@ */ import { NormalisedAppinfo } from "../../types"; -import { postWithFetch } from "../../utils"; +import { isTestEnv, postWithFetch } from "../../utils"; export async function createAndSendEmailUsingSupertokensService( appInfo: NormalisedAppinfo, @@ -25,7 +25,7 @@ export async function createAndSendEmailUsingSupertokensService( passwordResetURLWithToken: string ) { // related issue: https://github.com/supertokens/supertokens-node/issues/38 - if (process.env.TEST_MODE === "testing") { + if (isTestEnv()) { return; } diff --git a/lib/ts/recipe/emailpassword/recipe.ts b/lib/ts/recipe/emailpassword/recipe.ts index 3d899d77d..f6f98431d 100644 --- a/lib/ts/recipe/emailpassword/recipe.ts +++ b/lib/ts/recipe/emailpassword/recipe.ts @@ -31,7 +31,7 @@ import signUpAPI from "./api/signup"; import signInAPI from "./api/signin"; import generatePasswordResetTokenAPI from "./api/generatePasswordResetToken"; import passwordResetAPI from "./api/passwordReset"; -import { send200Response } from "../../utils"; +import { isTestEnv, send200Response } from "../../utils"; import emailExistsAPI from "./api/emailExists"; import RecipeImplementation from "./recipeImplementation"; import APIImplementation from "./api/implementation"; @@ -244,7 +244,7 @@ export default class Recipe extends RecipeModule { } static reset() { - if (process.env.TEST_MODE !== "testing") { + if (!isTestEnv()) { throw new Error("calling testing function in non testing env"); } Recipe.instance = undefined; diff --git a/lib/ts/recipe/emailverification/emailVerificationFunctions.ts b/lib/ts/recipe/emailverification/emailVerificationFunctions.ts index ff8dc9ec1..e0ab293a7 100644 --- a/lib/ts/recipe/emailverification/emailVerificationFunctions.ts +++ b/lib/ts/recipe/emailverification/emailVerificationFunctions.ts @@ -15,14 +15,14 @@ import { UserEmailInfo } from "./types"; import { NormalisedAppinfo } from "../../types"; -import { postWithFetch } from "../../utils"; +import { isTestEnv, postWithFetch } from "../../utils"; export async function createAndSendEmailUsingSupertokensService( appInfo: NormalisedAppinfo, user: UserEmailInfo, emailVerifyURLWithToken: string ) { - if (process.env.TEST_MODE === "testing") { + if (isTestEnv()) { return; } await postWithFetch( diff --git a/lib/ts/recipe/emailverification/recipe.ts b/lib/ts/recipe/emailverification/recipe.ts index 37378d499..d7ad46e38 100644 --- a/lib/ts/recipe/emailverification/recipe.ts +++ b/lib/ts/recipe/emailverification/recipe.ts @@ -38,6 +38,7 @@ import Session from "../session"; import { getUser } from "../.."; import RecipeUserId from "../../recipeUserId"; import { logDebugMessage } from "../../logger"; +import { isTestEnv } from "../../utils"; export default class Recipe extends RecipeModule { private static instance: Recipe | undefined = undefined; @@ -125,7 +126,7 @@ export default class Recipe extends RecipeModule { } static reset() { - if (process.env.TEST_MODE !== "testing") { + if (!isTestEnv()) { throw new Error("calling testing function in non testing env"); } Recipe.instance = undefined; diff --git a/lib/ts/recipe/jwt/recipe.ts b/lib/ts/recipe/jwt/recipe.ts index 5e7006a06..2abb9c1ec 100644 --- a/lib/ts/recipe/jwt/recipe.ts +++ b/lib/ts/recipe/jwt/recipe.ts @@ -21,6 +21,7 @@ import normalisedURLPath from "../../normalisedURLPath"; import { Querier } from "../../querier"; import RecipeModule from "../../recipeModule"; import { APIHandled, HTTPMethod, NormalisedAppinfo, RecipeListFunction, UserContext } from "../../types"; +import { isTestEnv } from "../../utils"; import getJWKS from "./api/getJWKS"; import APIImplementation from "./api/implementation"; import { GET_JWKS_API } from "./constants"; @@ -76,7 +77,7 @@ export default class Recipe extends RecipeModule { } static reset() { - if (process.env.TEST_MODE !== "testing") { + if (!isTestEnv()) { throw new Error("calling testing function in non testing env"); } Recipe.instance = undefined; diff --git a/lib/ts/recipe/multifactorauth/recipe.ts b/lib/ts/recipe/multifactorauth/recipe.ts index 9294987af..f39435498 100644 --- a/lib/ts/recipe/multifactorauth/recipe.ts +++ b/lib/ts/recipe/multifactorauth/recipe.ts @@ -42,6 +42,7 @@ import RecipeUserId from "../../recipeUserId"; import MultitenancyRecipe from "../multitenancy/recipe"; import { Querier } from "../../querier"; import { TenantConfig } from "../multitenancy/types"; +import { isTestEnv } from "../../utils"; export default class Recipe extends RecipeModule { private static instance: Recipe | undefined = undefined; @@ -128,7 +129,7 @@ export default class Recipe extends RecipeModule { } static reset() { - if (process.env.TEST_MODE !== "testing") { + if (!isTestEnv()) { throw new Error("calling testing function in non testing env"); } Recipe.instance = undefined; diff --git a/lib/ts/recipe/multitenancy/recipe.ts b/lib/ts/recipe/multitenancy/recipe.ts index e606c521a..5a87ec40b 100644 --- a/lib/ts/recipe/multitenancy/recipe.ts +++ b/lib/ts/recipe/multitenancy/recipe.ts @@ -30,6 +30,7 @@ import { AllowedDomainsClaim } from "./allowedDomainsClaim"; import { APIInterface, RecipeInterface, TypeInput, TypeNormalisedInput } from "./types"; import { validateAndNormaliseUserInput } from "./utils"; import loginMethodsAPI from "./api/loginMethods"; +import { isTestEnv } from "../../utils"; export default class Recipe extends RecipeModule { private static instance: Recipe | undefined = undefined; @@ -102,7 +103,7 @@ export default class Recipe extends RecipeModule { } static reset() { - if (process.env.TEST_MODE !== "testing") { + if (!isTestEnv()) { throw new Error("calling testing function in non testing env"); } Recipe.instance = undefined; diff --git a/lib/ts/recipe/openid/recipe.ts b/lib/ts/recipe/openid/recipe.ts index 1dc802de5..6d2d7e4af 100644 --- a/lib/ts/recipe/openid/recipe.ts +++ b/lib/ts/recipe/openid/recipe.ts @@ -26,6 +26,7 @@ import APIImplementation from "./api/implementation"; import NormalisedURLPath from "../../normalisedURLPath"; import { GET_DISCOVERY_CONFIG_URL } from "./constants"; import getOpenIdDiscoveryConfiguration from "./api/getOpenIdDiscoveryConfiguration"; +import { isTestEnv } from "../../utils"; export default class OpenIdRecipe extends RecipeModule { static RECIPE_ID = "openid"; @@ -72,7 +73,7 @@ export default class OpenIdRecipe extends RecipeModule { } static reset() { - if (process.env.TEST_MODE !== "testing") { + if (!isTestEnv()) { throw new Error("calling testing function in non testing env"); } OpenIdRecipe.instance = undefined; diff --git a/lib/ts/recipe/passwordless/emaildelivery/services/backwardCompatibility/index.ts b/lib/ts/recipe/passwordless/emaildelivery/services/backwardCompatibility/index.ts index 7c0c7fb15..3ee2fc5ac 100644 --- a/lib/ts/recipe/passwordless/emaildelivery/services/backwardCompatibility/index.ts +++ b/lib/ts/recipe/passwordless/emaildelivery/services/backwardCompatibility/index.ts @@ -15,7 +15,7 @@ import { TypePasswordlessEmailDeliveryInput } from "../../../types"; import { EmailDeliveryInterface } from "../../../../../ingredients/emaildelivery/types"; import { NormalisedAppinfo, UserContext } from "../../../../../types"; -import { postWithFetch } from "../../../../../utils"; +import { isTestEnv, postWithFetch } from "../../../../../utils"; async function createAndSendEmailUsingSupertokensService(input: { appInfo: NormalisedAppinfo; @@ -28,7 +28,7 @@ async function createAndSendEmailUsingSupertokensService(input: { codeLifetime: number; isFirstFactor: boolean; }): Promise { - if (process.env.TEST_MODE === "testing") { + if (isTestEnv()) { return; } const result = await postWithFetch( diff --git a/lib/ts/recipe/passwordless/recipe.ts b/lib/ts/recipe/passwordless/recipe.ts index 9410bfb00..3ee073911 100644 --- a/lib/ts/recipe/passwordless/recipe.ts +++ b/lib/ts/recipe/passwordless/recipe.ts @@ -48,6 +48,7 @@ import { User } from "../../user"; import { isFakeEmail } from "../thirdparty/utils"; import { FactorIds } from "../multifactorauth"; import { SessionContainerInterface } from "../session/types"; +import { isTestEnv } from "../../utils"; export default class Recipe extends RecipeModule { private static instance: Recipe | undefined = undefined; @@ -447,7 +448,7 @@ export default class Recipe extends RecipeModule { } static reset() { - if (process.env.TEST_MODE !== "testing") { + if (!isTestEnv()) { throw new Error("calling testing function in non testing env"); } Recipe.instance = undefined; diff --git a/lib/ts/recipe/session/recipe.ts b/lib/ts/recipe/session/recipe.ts index d73ad8ccf..87b3d6bf3 100644 --- a/lib/ts/recipe/session/recipe.ts +++ b/lib/ts/recipe/session/recipe.ts @@ -42,6 +42,7 @@ import OverrideableBuilder from "supertokens-js-override"; import { APIOptions } from "."; import OpenIdRecipe from "../openid/recipe"; import { logDebugMessage } from "../../logger"; +import { isTestEnv } from "../../utils"; // For Express export default class SessionRecipe extends RecipeModule { @@ -121,7 +122,7 @@ export default class SessionRecipe extends RecipeModule { } static reset() { - if (process.env.TEST_MODE !== "testing") { + if (!isTestEnv()) { throw new Error("calling testing function in non testing env"); } SessionRecipe.instance = undefined; diff --git a/lib/ts/recipe/session/recipeImplementation.ts b/lib/ts/recipe/session/recipeImplementation.ts index 64c526d03..437c7ddc4 100644 --- a/lib/ts/recipe/session/recipeImplementation.ts +++ b/lib/ts/recipe/session/recipeImplementation.ts @@ -23,6 +23,7 @@ import SessionError from "./error"; import RecipeUserId from "../../recipeUserId"; import { DEFAULT_TENANT_ID } from "../multitenancy/constants"; import { JWKCacheCooldownInMs, protectedProps } from "./constants"; +import { isTestEnv } from "../../utils"; export type Helpers = { querier: Querier; @@ -607,7 +608,7 @@ export default function getRecipeInterface( getRecipeImpl: getRecipeImplAfterOverrides, }; - if (process.env.TEST_MODE === "testing") { + if (isTestEnv()) { // testing mode, we add some of the help functions to the obj (obj as any).helpers = helpers; } diff --git a/lib/ts/recipe/thirdparty/recipe.ts b/lib/ts/recipe/thirdparty/recipe.ts index 1c342df13..d21ac782a 100644 --- a/lib/ts/recipe/thirdparty/recipe.ts +++ b/lib/ts/recipe/thirdparty/recipe.ts @@ -32,6 +32,7 @@ import appleRedirectHandler from "./api/appleRedirect"; import OverrideableBuilder from "supertokens-js-override"; import { PostSuperTokensInitCallbacks } from "../../postSuperTokensInitCallbacks"; import { FactorIds } from "../multifactorauth"; +import { isTestEnv } from "../../utils"; export default class Recipe extends RecipeModule { private static instance: Recipe | undefined = undefined; @@ -110,7 +111,7 @@ export default class Recipe extends RecipeModule { } static reset() { - if (process.env.TEST_MODE !== "testing") { + if (!isTestEnv()) { throw new Error("calling testing function in non testing env"); } Recipe.instance = undefined; diff --git a/lib/ts/recipe/totp/recipe.ts b/lib/ts/recipe/totp/recipe.ts index d1f776927..3c0e0bbaf 100644 --- a/lib/ts/recipe/totp/recipe.ts +++ b/lib/ts/recipe/totp/recipe.ts @@ -40,6 +40,7 @@ import removeDeviceAPI from "./api/removeDevice"; import { User } from "../.."; import { PostSuperTokensInitCallbacks } from "../../postSuperTokensInitCallbacks"; import MultiFactorAuthRecipe from "../multifactorauth/recipe"; +import { isTestEnv } from "../../utils"; export default class Recipe extends RecipeModule { private static instance: Recipe | undefined = undefined; @@ -118,7 +119,7 @@ export default class Recipe extends RecipeModule { } static reset() { - if (process.env.TEST_MODE !== "testing") { + if (!isTestEnv()) { throw new Error("calling testing function in non testing env"); } Recipe.instance = undefined; diff --git a/lib/ts/recipe/usermetadata/recipe.ts b/lib/ts/recipe/usermetadata/recipe.ts index e292ceb22..5cac41875 100644 --- a/lib/ts/recipe/usermetadata/recipe.ts +++ b/lib/ts/recipe/usermetadata/recipe.ts @@ -20,6 +20,7 @@ import normalisedURLPath from "../../normalisedURLPath"; import { Querier } from "../../querier"; import RecipeModule from "../../recipeModule"; import { APIHandled, HTTPMethod, NormalisedAppinfo, RecipeListFunction } from "../../types"; +import { isTestEnv } from "../../utils"; import RecipeImplementation from "./recipeImplementation"; import { RecipeInterface, TypeInput, TypeNormalisedInput } from "./types"; @@ -68,7 +69,7 @@ export default class Recipe extends RecipeModule { } static reset() { - if (process.env.TEST_MODE !== "testing") { + if (!isTestEnv()) { throw new Error("calling testing function in non testing env"); } Recipe.instance = undefined; diff --git a/lib/ts/recipe/userroles/recipe.ts b/lib/ts/recipe/userroles/recipe.ts index 0f0176c7b..38c5a3e5b 100644 --- a/lib/ts/recipe/userroles/recipe.ts +++ b/lib/ts/recipe/userroles/recipe.ts @@ -29,6 +29,7 @@ import { PostSuperTokensInitCallbacks } from "../../postSuperTokensInitCallbacks import SessionRecipe from "../session/recipe"; import { UserRoleClaim } from "./userRoleClaim"; import { PermissionClaim } from "./permissionClaim"; +import { isTestEnv } from "../../utils"; export default class Recipe extends RecipeModule { static RECIPE_ID = "userroles"; @@ -81,7 +82,7 @@ export default class Recipe extends RecipeModule { } static reset() { - if (process.env.TEST_MODE !== "testing") { + if (!isTestEnv()) { throw new Error("calling testing function in non testing env"); } Recipe.instance = undefined; diff --git a/lib/ts/supertokens.ts b/lib/ts/supertokens.ts index 78109d1d0..174fcdb4a 100644 --- a/lib/ts/supertokens.ts +++ b/lib/ts/supertokens.ts @@ -20,6 +20,7 @@ import { normaliseHttpMethod, sendNon200ResponseWithMessage, getRidFromHeader, + isTestEnv, } from "./utils"; import { Querier } from "./querier"; import RecipeModule from "./recipeModule"; @@ -142,7 +143,7 @@ export default class SuperTokens { // To let those cases function without initializing account linking we do not check it here, but when // the authentication endpoints are called. - this.telemetryEnabled = config.telemetry === undefined ? process.env.TEST_MODE !== "testing" : config.telemetry; + this.telemetryEnabled = config.telemetry === undefined ? !isTestEnv() : config.telemetry; } static init(config: TypeInput) { @@ -153,7 +154,7 @@ export default class SuperTokens { } static reset() { - if (process.env.TEST_MODE !== "testing") { + if (!isTestEnv()) { throw new Error("calling testing function in non testing env"); } Querier.reset(); diff --git a/lib/ts/utils.ts b/lib/ts/utils.ts index b09011bf9..17609ec0b 100644 --- a/lib/ts/utils.ts +++ b/lib/ts/utils.ts @@ -422,3 +422,15 @@ export function normaliseEmail(email: string): string { return email; } + +export const isTestEnv = (): boolean => { + /** + * Check if test mode is enabled by reading the environment variable. + */ + if (typeof process !== undefined) return process.env.TEST_MODE === "testing"; + + // Since `process` is not available, we will import and use it + // instead. + const ponyFilledProcess = require("process"); + return ponyFilledProcess.env.TEST_MODE === "testing"; +}; From bac1e8f569be5d091d40734067ac5422475a19b6 Mon Sep 17 00:00:00 2001 From: Deepjyoti Barman Date: Tue, 3 Sep 2024 13:12:04 +0530 Subject: [PATCH 18/32] Refactor process and expose an util function to make it accessible --- lib/build/utils.d.ts | 2 ++ lib/build/utils.js | 19 +++++++++++++------ lib/ts/utils.ts | 18 ++++++++++++------ 3 files changed, 27 insertions(+), 12 deletions(-) diff --git a/lib/build/utils.d.ts b/lib/build/utils.d.ts index 07e24e561..5bf18ac13 100644 --- a/lib/build/utils.d.ts +++ b/lib/build/utils.d.ts @@ -1,4 +1,5 @@ // @ts-nocheck +/// import type { AppInfo, NormalisedAppinfo, HTTPMethod, JSONObject, UserContext } from "./types"; import type { BaseRequest, BaseResponse } from "./framework"; import { User } from "./user"; @@ -57,4 +58,5 @@ export declare function postWithFetch( } >; export declare function normaliseEmail(email: string): string; +export declare const getProcess: () => NodeJS.Process; export declare const isTestEnv: () => boolean; diff --git a/lib/build/utils.js b/lib/build/utils.js index 6e9c369b3..6598ddd6e 100644 --- a/lib/build/utils.js +++ b/lib/build/utils.js @@ -41,7 +41,7 @@ var __importDefault = return mod && mod.__esModule ? mod : { default: mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); -exports.isTestEnv = exports.normaliseEmail = exports.postWithFetch = exports.getFromObjectCaseInsensitive = exports.getTopLevelDomainForSameSiteResolution = exports.setRequestInUserContextIfNotDefined = exports.getUserContext = exports.makeDefaultUserContextFromAPI = exports.humaniseMilliseconds = exports.frontendHasInterceptor = exports.getRidFromHeader = exports.hasGreaterThanEqualToFDI = exports.getLatestFDIVersionFromFDIList = exports.getBackwardsCompatibleUserInfo = exports.isAnIpAddress = exports.send200Response = exports.sendNon200Response = exports.sendNon200ResponseWithMessage = exports.normaliseHttpMethod = exports.normaliseInputAppInfoOrThrowError = exports.maxVersion = exports.getLargestVersionFromIntersection = exports.doFetch = void 0; +exports.isTestEnv = exports.getProcess = exports.normaliseEmail = exports.postWithFetch = exports.getFromObjectCaseInsensitive = exports.getTopLevelDomainForSameSiteResolution = exports.setRequestInUserContextIfNotDefined = exports.getUserContext = exports.makeDefaultUserContextFromAPI = exports.humaniseMilliseconds = exports.frontendHasInterceptor = exports.getRidFromHeader = exports.hasGreaterThanEqualToFDI = exports.getLatestFDIVersionFromFDIList = exports.getBackwardsCompatibleUserInfo = exports.isAnIpAddress = exports.send200Response = exports.sendNon200Response = exports.sendNon200ResponseWithMessage = exports.normaliseHttpMethod = exports.normaliseInputAppInfoOrThrowError = exports.maxVersion = exports.getLargestVersionFromIntersection = exports.doFetch = void 0; const psl = __importStar(require("psl")); const normalisedURLDomain_1 = __importDefault(require("./normalisedURLDomain")); const normalisedURLPath_1 = __importDefault(require("./normalisedURLPath")); @@ -425,14 +425,21 @@ function normaliseEmail(email) { return email; } exports.normaliseEmail = normaliseEmail; +const getProcess = () => { + /** + * Return the process instance if it is available falling back + * to one that is compatible where process may not be available + * (like `edge` runtime). + */ + if (typeof process !== undefined) return process; + const ponyFilledProcess = require("process"); + return ponyFilledProcess; +}; +exports.getProcess = getProcess; const isTestEnv = () => { /** * Check if test mode is enabled by reading the environment variable. */ - if (typeof process !== undefined) return process.env.TEST_MODE === "testing"; - // Since `process` is not available, we will import and use it - // instead. - const ponyFilledProcess = require("process"); - return ponyFilledProcess.env.TEST_MODE === "testing"; + return exports.getProcess().env.TEST_MODE === "testing"; }; exports.isTestEnv = isTestEnv; diff --git a/lib/ts/utils.ts b/lib/ts/utils.ts index 17609ec0b..e2f377a7f 100644 --- a/lib/ts/utils.ts +++ b/lib/ts/utils.ts @@ -423,14 +423,20 @@ export function normaliseEmail(email: string): string { return email; } +export const getProcess = (): NodeJS.Process => { + /** + * Return the process instance if it is available falling back + * to one that is compatible where process may not be available + * (like `edge` runtime). + */ + if (typeof process !== undefined) return process; + const ponyFilledProcess = require("process"); + return ponyFilledProcess; +}; + export const isTestEnv = (): boolean => { /** * Check if test mode is enabled by reading the environment variable. */ - if (typeof process !== undefined) return process.env.TEST_MODE === "testing"; - - // Since `process` is not available, we will import and use it - // instead. - const ponyFilledProcess = require("process"); - return ponyFilledProcess.env.TEST_MODE === "testing"; + return getProcess().env.TEST_MODE === "testing"; }; From 476cda0e0a4072ac0c9042ebce3f3b1f1fc00c1b Mon Sep 17 00:00:00 2001 From: Deepjyoti Barman Date: Tue, 3 Sep 2024 13:14:38 +0530 Subject: [PATCH 19/32] Add fallback implementation for accessing Buffer --- lib/build/utils.d.ts | 4 ++-- lib/build/utils.js | 15 +++++++++++++-- lib/ts/utils.ts | 15 +++++++++++++-- 3 files changed, 28 insertions(+), 6 deletions(-) diff --git a/lib/build/utils.d.ts b/lib/build/utils.d.ts index 5bf18ac13..3222a76d4 100644 --- a/lib/build/utils.d.ts +++ b/lib/build/utils.d.ts @@ -1,5 +1,4 @@ // @ts-nocheck -/// import type { AppInfo, NormalisedAppinfo, HTTPMethod, JSONObject, UserContext } from "./types"; import type { BaseRequest, BaseResponse } from "./framework"; import { User } from "./user"; @@ -58,5 +57,6 @@ export declare function postWithFetch( } >; export declare function normaliseEmail(email: string): string; -export declare const getProcess: () => NodeJS.Process; +export declare const getProcess: () => any; +export declare const getBuffer: () => any; export declare const isTestEnv: () => boolean; diff --git a/lib/build/utils.js b/lib/build/utils.js index 6598ddd6e..1aaa04970 100644 --- a/lib/build/utils.js +++ b/lib/build/utils.js @@ -41,7 +41,7 @@ var __importDefault = return mod && mod.__esModule ? mod : { default: mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); -exports.isTestEnv = exports.getProcess = exports.normaliseEmail = exports.postWithFetch = exports.getFromObjectCaseInsensitive = exports.getTopLevelDomainForSameSiteResolution = exports.setRequestInUserContextIfNotDefined = exports.getUserContext = exports.makeDefaultUserContextFromAPI = exports.humaniseMilliseconds = exports.frontendHasInterceptor = exports.getRidFromHeader = exports.hasGreaterThanEqualToFDI = exports.getLatestFDIVersionFromFDIList = exports.getBackwardsCompatibleUserInfo = exports.isAnIpAddress = exports.send200Response = exports.sendNon200Response = exports.sendNon200ResponseWithMessage = exports.normaliseHttpMethod = exports.normaliseInputAppInfoOrThrowError = exports.maxVersion = exports.getLargestVersionFromIntersection = exports.doFetch = void 0; +exports.isTestEnv = exports.getBuffer = exports.getProcess = exports.normaliseEmail = exports.postWithFetch = exports.getFromObjectCaseInsensitive = exports.getTopLevelDomainForSameSiteResolution = exports.setRequestInUserContextIfNotDefined = exports.getUserContext = exports.makeDefaultUserContextFromAPI = exports.humaniseMilliseconds = exports.frontendHasInterceptor = exports.getRidFromHeader = exports.hasGreaterThanEqualToFDI = exports.getLatestFDIVersionFromFDIList = exports.getBackwardsCompatibleUserInfo = exports.isAnIpAddress = exports.send200Response = exports.sendNon200Response = exports.sendNon200ResponseWithMessage = exports.normaliseHttpMethod = exports.normaliseInputAppInfoOrThrowError = exports.maxVersion = exports.getLargestVersionFromIntersection = exports.doFetch = void 0; const psl = __importStar(require("psl")); const normalisedURLDomain_1 = __importDefault(require("./normalisedURLDomain")); const normalisedURLPath_1 = __importDefault(require("./normalisedURLPath")); @@ -431,11 +431,22 @@ const getProcess = () => { * to one that is compatible where process may not be available * (like `edge` runtime). */ - if (typeof process !== undefined) return process; + if (typeof process !== "undefined") return process; const ponyFilledProcess = require("process"); return ponyFilledProcess; }; exports.getProcess = getProcess; +const getBuffer = () => { + /** + * Return the Buffer instance if it is available falling back + * to one that is compatible where it may not be available + * (like `edge` runtime). + */ + if (typeof Buffer !== "undefined") return Buffer; + const ponyFilledBuffer = require("buffer").Buffer; + return ponyFilledBuffer; +}; +exports.getBuffer = getBuffer; const isTestEnv = () => { /** * Check if test mode is enabled by reading the environment variable. diff --git a/lib/ts/utils.ts b/lib/ts/utils.ts index e2f377a7f..8a439ec75 100644 --- a/lib/ts/utils.ts +++ b/lib/ts/utils.ts @@ -423,17 +423,28 @@ export function normaliseEmail(email: string): string { return email; } -export const getProcess = (): NodeJS.Process => { +export const getProcess = () => { /** * Return the process instance if it is available falling back * to one that is compatible where process may not be available * (like `edge` runtime). */ - if (typeof process !== undefined) return process; + if (typeof process !== "undefined") return process; const ponyFilledProcess = require("process"); return ponyFilledProcess; }; +export const getBuffer = () => { + /** + * Return the Buffer instance if it is available falling back + * to one that is compatible where it may not be available + * (like `edge` runtime). + */ + if (typeof Buffer !== "undefined") return Buffer; + const ponyFilledBuffer = require("buffer").Buffer; + return ponyFilledBuffer; +}; + export const isTestEnv = (): boolean => { /** * Check if test mode is enabled by reading the environment variable. From a4645dab64c97ad5f91efb3854088922a98f7b77 Mon Sep 17 00:00:00 2001 From: Deepjyoti Barman Date: Tue, 3 Sep 2024 13:22:52 +0530 Subject: [PATCH 20/32] Refactor base64 encoding/decoding to use ponyfilled buffer --- .../createOrUpdateThirdPartyConfig.js | 3 ++- lib/build/recipe/session/cookieAndHeaders.js | 3 ++- lib/build/recipe/session/jwt.js | 13 ++++----- .../recipe/thirdparty/api/implementation.js | 3 ++- .../recipe/thirdparty/providers/github.js | 27 ++++++++++++++----- .../recipe/thirdparty/providers/twitter.js | 10 +++---- lib/build/utils.d.ts | 2 ++ lib/build/utils.js | 17 +++++++++++- .../createOrUpdateThirdPartyConfig.ts | 3 ++- lib/ts/recipe/session/cookieAndHeaders.ts | 3 ++- lib/ts/recipe/session/jwt.ts | 13 ++++----- .../recipe/thirdparty/api/implementation.ts | 3 ++- lib/ts/recipe/thirdparty/providers/github.ts | 5 ++-- lib/ts/recipe/thirdparty/providers/twitter.ts | 6 ++--- lib/ts/utils.ts | 15 +++++++++++ 15 files changed, 89 insertions(+), 37 deletions(-) diff --git a/lib/build/recipe/dashboard/api/multitenancy/createOrUpdateThirdPartyConfig.js b/lib/build/recipe/dashboard/api/multitenancy/createOrUpdateThirdPartyConfig.js index ea5218e04..14d3a7313 100644 --- a/lib/build/recipe/dashboard/api/multitenancy/createOrUpdateThirdPartyConfig.js +++ b/lib/build/recipe/dashboard/api/multitenancy/createOrUpdateThirdPartyConfig.js @@ -11,6 +11,7 @@ const normalisedURLDomain_1 = __importDefault(require("../../../../normalisedURL const normalisedURLPath_1 = __importDefault(require("../../../../normalisedURLPath")); const utils_1 = require("../../../thirdparty/providers/utils"); const constants_1 = require("../../../multitenancy/constants"); +const utils_2 = require("../../../../utils"); async function createOrUpdateThirdPartyConfig(_, tenantId, options, userContext) { var _a; const requestBody = await options.req.getJSONBody(); @@ -65,7 +66,7 @@ async function createOrUpdateThirdPartyConfig(_, tenantId, options, userContext) defaultRedirectUrl: providerConfig.clients[0].additionalConfig.redirectURLs[0], forceAuthn: false, encodedRawMetadata: providerConfig.clients[0].additionalConfig.samlXML - ? Buffer.from(providerConfig.clients[0].additionalConfig.samlXML).toString("base64") + ? utils_2.encodeBase64(providerConfig.clients[0].additionalConfig.samlXML) : "", redirectUrl: JSON.stringify(providerConfig.clients[0].additionalConfig.redirectURLs), metadataUrl: providerConfig.clients[0].additionalConfig.samlURL || "", diff --git a/lib/build/recipe/session/cookieAndHeaders.js b/lib/build/recipe/session/cookieAndHeaders.js index 149a3838d..553671956 100644 --- a/lib/build/recipe/session/cookieAndHeaders.js +++ b/lib/build/recipe/session/cookieAndHeaders.js @@ -22,6 +22,7 @@ exports.hasMultipleCookiesForTokenType = exports.clearSessionCookiesFromOlderCoo */ const constants_1 = require("../../constants"); const logger_1 = require("../../logger"); +const utils_1 = require("../../utils"); const constants_2 = require("./constants"); const error_1 = __importDefault(require("./error")); const authorizationHeaderKey = "authorization"; @@ -71,7 +72,7 @@ function buildFrontToken(userId, atExpiry, accessTokenPayload) { ate: atExpiry, up: accessTokenPayload, }; - return Buffer.from(JSON.stringify(tokenInfo)).toString("base64"); + return utils_1.encodeBase64(JSON.stringify(tokenInfo)); } exports.buildFrontToken = buildFrontToken; function setFrontTokenInHeaders(res, frontToken) { diff --git a/lib/build/recipe/session/jwt.js b/lib/build/recipe/session/jwt.js index 097ead1e3..8d8fd813e 100644 --- a/lib/build/recipe/session/jwt.js +++ b/lib/build/recipe/session/jwt.js @@ -16,21 +16,22 @@ Object.defineProperty(exports, "__esModule", { value: true }); exports.parseJWTWithoutSignatureVerification = void 0; const logger_1 = require("../../logger"); +const utils_1 = require("../../utils"); const HEADERS = new Set([ - Buffer.from( + utils_1.encodeBase64( JSON.stringify({ alg: "RS256", typ: "JWT", version: "1", }) - ).toString("base64"), - Buffer.from( + ), + utils_1.encodeBase64( JSON.stringify({ alg: "RS256", typ: "JWT", version: "2", }) - ).toString("base64"), + ), ]); function parseJWTWithoutSignatureVerification(jwt) { const splittedInput = jwt.split("."); @@ -44,7 +45,7 @@ function parseJWTWithoutSignatureVerification(jwt) { // V2 or older tokens did not save the key id; // checking header if (!HEADERS.has(splittedInput[0])) { - const parsedHeader = JSON.parse(Buffer.from(splittedInput[0], "base64").toString()); + const parsedHeader = JSON.parse(utils_1.decodeBase64(splittedInput[0])); if (parsedHeader.version !== undefined) { // We have to ensure version is a string, otherwise Number.parseInt can have unexpected results if (typeof parsedHeader.version !== "string") { @@ -72,7 +73,7 @@ function parseJWTWithoutSignatureVerification(jwt) { header: splittedInput[0], // Ideally we would only parse this after the signature verification is done. // We do this at the start, since we want to check if a token can be a supertokens access token or not - payload: JSON.parse(Buffer.from(splittedInput[1], "base64").toString()), + payload: JSON.parse(utils_1.decodeBase64(splittedInput[1])), signature: splittedInput[2], }; } diff --git a/lib/build/recipe/thirdparty/api/implementation.js b/lib/build/recipe/thirdparty/api/implementation.js index e688b95ae..a47368aff 100644 --- a/lib/build/recipe/thirdparty/api/implementation.js +++ b/lib/build/recipe/thirdparty/api/implementation.js @@ -9,6 +9,7 @@ const emailverification_1 = __importDefault(require("../../emailverification")); const recipe_1 = __importDefault(require("../../emailverification/recipe")); const authUtils_1 = require("../../../authUtils"); const logger_1 = require("../../../logger"); +const utils_1 = require("../../../utils"); function getAPIInterface() { return { authorisationUrlGET: async function ({ provider, redirectURIOnProviderDashboard, userContext }) { @@ -202,7 +203,7 @@ function getAPIInterface() { }, appleRedirectHandlerPOST: async function ({ formPostInfoFromProvider, options }) { const stateInBase64 = formPostInfoFromProvider.state; - const state = Buffer.from(stateInBase64, "base64").toString(); + const state = utils_1.decodeBase64(stateInBase64); const stateObj = JSON.parse(state); const redirectURI = stateObj.frontendRedirectURI; const urlObj = new URL(redirectURI); diff --git a/lib/build/recipe/thirdparty/providers/github.js b/lib/build/recipe/thirdparty/providers/github.js index a656dd895..a1d6e2e13 100644 --- a/lib/build/recipe/thirdparty/providers/github.js +++ b/lib/build/recipe/thirdparty/providers/github.js @@ -5,8 +5,23 @@ var __importDefault = return mod && mod.__esModule ? mod : { default: mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); +/* Copyright (c) 2021, VRAI Labs and/or its affiliates. All rights reserved. + * + * This software is licensed under the Apache License, Version 2.0 (the + * "License") as published by the Apache Software Foundation. + * + * You may not use this file except in compliance with the License. You may + * obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +const utils_1 = require("../../../utils"); const custom_1 = __importDefault(require("./custom")); -const utils_1 = require("./utils"); +const utils_2 = require("./utils"); function getSupertokensUserInfoFromRawUserInfoResponseForGithub(rawUserInfoResponse) { if (rawUserInfoResponse.fromUserInfoAPI === undefined) { throw new Error("rawUserInfoResponse.fromUserInfoAPI is not available"); @@ -41,10 +56,10 @@ function Github(input) { } if (input.config.validateAccessToken === undefined) { input.config.validateAccessToken = async ({ accessToken, clientConfig }) => { - const basicAuthToken = Buffer.from( + const basicAuthToken = utils_1.encodeBase64( `${clientConfig.clientId}:${clientConfig.clientSecret === undefined ? "" : clientConfig.clientSecret}` - ).toString("base64"); - const applicationResponse = await utils_1.doPostRequest( + ); + const applicationResponse = await utils_2.doPostRequest( `https://api.github.com/applications/${clientConfig.clientId}/token`, { access_token: accessToken, @@ -81,14 +96,14 @@ function Github(input) { Accept: "application/vnd.github.v3+json", }; const rawResponse = {}; - const emailInfoResp = await utils_1.doGetRequest("https://api.github.com/user/emails", undefined, headers); + const emailInfoResp = await utils_2.doGetRequest("https://api.github.com/user/emails", undefined, headers); if (emailInfoResp.status >= 400) { throw new Error( `Getting userInfo failed with ${emailInfoResp.status}: ${emailInfoResp.stringResponse}` ); } rawResponse.emails = emailInfoResp.jsonResponse; - const userInfoResp = await utils_1.doGetRequest("https://api.github.com/user", undefined, headers); + const userInfoResp = await utils_2.doGetRequest("https://api.github.com/user", undefined, headers); if (userInfoResp.status >= 400) { throw new Error(`Getting userInfo failed with ${userInfoResp.status}: ${userInfoResp.stringResponse}`); } diff --git a/lib/build/recipe/thirdparty/providers/twitter.js b/lib/build/recipe/thirdparty/providers/twitter.js index 3e54592c7..a901c40d6 100644 --- a/lib/build/recipe/thirdparty/providers/twitter.js +++ b/lib/build/recipe/thirdparty/providers/twitter.js @@ -51,8 +51,9 @@ Object.defineProperty(exports, "__esModule", { value: true }); * under the License. */ const logger_1 = require("../../../logger"); +const utils_1 = require("../../../utils"); const custom_1 = __importStar(require("./custom")); -const utils_1 = require("./utils"); +const utils_2 = require("./utils"); function Twitter(input) { var _a; if (input.config.name === undefined) { @@ -102,10 +103,7 @@ function Twitter(input) { redirectUri = custom_1.DEV_OAUTH_REDIRECT_URL; } /* Transformation needed for dev keys END */ - const basicAuthToken = Buffer.from( - `${clientId}:${originalImplementation.config.clientSecret}`, - "utf8" - ).toString("base64"); + const basicAuthToken = utils_1.encodeBase64(`${clientId}:${originalImplementation.config.clientSecret}`); const twitterOauthTokenParams = Object.assign( { grant_type: "authorization_code", @@ -116,7 +114,7 @@ function Twitter(input) { }, originalImplementation.config.tokenEndpointBodyParams ); - const tokenResponse = await utils_1.doPostRequest( + const tokenResponse = await utils_2.doPostRequest( originalImplementation.config.tokenEndpoint, twitterOauthTokenParams, { diff --git a/lib/build/utils.d.ts b/lib/build/utils.d.ts index 3222a76d4..56cff60db 100644 --- a/lib/build/utils.d.ts +++ b/lib/build/utils.d.ts @@ -60,3 +60,5 @@ export declare function normaliseEmail(email: string): string; export declare const getProcess: () => any; export declare const getBuffer: () => any; export declare const isTestEnv: () => boolean; +export declare const encodeBase64: (value: string) => string; +export declare const decodeBase64: (value: string) => string; diff --git a/lib/build/utils.js b/lib/build/utils.js index 1aaa04970..15ed9f907 100644 --- a/lib/build/utils.js +++ b/lib/build/utils.js @@ -41,7 +41,7 @@ var __importDefault = return mod && mod.__esModule ? mod : { default: mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); -exports.isTestEnv = exports.getBuffer = exports.getProcess = exports.normaliseEmail = exports.postWithFetch = exports.getFromObjectCaseInsensitive = exports.getTopLevelDomainForSameSiteResolution = exports.setRequestInUserContextIfNotDefined = exports.getUserContext = exports.makeDefaultUserContextFromAPI = exports.humaniseMilliseconds = exports.frontendHasInterceptor = exports.getRidFromHeader = exports.hasGreaterThanEqualToFDI = exports.getLatestFDIVersionFromFDIList = exports.getBackwardsCompatibleUserInfo = exports.isAnIpAddress = exports.send200Response = exports.sendNon200Response = exports.sendNon200ResponseWithMessage = exports.normaliseHttpMethod = exports.normaliseInputAppInfoOrThrowError = exports.maxVersion = exports.getLargestVersionFromIntersection = exports.doFetch = void 0; +exports.decodeBase64 = exports.encodeBase64 = exports.isTestEnv = exports.getBuffer = exports.getProcess = exports.normaliseEmail = exports.postWithFetch = exports.getFromObjectCaseInsensitive = exports.getTopLevelDomainForSameSiteResolution = exports.setRequestInUserContextIfNotDefined = exports.getUserContext = exports.makeDefaultUserContextFromAPI = exports.humaniseMilliseconds = exports.frontendHasInterceptor = exports.getRidFromHeader = exports.hasGreaterThanEqualToFDI = exports.getLatestFDIVersionFromFDIList = exports.getBackwardsCompatibleUserInfo = exports.isAnIpAddress = exports.send200Response = exports.sendNon200Response = exports.sendNon200ResponseWithMessage = exports.normaliseHttpMethod = exports.normaliseInputAppInfoOrThrowError = exports.maxVersion = exports.getLargestVersionFromIntersection = exports.doFetch = void 0; const psl = __importStar(require("psl")); const normalisedURLDomain_1 = __importDefault(require("./normalisedURLDomain")); const normalisedURLPath_1 = __importDefault(require("./normalisedURLPath")); @@ -454,3 +454,18 @@ const isTestEnv = () => { return exports.getProcess().env.TEST_MODE === "testing"; }; exports.isTestEnv = isTestEnv; +const encodeBase64 = (value) => { + /** + * Encode the passed value to base64 and return the encoded value. + */ + return exports.getBuffer().from(value).toString("base64"); +}; +exports.encodeBase64 = encodeBase64; +const decodeBase64 = (value) => { + /** + * Decode the passed value with base64 encoded and return the + * decoded value. + */ + return exports.getBuffer().from(value, "base64").toString(); +}; +exports.decodeBase64 = decodeBase64; diff --git a/lib/ts/recipe/dashboard/api/multitenancy/createOrUpdateThirdPartyConfig.ts b/lib/ts/recipe/dashboard/api/multitenancy/createOrUpdateThirdPartyConfig.ts index 0ec729649..16a6cd2a9 100644 --- a/lib/ts/recipe/dashboard/api/multitenancy/createOrUpdateThirdPartyConfig.ts +++ b/lib/ts/recipe/dashboard/api/multitenancy/createOrUpdateThirdPartyConfig.ts @@ -20,6 +20,7 @@ import NormalisedURLDomain from "../../../../normalisedURLDomain"; import NormalisedURLPath from "../../../../normalisedURLPath"; import { doPostRequest } from "../../../thirdparty/providers/utils"; import { DEFAULT_TENANT_ID } from "../../../multitenancy/constants"; +import { encodeBase64 } from "../../../../utils"; export type Response = | { @@ -87,7 +88,7 @@ export default async function createOrUpdateThirdPartyConfig( defaultRedirectUrl: providerConfig.clients[0].additionalConfig.redirectURLs[0], forceAuthn: false, encodedRawMetadata: providerConfig.clients[0].additionalConfig.samlXML - ? Buffer.from(providerConfig.clients[0].additionalConfig.samlXML).toString("base64") + ? encodeBase64(providerConfig.clients[0].additionalConfig.samlXML) : "", redirectUrl: JSON.stringify(providerConfig.clients[0].additionalConfig.redirectURLs), metadataUrl: providerConfig.clients[0].additionalConfig.samlURL || "", diff --git a/lib/ts/recipe/session/cookieAndHeaders.ts b/lib/ts/recipe/session/cookieAndHeaders.ts index 8d3165adf..206c7cfbf 100644 --- a/lib/ts/recipe/session/cookieAndHeaders.ts +++ b/lib/ts/recipe/session/cookieAndHeaders.ts @@ -16,6 +16,7 @@ import { HEADER_RID } from "../../constants"; import type { BaseRequest, BaseResponse } from "../../framework"; import { logDebugMessage } from "../../logger"; import { UserContext } from "../../types"; +import { encodeBase64 } from "../../utils"; import { availableTokenTransferMethods } from "./constants"; import SessionError from "./error"; import { TokenTransferMethod, TokenType, TypeNormalisedInput } from "./types"; @@ -83,7 +84,7 @@ export function buildFrontToken(userId: string, atExpiry: number, accessTokenPay ate: atExpiry, up: accessTokenPayload, }; - return Buffer.from(JSON.stringify(tokenInfo)).toString("base64"); + return encodeBase64(JSON.stringify(tokenInfo)); } export function setFrontTokenInHeaders(res: BaseResponse, frontToken: string) { diff --git a/lib/ts/recipe/session/jwt.ts b/lib/ts/recipe/session/jwt.ts index c89841bc1..32079b6bb 100644 --- a/lib/ts/recipe/session/jwt.ts +++ b/lib/ts/recipe/session/jwt.ts @@ -14,22 +14,23 @@ */ import { logDebugMessage } from "../../logger"; +import { decodeBase64, encodeBase64 } from "../../utils"; const HEADERS = new Set([ - Buffer.from( + encodeBase64( JSON.stringify({ alg: "RS256", typ: "JWT", version: "1", }) - ).toString("base64"), - Buffer.from( + ), + encodeBase64( JSON.stringify({ alg: "RS256", typ: "JWT", version: "2", }) - ).toString("base64"), + ), ]); export type ParsedJWTInfo = { @@ -56,7 +57,7 @@ export function parseJWTWithoutSignatureVerification(jwt: string): ParsedJWTInfo // V2 or older tokens did not save the key id; // checking header if (!HEADERS.has(splittedInput[0])) { - const parsedHeader = JSON.parse(Buffer.from(splittedInput[0], "base64").toString()); + const parsedHeader = JSON.parse(decodeBase64(splittedInput[0])); if (parsedHeader.version !== undefined) { // We have to ensure version is a string, otherwise Number.parseInt can have unexpected results @@ -88,7 +89,7 @@ export function parseJWTWithoutSignatureVerification(jwt: string): ParsedJWTInfo header: splittedInput[0], // Ideally we would only parse this after the signature verification is done. // We do this at the start, since we want to check if a token can be a supertokens access token or not - payload: JSON.parse(Buffer.from(splittedInput[1], "base64").toString()), + payload: JSON.parse(decodeBase64(splittedInput[1])), signature: splittedInput[2], }; } diff --git a/lib/ts/recipe/thirdparty/api/implementation.ts b/lib/ts/recipe/thirdparty/api/implementation.ts index e91bb2dc3..8bd4265d3 100644 --- a/lib/ts/recipe/thirdparty/api/implementation.ts +++ b/lib/ts/recipe/thirdparty/api/implementation.ts @@ -3,6 +3,7 @@ import EmailVerification from "../../emailverification"; import EmailVerificationRecipe from "../../emailverification/recipe"; import { AuthUtils } from "../../../authUtils"; import { logDebugMessage } from "../../../logger"; +import { decodeBase64 } from "../../../utils"; export default function getAPIInterface(): APIInterface { return { @@ -212,7 +213,7 @@ export default function getAPIInterface(): APIInterface { appleRedirectHandlerPOST: async function ({ formPostInfoFromProvider, options }): Promise { const stateInBase64 = formPostInfoFromProvider.state; - const state = Buffer.from(stateInBase64, "base64").toString(); + const state = decodeBase64(stateInBase64); const stateObj = JSON.parse(state); const redirectURI = stateObj.frontendRedirectURI; diff --git a/lib/ts/recipe/thirdparty/providers/github.ts b/lib/ts/recipe/thirdparty/providers/github.ts index f556eba71..5a62474fd 100644 --- a/lib/ts/recipe/thirdparty/providers/github.ts +++ b/lib/ts/recipe/thirdparty/providers/github.ts @@ -12,6 +12,7 @@ * License for the specific language governing permissions and limitations * under the License. */ +import { encodeBase64 } from "../../../utils"; import { ProviderInput, TypeProvider, UserInfo } from "../types"; import NewProvider from "./custom"; import { doGetRequest, doPostRequest } from "./utils"; @@ -60,9 +61,9 @@ export default function Github(input: ProviderInput): TypeProvider { if (input.config.validateAccessToken === undefined) { input.config.validateAccessToken = async ({ accessToken, clientConfig }) => { - const basicAuthToken = Buffer.from( + const basicAuthToken = encodeBase64( `${clientConfig.clientId}:${clientConfig.clientSecret === undefined ? "" : clientConfig.clientSecret}` - ).toString("base64"); + ); const applicationResponse = await doPostRequest( `https://api.github.com/applications/${clientConfig.clientId}/token`, diff --git a/lib/ts/recipe/thirdparty/providers/twitter.ts b/lib/ts/recipe/thirdparty/providers/twitter.ts index cb60db8d3..e6474465d 100644 --- a/lib/ts/recipe/thirdparty/providers/twitter.ts +++ b/lib/ts/recipe/thirdparty/providers/twitter.ts @@ -13,6 +13,7 @@ * under the License. */ import { logDebugMessage } from "../../../logger"; +import { encodeBase64 } from "../../../utils"; import { ProviderInput, TypeProvider } from "../types"; import NewProvider, { DEV_OAUTH_REDIRECT_URL, @@ -80,10 +81,7 @@ export default function Twitter(input: ProviderInput): TypeProvider { } /* Transformation needed for dev keys END */ - const basicAuthToken = Buffer.from( - `${clientId}:${originalImplementation.config.clientSecret}`, - "utf8" - ).toString("base64"); + const basicAuthToken = encodeBase64(`${clientId}:${originalImplementation.config.clientSecret}`); const twitterOauthTokenParams = { grant_type: "authorization_code", client_id: clientId, diff --git a/lib/ts/utils.ts b/lib/ts/utils.ts index 8a439ec75..4d5cd0a9a 100644 --- a/lib/ts/utils.ts +++ b/lib/ts/utils.ts @@ -451,3 +451,18 @@ export const isTestEnv = (): boolean => { */ return getProcess().env.TEST_MODE === "testing"; }; + +export const encodeBase64 = (value: string): string => { + /** + * Encode the passed value to base64 and return the encoded value. + */ + return getBuffer().from(value).toString("base64"); +}; + +export const decodeBase64 = (value: string): string => { + /** + * Decode the passed value with base64 encoded and return the + * decoded value. + */ + return getBuffer().from(value, "base64").toString(); +}; From 309c2e42ba8d44aacfa58e6a89368d0894801913 Mon Sep 17 00:00:00 2001 From: Deepjyoti Barman Date: Tue, 3 Sep 2024 13:28:23 +0530 Subject: [PATCH 21/32] Reuse ponyfilled buffer at more places --- lib/build/framework/express/framework.js | 2 +- lib/build/framework/loopback/framework.js | 2 +- lib/build/framework/utils.js | 10 +++++----- lib/build/nextjs.d.ts | 1 - lib/build/nextjs.js | 1 - lib/ts/framework/express/framework.ts | 4 ++-- lib/ts/framework/loopback/framework.ts | 4 ++-- lib/ts/framework/utils.ts | 16 ++++++++-------- lib/ts/nextjs.ts | 2 -- 9 files changed, 19 insertions(+), 23 deletions(-) diff --git a/lib/build/framework/express/framework.js b/lib/build/framework/express/framework.js index 091cc96df..0cd2651de 100644 --- a/lib/build/framework/express/framework.js +++ b/lib/build/framework/express/framework.js @@ -76,7 +76,7 @@ class ExpressResponse extends response_1.BaseResponse { * like response as well as nextjs like response */ this.response.setHeader("Content-Type", "text/html"); - this.response.status(this.statusCode).send(Buffer.from(html)); + this.response.status(this.statusCode).send(utils_1.getBuffer().from(html)); } }; this.setHeader = (key, value, allowDuplicateKey) => { diff --git a/lib/build/framework/loopback/framework.js b/lib/build/framework/loopback/framework.js index 610a00fa0..40157d518 100644 --- a/lib/build/framework/loopback/framework.js +++ b/lib/build/framework/loopback/framework.js @@ -69,7 +69,7 @@ class LoopbackResponse extends response_1.BaseResponse { this.sendHTMLResponse = (html) => { if (!this.response.writableEnded) { this.response.set("Content-Type", "text/html"); - this.response.status(this.statusCode).send(Buffer.from(html)); + this.response.status(this.statusCode).send(utils_1.getBuffer().from(html)); } }; this.setHeader = (key, value, allowDuplicateKey) => { diff --git a/lib/build/framework/utils.js b/lib/build/framework/utils.js index b57b5fd0d..995ed6b91 100644 --- a/lib/build/framework/utils.js +++ b/lib/build/framework/utils.js @@ -117,11 +117,11 @@ async function inflate(stream) { if (e_2) throw e_2.error; } } - const compressedData = Buffer.concat(chunks); + const compressedData = utils_1.getBuffer().concat(chunks); decompressedData = brotliDecompress(compressedData); } else { // Handle identity or unsupported encoding - decompressedData = Buffer.concat([]); + decompressedData = utils_1.getBuffer().concat([]); try { for ( var stream_3 = __asyncValues(stream), stream_3_1; @@ -129,7 +129,7 @@ async function inflate(stream) { ) { const chunk = stream_3_1.value; - decompressedData = Buffer.concat([decompressedData, chunk]); + decompressedData = utils_1.getBuffer().concat([decompressedData, chunk]); } } catch (e_3_1) { e_3 = { error: e_3_1 }; @@ -274,7 +274,7 @@ async function assertThatBodyParserHasBeenUsedForExpressLikeRequest(method, requ } } else if ( request.body === undefined || - Buffer.isBuffer(request.body) || + utils_1.getBuffer().isBuffer(request.body) || (Object.keys(request.body).length === 0 && request.readable) ) { try { @@ -314,7 +314,7 @@ async function assertFormDataBodyParserHasBeenUsedForExpressLikeRequest(request) } } else if ( request.body === undefined || - Buffer.isBuffer(request.body) || + utils_1.getBuffer().isBuffer(request.body) || (Object.keys(request.body).length === 0 && request.readable) ) { try { diff --git a/lib/build/nextjs.d.ts b/lib/build/nextjs.d.ts index 3493fd9ee..7b06b2936 100644 --- a/lib/build/nextjs.d.ts +++ b/lib/build/nextjs.d.ts @@ -1,5 +1,4 @@ // @ts-nocheck -import "./polyfill"; import { CollectingResponse, PreParsedRequest } from "./framework/custom"; import { SessionContainer, VerifySessionOptions } from "./recipe/session"; declare type PartialNextRequest = { diff --git a/lib/build/nextjs.js b/lib/build/nextjs.js index 7e6f35e90..28c1a63d6 100644 --- a/lib/build/nextjs.js +++ b/lib/build/nextjs.js @@ -31,7 +31,6 @@ var __importDefault = }; Object.defineProperty(exports, "__esModule", { value: true }); exports.withPreParsedRequestResponse = exports.withSession = exports.getSSRSession = exports.getAppDirRequestHandler = exports.superTokensNextWrapper = void 0; -require("./polyfill"); const cookie_1 = require("cookie"); const express_1 = require("./framework/express"); const utils_1 = require("./utils"); diff --git a/lib/ts/framework/express/framework.ts b/lib/ts/framework/express/framework.ts index 28848b22f..60820e060 100644 --- a/lib/ts/framework/express/framework.ts +++ b/lib/ts/framework/express/framework.ts @@ -15,7 +15,7 @@ import type { Request, Response, NextFunction } from "express"; import type { HTTPMethod } from "../../types"; -import { makeDefaultUserContextFromAPI, normaliseHttpMethod } from "../../utils"; +import { getBuffer, makeDefaultUserContextFromAPI, normaliseHttpMethod } from "../../utils"; import { BaseRequest } from "../request"; import { BaseResponse } from "../response"; import { @@ -98,7 +98,7 @@ export class ExpressResponse extends BaseResponse { * like response as well as nextjs like response */ this.response.setHeader("Content-Type", "text/html"); - this.response.status(this.statusCode).send(Buffer.from(html)); + this.response.status(this.statusCode).send(getBuffer().from(html)); } }; diff --git a/lib/ts/framework/loopback/framework.ts b/lib/ts/framework/loopback/framework.ts index 21a535ef7..e547f1fd9 100644 --- a/lib/ts/framework/loopback/framework.ts +++ b/lib/ts/framework/loopback/framework.ts @@ -17,7 +17,7 @@ import type { MiddlewareContext, Request, Response, Middleware } from "@loopback import type { Next } from "@loopback/core"; import { SessionContainerInterface } from "../../recipe/session/types"; import { HTTPMethod } from "../../types"; -import { makeDefaultUserContextFromAPI, normaliseHttpMethod } from "../../utils"; +import { getBuffer, makeDefaultUserContextFromAPI, normaliseHttpMethod } from "../../utils"; import { BaseRequest } from "../request"; import { BaseResponse } from "../response"; import { @@ -92,7 +92,7 @@ export class LoopbackResponse extends BaseResponse { sendHTMLResponse = (html: string) => { if (!this.response.writableEnded) { this.response.set("Content-Type", "text/html"); - this.response.status(this.statusCode).send(Buffer.from(html)); + this.response.status(this.statusCode).send(getBuffer().from(html)); } }; diff --git a/lib/ts/framework/utils.ts b/lib/ts/framework/utils.ts index 90f52efa7..c8b3b82a0 100644 --- a/lib/ts/framework/utils.ts +++ b/lib/ts/framework/utils.ts @@ -20,11 +20,11 @@ import { ServerResponse } from "http"; import STError from "../error"; import type { HTTPMethod } from "../types"; import { BROTLI_DECOMPRESSION_ERROR_MESSAGE, COOKIE_HEADER } from "./constants"; -import { getFromObjectCaseInsensitive } from "../utils"; +import { getBuffer, getFromObjectCaseInsensitive } from "../utils"; import contentType from "content-type"; import pako from "pako"; -let brotliDecompress: ((input: Buffer) => Buffer) | null = null; +let brotliDecompress: ((input: any) => any) | null = null; try { // @ts-ignore @@ -57,17 +57,17 @@ async function inflate(stream: IncomingMessage): Promise { } else if (encoding === "br") { if (!brotliDecompress) throw new Error(BROTLI_DECOMPRESSION_ERROR_MESSAGE); - const chunks: Buffer[] = []; + const chunks = []; for await (const chunk of stream) { chunks.push(chunk); } - const compressedData = Buffer.concat(chunks); + const compressedData = getBuffer().concat(chunks); decompressedData = brotliDecompress(compressedData); } else { // Handle identity or unsupported encoding - decompressedData = Buffer.concat([]); + decompressedData = getBuffer().concat([]); for await (const chunk of stream) { - decompressedData = Buffer.concat([decompressedData, chunk]); + decompressedData = getBuffer().concat([decompressedData, chunk]); } } @@ -222,7 +222,7 @@ export async function assertThatBodyParserHasBeenUsedForExpressLikeRequest(metho } } else if ( request.body === undefined || - Buffer.isBuffer(request.body) || + getBuffer().isBuffer(request.body) || (Object.keys(request.body).length === 0 && request.readable) ) { try { @@ -263,7 +263,7 @@ export async function assertFormDataBodyParserHasBeenUsedForExpressLikeRequest(r } } else if ( request.body === undefined || - Buffer.isBuffer(request.body) || + getBuffer().isBuffer(request.body) || (Object.keys(request.body).length === 0 && request.readable) ) { try { diff --git a/lib/ts/nextjs.ts b/lib/ts/nextjs.ts index b9668f31b..266213b22 100644 --- a/lib/ts/nextjs.ts +++ b/lib/ts/nextjs.ts @@ -13,8 +13,6 @@ * under the License. */ -import "./polyfill"; - import { serialize } from "cookie"; import { errorHandler } from "./framework/express"; import { getUserContext } from "./utils"; From 66e3cdb6c0c279b519879cc0a5d1b10e80e2b9e9 Mon Sep 17 00:00:00 2001 From: Deepjyoti Barman Date: Tue, 3 Sep 2024 13:32:18 +0530 Subject: [PATCH 22/32] Remove polyfill functionality for buffer and process --- lib/build/polyfill.d.ts | 1 - lib/build/polyfill.js | 9 --------- lib/ts/polyfill.ts | 9 --------- 3 files changed, 19 deletions(-) delete mode 100644 lib/build/polyfill.d.ts delete mode 100644 lib/build/polyfill.js delete mode 100644 lib/ts/polyfill.ts diff --git a/lib/build/polyfill.d.ts b/lib/build/polyfill.d.ts deleted file mode 100644 index f6617924f..000000000 --- a/lib/build/polyfill.d.ts +++ /dev/null @@ -1 +0,0 @@ -// @ts-nocheck diff --git a/lib/build/polyfill.js b/lib/build/polyfill.js deleted file mode 100644 index 26b21b34e..000000000 --- a/lib/build/polyfill.js +++ /dev/null @@ -1,9 +0,0 @@ -"use strict"; -// Check if 'Buffer' is available, if not, polyfill it -if (typeof Buffer === "undefined") { - global.Buffer = require("buffer").Buffer; -} -// Check if 'process' is available, if not, polyfill it -if (typeof process === "undefined") { - global.process = require("process"); -} diff --git a/lib/ts/polyfill.ts b/lib/ts/polyfill.ts deleted file mode 100644 index 3f39afdb5..000000000 --- a/lib/ts/polyfill.ts +++ /dev/null @@ -1,9 +0,0 @@ -// Check if 'Buffer' is available, if not, polyfill it -if (typeof Buffer === "undefined") { - global.Buffer = require("buffer").Buffer; -} - -// Check if 'process' is available, if not, polyfill it -if (typeof process === "undefined") { - global.process = require("process"); -} From 043c05aeaddfa23cab401f0c3af7e84b67134bdc Mon Sep 17 00:00:00 2001 From: Deepjyoti Barman Date: Wed, 4 Sep 2024 10:27:14 +0530 Subject: [PATCH 23/32] Remove unused test file --- test/framework/utils.test.js | 14 -------------- 1 file changed, 14 deletions(-) delete mode 100644 test/framework/utils.test.js diff --git a/test/framework/utils.test.js b/test/framework/utils.test.js deleted file mode 100644 index 91b82644a..000000000 --- a/test/framework/utils.test.js +++ /dev/null @@ -1,14 +0,0 @@ -let assert = require("assert"); -const { parseParams } = require("../../lib/build/framework/utils"); - -describe("test framework related util functions", () => { - it("should be able to parse params", () => { - assert.deepEqual(parseParams("?a=1&b=secondValue&c="), { a: ["1"], b: ["secondValue"] }); - assert.deepEqual(parseParams("?a=1&b=first,second&c=third"), { - a: ["1"], - b: ["first", "second"], - c: ["third"], - }); - assert.deepEqual(parseParams(""), {}); - }); -}); From d2e4c32fe632f1868a4de2d36479065706e30a0c Mon Sep 17 00:00:00 2001 From: Deepjyoti Barman Date: Wed, 4 Sep 2024 10:33:32 +0530 Subject: [PATCH 24/32] Update some functions according to comments in PR --- lib/build/framework/express/framework.js | 2 +- lib/build/framework/utils.js | 4 ++-- lib/build/utils.d.ts | 1 + lib/build/utils.js | 9 ++++++++- lib/ts/framework/express/framework.ts | 4 ++-- lib/ts/framework/utils.ts | 6 +++--- lib/ts/utils.ts | 7 +++++++ 7 files changed, 24 insertions(+), 9 deletions(-) diff --git a/lib/build/framework/express/framework.js b/lib/build/framework/express/framework.js index 0cd2651de..d8a58729b 100644 --- a/lib/build/framework/express/framework.js +++ b/lib/build/framework/express/framework.js @@ -76,7 +76,7 @@ class ExpressResponse extends response_1.BaseResponse { * like response as well as nextjs like response */ this.response.setHeader("Content-Type", "text/html"); - this.response.status(this.statusCode).send(utils_1.getBuffer().from(html)); + this.response.status(this.statusCode).send(html); } }; this.setHeader = (key, value, allowDuplicateKey) => { diff --git a/lib/build/framework/utils.js b/lib/build/framework/utils.js index 995ed6b91..804d39da2 100644 --- a/lib/build/framework/utils.js +++ b/lib/build/framework/utils.js @@ -274,7 +274,7 @@ async function assertThatBodyParserHasBeenUsedForExpressLikeRequest(method, requ } } else if ( request.body === undefined || - utils_1.getBuffer().isBuffer(request.body) || + utils_1.isBuffer(request.body) || (Object.keys(request.body).length === 0 && request.readable) ) { try { @@ -314,7 +314,7 @@ async function assertFormDataBodyParserHasBeenUsedForExpressLikeRequest(request) } } else if ( request.body === undefined || - utils_1.getBuffer().isBuffer(request.body) || + utils_1.isBuffer(request.body) || (Object.keys(request.body).length === 0 && request.readable) ) { try { diff --git a/lib/build/utils.d.ts b/lib/build/utils.d.ts index 56cff60db..e16cbed34 100644 --- a/lib/build/utils.d.ts +++ b/lib/build/utils.d.ts @@ -62,3 +62,4 @@ export declare const getBuffer: () => any; export declare const isTestEnv: () => boolean; export declare const encodeBase64: (value: string) => string; export declare const decodeBase64: (value: string) => string; +export declare const isBuffer: (obj: any) => boolean; diff --git a/lib/build/utils.js b/lib/build/utils.js index 15ed9f907..6650ec325 100644 --- a/lib/build/utils.js +++ b/lib/build/utils.js @@ -41,7 +41,7 @@ var __importDefault = return mod && mod.__esModule ? mod : { default: mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); -exports.decodeBase64 = exports.encodeBase64 = exports.isTestEnv = exports.getBuffer = exports.getProcess = exports.normaliseEmail = exports.postWithFetch = exports.getFromObjectCaseInsensitive = exports.getTopLevelDomainForSameSiteResolution = exports.setRequestInUserContextIfNotDefined = exports.getUserContext = exports.makeDefaultUserContextFromAPI = exports.humaniseMilliseconds = exports.frontendHasInterceptor = exports.getRidFromHeader = exports.hasGreaterThanEqualToFDI = exports.getLatestFDIVersionFromFDIList = exports.getBackwardsCompatibleUserInfo = exports.isAnIpAddress = exports.send200Response = exports.sendNon200Response = exports.sendNon200ResponseWithMessage = exports.normaliseHttpMethod = exports.normaliseInputAppInfoOrThrowError = exports.maxVersion = exports.getLargestVersionFromIntersection = exports.doFetch = void 0; +exports.isBuffer = exports.decodeBase64 = exports.encodeBase64 = exports.isTestEnv = exports.getBuffer = exports.getProcess = exports.normaliseEmail = exports.postWithFetch = exports.getFromObjectCaseInsensitive = exports.getTopLevelDomainForSameSiteResolution = exports.setRequestInUserContextIfNotDefined = exports.getUserContext = exports.makeDefaultUserContextFromAPI = exports.humaniseMilliseconds = exports.frontendHasInterceptor = exports.getRidFromHeader = exports.hasGreaterThanEqualToFDI = exports.getLatestFDIVersionFromFDIList = exports.getBackwardsCompatibleUserInfo = exports.isAnIpAddress = exports.send200Response = exports.sendNon200Response = exports.sendNon200ResponseWithMessage = exports.normaliseHttpMethod = exports.normaliseInputAppInfoOrThrowError = exports.maxVersion = exports.getLargestVersionFromIntersection = exports.doFetch = void 0; const psl = __importStar(require("psl")); const normalisedURLDomain_1 = __importDefault(require("./normalisedURLDomain")); const normalisedURLPath_1 = __importDefault(require("./normalisedURLPath")); @@ -469,3 +469,10 @@ const decodeBase64 = (value) => { return exports.getBuffer().from(value, "base64").toString(); }; exports.decodeBase64 = decodeBase64; +const isBuffer = (obj) => { + /** + * Check if the passed object is a buffer or not. + */ + return exports.getBuffer().isBuffer(obj); +}; +exports.isBuffer = isBuffer; diff --git a/lib/ts/framework/express/framework.ts b/lib/ts/framework/express/framework.ts index 60820e060..a9f66a1c9 100644 --- a/lib/ts/framework/express/framework.ts +++ b/lib/ts/framework/express/framework.ts @@ -15,7 +15,7 @@ import type { Request, Response, NextFunction } from "express"; import type { HTTPMethod } from "../../types"; -import { getBuffer, makeDefaultUserContextFromAPI, normaliseHttpMethod } from "../../utils"; +import { makeDefaultUserContextFromAPI, normaliseHttpMethod } from "../../utils"; import { BaseRequest } from "../request"; import { BaseResponse } from "../response"; import { @@ -98,7 +98,7 @@ export class ExpressResponse extends BaseResponse { * like response as well as nextjs like response */ this.response.setHeader("Content-Type", "text/html"); - this.response.status(this.statusCode).send(getBuffer().from(html)); + this.response.status(this.statusCode).send(html); } }; diff --git a/lib/ts/framework/utils.ts b/lib/ts/framework/utils.ts index c8b3b82a0..92e384747 100644 --- a/lib/ts/framework/utils.ts +++ b/lib/ts/framework/utils.ts @@ -20,7 +20,7 @@ import { ServerResponse } from "http"; import STError from "../error"; import type { HTTPMethod } from "../types"; import { BROTLI_DECOMPRESSION_ERROR_MESSAGE, COOKIE_HEADER } from "./constants"; -import { getBuffer, getFromObjectCaseInsensitive } from "../utils"; +import { getBuffer, getFromObjectCaseInsensitive, isBuffer } from "../utils"; import contentType from "content-type"; import pako from "pako"; @@ -222,7 +222,7 @@ export async function assertThatBodyParserHasBeenUsedForExpressLikeRequest(metho } } else if ( request.body === undefined || - getBuffer().isBuffer(request.body) || + isBuffer(request.body) || (Object.keys(request.body).length === 0 && request.readable) ) { try { @@ -263,7 +263,7 @@ export async function assertFormDataBodyParserHasBeenUsedForExpressLikeRequest(r } } else if ( request.body === undefined || - getBuffer().isBuffer(request.body) || + isBuffer(request.body) || (Object.keys(request.body).length === 0 && request.readable) ) { try { diff --git a/lib/ts/utils.ts b/lib/ts/utils.ts index 4d5cd0a9a..257159e29 100644 --- a/lib/ts/utils.ts +++ b/lib/ts/utils.ts @@ -466,3 +466,10 @@ export const decodeBase64 = (value: string): string => { */ return getBuffer().from(value, "base64").toString(); }; + +export const isBuffer = (obj: any): boolean => { + /** + * Check if the passed object is a buffer or not. + */ + return getBuffer().isBuffer(obj); +}; From 1627d3b21fd17bac5c0d29934f07e8b35a4763f9 Mon Sep 17 00:00:00 2001 From: Deepjyoti Barman Date: Wed, 4 Sep 2024 10:35:56 +0530 Subject: [PATCH 25/32] Update workflow to use more values from secrets --- .github/workflows/test-cf-worker-next.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test-cf-worker-next.yml b/.github/workflows/test-cf-worker-next.yml index 3b9f9a513..6cead47b8 100644 --- a/.github/workflows/test-cf-worker-next.yml +++ b/.github/workflows/test-cf-worker-next.yml @@ -6,7 +6,8 @@ jobs: env: CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }} CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }} - APP_URL: supertokens-node-b95.pages.dev + APP_URL: ${{ secrets.CLOUDFLARE_APP_URL }} + CLOUDFLARE_PROJECT_NAME: ${{ secrets.CLOUDFLARE_PROJECT_NAME }} TEST_DEPLOYED_VERSION: true defaults: run: @@ -46,7 +47,7 @@ jobs: with: apiToken: ${{ env.CLOUDFLARE_API_TOKEN }} accountId: ${{ env.CLOUDFLARE_ACCOUNT_ID }} - projectName: "supertokens-node-pr-check-for-edge-function-compat" + projectName: ${{ env.CLOUDFLARE_PROJECT_NAME }} directory: "./examples/next/with-emailpassword/.vercel/output/static" wranglerVersion: "3" branch: "master" From 35a37481e8ece6c89c8d9524b0606cc9d84cba85 Mon Sep 17 00:00:00 2001 From: Deepjyoti Barman Date: Wed, 4 Sep 2024 10:37:28 +0530 Subject: [PATCH 26/32] Get rid of pages directory in next emailpassword example --- .github/workflows/test-cf-worker-next.yml | 4 +--- .github/workflows/test-edge-function.yml | 5 ---- .../pages/api/auth/[[...path]].tsx | 24 ------------------- 3 files changed, 1 insertion(+), 32 deletions(-) delete mode 100644 examples/next/with-emailpassword/pages/api/auth/[[...path]].tsx diff --git a/.github/workflows/test-cf-worker-next.yml b/.github/workflows/test-cf-worker-next.yml index 6cead47b8..2d4e11fa6 100644 --- a/.github/workflows/test-cf-worker-next.yml +++ b/.github/workflows/test-cf-worker-next.yml @@ -19,11 +19,9 @@ jobs: - run: npm install - run: npm install mocha@6.1.4 jsdom-global@3.0.2 puppeteer@^11.0.0 isomorphic-fetch@^3.0.0 - # Step to update the runtime to edge to all files in app/api/ and remove pages path - # to avoid conflicts + # Step to update the runtime to edge to all files in app/api/ - name: Add runtime export to API files run: | - rm -rf pages find app/api -type f \( -name "*.js" -o -name "*.ts" \) -exec sed -i '1s/^/export const runtime = "edge";\n/' {} + echo 'export const runtime = "edge";' >> app/auth/[[...path]]/page.tsx diff --git a/.github/workflows/test-edge-function.yml b/.github/workflows/test-edge-function.yml index 54029da46..e938be776 100644 --- a/.github/workflows/test-edge-function.yml +++ b/.github/workflows/test-edge-function.yml @@ -17,11 +17,6 @@ jobs: - run: npm install - run: npm install mocha@6.1.4 jsdom-global@3.0.2 puppeteer@^11.0.0 isomorphic-fetch@^3.0.0 - # Remove the `/app/api/auth` directory as it will conflict with the `pages` routes - # which were added for compatibility with edge in Cloudflare. - - name: Remove possibly conflicting directory. - run: rm -rf app/api/auth - - run: netlify deploy --alias 0 --build --json --auth=$NETLIFY_AUTH_TOKEN > deployInfo.json - run: cat deployInfo.json - run: | diff --git a/examples/next/with-emailpassword/pages/api/auth/[[...path]].tsx b/examples/next/with-emailpassword/pages/api/auth/[[...path]].tsx deleted file mode 100644 index a4f5028b3..000000000 --- a/examples/next/with-emailpassword/pages/api/auth/[[...path]].tsx +++ /dev/null @@ -1,24 +0,0 @@ -import { superTokensNextWrapper } from "supertokens-node/nextjs"; -import { middleware } from "supertokens-node/framework/express"; -import { NextApiRequest, NextApiResponse } from "next"; -import supertokens from "supertokens-node"; -import { backendConfig } from "../../../config/backendConfig"; - -supertokens.init(backendConfig()); - -export default async function superTokens(req: NextApiRequest, res: NextApiResponse) { - await superTokensNextWrapper( - async (next) => { - // This is needed for production deployments with Vercel - // It'll be overwritten by the middleware in some cases (the jwks.json endpoint) - res.setHeader("Cache-Control", "no-cache, no-store, max-age=0, must-revalidate"); - - await middleware()(req as any, res as any, next); - }, - req, - res - ); - if (!res.writableEnded) { - res.status(404).send("Not found"); - } -} From df2ac225fb5890457d81353af97488efdea016f4 Mon Sep 17 00:00:00 2001 From: Deepjyoti Barman Date: Wed, 4 Sep 2024 10:39:31 +0530 Subject: [PATCH 27/32] Remove use of getBuffer in loopback framework --- lib/build/framework/loopback/framework.js | 2 +- lib/ts/framework/loopback/framework.ts | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/build/framework/loopback/framework.js b/lib/build/framework/loopback/framework.js index 40157d518..fc4097b3f 100644 --- a/lib/build/framework/loopback/framework.js +++ b/lib/build/framework/loopback/framework.js @@ -69,7 +69,7 @@ class LoopbackResponse extends response_1.BaseResponse { this.sendHTMLResponse = (html) => { if (!this.response.writableEnded) { this.response.set("Content-Type", "text/html"); - this.response.status(this.statusCode).send(utils_1.getBuffer().from(html)); + this.response.status(this.statusCode).send(html); } }; this.setHeader = (key, value, allowDuplicateKey) => { diff --git a/lib/ts/framework/loopback/framework.ts b/lib/ts/framework/loopback/framework.ts index e547f1fd9..bcb09bfe3 100644 --- a/lib/ts/framework/loopback/framework.ts +++ b/lib/ts/framework/loopback/framework.ts @@ -17,7 +17,7 @@ import type { MiddlewareContext, Request, Response, Middleware } from "@loopback import type { Next } from "@loopback/core"; import { SessionContainerInterface } from "../../recipe/session/types"; import { HTTPMethod } from "../../types"; -import { getBuffer, makeDefaultUserContextFromAPI, normaliseHttpMethod } from "../../utils"; +import { makeDefaultUserContextFromAPI, normaliseHttpMethod } from "../../utils"; import { BaseRequest } from "../request"; import { BaseResponse } from "../response"; import { @@ -92,7 +92,7 @@ export class LoopbackResponse extends BaseResponse { sendHTMLResponse = (html: string) => { if (!this.response.writableEnded) { this.response.set("Content-Type", "text/html"); - this.response.status(this.statusCode).send(getBuffer().from(html)); + this.response.status(this.statusCode).send(html); } }; From 2f2fb6213b7185348075650f0b5ac4c97f5daa8f Mon Sep 17 00:00:00 2001 From: Deepjyoti Barman Date: Wed, 4 Sep 2024 10:44:31 +0530 Subject: [PATCH 28/32] Add error handling for possible malformed body in lambda request --- lib/build/framework/awsLambda/framework.js | 12 ++++++++++-- lib/ts/framework/awsLambda/framework.ts | 12 ++++++++++-- 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/lib/build/framework/awsLambda/framework.js b/lib/build/framework/awsLambda/framework.js index 8c2679cfc..9ad56d91b 100644 --- a/lib/build/framework/awsLambda/framework.js +++ b/lib/build/framework/awsLambda/framework.js @@ -12,6 +12,7 @@ const response_1 = require("../response"); const utils_2 = require("../utils"); const constants_1 = require("../constants"); const supertokens_1 = __importDefault(require("../../supertokens")); +const error_1 = __importDefault(require("../../error")); class AWSRequest extends request_1.BaseRequest { constructor(event) { super(); @@ -19,8 +20,15 @@ class AWSRequest extends request_1.BaseRequest { if (this.event.body === null || this.event.body === undefined) { return {}; } else { - const parsedUrlEncodedFormData = Object.fromEntries(new URLSearchParams(this.event.body).entries()); - return parsedUrlEncodedFormData === undefined ? {} : parsedUrlEncodedFormData; + try { + const parsedUrlEncodedFormData = Object.fromEntries(new URLSearchParams(this.event.body).entries()); + return parsedUrlEncodedFormData === undefined ? {} : parsedUrlEncodedFormData; + } catch (err) { + throw new error_1.default({ + type: error_1.default.BAD_INPUT_ERROR, + message: "API input error: Please make sure to pass valid url encoded form in the request body", + }); + } } }; this.getJSONFromRequestBody = async () => { diff --git a/lib/ts/framework/awsLambda/framework.ts b/lib/ts/framework/awsLambda/framework.ts index 12b912fdc..137a2dbf2 100644 --- a/lib/ts/framework/awsLambda/framework.ts +++ b/lib/ts/framework/awsLambda/framework.ts @@ -30,6 +30,7 @@ import { COOKIE_HEADER } from "../constants"; import { SessionContainerInterface } from "../../recipe/session/types"; import SuperTokens from "../../supertokens"; import { Framework } from "../types"; +import STError from "../../error"; export class AWSRequest extends BaseRequest { private event: APIGatewayProxyEventV2 | APIGatewayProxyEvent; @@ -44,8 +45,15 @@ export class AWSRequest extends BaseRequest { if (this.event.body === null || this.event.body === undefined) { return {}; } else { - const parsedUrlEncodedFormData = Object.fromEntries(new URLSearchParams(this.event.body).entries()); - return parsedUrlEncodedFormData === undefined ? {} : parsedUrlEncodedFormData; + try { + const parsedUrlEncodedFormData = Object.fromEntries(new URLSearchParams(this.event.body).entries()); + return parsedUrlEncodedFormData === undefined ? {} : parsedUrlEncodedFormData; + } catch (err) { + throw new STError({ + type: STError.BAD_INPUT_ERROR, + message: "API input error: Please make sure to pass valid url encoded form in the request body", + }); + } } }; From 58ab0e54098ca15b071038ff22f60169b5c9dcea Mon Sep 17 00:00:00 2001 From: deepjyoti30Alt Date: Wed, 4 Sep 2024 23:58:03 +0530 Subject: [PATCH 29/32] Feat/hono api example repo (#2) * Add init support for testing hono deployments on CF with edge * Fix the directory path in hono workflow * Fix the deploy command * Fix tests to use assert instead * Remove unused build command * Update hono edge tests to test session endpoint as well * Update README to contain proper details * Drop brotli decompression support * Remove brotli as a dependency --- .github/workflows/test-cf-worker-hono.yml | 43 + .../with-be-emailpassword/README.md | 25 + .../with-be-emailpassword/config.ts | 33 + .../with-be-emailpassword/hono.d.ts | 7 + .../with-be-emailpassword/index.ts | 41 + .../with-be-emailpassword/middleware.ts | 88 + .../with-be-emailpassword/package-lock.json | 3221 +++++++++++++++++ .../with-be-emailpassword/package.json | 24 + .../with-be-emailpassword/test/basic.test.js | 90 + .../with-be-emailpassword/tsconfig.json | 63 + .../with-be-emailpassword/wrangler.toml | 2 + lib/build/framework/constants.d.ts | 3 +- lib/build/framework/constants.js | 2 +- lib/build/framework/custom/nodeHeaders.js | 6 +- lib/build/framework/utils.d.ts | 1 + lib/build/framework/utils.js | 47 +- lib/ts/framework/constants.ts | 2 +- lib/ts/framework/custom/nodeHeaders.ts | 6 +- lib/ts/framework/utils.ts | 33 +- package-lock.json | 17 - package.json | 1 - 21 files changed, 3674 insertions(+), 81 deletions(-) create mode 100644 .github/workflows/test-cf-worker-hono.yml create mode 100644 examples/cloudflare-workers/with-be-emailpassword/README.md create mode 100644 examples/cloudflare-workers/with-be-emailpassword/config.ts create mode 100644 examples/cloudflare-workers/with-be-emailpassword/hono.d.ts create mode 100644 examples/cloudflare-workers/with-be-emailpassword/index.ts create mode 100644 examples/cloudflare-workers/with-be-emailpassword/middleware.ts create mode 100644 examples/cloudflare-workers/with-be-emailpassword/package-lock.json create mode 100644 examples/cloudflare-workers/with-be-emailpassword/package.json create mode 100644 examples/cloudflare-workers/with-be-emailpassword/test/basic.test.js create mode 100644 examples/cloudflare-workers/with-be-emailpassword/tsconfig.json create mode 100644 examples/cloudflare-workers/with-be-emailpassword/wrangler.toml diff --git a/.github/workflows/test-cf-worker-hono.yml b/.github/workflows/test-cf-worker-hono.yml new file mode 100644 index 000000000..a5b966536 --- /dev/null +++ b/.github/workflows/test-cf-worker-hono.yml @@ -0,0 +1,43 @@ +name: "Test edge function compatibility for Hono on Cloudflare Workers" +on: push +jobs: + test: + runs-on: ubuntu-latest + env: + CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }} + CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }} + APP_URL: ${{ secrets.CLOUDFLARE_HONO_APP_URL }} + CLOUDFLARE_PROJECT_NAME: ${{ secrets.CLOUDFLARE_HONO_PROJECT_NAME }} + TEST_DEPLOYED_VERSION: true + defaults: + run: + working-directory: examples/cloudflare-workers/with-be-emailpassword + steps: + - uses: actions/checkout@v2 + - run: echo $GITHUB_SHA + - run: npm install git+https://github.com:supertokens/supertokens-node.git#$GITHUB_SHA + - run: npm install + - run: npm install mocha@6.1.4 jsdom-global@3.0.2 puppeteer@^11.0.0 isomorphic-fetch@^3.0.0 + + - name: Replace APP_URL with deployed URL value + run: | + sed -i "s|process.env.REACT_APP_API_URL|\"${{ env.APP_URL }}\"|" config.ts + sed -i "s|process.env.REACT_APP_WEBSITE_URL|\"${{ env.APP_URL }}\"|" config.ts + + - name: Deploy the changes + run: npx wrangler deploy --name ${{ env.CLOUDFLARE_PROJECT_NAME }} index.ts + + - name: Run tests + run: | + ( \ + (echo "=========== Test attempt 1 ===========" && npx mocha --no-config --timeout 80000 test/**/*.test.js) || \ + (echo "=========== Test attempt 2 ===========" && npx mocha --no-config --timeout 80000 test/**/*.test.js) || \ + (echo "=========== Test attempt 3 ===========" && npx mocha --no-config --timeout 80000 test/**/*.test.js) \ + ) + - name: The job has failed + if: ${{ failure() }} + uses: actions/upload-artifact@v3 + with: + name: screenshots + path: | + ./**/*screenshot.jpeg diff --git a/examples/cloudflare-workers/with-be-emailpassword/README.md b/examples/cloudflare-workers/with-be-emailpassword/README.md new file mode 100644 index 000000000..f38212857 --- /dev/null +++ b/examples/cloudflare-workers/with-be-emailpassword/README.md @@ -0,0 +1,25 @@ +![SuperTokens banner](https://raw.githubusercontent.com/supertokens/supertokens-logo/master/images/Artboard%20%E2%80%93%2027%402x.png) + +# SuperTokens EmailPassword with Cloudflare Workers (HonoJS) on Edge Runtime + +This demo app uses HonoJS with Cloudflare Workers for the backend server. We use [Wrangler](https://developers.cloudflare.com/workers/wrangler/) in the backend server to simulate the Cloudflare Worker runtime. This is a pure Edge runtime implementation (works without `nodejs_compat` flag). + +## Project setup + +Clone the repo, enter the directory, and use `npm` to install the project dependencies: + +```bash +git clone https://github.com/supertokens/supertokens-node +cd supertokens-node/examples/cloudflare-workers/with-be-emailpassword +npm install +``` + +## Run the demo app + +This compiles and serves the React app and starts the backend API server on port 3001. + +```bash +npm run start +``` + +The app will start on `http://localhost:3000` diff --git a/examples/cloudflare-workers/with-be-emailpassword/config.ts b/examples/cloudflare-workers/with-be-emailpassword/config.ts new file mode 100644 index 000000000..30fbc08bb --- /dev/null +++ b/examples/cloudflare-workers/with-be-emailpassword/config.ts @@ -0,0 +1,33 @@ +import EmailPassword from "supertokens-node/recipe/emailpassword"; +import Session from "supertokens-node/recipe/session"; +import { TypeInput } from "supertokens-node/types"; +import process from "process"; + +export const runtime = "edge"; + +export function getApiDomain() { + const apiPort = process.env.REACT_APP_API_PORT || 3001; + const apiUrl = process.env.REACT_APP_API_URL || `http://localhost:${apiPort}`; + return apiUrl; +} + +export function getWebsiteDomain() { + const websitePort = process.env.REACT_APP_WEBSITE_PORT || 3000; + const websiteUrl = process.env.REACT_APP_WEBSITE_URL || `http://localhost:${websitePort}`; + return websiteUrl; +} + +export const SuperTokensConfig: TypeInput = { + supertokens: { + // this is the location of the SuperTokens core. + connectionURI: "https://try.supertokens.com", + }, + appInfo: { + appName: "SuperTokens Demo App", + apiDomain: getApiDomain(), + websiteDomain: getWebsiteDomain(), + }, + // recipeList contains all the modules that you want to + // use from SuperTokens. See the full list here: https://supertokens.com/docs/guides + recipeList: [EmailPassword.init(), Session.init()], +}; diff --git a/examples/cloudflare-workers/with-be-emailpassword/hono.d.ts b/examples/cloudflare-workers/with-be-emailpassword/hono.d.ts new file mode 100644 index 000000000..bc752f28c --- /dev/null +++ b/examples/cloudflare-workers/with-be-emailpassword/hono.d.ts @@ -0,0 +1,7 @@ +import { SessionContainer } from "supertokens-node/recipe/session"; + +declare module "hono" { + interface HonoRequest { + session?: SessionContainer; + } +} diff --git a/examples/cloudflare-workers/with-be-emailpassword/index.ts b/examples/cloudflare-workers/with-be-emailpassword/index.ts new file mode 100644 index 000000000..f1b74ccdd --- /dev/null +++ b/examples/cloudflare-workers/with-be-emailpassword/index.ts @@ -0,0 +1,41 @@ +import { Hono } from "hono"; +import { cors } from "hono/cors"; +import supertokens from "supertokens-node"; +import { middleware } from "./middleware"; +import { getWebsiteDomain, SuperTokensConfig } from "./config"; +import type { PageConfig } from "next"; + +export const config: PageConfig = { + runtime: "edge", +}; + +supertokens.init(SuperTokensConfig); + +const app = new Hono(); + +app.use("*", async (c, next) => { + return await cors({ + origin: getWebsiteDomain(), + credentials: true, + allowHeaders: ["Content-Type", ...supertokens.getAllCORSHeaders()], + allowMethods: ["GET", "POST", "PUT", "PATCH", "DELETE"], + })(c, next); +}); + +// This exposes all the APIs from SuperTokens to the client. +app.use("*", middleware()); + +// An example API that requires session verification +app.get("/sessioninfo", (c) => { + let session = c.req.session; + if (!session) { + return c.text("Unauthorized", 401); + } + return c.json({ + sessionHandle: session!.getHandle(), + userId: session!.getUserId(), + accessTokenPayload: session!.getAccessTokenPayload(), + }); +}); + +export default app; diff --git a/examples/cloudflare-workers/with-be-emailpassword/middleware.ts b/examples/cloudflare-workers/with-be-emailpassword/middleware.ts new file mode 100644 index 000000000..f96d0c98f --- /dev/null +++ b/examples/cloudflare-workers/with-be-emailpassword/middleware.ts @@ -0,0 +1,88 @@ +import { Context, Next } from "hono"; +import { getCookie } from "hono/cookie"; +import { + CollectingResponse, + PreParsedRequest, + middleware as customMiddleware, +} from "supertokens-node/framework/custom"; +import Session from "supertokens-node/recipe/session"; +import { HTTPMethod } from "supertokens-node/types"; +import { serialize } from "cookie"; + +export const runtime = "edge"; + +function setCookiesInHeaders(headers: Headers, cookies: CollectingResponse["cookies"]) { + for (const cookie of cookies) { + headers.append( + "Set-Cookie", + serialize(cookie.key, cookie.value, { + domain: cookie.domain, + expires: new Date(cookie.expires), + httpOnly: cookie.httpOnly, + path: cookie.path, + sameSite: cookie.sameSite, + secure: cookie.secure, + }) + ); + } +} + +function copyHeaders(source: Headers, destination: Headers): void { + for (const [key, value] of source.entries()) { + destination.append(key, value); + } +} + +export const middleware = () => { + return async function (c: Context, next: Next) { + const request = new PreParsedRequest({ + method: c.req.method as HTTPMethod, + url: c.req.url, + query: Object.fromEntries(new URL(c.req.url).searchParams.entries()), + cookies: getCookie(c), + headers: c.req.raw.headers as Headers, + getFormBody: () => c.req.formData(), + getJSONBody: () => c.req.json(), + }); + const baseResponse = new CollectingResponse(); + + const stMiddleware = customMiddleware(() => request); + + const { handled, error } = await stMiddleware(request, baseResponse); + + if (error) { + throw error; + } + + if (handled) { + setCookiesInHeaders(baseResponse.headers, baseResponse.cookies); + return new Response(baseResponse.body, { + status: baseResponse.statusCode, + headers: baseResponse.headers, + }); + } + + // Add session to c.req if it exists + try { + c.req.session = await Session.getSession(request, baseResponse, { + sessionRequired: false, + }); + + await next(); + + // Add cookies that were set by `getSession` to response + setCookiesInHeaders(c.res.headers, baseResponse.cookies); + // Copy headers that were set by `getSession` to response + copyHeaders(baseResponse.headers, c.res.headers); + return c.res; + } catch (err) { + if (Session.Error.isErrorFromSuperTokens(err)) { + if (err.type === Session.Error.TRY_REFRESH_TOKEN || err.type === Session.Error.INVALID_CLAIMS) { + return new Response("Unauthorized", { + status: err.type === Session.Error.INVALID_CLAIMS ? 403 : 401, + }); + } + } + } + }; +}; diff --git a/examples/cloudflare-workers/with-be-emailpassword/package-lock.json b/examples/cloudflare-workers/with-be-emailpassword/package-lock.json new file mode 100644 index 000000000..9234749ce --- /dev/null +++ b/examples/cloudflare-workers/with-be-emailpassword/package-lock.json @@ -0,0 +1,3221 @@ +{ + "name": "with-be-email-password-hono", + "version": "0.0.1", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "name": "with-be-email-password-hono", + "version": "0.0.1", + "license": "ISC", + "dependencies": { + "hono": "^4.3.9", + "process": "^0.11.10", + "supertokens-node": "file:../../../lib/build" + }, + "devDependencies": { + "@cloudflare/workers-types": "^4.20240403.0", + "@types/node": "^18.0.0", + "jsdom-global": "^3.0.2", + "wrangler": "^3.57.0" + } + }, + "../../../lib/build": {}, + "node_modules/@cloudflare/kv-asset-handler": { + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/@cloudflare/kv-asset-handler/-/kv-asset-handler-0.3.4.tgz", + "integrity": "sha512-YLPHc8yASwjNkmcDMQMY35yiWjoKAKnhUbPRszBRS0YgH+IXtsMp61j+yTcnCE3oO2DgP0U3iejLC8FTtKDC8Q==", + "dev": true, + "dependencies": { + "mime": "^3.0.0" + }, + "engines": { + "node": ">=16.13" + } + }, + "node_modules/@cloudflare/kv-asset-handler/node_modules/mime": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-3.0.0.tgz", + "integrity": "sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A==", + "dev": true, + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/@cloudflare/workerd-darwin-64": { + "version": "1.20240821.1", + "resolved": "https://registry.npmjs.org/@cloudflare/workerd-darwin-64/-/workerd-darwin-64-1.20240821.1.tgz", + "integrity": "sha512-CDBpfZKrSy4YrIdqS84z67r3Tzal2pOhjCsIb63IuCnvVes59/ft1qhczBzk9EffeOE2iTCrA4YBT7Sbn7USew==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=16" + } + }, + "node_modules/@cloudflare/workerd-darwin-arm64": { + "version": "1.20240821.1", + "resolved": "https://registry.npmjs.org/@cloudflare/workerd-darwin-arm64/-/workerd-darwin-arm64-1.20240821.1.tgz", + "integrity": "sha512-Q+9RedvNbPcEt/dKni1oN94OxbvuNAeJkgHmrLFTGF8zu21wzOhVkQeRNxcYxrMa9mfStc457NAg13OVCj2kHQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=16" + } + }, + "node_modules/@cloudflare/workerd-linux-64": { + "version": "1.20240821.1", + "resolved": "https://registry.npmjs.org/@cloudflare/workerd-linux-64/-/workerd-linux-64-1.20240821.1.tgz", + "integrity": "sha512-j6z3KsPtawrscoLuP985LbqFrmsJL6q1mvSXOXTqXGODAHIzGBipHARdOjms3UQqovzvqB2lQaQsZtLBwCZxtA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=16" + } + }, + "node_modules/@cloudflare/workerd-linux-arm64": { + "version": "1.20240821.1", + "resolved": "https://registry.npmjs.org/@cloudflare/workerd-linux-arm64/-/workerd-linux-arm64-1.20240821.1.tgz", + "integrity": "sha512-I9bHgZOxJQW0CV5gTdilyxzTG7ILzbTirehQWgfPx9X77E/7eIbR9sboOMgyeC69W4he0SKtpx0sYZuTJu4ERw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=16" + } + }, + "node_modules/@cloudflare/workerd-windows-64": { + "version": "1.20240821.1", + "resolved": "https://registry.npmjs.org/@cloudflare/workerd-windows-64/-/workerd-windows-64-1.20240821.1.tgz", + "integrity": "sha512-keC97QPArs6LWbPejQM7/Y8Jy8QqyaZow4/ZdsGo+QjlOLiZRDpAenfZx3CBUoWwEeFwQTl2FLO+8hV1SWFFYw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=16" + } + }, + "node_modules/@cloudflare/workers-shared": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@cloudflare/workers-shared/-/workers-shared-0.4.1.tgz", + "integrity": "sha512-nYh4r8JwOOjYIdH2zub++CmIKlkYFlpxI1nBHimoiHcytJXD/b7ldJ21TtfzUZMCgI78mxVlymMHA/ReaOxKlA==", + "dev": true, + "engines": { + "node": ">=16.7.0" + } + }, + "node_modules/@cloudflare/workers-types": { + "version": "4.20240903.0", + "resolved": "https://registry.npmjs.org/@cloudflare/workers-types/-/workers-types-4.20240903.0.tgz", + "integrity": "sha512-a4mqgtVsPWg3JNNlQdLRE0Z6/mHr/uXa1ANDw6Zd7in438UCbeb+j7Z954Sf93G24jExpAn9VZ8kUUml0RwZbQ==", + "dev": true + }, + "node_modules/@cspotcode/source-map-support": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", + "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", + "dev": true, + "dependencies": { + "@jridgewell/trace-mapping": "0.3.9" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild-plugins/node-globals-polyfill": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@esbuild-plugins/node-globals-polyfill/-/node-globals-polyfill-0.2.3.tgz", + "integrity": "sha512-r3MIryXDeXDOZh7ih1l/yE9ZLORCd5e8vWg02azWRGj5SPTuoh69A2AIyn0Z31V/kHBfZ4HgWJ+OK3GTTwLmnw==", + "dev": true, + "peerDependencies": { + "esbuild": "*" + } + }, + "node_modules/@esbuild-plugins/node-modules-polyfill": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/@esbuild-plugins/node-modules-polyfill/-/node-modules-polyfill-0.2.2.tgz", + "integrity": "sha512-LXV7QsWJxRuMYvKbiznh+U1ilIop3g2TeKRzUxOG5X3YITc8JyyTa90BmLwqqv0YnX4v32CSlG+vsziZp9dMvA==", + "dev": true, + "dependencies": { + "escape-string-regexp": "^4.0.0", + "rollup-plugin-node-polyfills": "^0.2.1" + }, + "peerDependencies": { + "esbuild": "*" + } + }, + "node_modules/@esbuild-plugins/node-modules-polyfill/node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.17.19.tgz", + "integrity": "sha512-rIKddzqhmav7MSmoFCmDIb6e2W57geRsM94gV2l38fzhXMwq7hZoClug9USI2pFRGL06f4IOPHHpFNOkWieR8A==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.17.19.tgz", + "integrity": "sha512-KBMWvEZooR7+kzY0BtbTQn0OAYY7CsiydT63pVEaPtVYF0hXbUaOyZog37DKxK7NF3XacBJOpYT4adIJh+avxA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.17.19.tgz", + "integrity": "sha512-uUTTc4xGNDT7YSArp/zbtmbhO0uEEK9/ETW29Wk1thYUJBz3IVnvgEiEwEa9IeLyvnpKrWK64Utw2bgUmDveww==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.17.19.tgz", + "integrity": "sha512-80wEoCfF/hFKM6WE1FyBHc9SfUblloAWx6FJkFWTWiCoht9Mc0ARGEM47e67W9rI09YoUxJL68WHfDRYEAvOhg==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.17.19.tgz", + "integrity": "sha512-IJM4JJsLhRYr9xdtLytPLSH9k/oxR3boaUIYiHkAawtwNOXKE8KoU8tMvryogdcT8AU+Bflmh81Xn6Q0vTZbQw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.17.19.tgz", + "integrity": "sha512-pBwbc7DufluUeGdjSU5Si+P3SoMF5DQ/F/UmTSb8HXO80ZEAJmrykPyzo1IfNbAoaqw48YRpv8shwd1NoI0jcQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.17.19.tgz", + "integrity": "sha512-4lu+n8Wk0XlajEhbEffdy2xy53dpR06SlzvhGByyg36qJw6Kpfk7cp45DR/62aPH9mtJRmIyrXAS5UWBrJT6TQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.17.19.tgz", + "integrity": "sha512-cdmT3KxjlOQ/gZ2cjfrQOtmhG4HJs6hhvm3mWSRDPtZ/lP5oe8FWceS10JaSJC13GBd4eH/haHnqf7hhGNLerA==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.17.19.tgz", + "integrity": "sha512-ct1Tg3WGwd3P+oZYqic+YZF4snNl2bsnMKRkb3ozHmnM0dGWuxcPTTntAF6bOP0Sp4x0PjSF+4uHQ1xvxfRKqg==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.17.19.tgz", + "integrity": "sha512-w4IRhSy1VbsNxHRQpeGCHEmibqdTUx61Vc38APcsRbuVgK0OPEnQ0YD39Brymn96mOx48Y2laBQGqgZ0j9w6SQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.17.19.tgz", + "integrity": "sha512-2iAngUbBPMq439a+z//gE+9WBldoMp1s5GWsUSgqHLzLJ9WoZLZhpwWuym0u0u/4XmZ3gpHmzV84PonE+9IIdQ==", + "cpu": [ + "loong64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.17.19.tgz", + "integrity": "sha512-LKJltc4LVdMKHsrFe4MGNPp0hqDFA1Wpt3jE1gEyM3nKUvOiO//9PheZZHfYRfYl6AwdTH4aTcXSqBerX0ml4A==", + "cpu": [ + "mips64el" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.17.19.tgz", + "integrity": "sha512-/c/DGybs95WXNS8y3Ti/ytqETiW7EU44MEKuCAcpPto3YjQbyK3IQVKfF6nbghD7EcLUGl0NbiL5Rt5DMhn5tg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.17.19.tgz", + "integrity": "sha512-FC3nUAWhvFoutlhAkgHf8f5HwFWUL6bYdvLc/TTuxKlvLi3+pPzdZiFKSWz/PF30TB1K19SuCxDTI5KcqASJqA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.17.19.tgz", + "integrity": "sha512-IbFsFbxMWLuKEbH+7sTkKzL6NJmG2vRyy6K7JJo55w+8xDk7RElYn6xvXtDW8HCfoKBFK69f3pgBJSUSQPr+4Q==", + "cpu": [ + "s390x" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.17.19.tgz", + "integrity": "sha512-68ngA9lg2H6zkZcyp22tsVt38mlhWde8l3eJLWkyLrp4HwMUr3c1s/M2t7+kHIhvMjglIBrFpncX1SzMckomGw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.17.19.tgz", + "integrity": "sha512-CwFq42rXCR8TYIjIfpXCbRX0rp1jo6cPIUPSaWwzbVI4aOfX96OXY8M6KNmtPcg7QjYeDmN+DD0Wp3LaBOLf4Q==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.17.19.tgz", + "integrity": "sha512-cnq5brJYrSZ2CF6c35eCmviIN3k3RczmHz8eYaVlNasVqsNY+JKohZU5MKmaOI+KkllCdzOKKdPs762VCPC20g==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.17.19.tgz", + "integrity": "sha512-vCRT7yP3zX+bKWFeP/zdS6SqdWB8OIpaRq/mbXQxTGHnIxspRtigpkUcDMlSCOejlHowLqII7K2JKevwyRP2rg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.17.19.tgz", + "integrity": "sha512-yYx+8jwowUstVdorcMdNlzklLYhPxjniHWFKgRqH7IFlUEa0Umu3KuYplf1HUZZ422e3NU9F4LGb+4O0Kdcaag==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.17.19.tgz", + "integrity": "sha512-eggDKanJszUtCdlVs0RB+h35wNlb5v4TWEkq4vZcmVt5u/HiDZrTXe2bWFQUez3RgNHwx/x4sk5++4NSSicKkw==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.17.19.tgz", + "integrity": "sha512-lAhycmKnVOuRYNtRtatQR1LPQf2oYCkRGkSFnseDAKPl8lu5SOsK/e1sXe5a0Pc5kHIHe6P2I/ilntNv2xf3cA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@fastify/busboy": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@fastify/busboy/-/busboy-2.1.1.tgz", + "integrity": "sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA==", + "dev": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz", + "integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.15", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", + "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", + "dev": true + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", + "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", + "dev": true, + "dependencies": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, + "node_modules/@types/node": { + "version": "18.19.49", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.49.tgz", + "integrity": "sha512-ALCeIR6n0nQ7j0FUF1ycOhrp6+XutJWqEu/vtdEqXFUQwkBfgUA5cEg3ZNmjWGF/ZYA/FcF9QMkL55Ar0O6UrA==", + "dev": true, + "dependencies": { + "undici-types": "~5.26.4" + } + }, + "node_modules/@types/node-forge": { + "version": "1.3.11", + "resolved": "https://registry.npmjs.org/@types/node-forge/-/node-forge-1.3.11.tgz", + "integrity": "sha512-FQx220y22OKNTqaByeBGqHWYz4cl94tpcxeFdvBo3wjG6XPBuZ0BNgNZRV5J5TFmmcsJ4IzsLkmGRiQbnYsBEQ==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/acorn": { + "version": "8.9.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.9.0.tgz", + "integrity": "sha512-jaVNAFBHNLXspO543WnNNPZFRtavh3skAkITqD0/2aeMkKZTN+254PyhwxFYrk3vQ1xfY+2wbesJMs/JC8/PwQ==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-walk": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", + "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/agent-base": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.1.tgz", + "integrity": "sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==", + "dev": true, + "peer": true, + "dependencies": { + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/agent-base/node_modules/debug": { + "version": "4.3.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.6.tgz", + "integrity": "sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg==", + "dev": true, + "peer": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/agent-base/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true, + "peer": true + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/as-table": { + "version": "1.0.55", + "resolved": "https://registry.npmjs.org/as-table/-/as-table-1.0.55.tgz", + "integrity": "sha512-xvsWESUJn0JN421Xb9MQw6AsMHRCUknCe0Wjlxvjud80mU4E6hQf1A6NzQKcYNmYw62MfzEtXc+badstZP3JpQ==", + "dev": true, + "dependencies": { + "printable-characters": "^1.0.42" + } + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "dev": true, + "peer": true + }, + "node_modules/binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/blake3-wasm": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/blake3-wasm/-/blake3-wasm-2.1.5.tgz", + "integrity": "sha512-F1+K8EbfOZE49dtoPtmxUQrpXaBIl3ICvasLh+nJta0xkz+9kF/7uet9fLnwKqhDrmj6g+6K3Tw9yQPUg2ka5g==", + "dev": true + }, + "node_modules/braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/capnp-ts": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/capnp-ts/-/capnp-ts-0.7.0.tgz", + "integrity": "sha512-XKxXAC3HVPv7r674zP0VC3RTXz+/JKhfyw94ljvF80yynK6VkTnqE3jMuN8b3dUVmmc43TjyxjW4KTsmB3c86g==", + "dev": true, + "dependencies": { + "debug": "^4.3.1", + "tslib": "^2.2.0" + } + }, + "node_modules/capnp-ts/node_modules/debug": { + "version": "4.3.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.6.tgz", + "integrity": "sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/capnp-ts/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/chokidar": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", + "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ], + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dev": true, + "peer": true, + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/cookie": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", + "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cssstyle": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-4.0.1.tgz", + "integrity": "sha512-8ZYiJ3A/3OkDd093CBT/0UKDWry7ak4BdPTFP2+QEP7cmhouyq/Up709ASSj2cK02BbZiMgk7kYjZNS4QP5qrQ==", + "dev": true, + "peer": true, + "dependencies": { + "rrweb-cssom": "^0.6.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/cssstyle/node_modules/rrweb-cssom": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/rrweb-cssom/-/rrweb-cssom-0.6.0.tgz", + "integrity": "sha512-APM0Gt1KoXBz0iIkkdB/kfvGOwC4UuJFeG/c+yV7wSc7q96cG/kJ0HiYCnzivD9SB53cLV1MlHFNfOuPaadYSw==", + "dev": true, + "peer": true + }, + "node_modules/data-urls": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-5.0.0.tgz", + "integrity": "sha512-ZYP5VBHshaDAiVZxjbRVcFJpc+4xGgT0bK3vzy1HLN8jTO975HEbuYzZJcHoQEY5K1a0z8YayJkyVETa08eNTg==", + "dev": true, + "peer": true, + "dependencies": { + "whatwg-mimetype": "^4.0.0", + "whatwg-url": "^14.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/date-fns": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-3.6.0.tgz", + "integrity": "sha512-fRHTG8g/Gif+kSh50gaGEdToemgfj74aRX3swtiouboip5JDLAyDE9F11nHMIcvOaXeOC6D7SpNhi7uFyB7Uww==", + "dev": true, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/kossnocorp" + } + }, + "node_modules/decimal.js": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.4.3.tgz", + "integrity": "sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA==", + "dev": true, + "peer": true + }, + "node_modules/defu": { + "version": "6.1.4", + "resolved": "https://registry.npmjs.org/defu/-/defu-6.1.4.tgz", + "integrity": "sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==", + "dev": true + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "dev": true, + "peer": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "dev": true, + "peer": true, + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/esbuild": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.17.19.tgz", + "integrity": "sha512-XQ0jAPFkK/u3LcVRcvVHQcTIqD6E2H1fvZMA5dQPSOWb3suUbWbfbRf94pjc0bNzRYLfIrDRQXr7X+LHIm5oHw==", + "dev": true, + "hasInstallScript": true, + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/android-arm": "0.17.19", + "@esbuild/android-arm64": "0.17.19", + "@esbuild/android-x64": "0.17.19", + "@esbuild/darwin-arm64": "0.17.19", + "@esbuild/darwin-x64": "0.17.19", + "@esbuild/freebsd-arm64": "0.17.19", + "@esbuild/freebsd-x64": "0.17.19", + "@esbuild/linux-arm": "0.17.19", + "@esbuild/linux-arm64": "0.17.19", + "@esbuild/linux-ia32": "0.17.19", + "@esbuild/linux-loong64": "0.17.19", + "@esbuild/linux-mips64el": "0.17.19", + "@esbuild/linux-ppc64": "0.17.19", + "@esbuild/linux-riscv64": "0.17.19", + "@esbuild/linux-s390x": "0.17.19", + "@esbuild/linux-x64": "0.17.19", + "@esbuild/netbsd-x64": "0.17.19", + "@esbuild/openbsd-x64": "0.17.19", + "@esbuild/sunos-x64": "0.17.19", + "@esbuild/win32-arm64": "0.17.19", + "@esbuild/win32-ia32": "0.17.19", + "@esbuild/win32-x64": "0.17.19" + } + }, + "node_modules/estree-walker": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-0.6.1.tgz", + "integrity": "sha512-SqmZANLWS0mnatqbSfRP5g8OXZC12Fgg1IwNtLsyHDzJizORW4khDfjPqJZsemPWBB2uqykUah5YpQ6epsqC/w==", + "dev": true + }, + "node_modules/exit-hook": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/exit-hook/-/exit-hook-2.2.1.tgz", + "integrity": "sha512-eNTPlAD67BmP31LDINZ3U7HSF8l57TxOY2PmBJ1shpCvpnxBF93mWCE8YHBnXs8qiUZJc9WDcWIeC3a2HIAMfw==", + "dev": true, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "dev": true, + "peer": true, + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-source": { + "version": "2.0.12", + "resolved": "https://registry.npmjs.org/get-source/-/get-source-2.0.12.tgz", + "integrity": "sha512-X5+4+iD+HoSeEED+uwrQ07BOQr0kEDFMVqqpBuI+RaZBpBpHCuXxo70bjar6f0b0u/DQJsJ7ssurpP0V60Az+w==", + "dev": true, + "dependencies": { + "data-uri-to-buffer": "^2.0.0", + "source-map": "^0.6.1" + } + }, + "node_modules/get-source/node_modules/data-uri-to-buffer": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-2.0.2.tgz", + "integrity": "sha512-ND9qDTLc6diwj+Xe5cdAgVTbLVdXbtxTJRXRhli8Mowuaan+0EJOtdqJ0QCHNSSPyoXGx9HX2/VMnKeC34AChA==", + "dev": true + }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/glob-to-regexp": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", + "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", + "dev": true + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/hono": { + "version": "4.5.11", + "resolved": "https://registry.npmjs.org/hono/-/hono-4.5.11.tgz", + "integrity": "sha512-62FcjLPtjAFwISVBUshryl+vbHOjg8rE4uIK/dxyR8GpLztunZpwFmfEvmJCUI7xoGh/Sr3CGCDPCmYxVw7wUQ==", + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/html-encoding-sniffer": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-4.0.0.tgz", + "integrity": "sha512-Y22oTqIU4uuPgEemfz7NDJz6OeKf12Lsu+QC+s3BVpda64lTiMYCyGwg5ki4vFxkMwQdeZDl2adZoqUgdFuTgQ==", + "dev": true, + "peer": true, + "dependencies": { + "whatwg-encoding": "^3.1.1" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/http-proxy-agent": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", + "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", + "dev": true, + "peer": true, + "dependencies": { + "agent-base": "^7.1.0", + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/http-proxy-agent/node_modules/debug": { + "version": "4.3.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.6.tgz", + "integrity": "sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg==", + "dev": true, + "peer": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/http-proxy-agent/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true, + "peer": true + }, + "node_modules/https-proxy-agent": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.5.tgz", + "integrity": "sha512-1e4Wqeblerz+tMKPIq2EMGiiWW1dIjZOksyHWSUm1rmuvw/how9hBHZ38lAGj5ID4Ik6EdkOw7NmWPy6LAwalw==", + "dev": true, + "peer": true, + "dependencies": { + "agent-base": "^7.0.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/https-proxy-agent/node_modules/debug": { + "version": "4.3.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.6.tgz", + "integrity": "sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg==", + "dev": true, + "peer": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/https-proxy-agent/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true, + "peer": true + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-core-module": { + "version": "2.15.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.15.1.tgz", + "integrity": "sha512-z0vtXSwucUJtANQWldhbtbt7BnL0vxiFjIdDLAatwhDYty2bad6s+rijD6Ri4YuYJubLzIJLUidCh09e1djEVQ==", + "dev": true, + "dependencies": { + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-potential-custom-element-name": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", + "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==", + "dev": true, + "peer": true + }, + "node_modules/jsdom": { + "version": "25.0.0", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-25.0.0.tgz", + "integrity": "sha512-OhoFVT59T7aEq75TVw9xxEfkXgacpqAhQaYgP9y/fDqWQCMB/b1H66RfmPm/MaeaAIU9nDwMOVTlPN51+ao6CQ==", + "dev": true, + "peer": true, + "dependencies": { + "cssstyle": "^4.0.1", + "data-urls": "^5.0.0", + "decimal.js": "^10.4.3", + "form-data": "^4.0.0", + "html-encoding-sniffer": "^4.0.0", + "http-proxy-agent": "^7.0.2", + "https-proxy-agent": "^7.0.5", + "is-potential-custom-element-name": "^1.0.1", + "nwsapi": "^2.2.12", + "parse5": "^7.1.2", + "rrweb-cssom": "^0.7.1", + "saxes": "^6.0.0", + "symbol-tree": "^3.2.4", + "tough-cookie": "^4.1.4", + "w3c-xmlserializer": "^5.0.0", + "webidl-conversions": "^7.0.0", + "whatwg-encoding": "^3.1.1", + "whatwg-mimetype": "^4.0.0", + "whatwg-url": "^14.0.0", + "ws": "^8.18.0", + "xml-name-validator": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "canvas": "^2.11.2" + }, + "peerDependenciesMeta": { + "canvas": { + "optional": true + } + } + }, + "node_modules/jsdom-global": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/jsdom-global/-/jsdom-global-3.0.2.tgz", + "integrity": "sha512-t1KMcBkz/pT5JrvcJbpUR2u/w1kO9jXctaaGJ0vZDzwFnIvGWw9IDSRciT83kIs8Bnw4qpOl8bQK08V01YgMPg==", + "dev": true, + "peerDependencies": { + "jsdom": ">=10.0.0" + } + }, + "node_modules/magic-string": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.9.tgz", + "integrity": "sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ==", + "dev": true, + "dependencies": { + "sourcemap-codec": "^1.4.8" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "dev": true, + "peer": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dev": true, + "peer": true, + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/miniflare": { + "version": "3.20240821.1", + "resolved": "https://registry.npmjs.org/miniflare/-/miniflare-3.20240821.1.tgz", + "integrity": "sha512-81qdiryDG7VXzZuoa0EwhkaIYYrn7+StRIrd/2i7SPqPUNICUBjbhFFKqTnvE1+fqIPPB6l8ShKFaFvmnZOASg==", + "dev": true, + "dependencies": { + "@cspotcode/source-map-support": "0.8.1", + "acorn": "^8.8.0", + "acorn-walk": "^8.2.0", + "capnp-ts": "^0.7.0", + "exit-hook": "^2.2.1", + "glob-to-regexp": "^0.4.1", + "stoppable": "^1.1.0", + "undici": "^5.28.4", + "workerd": "1.20240821.1", + "ws": "^8.17.1", + "youch": "^3.2.2", + "zod": "^3.22.3" + }, + "bin": { + "miniflare": "bootstrap.js" + }, + "engines": { + "node": ">=16.13" + } + }, + "node_modules/mustache": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/mustache/-/mustache-4.2.0.tgz", + "integrity": "sha512-71ippSywq5Yb7/tVYyGbkBggbU8H3u5Rz56fH60jGFgr8uHwxs+aSKeqmluIVzM0m0kB7xQjKS6qPfd0b2ZoqQ==", + "dev": true, + "bin": { + "mustache": "bin/mustache" + } + }, + "node_modules/nanoid": { + "version": "3.3.7", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", + "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/node-forge": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz", + "integrity": "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==", + "dev": true, + "engines": { + "node": ">= 6.13.0" + } + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/nwsapi": { + "version": "2.2.12", + "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.12.tgz", + "integrity": "sha512-qXDmcVlZV4XRtKFzddidpfVP4oMSGhga+xdMc25mv8kaLUHtgzCDhUxkrN8exkGdTlLNaXj7CV3GtON7zuGZ+w==", + "dev": true, + "peer": true + }, + "node_modules/ohash": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/ohash/-/ohash-1.1.3.tgz", + "integrity": "sha512-zuHHiGTYTA1sYJ/wZN+t5HKZaH23i4yI1HMwbuXm24Nid7Dv0KcuRlKoNKS9UNfAVSBlnGLcuQrnOKWOZoEGaw==", + "dev": true + }, + "node_modules/parse5": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz", + "integrity": "sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==", + "dev": true, + "peer": true, + "dependencies": { + "entities": "^4.4.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true + }, + "node_modules/pathe": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-1.1.2.tgz", + "integrity": "sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==", + "dev": true + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/printable-characters": { + "version": "1.0.42", + "resolved": "https://registry.npmjs.org/printable-characters/-/printable-characters-1.0.42.tgz", + "integrity": "sha512-dKp+C4iXWK4vVYZmYSd0KBH5F/h1HoZRsbJ82AVKRO3PEo8L4lBS/vLwhVtpwwuYcoIsVY+1JYKR268yn480uQ==", + "dev": true + }, + "node_modules/process": { + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", + "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==", + "engines": { + "node": ">= 0.6.0" + } + }, + "node_modules/psl": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz", + "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==", + "dev": true, + "peer": true + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "peer": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/querystringify": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", + "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==", + "dev": true, + "peer": true + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", + "dev": true, + "peer": true + }, + "node_modules/resolve": { + "version": "1.22.8", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", + "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", + "dev": true, + "dependencies": { + "is-core-module": "^2.13.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve.exports": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-2.0.2.tgz", + "integrity": "sha512-X2UW6Nw3n/aMgDVy+0rSqgHlv39WZAlZrXCdnbyEiKm17DSqHX4MmQMaST3FbeWR5FTuRcUwYAziZajji0Y7mg==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/rollup-plugin-inject": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rollup-plugin-inject/-/rollup-plugin-inject-3.0.2.tgz", + "integrity": "sha512-ptg9PQwzs3orn4jkgXJ74bfs5vYz1NCZlSQMBUA0wKcGp5i5pA1AO3fOUEte8enhGUC+iapTCzEWw2jEFFUO/w==", + "deprecated": "This package has been deprecated and is no longer maintained. Please use @rollup/plugin-inject.", + "dev": true, + "dependencies": { + "estree-walker": "^0.6.1", + "magic-string": "^0.25.3", + "rollup-pluginutils": "^2.8.1" + } + }, + "node_modules/rollup-plugin-node-polyfills": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/rollup-plugin-node-polyfills/-/rollup-plugin-node-polyfills-0.2.1.tgz", + "integrity": "sha512-4kCrKPTJ6sK4/gLL/U5QzVT8cxJcofO0OU74tnB19F40cmuAKSzH5/siithxlofFEjwvw1YAhPmbvGNA6jEroA==", + "dev": true, + "dependencies": { + "rollup-plugin-inject": "^3.0.0" + } + }, + "node_modules/rollup-pluginutils": { + "version": "2.8.2", + "resolved": "https://registry.npmjs.org/rollup-pluginutils/-/rollup-pluginutils-2.8.2.tgz", + "integrity": "sha512-EEp9NhnUkwY8aif6bxgovPHMoMoNr2FulJziTndpt5H9RdwC47GSGuII9XxpSdzVGM0GWrNPHV6ie1LTNJPaLQ==", + "dev": true, + "dependencies": { + "estree-walker": "^0.6.1" + } + }, + "node_modules/rrweb-cssom": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/rrweb-cssom/-/rrweb-cssom-0.7.1.tgz", + "integrity": "sha512-TrEMa7JGdVm0UThDJSx7ddw5nVm3UJS9o9CCIZ72B1vSyEZoziDqBYP3XIoi/12lKrJR8rE3jeFHMok2F/Mnsg==", + "dev": true, + "peer": true + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true, + "peer": true + }, + "node_modules/saxes": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/saxes/-/saxes-6.0.0.tgz", + "integrity": "sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==", + "dev": true, + "peer": true, + "dependencies": { + "xmlchars": "^2.2.0" + }, + "engines": { + "node": ">=v12.22.7" + } + }, + "node_modules/selfsigned": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-2.4.1.tgz", + "integrity": "sha512-th5B4L2U+eGLq1TVh7zNRGBapioSORUeymIydxgFpwww9d2qyKvtuPU2jJuHvYAwwqi2Y596QBL3eEqcPEYL8Q==", + "dev": true, + "dependencies": { + "@types/node-forge": "^1.3.0", + "node-forge": "^1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/sourcemap-codec": { + "version": "1.4.8", + "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz", + "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==", + "deprecated": "Please use @jridgewell/sourcemap-codec instead", + "dev": true + }, + "node_modules/stacktracey": { + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/stacktracey/-/stacktracey-2.1.8.tgz", + "integrity": "sha512-Kpij9riA+UNg7TnphqjH7/CzctQ/owJGNbFkfEeve4Z4uxT5+JapVLFXcsurIfN34gnTWZNJ/f7NMG0E8JDzTw==", + "dev": true, + "dependencies": { + "as-table": "^1.0.36", + "get-source": "^2.0.12" + } + }, + "node_modules/stoppable": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/stoppable/-/stoppable-1.1.0.tgz", + "integrity": "sha512-KXDYZ9dszj6bzvnEMRYvxgeTHU74QBFL54XKtP3nyMuJ81CFYtABZ3bAzL2EdFUaEwJOBOgENyFj3R7oTzDyyw==", + "dev": true, + "engines": { + "node": ">=4", + "npm": ">=6" + } + }, + "node_modules/supertokens-node": { + "resolved": "../../../lib/build", + "link": true + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/symbol-tree": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", + "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", + "dev": true, + "peer": true + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/tough-cookie": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.4.tgz", + "integrity": "sha512-Loo5UUvLD9ScZ6jh8beX1T6sO1w2/MpCRpEP7V280GKMVUQ0Jzar2U3UJPsrdbziLEMMhu3Ujnq//rhiFuIeag==", + "dev": true, + "peer": true, + "dependencies": { + "psl": "^1.1.33", + "punycode": "^2.1.1", + "universalify": "^0.2.0", + "url-parse": "^1.5.3" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/tough-cookie/node_modules/universalify": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz", + "integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==", + "dev": true, + "peer": true, + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/tr46": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-5.0.0.tgz", + "integrity": "sha512-tk2G5R2KRwBd+ZN0zaEXpmzdKyOYksXwywulIX95MBODjSzMIuQnQ3m8JxgbhnL1LeVo7lqQKsYa1O3Htl7K5g==", + "dev": true, + "peer": true, + "dependencies": { + "punycode": "^2.3.1" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/tslib": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.7.0.tgz", + "integrity": "sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA==", + "dev": true + }, + "node_modules/ufo": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.5.4.tgz", + "integrity": "sha512-UsUk3byDzKd04EyoZ7U4DOlxQaD14JUKQl6/P7wiX4FNvUfm3XL246n9W5AmqwW5RSFJ27NAuM0iLscAOYUiGQ==", + "dev": true + }, + "node_modules/undici": { + "version": "5.28.4", + "resolved": "https://registry.npmjs.org/undici/-/undici-5.28.4.tgz", + "integrity": "sha512-72RFADWFqKmUb2hmmvNODKL3p9hcB6Gt2DOQMis1SEBaV6a4MH8soBvzg+95CYhCKPFedut2JY9bMfrDl9D23g==", + "dev": true, + "dependencies": { + "@fastify/busboy": "^2.0.0" + }, + "engines": { + "node": ">=14.0" + } + }, + "node_modules/undici-types": { + "version": "5.26.5", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", + "dev": true + }, + "node_modules/unenv": { + "name": "unenv-nightly", + "version": "2.0.0-1724863496.70db6f1", + "resolved": "https://registry.npmjs.org/unenv-nightly/-/unenv-nightly-2.0.0-1724863496.70db6f1.tgz", + "integrity": "sha512-r+VIl1gnsI4WQxluruSQhy8alpAf1AsLRLm4sEKp3otCyTIVD6I6wHEYzeQnwsyWgaD4+3BD4A/eqrgOpdTzhw==", + "dev": true, + "dependencies": { + "defu": "^6.1.4", + "ohash": "^1.1.3", + "pathe": "^1.1.2", + "ufo": "^1.5.4" + } + }, + "node_modules/url-parse": { + "version": "1.5.10", + "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz", + "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==", + "dev": true, + "peer": true, + "dependencies": { + "querystringify": "^2.1.1", + "requires-port": "^1.0.0" + } + }, + "node_modules/w3c-xmlserializer": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-5.0.0.tgz", + "integrity": "sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==", + "dev": true, + "peer": true, + "dependencies": { + "xml-name-validator": "^5.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/webidl-conversions": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", + "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", + "dev": true, + "peer": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/whatwg-encoding": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-3.1.1.tgz", + "integrity": "sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==", + "dev": true, + "peer": true, + "dependencies": { + "iconv-lite": "0.6.3" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/whatwg-encoding/node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dev": true, + "peer": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/whatwg-mimetype": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-4.0.0.tgz", + "integrity": "sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==", + "dev": true, + "peer": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/whatwg-url": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-14.0.0.tgz", + "integrity": "sha512-1lfMEm2IEr7RIV+f4lUNPOqfFL+pO+Xw3fJSqmjX9AbXcXcYOkCe1P6+9VBZB6n94af16NfZf+sSk0JCBZC9aw==", + "dev": true, + "peer": true, + "dependencies": { + "tr46": "^5.0.0", + "webidl-conversions": "^7.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/workerd": { + "version": "1.20240821.1", + "resolved": "https://registry.npmjs.org/workerd/-/workerd-1.20240821.1.tgz", + "integrity": "sha512-y4phjCnEG96u8ZkgkkHB+gSw0i6uMNo23rBmixylWpjxDklB+LWD8dztasvsu7xGaZbLoTxQESdEw956F7VJDA==", + "dev": true, + "hasInstallScript": true, + "bin": { + "workerd": "bin/workerd" + }, + "engines": { + "node": ">=16" + }, + "optionalDependencies": { + "@cloudflare/workerd-darwin-64": "1.20240821.1", + "@cloudflare/workerd-darwin-arm64": "1.20240821.1", + "@cloudflare/workerd-linux-64": "1.20240821.1", + "@cloudflare/workerd-linux-arm64": "1.20240821.1", + "@cloudflare/workerd-windows-64": "1.20240821.1" + } + }, + "node_modules/wrangler": { + "version": "3.74.0", + "resolved": "https://registry.npmjs.org/wrangler/-/wrangler-3.74.0.tgz", + "integrity": "sha512-wmtb+tQrgb61yN+Wa2JM98G1Gt4tKFRYPw6xwuyzUcA74L+Dum1A13w22/manl9Gq1jA3dPn+7UzT5sYEVHRog==", + "dev": true, + "dependencies": { + "@cloudflare/kv-asset-handler": "0.3.4", + "@cloudflare/workers-shared": "0.4.1", + "@esbuild-plugins/node-globals-polyfill": "^0.2.3", + "@esbuild-plugins/node-modules-polyfill": "^0.2.2", + "blake3-wasm": "^2.1.5", + "chokidar": "^3.5.3", + "date-fns": "^3.6.0", + "esbuild": "0.17.19", + "miniflare": "3.20240821.1", + "nanoid": "^3.3.3", + "path-to-regexp": "^6.2.0", + "resolve": "^1.22.8", + "resolve.exports": "^2.0.2", + "selfsigned": "^2.0.1", + "source-map": "^0.6.1", + "unenv": "npm:unenv-nightly@2.0.0-1724863496.70db6f1", + "workerd": "1.20240821.1", + "xxhash-wasm": "^1.0.1" + }, + "bin": { + "wrangler": "bin/wrangler.js", + "wrangler2": "bin/wrangler.js" + }, + "engines": { + "node": ">=16.17.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + }, + "peerDependencies": { + "@cloudflare/workers-types": "^4.20240821.1" + }, + "peerDependenciesMeta": { + "@cloudflare/workers-types": { + "optional": true + } + } + }, + "node_modules/wrangler/node_modules/path-to-regexp": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-6.2.2.tgz", + "integrity": "sha512-GQX3SSMokngb36+whdpRXE+3f9V8UzyAorlYvOGx87ufGHehNTn5lCxrKtLyZ4Yl/wEKnNnr98ZzOwwDZV5ogw==", + "dev": true + }, + "node_modules/ws": { + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz", + "integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==", + "dev": true, + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/xml-name-validator": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-5.0.0.tgz", + "integrity": "sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==", + "dev": true, + "peer": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/xmlchars": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", + "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", + "dev": true, + "peer": true + }, + "node_modules/xxhash-wasm": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/xxhash-wasm/-/xxhash-wasm-1.0.2.tgz", + "integrity": "sha512-ibF0Or+FivM9lNrg+HGJfVX8WJqgo+kCLDc4vx6xMeTce7Aj+DLttKbxxRR/gNLSAelRc1omAPlJ77N/Jem07A==", + "dev": true + }, + "node_modules/youch": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/youch/-/youch-3.3.3.tgz", + "integrity": "sha512-qSFXUk3UZBLfggAW3dJKg0BMblG5biqSF8M34E06o5CSsZtH92u9Hqmj2RzGiHDi64fhe83+4tENFP2DB6t6ZA==", + "dev": true, + "dependencies": { + "cookie": "^0.5.0", + "mustache": "^4.2.0", + "stacktracey": "^2.1.8" + } + }, + "node_modules/zod": { + "version": "3.23.8", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.23.8.tgz", + "integrity": "sha512-XBx9AXhXktjUqnepgTiE5flcKIYWi/rme0Eaj+5Y0lftuGBq+jyRu/md4WnuxqgP1ubdpNCsYEYPxrzVHD8d6g==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + } + }, + "dependencies": { + "@cloudflare/kv-asset-handler": { + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/@cloudflare/kv-asset-handler/-/kv-asset-handler-0.3.4.tgz", + "integrity": "sha512-YLPHc8yASwjNkmcDMQMY35yiWjoKAKnhUbPRszBRS0YgH+IXtsMp61j+yTcnCE3oO2DgP0U3iejLC8FTtKDC8Q==", + "dev": true, + "requires": { + "mime": "^3.0.0" + }, + "dependencies": { + "mime": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-3.0.0.tgz", + "integrity": "sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A==", + "dev": true + } + } + }, + "@cloudflare/workerd-darwin-64": { + "version": "1.20240821.1", + "resolved": "https://registry.npmjs.org/@cloudflare/workerd-darwin-64/-/workerd-darwin-64-1.20240821.1.tgz", + "integrity": "sha512-CDBpfZKrSy4YrIdqS84z67r3Tzal2pOhjCsIb63IuCnvVes59/ft1qhczBzk9EffeOE2iTCrA4YBT7Sbn7USew==", + "dev": true, + "optional": true + }, + "@cloudflare/workerd-darwin-arm64": { + "version": "1.20240821.1", + "resolved": "https://registry.npmjs.org/@cloudflare/workerd-darwin-arm64/-/workerd-darwin-arm64-1.20240821.1.tgz", + "integrity": "sha512-Q+9RedvNbPcEt/dKni1oN94OxbvuNAeJkgHmrLFTGF8zu21wzOhVkQeRNxcYxrMa9mfStc457NAg13OVCj2kHQ==", + "dev": true, + "optional": true + }, + "@cloudflare/workerd-linux-64": { + "version": "1.20240821.1", + "resolved": "https://registry.npmjs.org/@cloudflare/workerd-linux-64/-/workerd-linux-64-1.20240821.1.tgz", + "integrity": "sha512-j6z3KsPtawrscoLuP985LbqFrmsJL6q1mvSXOXTqXGODAHIzGBipHARdOjms3UQqovzvqB2lQaQsZtLBwCZxtA==", + "dev": true, + "optional": true + }, + "@cloudflare/workerd-linux-arm64": { + "version": "1.20240821.1", + "resolved": "https://registry.npmjs.org/@cloudflare/workerd-linux-arm64/-/workerd-linux-arm64-1.20240821.1.tgz", + "integrity": "sha512-I9bHgZOxJQW0CV5gTdilyxzTG7ILzbTirehQWgfPx9X77E/7eIbR9sboOMgyeC69W4he0SKtpx0sYZuTJu4ERw==", + "dev": true, + "optional": true + }, + "@cloudflare/workerd-windows-64": { + "version": "1.20240821.1", + "resolved": "https://registry.npmjs.org/@cloudflare/workerd-windows-64/-/workerd-windows-64-1.20240821.1.tgz", + "integrity": "sha512-keC97QPArs6LWbPejQM7/Y8Jy8QqyaZow4/ZdsGo+QjlOLiZRDpAenfZx3CBUoWwEeFwQTl2FLO+8hV1SWFFYw==", + "dev": true, + "optional": true + }, + "@cloudflare/workers-shared": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@cloudflare/workers-shared/-/workers-shared-0.4.1.tgz", + "integrity": "sha512-nYh4r8JwOOjYIdH2zub++CmIKlkYFlpxI1nBHimoiHcytJXD/b7ldJ21TtfzUZMCgI78mxVlymMHA/ReaOxKlA==", + "dev": true + }, + "@cloudflare/workers-types": { + "version": "4.20240903.0", + "resolved": "https://registry.npmjs.org/@cloudflare/workers-types/-/workers-types-4.20240903.0.tgz", + "integrity": "sha512-a4mqgtVsPWg3JNNlQdLRE0Z6/mHr/uXa1ANDw6Zd7in438UCbeb+j7Z954Sf93G24jExpAn9VZ8kUUml0RwZbQ==", + "dev": true + }, + "@cspotcode/source-map-support": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", + "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", + "dev": true, + "requires": { + "@jridgewell/trace-mapping": "0.3.9" + } + }, + "@esbuild-plugins/node-globals-polyfill": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@esbuild-plugins/node-globals-polyfill/-/node-globals-polyfill-0.2.3.tgz", + "integrity": "sha512-r3MIryXDeXDOZh7ih1l/yE9ZLORCd5e8vWg02azWRGj5SPTuoh69A2AIyn0Z31V/kHBfZ4HgWJ+OK3GTTwLmnw==", + "dev": true, + "requires": {} + }, + "@esbuild-plugins/node-modules-polyfill": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/@esbuild-plugins/node-modules-polyfill/-/node-modules-polyfill-0.2.2.tgz", + "integrity": "sha512-LXV7QsWJxRuMYvKbiznh+U1ilIop3g2TeKRzUxOG5X3YITc8JyyTa90BmLwqqv0YnX4v32CSlG+vsziZp9dMvA==", + "dev": true, + "requires": { + "escape-string-regexp": "^4.0.0", + "rollup-plugin-node-polyfills": "^0.2.1" + }, + "dependencies": { + "escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true + } + } + }, + "@esbuild/android-arm": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.17.19.tgz", + "integrity": "sha512-rIKddzqhmav7MSmoFCmDIb6e2W57geRsM94gV2l38fzhXMwq7hZoClug9USI2pFRGL06f4IOPHHpFNOkWieR8A==", + "dev": true, + "optional": true + }, + "@esbuild/android-arm64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.17.19.tgz", + "integrity": "sha512-KBMWvEZooR7+kzY0BtbTQn0OAYY7CsiydT63pVEaPtVYF0hXbUaOyZog37DKxK7NF3XacBJOpYT4adIJh+avxA==", + "dev": true, + "optional": true + }, + "@esbuild/android-x64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.17.19.tgz", + "integrity": "sha512-uUTTc4xGNDT7YSArp/zbtmbhO0uEEK9/ETW29Wk1thYUJBz3IVnvgEiEwEa9IeLyvnpKrWK64Utw2bgUmDveww==", + "dev": true, + "optional": true + }, + "@esbuild/darwin-arm64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.17.19.tgz", + "integrity": "sha512-80wEoCfF/hFKM6WE1FyBHc9SfUblloAWx6FJkFWTWiCoht9Mc0ARGEM47e67W9rI09YoUxJL68WHfDRYEAvOhg==", + "dev": true, + "optional": true + }, + "@esbuild/darwin-x64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.17.19.tgz", + "integrity": "sha512-IJM4JJsLhRYr9xdtLytPLSH9k/oxR3boaUIYiHkAawtwNOXKE8KoU8tMvryogdcT8AU+Bflmh81Xn6Q0vTZbQw==", + "dev": true, + "optional": true + }, + "@esbuild/freebsd-arm64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.17.19.tgz", + "integrity": "sha512-pBwbc7DufluUeGdjSU5Si+P3SoMF5DQ/F/UmTSb8HXO80ZEAJmrykPyzo1IfNbAoaqw48YRpv8shwd1NoI0jcQ==", + "dev": true, + "optional": true + }, + "@esbuild/freebsd-x64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.17.19.tgz", + "integrity": "sha512-4lu+n8Wk0XlajEhbEffdy2xy53dpR06SlzvhGByyg36qJw6Kpfk7cp45DR/62aPH9mtJRmIyrXAS5UWBrJT6TQ==", + "dev": true, + "optional": true + }, + "@esbuild/linux-arm": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.17.19.tgz", + "integrity": "sha512-cdmT3KxjlOQ/gZ2cjfrQOtmhG4HJs6hhvm3mWSRDPtZ/lP5oe8FWceS10JaSJC13GBd4eH/haHnqf7hhGNLerA==", + "dev": true, + "optional": true + }, + "@esbuild/linux-arm64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.17.19.tgz", + "integrity": "sha512-ct1Tg3WGwd3P+oZYqic+YZF4snNl2bsnMKRkb3ozHmnM0dGWuxcPTTntAF6bOP0Sp4x0PjSF+4uHQ1xvxfRKqg==", + "dev": true, + "optional": true + }, + "@esbuild/linux-ia32": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.17.19.tgz", + "integrity": "sha512-w4IRhSy1VbsNxHRQpeGCHEmibqdTUx61Vc38APcsRbuVgK0OPEnQ0YD39Brymn96mOx48Y2laBQGqgZ0j9w6SQ==", + "dev": true, + "optional": true + }, + "@esbuild/linux-loong64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.17.19.tgz", + "integrity": "sha512-2iAngUbBPMq439a+z//gE+9WBldoMp1s5GWsUSgqHLzLJ9WoZLZhpwWuym0u0u/4XmZ3gpHmzV84PonE+9IIdQ==", + "dev": true, + "optional": true + }, + "@esbuild/linux-mips64el": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.17.19.tgz", + "integrity": "sha512-LKJltc4LVdMKHsrFe4MGNPp0hqDFA1Wpt3jE1gEyM3nKUvOiO//9PheZZHfYRfYl6AwdTH4aTcXSqBerX0ml4A==", + "dev": true, + "optional": true + }, + "@esbuild/linux-ppc64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.17.19.tgz", + "integrity": "sha512-/c/DGybs95WXNS8y3Ti/ytqETiW7EU44MEKuCAcpPto3YjQbyK3IQVKfF6nbghD7EcLUGl0NbiL5Rt5DMhn5tg==", + "dev": true, + "optional": true + }, + "@esbuild/linux-riscv64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.17.19.tgz", + "integrity": "sha512-FC3nUAWhvFoutlhAkgHf8f5HwFWUL6bYdvLc/TTuxKlvLi3+pPzdZiFKSWz/PF30TB1K19SuCxDTI5KcqASJqA==", + "dev": true, + "optional": true + }, + "@esbuild/linux-s390x": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.17.19.tgz", + "integrity": "sha512-IbFsFbxMWLuKEbH+7sTkKzL6NJmG2vRyy6K7JJo55w+8xDk7RElYn6xvXtDW8HCfoKBFK69f3pgBJSUSQPr+4Q==", + "dev": true, + "optional": true + }, + "@esbuild/linux-x64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.17.19.tgz", + "integrity": "sha512-68ngA9lg2H6zkZcyp22tsVt38mlhWde8l3eJLWkyLrp4HwMUr3c1s/M2t7+kHIhvMjglIBrFpncX1SzMckomGw==", + "dev": true, + "optional": true + }, + "@esbuild/netbsd-x64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.17.19.tgz", + "integrity": "sha512-CwFq42rXCR8TYIjIfpXCbRX0rp1jo6cPIUPSaWwzbVI4aOfX96OXY8M6KNmtPcg7QjYeDmN+DD0Wp3LaBOLf4Q==", + "dev": true, + "optional": true + }, + "@esbuild/openbsd-x64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.17.19.tgz", + "integrity": "sha512-cnq5brJYrSZ2CF6c35eCmviIN3k3RczmHz8eYaVlNasVqsNY+JKohZU5MKmaOI+KkllCdzOKKdPs762VCPC20g==", + "dev": true, + "optional": true + }, + "@esbuild/sunos-x64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.17.19.tgz", + "integrity": "sha512-vCRT7yP3zX+bKWFeP/zdS6SqdWB8OIpaRq/mbXQxTGHnIxspRtigpkUcDMlSCOejlHowLqII7K2JKevwyRP2rg==", + "dev": true, + "optional": true + }, + "@esbuild/win32-arm64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.17.19.tgz", + "integrity": "sha512-yYx+8jwowUstVdorcMdNlzklLYhPxjniHWFKgRqH7IFlUEa0Umu3KuYplf1HUZZ422e3NU9F4LGb+4O0Kdcaag==", + "dev": true, + "optional": true + }, + "@esbuild/win32-ia32": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.17.19.tgz", + "integrity": "sha512-eggDKanJszUtCdlVs0RB+h35wNlb5v4TWEkq4vZcmVt5u/HiDZrTXe2bWFQUez3RgNHwx/x4sk5++4NSSicKkw==", + "dev": true, + "optional": true + }, + "@esbuild/win32-x64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.17.19.tgz", + "integrity": "sha512-lAhycmKnVOuRYNtRtatQR1LPQf2oYCkRGkSFnseDAKPl8lu5SOsK/e1sXe5a0Pc5kHIHe6P2I/ilntNv2xf3cA==", + "dev": true, + "optional": true + }, + "@fastify/busboy": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@fastify/busboy/-/busboy-2.1.1.tgz", + "integrity": "sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA==", + "dev": true + }, + "@jridgewell/resolve-uri": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz", + "integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==", + "dev": true + }, + "@jridgewell/sourcemap-codec": { + "version": "1.4.15", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", + "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", + "dev": true + }, + "@jridgewell/trace-mapping": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", + "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", + "dev": true, + "requires": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, + "@types/node": { + "version": "18.19.49", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.49.tgz", + "integrity": "sha512-ALCeIR6n0nQ7j0FUF1ycOhrp6+XutJWqEu/vtdEqXFUQwkBfgUA5cEg3ZNmjWGF/ZYA/FcF9QMkL55Ar0O6UrA==", + "dev": true, + "requires": { + "undici-types": "~5.26.4" + } + }, + "@types/node-forge": { + "version": "1.3.11", + "resolved": "https://registry.npmjs.org/@types/node-forge/-/node-forge-1.3.11.tgz", + "integrity": "sha512-FQx220y22OKNTqaByeBGqHWYz4cl94tpcxeFdvBo3wjG6XPBuZ0BNgNZRV5J5TFmmcsJ4IzsLkmGRiQbnYsBEQ==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "acorn": { + "version": "8.9.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.9.0.tgz", + "integrity": "sha512-jaVNAFBHNLXspO543WnNNPZFRtavh3skAkITqD0/2aeMkKZTN+254PyhwxFYrk3vQ1xfY+2wbesJMs/JC8/PwQ==", + "dev": true + }, + "acorn-walk": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", + "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", + "dev": true + }, + "agent-base": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.1.tgz", + "integrity": "sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==", + "dev": true, + "peer": true, + "requires": { + "debug": "^4.3.4" + }, + "dependencies": { + "debug": { + "version": "4.3.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.6.tgz", + "integrity": "sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg==", + "dev": true, + "peer": true, + "requires": { + "ms": "2.1.2" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true, + "peer": true + } + } + }, + "anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "requires": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + } + }, + "as-table": { + "version": "1.0.55", + "resolved": "https://registry.npmjs.org/as-table/-/as-table-1.0.55.tgz", + "integrity": "sha512-xvsWESUJn0JN421Xb9MQw6AsMHRCUknCe0Wjlxvjud80mU4E6hQf1A6NzQKcYNmYw62MfzEtXc+badstZP3JpQ==", + "dev": true, + "requires": { + "printable-characters": "^1.0.42" + } + }, + "asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "dev": true, + "peer": true + }, + "binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "dev": true + }, + "blake3-wasm": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/blake3-wasm/-/blake3-wasm-2.1.5.tgz", + "integrity": "sha512-F1+K8EbfOZE49dtoPtmxUQrpXaBIl3ICvasLh+nJta0xkz+9kF/7uet9fLnwKqhDrmj6g+6K3Tw9yQPUg2ka5g==", + "dev": true + }, + "braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "requires": { + "fill-range": "^7.0.1" + } + }, + "capnp-ts": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/capnp-ts/-/capnp-ts-0.7.0.tgz", + "integrity": "sha512-XKxXAC3HVPv7r674zP0VC3RTXz+/JKhfyw94ljvF80yynK6VkTnqE3jMuN8b3dUVmmc43TjyxjW4KTsmB3c86g==", + "dev": true, + "requires": { + "debug": "^4.3.1", + "tslib": "^2.2.0" + }, + "dependencies": { + "debug": { + "version": "4.3.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.6.tgz", + "integrity": "sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + } + } + }, + "chokidar": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", + "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", + "dev": true, + "requires": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "fsevents": "~2.3.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + } + }, + "combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dev": true, + "peer": true, + "requires": { + "delayed-stream": "~1.0.0" + } + }, + "cookie": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", + "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==", + "dev": true + }, + "cssstyle": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-4.0.1.tgz", + "integrity": "sha512-8ZYiJ3A/3OkDd093CBT/0UKDWry7ak4BdPTFP2+QEP7cmhouyq/Up709ASSj2cK02BbZiMgk7kYjZNS4QP5qrQ==", + "dev": true, + "peer": true, + "requires": { + "rrweb-cssom": "^0.6.0" + }, + "dependencies": { + "rrweb-cssom": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/rrweb-cssom/-/rrweb-cssom-0.6.0.tgz", + "integrity": "sha512-APM0Gt1KoXBz0iIkkdB/kfvGOwC4UuJFeG/c+yV7wSc7q96cG/kJ0HiYCnzivD9SB53cLV1MlHFNfOuPaadYSw==", + "dev": true, + "peer": true + } + } + }, + "data-urls": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-5.0.0.tgz", + "integrity": "sha512-ZYP5VBHshaDAiVZxjbRVcFJpc+4xGgT0bK3vzy1HLN8jTO975HEbuYzZJcHoQEY5K1a0z8YayJkyVETa08eNTg==", + "dev": true, + "peer": true, + "requires": { + "whatwg-mimetype": "^4.0.0", + "whatwg-url": "^14.0.0" + } + }, + "date-fns": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-3.6.0.tgz", + "integrity": "sha512-fRHTG8g/Gif+kSh50gaGEdToemgfj74aRX3swtiouboip5JDLAyDE9F11nHMIcvOaXeOC6D7SpNhi7uFyB7Uww==", + "dev": true + }, + "decimal.js": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.4.3.tgz", + "integrity": "sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA==", + "dev": true, + "peer": true + }, + "defu": { + "version": "6.1.4", + "resolved": "https://registry.npmjs.org/defu/-/defu-6.1.4.tgz", + "integrity": "sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==", + "dev": true + }, + "delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "dev": true, + "peer": true + }, + "entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "dev": true, + "peer": true + }, + "esbuild": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.17.19.tgz", + "integrity": "sha512-XQ0jAPFkK/u3LcVRcvVHQcTIqD6E2H1fvZMA5dQPSOWb3suUbWbfbRf94pjc0bNzRYLfIrDRQXr7X+LHIm5oHw==", + "dev": true, + "requires": { + "@esbuild/android-arm": "0.17.19", + "@esbuild/android-arm64": "0.17.19", + "@esbuild/android-x64": "0.17.19", + "@esbuild/darwin-arm64": "0.17.19", + "@esbuild/darwin-x64": "0.17.19", + "@esbuild/freebsd-arm64": "0.17.19", + "@esbuild/freebsd-x64": "0.17.19", + "@esbuild/linux-arm": "0.17.19", + "@esbuild/linux-arm64": "0.17.19", + "@esbuild/linux-ia32": "0.17.19", + "@esbuild/linux-loong64": "0.17.19", + "@esbuild/linux-mips64el": "0.17.19", + "@esbuild/linux-ppc64": "0.17.19", + "@esbuild/linux-riscv64": "0.17.19", + "@esbuild/linux-s390x": "0.17.19", + "@esbuild/linux-x64": "0.17.19", + "@esbuild/netbsd-x64": "0.17.19", + "@esbuild/openbsd-x64": "0.17.19", + "@esbuild/sunos-x64": "0.17.19", + "@esbuild/win32-arm64": "0.17.19", + "@esbuild/win32-ia32": "0.17.19", + "@esbuild/win32-x64": "0.17.19" + } + }, + "estree-walker": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-0.6.1.tgz", + "integrity": "sha512-SqmZANLWS0mnatqbSfRP5g8OXZC12Fgg1IwNtLsyHDzJizORW4khDfjPqJZsemPWBB2uqykUah5YpQ6epsqC/w==", + "dev": true + }, + "exit-hook": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/exit-hook/-/exit-hook-2.2.1.tgz", + "integrity": "sha512-eNTPlAD67BmP31LDINZ3U7HSF8l57TxOY2PmBJ1shpCvpnxBF93mWCE8YHBnXs8qiUZJc9WDcWIeC3a2HIAMfw==", + "dev": true + }, + "fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "requires": { + "to-regex-range": "^5.0.1" + } + }, + "form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "dev": true, + "peer": true, + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + } + }, + "fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "optional": true + }, + "function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true + }, + "get-source": { + "version": "2.0.12", + "resolved": "https://registry.npmjs.org/get-source/-/get-source-2.0.12.tgz", + "integrity": "sha512-X5+4+iD+HoSeEED+uwrQ07BOQr0kEDFMVqqpBuI+RaZBpBpHCuXxo70bjar6f0b0u/DQJsJ7ssurpP0V60Az+w==", + "dev": true, + "requires": { + "data-uri-to-buffer": "^2.0.0", + "source-map": "^0.6.1" + }, + "dependencies": { + "data-uri-to-buffer": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-2.0.2.tgz", + "integrity": "sha512-ND9qDTLc6diwj+Xe5cdAgVTbLVdXbtxTJRXRhli8Mowuaan+0EJOtdqJ0QCHNSSPyoXGx9HX2/VMnKeC34AChA==", + "dev": true + } + } + }, + "glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "requires": { + "is-glob": "^4.0.1" + } + }, + "glob-to-regexp": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", + "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", + "dev": true + }, + "hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "dev": true, + "requires": { + "function-bind": "^1.1.2" + } + }, + "hono": { + "version": "4.5.11", + "resolved": "https://registry.npmjs.org/hono/-/hono-4.5.11.tgz", + "integrity": "sha512-62FcjLPtjAFwISVBUshryl+vbHOjg8rE4uIK/dxyR8GpLztunZpwFmfEvmJCUI7xoGh/Sr3CGCDPCmYxVw7wUQ==" + }, + "html-encoding-sniffer": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-4.0.0.tgz", + "integrity": "sha512-Y22oTqIU4uuPgEemfz7NDJz6OeKf12Lsu+QC+s3BVpda64lTiMYCyGwg5ki4vFxkMwQdeZDl2adZoqUgdFuTgQ==", + "dev": true, + "peer": true, + "requires": { + "whatwg-encoding": "^3.1.1" + } + }, + "http-proxy-agent": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", + "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", + "dev": true, + "peer": true, + "requires": { + "agent-base": "^7.1.0", + "debug": "^4.3.4" + }, + "dependencies": { + "debug": { + "version": "4.3.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.6.tgz", + "integrity": "sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg==", + "dev": true, + "peer": true, + "requires": { + "ms": "2.1.2" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true, + "peer": true + } + } + }, + "https-proxy-agent": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.5.tgz", + "integrity": "sha512-1e4Wqeblerz+tMKPIq2EMGiiWW1dIjZOksyHWSUm1rmuvw/how9hBHZ38lAGj5ID4Ik6EdkOw7NmWPy6LAwalw==", + "dev": true, + "peer": true, + "requires": { + "agent-base": "^7.0.2", + "debug": "4" + }, + "dependencies": { + "debug": { + "version": "4.3.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.6.tgz", + "integrity": "sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg==", + "dev": true, + "peer": true, + "requires": { + "ms": "2.1.2" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true, + "peer": true + } + } + }, + "is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "requires": { + "binary-extensions": "^2.0.0" + } + }, + "is-core-module": { + "version": "2.15.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.15.1.tgz", + "integrity": "sha512-z0vtXSwucUJtANQWldhbtbt7BnL0vxiFjIdDLAatwhDYty2bad6s+rijD6Ri4YuYJubLzIJLUidCh09e1djEVQ==", + "dev": true, + "requires": { + "hasown": "^2.0.2" + } + }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true + }, + "is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "requires": { + "is-extglob": "^2.1.1" + } + }, + "is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true + }, + "is-potential-custom-element-name": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", + "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==", + "dev": true, + "peer": true + }, + "jsdom": { + "version": "25.0.0", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-25.0.0.tgz", + "integrity": "sha512-OhoFVT59T7aEq75TVw9xxEfkXgacpqAhQaYgP9y/fDqWQCMB/b1H66RfmPm/MaeaAIU9nDwMOVTlPN51+ao6CQ==", + "dev": true, + "peer": true, + "requires": { + "cssstyle": "^4.0.1", + "data-urls": "^5.0.0", + "decimal.js": "^10.4.3", + "form-data": "^4.0.0", + "html-encoding-sniffer": "^4.0.0", + "http-proxy-agent": "^7.0.2", + "https-proxy-agent": "^7.0.5", + "is-potential-custom-element-name": "^1.0.1", + "nwsapi": "^2.2.12", + "parse5": "^7.1.2", + "rrweb-cssom": "^0.7.1", + "saxes": "^6.0.0", + "symbol-tree": "^3.2.4", + "tough-cookie": "^4.1.4", + "w3c-xmlserializer": "^5.0.0", + "webidl-conversions": "^7.0.0", + "whatwg-encoding": "^3.1.1", + "whatwg-mimetype": "^4.0.0", + "whatwg-url": "^14.0.0", + "ws": "^8.18.0", + "xml-name-validator": "^5.0.0" + } + }, + "jsdom-global": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/jsdom-global/-/jsdom-global-3.0.2.tgz", + "integrity": "sha512-t1KMcBkz/pT5JrvcJbpUR2u/w1kO9jXctaaGJ0vZDzwFnIvGWw9IDSRciT83kIs8Bnw4qpOl8bQK08V01YgMPg==", + "dev": true, + "requires": {} + }, + "magic-string": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.9.tgz", + "integrity": "sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ==", + "dev": true, + "requires": { + "sourcemap-codec": "^1.4.8" + } + }, + "mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "dev": true, + "peer": true + }, + "mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dev": true, + "peer": true, + "requires": { + "mime-db": "1.52.0" + } + }, + "miniflare": { + "version": "3.20240821.1", + "resolved": "https://registry.npmjs.org/miniflare/-/miniflare-3.20240821.1.tgz", + "integrity": "sha512-81qdiryDG7VXzZuoa0EwhkaIYYrn7+StRIrd/2i7SPqPUNICUBjbhFFKqTnvE1+fqIPPB6l8ShKFaFvmnZOASg==", + "dev": true, + "requires": { + "@cspotcode/source-map-support": "0.8.1", + "acorn": "^8.8.0", + "acorn-walk": "^8.2.0", + "capnp-ts": "^0.7.0", + "exit-hook": "^2.2.1", + "glob-to-regexp": "^0.4.1", + "stoppable": "^1.1.0", + "undici": "^5.28.4", + "workerd": "1.20240821.1", + "ws": "^8.17.1", + "youch": "^3.2.2", + "zod": "^3.22.3" + } + }, + "mustache": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/mustache/-/mustache-4.2.0.tgz", + "integrity": "sha512-71ippSywq5Yb7/tVYyGbkBggbU8H3u5Rz56fH60jGFgr8uHwxs+aSKeqmluIVzM0m0kB7xQjKS6qPfd0b2ZoqQ==", + "dev": true + }, + "nanoid": { + "version": "3.3.7", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", + "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", + "dev": true + }, + "node-forge": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz", + "integrity": "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==", + "dev": true + }, + "normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true + }, + "nwsapi": { + "version": "2.2.12", + "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.12.tgz", + "integrity": "sha512-qXDmcVlZV4XRtKFzddidpfVP4oMSGhga+xdMc25mv8kaLUHtgzCDhUxkrN8exkGdTlLNaXj7CV3GtON7zuGZ+w==", + "dev": true, + "peer": true + }, + "ohash": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/ohash/-/ohash-1.1.3.tgz", + "integrity": "sha512-zuHHiGTYTA1sYJ/wZN+t5HKZaH23i4yI1HMwbuXm24Nid7Dv0KcuRlKoNKS9UNfAVSBlnGLcuQrnOKWOZoEGaw==", + "dev": true + }, + "parse5": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz", + "integrity": "sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==", + "dev": true, + "peer": true, + "requires": { + "entities": "^4.4.0" + } + }, + "path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true + }, + "pathe": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-1.1.2.tgz", + "integrity": "sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==", + "dev": true + }, + "picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true + }, + "printable-characters": { + "version": "1.0.42", + "resolved": "https://registry.npmjs.org/printable-characters/-/printable-characters-1.0.42.tgz", + "integrity": "sha512-dKp+C4iXWK4vVYZmYSd0KBH5F/h1HoZRsbJ82AVKRO3PEo8L4lBS/vLwhVtpwwuYcoIsVY+1JYKR268yn480uQ==", + "dev": true + }, + "process": { + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", + "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==" + }, + "psl": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz", + "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==", + "dev": true, + "peer": true + }, + "punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "peer": true + }, + "querystringify": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", + "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==", + "dev": true, + "peer": true + }, + "readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "requires": { + "picomatch": "^2.2.1" + } + }, + "requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", + "dev": true, + "peer": true + }, + "resolve": { + "version": "1.22.8", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", + "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", + "dev": true, + "requires": { + "is-core-module": "^2.13.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + } + }, + "resolve.exports": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-2.0.2.tgz", + "integrity": "sha512-X2UW6Nw3n/aMgDVy+0rSqgHlv39WZAlZrXCdnbyEiKm17DSqHX4MmQMaST3FbeWR5FTuRcUwYAziZajji0Y7mg==", + "dev": true + }, + "rollup-plugin-inject": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rollup-plugin-inject/-/rollup-plugin-inject-3.0.2.tgz", + "integrity": "sha512-ptg9PQwzs3orn4jkgXJ74bfs5vYz1NCZlSQMBUA0wKcGp5i5pA1AO3fOUEte8enhGUC+iapTCzEWw2jEFFUO/w==", + "dev": true, + "requires": { + "estree-walker": "^0.6.1", + "magic-string": "^0.25.3", + "rollup-pluginutils": "^2.8.1" + } + }, + "rollup-plugin-node-polyfills": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/rollup-plugin-node-polyfills/-/rollup-plugin-node-polyfills-0.2.1.tgz", + "integrity": "sha512-4kCrKPTJ6sK4/gLL/U5QzVT8cxJcofO0OU74tnB19F40cmuAKSzH5/siithxlofFEjwvw1YAhPmbvGNA6jEroA==", + "dev": true, + "requires": { + "rollup-plugin-inject": "^3.0.0" + } + }, + "rollup-pluginutils": { + "version": "2.8.2", + "resolved": "https://registry.npmjs.org/rollup-pluginutils/-/rollup-pluginutils-2.8.2.tgz", + "integrity": "sha512-EEp9NhnUkwY8aif6bxgovPHMoMoNr2FulJziTndpt5H9RdwC47GSGuII9XxpSdzVGM0GWrNPHV6ie1LTNJPaLQ==", + "dev": true, + "requires": { + "estree-walker": "^0.6.1" + } + }, + "rrweb-cssom": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/rrweb-cssom/-/rrweb-cssom-0.7.1.tgz", + "integrity": "sha512-TrEMa7JGdVm0UThDJSx7ddw5nVm3UJS9o9CCIZ72B1vSyEZoziDqBYP3XIoi/12lKrJR8rE3jeFHMok2F/Mnsg==", + "dev": true, + "peer": true + }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true, + "peer": true + }, + "saxes": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/saxes/-/saxes-6.0.0.tgz", + "integrity": "sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==", + "dev": true, + "peer": true, + "requires": { + "xmlchars": "^2.2.0" + } + }, + "selfsigned": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-2.4.1.tgz", + "integrity": "sha512-th5B4L2U+eGLq1TVh7zNRGBapioSORUeymIydxgFpwww9d2qyKvtuPU2jJuHvYAwwqi2Y596QBL3eEqcPEYL8Q==", + "dev": true, + "requires": { + "@types/node-forge": "^1.3.0", + "node-forge": "^1" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "sourcemap-codec": { + "version": "1.4.8", + "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz", + "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==", + "dev": true + }, + "stacktracey": { + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/stacktracey/-/stacktracey-2.1.8.tgz", + "integrity": "sha512-Kpij9riA+UNg7TnphqjH7/CzctQ/owJGNbFkfEeve4Z4uxT5+JapVLFXcsurIfN34gnTWZNJ/f7NMG0E8JDzTw==", + "dev": true, + "requires": { + "as-table": "^1.0.36", + "get-source": "^2.0.12" + } + }, + "stoppable": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/stoppable/-/stoppable-1.1.0.tgz", + "integrity": "sha512-KXDYZ9dszj6bzvnEMRYvxgeTHU74QBFL54XKtP3nyMuJ81CFYtABZ3bAzL2EdFUaEwJOBOgENyFj3R7oTzDyyw==", + "dev": true + }, + "supertokens-node": { + "version": "file:../../../lib/build" + }, + "supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true + }, + "symbol-tree": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", + "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", + "dev": true, + "peer": true + }, + "to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "requires": { + "is-number": "^7.0.0" + } + }, + "tough-cookie": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.4.tgz", + "integrity": "sha512-Loo5UUvLD9ScZ6jh8beX1T6sO1w2/MpCRpEP7V280GKMVUQ0Jzar2U3UJPsrdbziLEMMhu3Ujnq//rhiFuIeag==", + "dev": true, + "peer": true, + "requires": { + "psl": "^1.1.33", + "punycode": "^2.1.1", + "universalify": "^0.2.0", + "url-parse": "^1.5.3" + }, + "dependencies": { + "universalify": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz", + "integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==", + "dev": true, + "peer": true + } + } + }, + "tr46": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-5.0.0.tgz", + "integrity": "sha512-tk2G5R2KRwBd+ZN0zaEXpmzdKyOYksXwywulIX95MBODjSzMIuQnQ3m8JxgbhnL1LeVo7lqQKsYa1O3Htl7K5g==", + "dev": true, + "peer": true, + "requires": { + "punycode": "^2.3.1" + } + }, + "tslib": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.7.0.tgz", + "integrity": "sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA==", + "dev": true + }, + "ufo": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.5.4.tgz", + "integrity": "sha512-UsUk3byDzKd04EyoZ7U4DOlxQaD14JUKQl6/P7wiX4FNvUfm3XL246n9W5AmqwW5RSFJ27NAuM0iLscAOYUiGQ==", + "dev": true + }, + "undici": { + "version": "5.28.4", + "resolved": "https://registry.npmjs.org/undici/-/undici-5.28.4.tgz", + "integrity": "sha512-72RFADWFqKmUb2hmmvNODKL3p9hcB6Gt2DOQMis1SEBaV6a4MH8soBvzg+95CYhCKPFedut2JY9bMfrDl9D23g==", + "dev": true, + "requires": { + "@fastify/busboy": "^2.0.0" + } + }, + "undici-types": { + "version": "5.26.5", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", + "dev": true + }, + "unenv": { + "version": "npm:unenv-nightly@2.0.0-1724863496.70db6f1", + "resolved": "https://registry.npmjs.org/unenv-nightly/-/unenv-nightly-2.0.0-1724863496.70db6f1.tgz", + "integrity": "sha512-r+VIl1gnsI4WQxluruSQhy8alpAf1AsLRLm4sEKp3otCyTIVD6I6wHEYzeQnwsyWgaD4+3BD4A/eqrgOpdTzhw==", + "dev": true, + "requires": { + "defu": "^6.1.4", + "ohash": "^1.1.3", + "pathe": "^1.1.2", + "ufo": "^1.5.4" + } + }, + "url-parse": { + "version": "1.5.10", + "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz", + "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==", + "dev": true, + "peer": true, + "requires": { + "querystringify": "^2.1.1", + "requires-port": "^1.0.0" + } + }, + "w3c-xmlserializer": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-5.0.0.tgz", + "integrity": "sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==", + "dev": true, + "peer": true, + "requires": { + "xml-name-validator": "^5.0.0" + } + }, + "webidl-conversions": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", + "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", + "dev": true, + "peer": true + }, + "whatwg-encoding": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-3.1.1.tgz", + "integrity": "sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==", + "dev": true, + "peer": true, + "requires": { + "iconv-lite": "0.6.3" + }, + "dependencies": { + "iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dev": true, + "peer": true, + "requires": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + } + } + } + }, + "whatwg-mimetype": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-4.0.0.tgz", + "integrity": "sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==", + "dev": true, + "peer": true + }, + "whatwg-url": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-14.0.0.tgz", + "integrity": "sha512-1lfMEm2IEr7RIV+f4lUNPOqfFL+pO+Xw3fJSqmjX9AbXcXcYOkCe1P6+9VBZB6n94af16NfZf+sSk0JCBZC9aw==", + "dev": true, + "peer": true, + "requires": { + "tr46": "^5.0.0", + "webidl-conversions": "^7.0.0" + } + }, + "workerd": { + "version": "1.20240821.1", + "resolved": "https://registry.npmjs.org/workerd/-/workerd-1.20240821.1.tgz", + "integrity": "sha512-y4phjCnEG96u8ZkgkkHB+gSw0i6uMNo23rBmixylWpjxDklB+LWD8dztasvsu7xGaZbLoTxQESdEw956F7VJDA==", + "dev": true, + "requires": { + "@cloudflare/workerd-darwin-64": "1.20240821.1", + "@cloudflare/workerd-darwin-arm64": "1.20240821.1", + "@cloudflare/workerd-linux-64": "1.20240821.1", + "@cloudflare/workerd-linux-arm64": "1.20240821.1", + "@cloudflare/workerd-windows-64": "1.20240821.1" + } + }, + "wrangler": { + "version": "3.74.0", + "resolved": "https://registry.npmjs.org/wrangler/-/wrangler-3.74.0.tgz", + "integrity": "sha512-wmtb+tQrgb61yN+Wa2JM98G1Gt4tKFRYPw6xwuyzUcA74L+Dum1A13w22/manl9Gq1jA3dPn+7UzT5sYEVHRog==", + "dev": true, + "requires": { + "@cloudflare/kv-asset-handler": "0.3.4", + "@cloudflare/workers-shared": "0.4.1", + "@esbuild-plugins/node-globals-polyfill": "^0.2.3", + "@esbuild-plugins/node-modules-polyfill": "^0.2.2", + "blake3-wasm": "^2.1.5", + "chokidar": "^3.5.3", + "date-fns": "^3.6.0", + "esbuild": "0.17.19", + "fsevents": "~2.3.2", + "miniflare": "3.20240821.1", + "nanoid": "^3.3.3", + "path-to-regexp": "^6.2.0", + "resolve": "^1.22.8", + "resolve.exports": "^2.0.2", + "selfsigned": "^2.0.1", + "source-map": "^0.6.1", + "unenv": "npm:unenv-nightly@2.0.0-1724863496.70db6f1", + "workerd": "1.20240821.1", + "xxhash-wasm": "^1.0.1" + }, + "dependencies": { + "path-to-regexp": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-6.2.2.tgz", + "integrity": "sha512-GQX3SSMokngb36+whdpRXE+3f9V8UzyAorlYvOGx87ufGHehNTn5lCxrKtLyZ4Yl/wEKnNnr98ZzOwwDZV5ogw==", + "dev": true + } + } + }, + "ws": { + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz", + "integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==", + "dev": true, + "requires": {} + }, + "xml-name-validator": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-5.0.0.tgz", + "integrity": "sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==", + "dev": true, + "peer": true + }, + "xmlchars": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", + "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", + "dev": true, + "peer": true + }, + "xxhash-wasm": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/xxhash-wasm/-/xxhash-wasm-1.0.2.tgz", + "integrity": "sha512-ibF0Or+FivM9lNrg+HGJfVX8WJqgo+kCLDc4vx6xMeTce7Aj+DLttKbxxRR/gNLSAelRc1omAPlJ77N/Jem07A==", + "dev": true + }, + "youch": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/youch/-/youch-3.3.3.tgz", + "integrity": "sha512-qSFXUk3UZBLfggAW3dJKg0BMblG5biqSF8M34E06o5CSsZtH92u9Hqmj2RzGiHDi64fhe83+4tENFP2DB6t6ZA==", + "dev": true, + "requires": { + "cookie": "^0.5.0", + "mustache": "^4.2.0", + "stacktracey": "^2.1.8" + } + }, + "zod": { + "version": "3.23.8", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.23.8.tgz", + "integrity": "sha512-XBx9AXhXktjUqnepgTiE5flcKIYWi/rme0Eaj+5Y0lftuGBq+jyRu/md4WnuxqgP1ubdpNCsYEYPxrzVHD8d6g==", + "dev": true + } + } +} diff --git a/examples/cloudflare-workers/with-be-emailpassword/package.json b/examples/cloudflare-workers/with-be-emailpassword/package.json new file mode 100644 index 000000000..e9d86d9c2 --- /dev/null +++ b/examples/cloudflare-workers/with-be-emailpassword/package.json @@ -0,0 +1,24 @@ +{ + "name": "with-be-email-password-hono", + "version": "0.0.1", + "private": true, + "description": "", + "main": "index.js", + "scripts": { + "start": "wrangler dev index.ts --port 3001" + }, + "dependencies": { + "hono": "^4.3.9", + "process": "^0.11.10", + "supertokens-node": "file:../../../lib/build" + }, + "devDependencies": { + "@cloudflare/workers-types": "^4.20240403.0", + "@types/node": "^18.0.0", + "jsdom-global": "^3.0.2", + "wrangler": "^3.57.0" + }, + "keywords": [], + "author": "", + "license": "ISC" +} diff --git a/examples/cloudflare-workers/with-be-emailpassword/test/basic.test.js b/examples/cloudflare-workers/with-be-emailpassword/test/basic.test.js new file mode 100644 index 000000000..ea7b073bf --- /dev/null +++ b/examples/cloudflare-workers/with-be-emailpassword/test/basic.test.js @@ -0,0 +1,90 @@ +/* Copyright (c) 2024, VRAI Labs and/or its affiliates. All rights reserved. + * + * This software is licensed under the Apache License, Version 2.0 (the + * "License") as published by the Apache Software Foundation. + * + * You may not use this file except in compliance with the License. You may + * obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ + +/* + * Imports + */ + +const assert = require("assert"); + +// Run the tests in a DOM environment. +require("jsdom-global")(); + +const APP_URL = process.env.APP_URL || "http://localhost:8787"; + +describe("Auth API Tests", () => { + const signupBody = { + formFields: [ + { + id: "email", + value: "test@test.com", + }, + { + id: "password", + value: "testpw1234", + }, + ], + }; + + it("should sign up successfully and return status 200 with OK status", async () => { + const response = await fetch(`${APP_URL}/auth/signup`, { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify(signupBody), + }); + + const data = await response.json(); + + assert.strictEqual(response.status, 200, "Expected status code to be 200"); + assert.strictEqual(data.status, "FIELD_ERROR", "Expected status to be FIELD_ERROR"); + assert.strictEqual(data.formFields.length, 1, "Expected formFields length to be 1"); + }); + + it("should sign in successfully and return status 200 with OK status", async () => { + const response = await fetch(`${APP_URL}/auth/signin`, { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify(signupBody), + }); + + const data = await response.json(); + + assert.strictEqual(response.status, 200, "Expected status code to be 200"); + assert.strictEqual(data.status, "OK", "Expected status to be OK"); + + // Assert that session is working by getting the sessioninfo + const accessToken = response.headers.get("St-Access-Token"); + assert(accessToken, "Expected access token to be present in headers"); + + // Use the access token to get session info + const sessionResponse = await fetch(`${APP_URL}/sessioninfo`, { + method: "GET", + headers: { + Authorization: `Bearer ${accessToken}`, + "Content-Type": "application/json", + }, + }); + + const sessionData = await sessionResponse.json(); + + // Check that session info is retrieved successfully + assert.strictEqual(sessionResponse.status, 200, "Expected session info status code to be 200"); + assert(sessionData, "Expected session data to be present"); + }); +}); diff --git a/examples/cloudflare-workers/with-be-emailpassword/tsconfig.json b/examples/cloudflare-workers/with-be-emailpassword/tsconfig.json new file mode 100644 index 000000000..06ac0c543 --- /dev/null +++ b/examples/cloudflare-workers/with-be-emailpassword/tsconfig.json @@ -0,0 +1,63 @@ +{ + "compilerOptions": { + /* Visit https://aka.ms/tsconfig.json to read more about this file */ + /* Basic Options */ + // "incremental": true, /* Enable incremental compilation */ + "target": "ES6" /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */, + "module": "commonjs" /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */, + // "lib": [], /* Specify library files to be included in the compilation. */ + // "allowJs": true, /* Allow javascript files to be compiled. */ + // "checkJs": true, /* Report errors in .js files. */ + // "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */ + // "declaration": true, /* Generates corresponding '.d.ts' file. */ + // "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */ + // "sourceMap": true, /* Generates corresponding '.map' file. */ + // "outFile": "./", /* Concatenate and emit output to single file. */ + // "outDir": "./", /* Redirect output structure to the directory. */ + // "rootDir": "./", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */ + // "composite": true, /* Enable project compilation */ + // "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */ + // "removeComments": true, /* Do not emit comments to output. */ + // "noEmit": true, /* Do not emit outputs. */ + // "importHelpers": true, /* Import emit helpers from 'tslib'. */ + // "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */ + // "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */ + /* Strict Type-Checking Options */ + "strict": true /* Enable all strict type-checking options. */, + // "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */ + // "strictNullChecks": true, /* Enable strict null checks. */ + // "strictFunctionTypes": true, /* Enable strict checking of function types. */ + // "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */ + // "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */ + // "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */ + // "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */ + /* Additional Checks */ + // "noUnusedLocals": true, /* Report errors on unused locals. */ + // "noUnusedParameters": true, /* Report errors on unused parameters. */ + // "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */ + // "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */ + /* Module Resolution Options */ + // "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */ + // "baseUrl": "./", /* Base directory to resolve non-absolute module names. */ + // "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */ + // "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */ + // "typeRoots": [], /* List of folders to include type definitions from. */ + // "types": [], /* Type declaration files to be included in compilation. */ + // "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */ + "esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */, + // "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */ + // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ + /* Source Map Options */ + // "sourceRoot": "", /* Specify the location where debugger should locate TypeScript files instead of source locations. */ + // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ + // "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */ + // "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */ + /* Experimental Options */ + // "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */ + // "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */ + /* Advanced Options */ + "skipLibCheck": true /* Skip type checking of declaration files. */, + "forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */, + "types": ["@cloudflare/workers-types"] + } +} diff --git a/examples/cloudflare-workers/with-be-emailpassword/wrangler.toml b/examples/cloudflare-workers/with-be-emailpassword/wrangler.toml new file mode 100644 index 000000000..998e65947 --- /dev/null +++ b/examples/cloudflare-workers/with-be-emailpassword/wrangler.toml @@ -0,0 +1,2 @@ +name = "hono" +compatibility_date = "2023-12-01" diff --git a/lib/build/framework/constants.d.ts b/lib/build/framework/constants.d.ts index 2dd4989bd..f9e069925 100644 --- a/lib/build/framework/constants.d.ts +++ b/lib/build/framework/constants.d.ts @@ -1,3 +1,4 @@ // @ts-nocheck export declare const COOKIE_HEADER = "Set-Cookie"; -export declare const BROTLI_DECOMPRESSION_ERROR_MESSAGE = "Brotli decompression not supported on the platform"; +export declare const BROTLI_DECOMPRESSION_ERROR_MESSAGE = + "Brotli decompression not implement, use a middleware instead"; diff --git a/lib/build/framework/constants.js b/lib/build/framework/constants.js index d5f167a4c..3e6ced94c 100644 --- a/lib/build/framework/constants.js +++ b/lib/build/framework/constants.js @@ -17,4 +17,4 @@ exports.BROTLI_DECOMPRESSION_ERROR_MESSAGE = exports.COOKIE_HEADER = void 0; */ exports.COOKIE_HEADER = "Set-Cookie"; // Define error message for brotli decompression not being supported -exports.BROTLI_DECOMPRESSION_ERROR_MESSAGE = "Brotli decompression not supported on the platform"; +exports.BROTLI_DECOMPRESSION_ERROR_MESSAGE = "Brotli decompression not implement, use a middleware instead"; diff --git a/lib/build/framework/custom/nodeHeaders.js b/lib/build/framework/custom/nodeHeaders.js index 9fa0cfa08..fec293524 100644 --- a/lib/build/framework/custom/nodeHeaders.js +++ b/lib/build/framework/custom/nodeHeaders.js @@ -15,7 +15,7 @@ The above copyright notice and this permission notice shall be included in all c THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -const util_1 = require("util"); +const utils_1 = require("../utils"); const validateHeaderName = (name) => { if (!/^[\^`\-\w!#$%&'*+.|~]+$/.test(name)) { const err = new TypeError(`Header name must be a valid HTTP token [${name}]`); @@ -60,7 +60,7 @@ class Headers extends URLSearchParams { } else if (init == null) { // eslint-disable-line no-eq-null, eqeqeq // No op - } else if (typeof init === "object" && !util_1.types.isBoxedPrimitive(init)) { + } else if (typeof init === "object" && utils_1.isBoxedPrimitive(init)) { const method = init[Symbol.iterator]; // eslint-disable-next-line no-eq-null, eqeqeq if (method == null) { @@ -74,7 +74,7 @@ class Headers extends URLSearchParams { // Note: per spec we have to first exhaust the lists then process them result = [...init] .map((pair) => { - if (typeof pair !== "object" || util_1.types.isBoxedPrimitive(pair)) { + if (typeof pair !== "object" || utils_1.isBoxedPrimitive(pair)) { throw new TypeError("Each header pair must be an iterable object"); } return [...pair]; diff --git a/lib/build/framework/utils.d.ts b/lib/build/framework/utils.d.ts index 9350de8b2..4ef5fc0f5 100644 --- a/lib/build/framework/utils.d.ts +++ b/lib/build/framework/utils.d.ts @@ -58,3 +58,4 @@ export declare function serializeCookieValue( path: string, sameSite: "strict" | "lax" | "none" ): string; +export declare function isBoxedPrimitive(value: any): boolean; diff --git a/lib/build/framework/utils.js b/lib/build/framework/utils.js index 804d39da2..eb78c07df 100644 --- a/lib/build/framework/utils.js +++ b/lib/build/framework/utils.js @@ -51,22 +51,15 @@ var __importDefault = return mod && mod.__esModule ? mod : { default: mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); -exports.serializeCookieValue = exports.getCookieValueToSetInHeader = exports.setCookieForServerResponse = exports.setHeaderForExpressLikeResponse = exports.assertFormDataBodyParserHasBeenUsedForExpressLikeRequest = exports.assertThatBodyParserHasBeenUsedForExpressLikeRequest = exports.parseURLEncodedFormData = exports.parseJSONBodyFromRequest = exports.normalizeHeaderValue = exports.getHeaderValueFromIncomingMessage = exports.getCookieValueFromIncomingMessage = exports.getCookieValueFromHeaders = void 0; +exports.isBoxedPrimitive = exports.serializeCookieValue = exports.getCookieValueToSetInHeader = exports.setCookieForServerResponse = exports.setHeaderForExpressLikeResponse = exports.assertFormDataBodyParserHasBeenUsedForExpressLikeRequest = exports.assertThatBodyParserHasBeenUsedForExpressLikeRequest = exports.parseURLEncodedFormData = exports.parseJSONBodyFromRequest = exports.normalizeHeaderValue = exports.getHeaderValueFromIncomingMessage = exports.getCookieValueFromIncomingMessage = exports.getCookieValueFromHeaders = void 0; const cookie_1 = require("cookie"); const error_1 = __importDefault(require("../error")); const constants_1 = require("./constants"); const utils_1 = require("../utils"); const content_type_1 = __importDefault(require("content-type")); const pako_1 = __importDefault(require("pako")); -let brotliDecompress = null; -try { - // @ts-ignore - if (typeof EdgeRuntime === "undefined") brotliDecompress = require("brotli").decompress; -} catch (error) { - brotliDecompress = null; -} async function inflate(stream) { - var e_1, _a, e_2, _b, e_3, _c; + var e_1, _a, e_2, _b; if (!stream) { throw new TypeError("argument stream is required"); } @@ -97,8 +90,10 @@ async function inflate(stream) { } decompressedData = inflator.result; } else if (encoding === "br") { - if (!brotliDecompress) throw new Error(constants_1.BROTLI_DECOMPRESSION_ERROR_MESSAGE); - const chunks = []; + throw new Error(constants_1.BROTLI_DECOMPRESSION_ERROR_MESSAGE); + } else { + // Handle identity or unsupported encoding + decompressedData = utils_1.getBuffer().concat([]); try { for ( var stream_2 = __asyncValues(stream), stream_2_1; @@ -106,7 +101,7 @@ async function inflate(stream) { ) { const chunk = stream_2_1.value; - chunks.push(chunk); + decompressedData = utils_1.getBuffer().concat([decompressedData, chunk]); } } catch (e_2_1) { e_2 = { error: e_2_1 }; @@ -117,29 +112,6 @@ async function inflate(stream) { if (e_2) throw e_2.error; } } - const compressedData = utils_1.getBuffer().concat(chunks); - decompressedData = brotliDecompress(compressedData); - } else { - // Handle identity or unsupported encoding - decompressedData = utils_1.getBuffer().concat([]); - try { - for ( - var stream_3 = __asyncValues(stream), stream_3_1; - (stream_3_1 = await stream_3.next()), !stream_3_1.done; - - ) { - const chunk = stream_3_1.value; - decompressedData = utils_1.getBuffer().concat([decompressedData, chunk]); - } - } catch (e_3_1) { - e_3 = { error: e_3_1 }; - } finally { - try { - if (stream_3_1 && !stream_3_1.done && (_c = stream_3.return)) await _c.call(stream_3); - } finally { - if (e_3) throw e_3.error; - } - } } if (typeof decompressedData === "string") return decompressedData; return new TextDecoder().decode(decompressedData); @@ -448,3 +420,8 @@ function serializeCookieValue(key, value, domain, secure, httpOnly, expires, pat return cookie_1.serialize(key, value, opts); } exports.serializeCookieValue = serializeCookieValue; +function isBoxedPrimitive(value) { + const boxedTypes = [Boolean, Number, String, Symbol, BigInt]; + return boxedTypes.some((type) => value instanceof type); +} +exports.isBoxedPrimitive = isBoxedPrimitive; diff --git a/lib/ts/framework/constants.ts b/lib/ts/framework/constants.ts index c194e19f5..2569cf8ec 100644 --- a/lib/ts/framework/constants.ts +++ b/lib/ts/framework/constants.ts @@ -15,4 +15,4 @@ export const COOKIE_HEADER = "Set-Cookie"; // Define error message for brotli decompression not being supported -export const BROTLI_DECOMPRESSION_ERROR_MESSAGE = "Brotli decompression not supported on the platform"; +export const BROTLI_DECOMPRESSION_ERROR_MESSAGE = "Brotli decompression not implement, use a middleware instead"; diff --git a/lib/ts/framework/custom/nodeHeaders.ts b/lib/ts/framework/custom/nodeHeaders.ts index 478ba0e2d..ff1dd7e96 100644 --- a/lib/ts/framework/custom/nodeHeaders.ts +++ b/lib/ts/framework/custom/nodeHeaders.ts @@ -15,7 +15,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI */ -import { types } from "util"; +import { isBoxedPrimitive } from "../utils"; const validateHeaderName = (name) => { if (!/^[\^`\-\w!#$%&'*+.|~]+$/.test(name)) { @@ -64,7 +64,7 @@ export default class Headers extends URLSearchParams { } else if (init == null) { // eslint-disable-line no-eq-null, eqeqeq // No op - } else if (typeof init === "object" && !types.isBoxedPrimitive(init)) { + } else if (typeof init === "object" && isBoxedPrimitive(init)) { const method = init[Symbol.iterator]; // eslint-disable-next-line no-eq-null, eqeqeq if (method == null) { @@ -79,7 +79,7 @@ export default class Headers extends URLSearchParams { // Note: per spec we have to first exhaust the lists then process them result = [...init] .map((pair) => { - if (typeof pair !== "object" || types.isBoxedPrimitive(pair)) { + if (typeof pair !== "object" || isBoxedPrimitive(pair)) { throw new TypeError("Each header pair must be an iterable object"); } diff --git a/lib/ts/framework/utils.ts b/lib/ts/framework/utils.ts index 92e384747..b8c7db0b5 100644 --- a/lib/ts/framework/utils.ts +++ b/lib/ts/framework/utils.ts @@ -24,15 +24,6 @@ import { getBuffer, getFromObjectCaseInsensitive, isBuffer } from "../utils"; import contentType from "content-type"; import pako from "pako"; -let brotliDecompress: ((input: any) => any) | null = null; - -try { - // @ts-ignore - if (typeof EdgeRuntime === "undefined") brotliDecompress = require("brotli").decompress; -} catch (error) { - brotliDecompress = null; -} - async function inflate(stream: IncomingMessage): Promise { if (!stream) { throw new TypeError("argument stream is required"); @@ -55,14 +46,7 @@ async function inflate(stream: IncomingMessage): Promise { decompressedData = inflator.result; } else if (encoding === "br") { - if (!brotliDecompress) throw new Error(BROTLI_DECOMPRESSION_ERROR_MESSAGE); - - const chunks = []; - for await (const chunk of stream) { - chunks.push(chunk); - } - const compressedData = getBuffer().concat(chunks); - decompressedData = brotliDecompress(compressedData); + throw new Error(BROTLI_DECOMPRESSION_ERROR_MESSAGE); } else { // Handle identity or unsupported encoding decompressedData = getBuffer().concat([]); @@ -231,7 +215,7 @@ export async function assertThatBodyParserHasBeenUsedForExpressLikeRequest(metho } catch (err) { // If the error message matches the brotli decompression // related error, then throw that error. - if (err.message === BROTLI_DECOMPRESSION_ERROR_MESSAGE) { + if ((err as any).message === BROTLI_DECOMPRESSION_ERROR_MESSAGE) { throw new STError({ type: STError.BAD_INPUT_ERROR, message: `API input error: ${BROTLI_DECOMPRESSION_ERROR_MESSAGE}`, @@ -313,7 +297,12 @@ export function setHeaderForExpressLikeResponse(res: Response, key: string, valu } } catch (err) { throw new Error( - "Error while setting header with key: " + key + " and value: " + value + "\nError: " + (err.message ?? err) + "Error while setting header with key: " + + key + + " and value: " + + value + + "\nError: " + + ((err as any).message ?? err) ); } } @@ -418,3 +407,9 @@ export function serializeCookieValue( return serialize(key, value, opts); } + +export function isBoxedPrimitive(value: any): boolean { + const boxedTypes = [Boolean, Number, String, Symbol, BigInt]; + + return boxedTypes.some((type) => value instanceof type); +} diff --git a/package-lock.json b/package-lock.json index bdd877b9c..4198119b4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,7 +9,6 @@ "version": "20.0.3", "license": "Apache-2.0", "dependencies": { - "brotli": "^1.3.3", "buffer": "^6.0.3", "content-type": "^1.0.5", "cookie": "0.4.0", @@ -2357,14 +2356,6 @@ "node": ">=8" } }, - "node_modules/brotli": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/brotli/-/brotli-1.3.3.tgz", - "integrity": "sha512-oTKjJdShmDuGW94SyyaoQvAjf30dZaHnjJ8uAF+u2/vGJkJbJPJAT1gDiOJP5v1Zb6f9KEyW/1HpuaWIXtGHPg==", - "dependencies": { - "base64-js": "^1.1.2" - } - }, "node_modules/browser-stdout": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", @@ -10172,14 +10163,6 @@ "fill-range": "^7.0.1" } }, - "brotli": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/brotli/-/brotli-1.3.3.tgz", - "integrity": "sha512-oTKjJdShmDuGW94SyyaoQvAjf30dZaHnjJ8uAF+u2/vGJkJbJPJAT1gDiOJP5v1Zb6f9KEyW/1HpuaWIXtGHPg==", - "requires": { - "base64-js": "^1.1.2" - } - }, "browser-stdout": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", diff --git a/package.json b/package.json index d0e6f338b..87a4a246d 100644 --- a/package.json +++ b/package.json @@ -113,7 +113,6 @@ }, "homepage": "https://github.com/supertokens/supertokens-node#readme", "dependencies": { - "brotli": "^1.3.3", "buffer": "^6.0.3", "content-type": "^1.0.5", "cookie": "0.4.0", From 793925a255a1c6206fdbc92c508d679f2a1149f6 Mon Sep 17 00:00:00 2001 From: Deepjyoti Barman Date: Thu, 5 Sep 2024 18:15:38 +0530 Subject: [PATCH 30/32] Address requested changes --- .github/workflows/test-cf-worker-hono.yml | 2 +- .../README.md | 0 .../config.ts | 0 .../hono.d.ts | 0 .../index.ts | 1 + .../middleware.ts | 0 .../package-lock.json | 4 ++-- .../package.json | 2 +- .../test/basic.test.js | 0 .../tsconfig.json | 0 .../wrangler.toml | 0 lib/build/framework/constants.d.ts | 2 +- lib/build/framework/constants.js | 3 ++- lib/ts/framework/constants.ts | 3 ++- 14 files changed, 10 insertions(+), 7 deletions(-) rename examples/cloudflare-workers/{with-be-emailpassword => with-email-password-hono-be-only}/README.md (100%) rename examples/cloudflare-workers/{with-be-emailpassword => with-email-password-hono-be-only}/config.ts (100%) rename examples/cloudflare-workers/{with-be-emailpassword => with-email-password-hono-be-only}/hono.d.ts (100%) rename examples/cloudflare-workers/{with-be-emailpassword => with-email-password-hono-be-only}/index.ts (94%) rename examples/cloudflare-workers/{with-be-emailpassword => with-email-password-hono-be-only}/middleware.ts (100%) rename examples/cloudflare-workers/{with-be-emailpassword => with-email-password-hono-be-only}/package-lock.json (99%) rename examples/cloudflare-workers/{with-be-emailpassword => with-email-password-hono-be-only}/package.json (92%) rename examples/cloudflare-workers/{with-be-emailpassword => with-email-password-hono-be-only}/test/basic.test.js (100%) rename examples/cloudflare-workers/{with-be-emailpassword => with-email-password-hono-be-only}/tsconfig.json (100%) rename examples/cloudflare-workers/{with-be-emailpassword => with-email-password-hono-be-only}/wrangler.toml (100%) diff --git a/.github/workflows/test-cf-worker-hono.yml b/.github/workflows/test-cf-worker-hono.yml index a5b966536..a49e995a1 100644 --- a/.github/workflows/test-cf-worker-hono.yml +++ b/.github/workflows/test-cf-worker-hono.yml @@ -11,7 +11,7 @@ jobs: TEST_DEPLOYED_VERSION: true defaults: run: - working-directory: examples/cloudflare-workers/with-be-emailpassword + working-directory: examples/cloudflare-workers/with-email-password-hono-be-only steps: - uses: actions/checkout@v2 - run: echo $GITHUB_SHA diff --git a/examples/cloudflare-workers/with-be-emailpassword/README.md b/examples/cloudflare-workers/with-email-password-hono-be-only/README.md similarity index 100% rename from examples/cloudflare-workers/with-be-emailpassword/README.md rename to examples/cloudflare-workers/with-email-password-hono-be-only/README.md diff --git a/examples/cloudflare-workers/with-be-emailpassword/config.ts b/examples/cloudflare-workers/with-email-password-hono-be-only/config.ts similarity index 100% rename from examples/cloudflare-workers/with-be-emailpassword/config.ts rename to examples/cloudflare-workers/with-email-password-hono-be-only/config.ts diff --git a/examples/cloudflare-workers/with-be-emailpassword/hono.d.ts b/examples/cloudflare-workers/with-email-password-hono-be-only/hono.d.ts similarity index 100% rename from examples/cloudflare-workers/with-be-emailpassword/hono.d.ts rename to examples/cloudflare-workers/with-email-password-hono-be-only/hono.d.ts diff --git a/examples/cloudflare-workers/with-be-emailpassword/index.ts b/examples/cloudflare-workers/with-email-password-hono-be-only/index.ts similarity index 94% rename from examples/cloudflare-workers/with-be-emailpassword/index.ts rename to examples/cloudflare-workers/with-email-password-hono-be-only/index.ts index f1b74ccdd..fbf7813a9 100644 --- a/examples/cloudflare-workers/with-be-emailpassword/index.ts +++ b/examples/cloudflare-workers/with-email-password-hono-be-only/index.ts @@ -23,6 +23,7 @@ app.use("*", async (c, next) => { }); // This exposes all the APIs from SuperTokens to the client. +// and adds the session to the request object if one exists. app.use("*", middleware()); // An example API that requires session verification diff --git a/examples/cloudflare-workers/with-be-emailpassword/middleware.ts b/examples/cloudflare-workers/with-email-password-hono-be-only/middleware.ts similarity index 100% rename from examples/cloudflare-workers/with-be-emailpassword/middleware.ts rename to examples/cloudflare-workers/with-email-password-hono-be-only/middleware.ts diff --git a/examples/cloudflare-workers/with-be-emailpassword/package-lock.json b/examples/cloudflare-workers/with-email-password-hono-be-only/package-lock.json similarity index 99% rename from examples/cloudflare-workers/with-be-emailpassword/package-lock.json rename to examples/cloudflare-workers/with-email-password-hono-be-only/package-lock.json index 9234749ce..ed96d38c3 100644 --- a/examples/cloudflare-workers/with-be-emailpassword/package-lock.json +++ b/examples/cloudflare-workers/with-email-password-hono-be-only/package-lock.json @@ -1,11 +1,11 @@ { - "name": "with-be-email-password-hono", + "name": "with-email-password-hono-be-only", "version": "0.0.1", "lockfileVersion": 2, "requires": true, "packages": { "": { - "name": "with-be-email-password-hono", + "name": "with-email-password-hono-be-only", "version": "0.0.1", "license": "ISC", "dependencies": { diff --git a/examples/cloudflare-workers/with-be-emailpassword/package.json b/examples/cloudflare-workers/with-email-password-hono-be-only/package.json similarity index 92% rename from examples/cloudflare-workers/with-be-emailpassword/package.json rename to examples/cloudflare-workers/with-email-password-hono-be-only/package.json index e9d86d9c2..b8f4dba21 100644 --- a/examples/cloudflare-workers/with-be-emailpassword/package.json +++ b/examples/cloudflare-workers/with-email-password-hono-be-only/package.json @@ -1,5 +1,5 @@ { - "name": "with-be-email-password-hono", + "name": "with-email-password-hono-be-only", "version": "0.0.1", "private": true, "description": "", diff --git a/examples/cloudflare-workers/with-be-emailpassword/test/basic.test.js b/examples/cloudflare-workers/with-email-password-hono-be-only/test/basic.test.js similarity index 100% rename from examples/cloudflare-workers/with-be-emailpassword/test/basic.test.js rename to examples/cloudflare-workers/with-email-password-hono-be-only/test/basic.test.js diff --git a/examples/cloudflare-workers/with-be-emailpassword/tsconfig.json b/examples/cloudflare-workers/with-email-password-hono-be-only/tsconfig.json similarity index 100% rename from examples/cloudflare-workers/with-be-emailpassword/tsconfig.json rename to examples/cloudflare-workers/with-email-password-hono-be-only/tsconfig.json diff --git a/examples/cloudflare-workers/with-be-emailpassword/wrangler.toml b/examples/cloudflare-workers/with-email-password-hono-be-only/wrangler.toml similarity index 100% rename from examples/cloudflare-workers/with-be-emailpassword/wrangler.toml rename to examples/cloudflare-workers/with-email-password-hono-be-only/wrangler.toml diff --git a/lib/build/framework/constants.d.ts b/lib/build/framework/constants.d.ts index f9e069925..79db4b944 100644 --- a/lib/build/framework/constants.d.ts +++ b/lib/build/framework/constants.d.ts @@ -1,4 +1,4 @@ // @ts-nocheck export declare const COOKIE_HEADER = "Set-Cookie"; export declare const BROTLI_DECOMPRESSION_ERROR_MESSAGE = - "Brotli decompression not implement, use a middleware instead"; + "Brotli decompression not implement, Please add a middleware that handles decompression before the SuperTokens middleware."; diff --git a/lib/build/framework/constants.js b/lib/build/framework/constants.js index 3e6ced94c..1038b6933 100644 --- a/lib/build/framework/constants.js +++ b/lib/build/framework/constants.js @@ -17,4 +17,5 @@ exports.BROTLI_DECOMPRESSION_ERROR_MESSAGE = exports.COOKIE_HEADER = void 0; */ exports.COOKIE_HEADER = "Set-Cookie"; // Define error message for brotli decompression not being supported -exports.BROTLI_DECOMPRESSION_ERROR_MESSAGE = "Brotli decompression not implement, use a middleware instead"; +exports.BROTLI_DECOMPRESSION_ERROR_MESSAGE = + "Brotli decompression not implement, Please add a middleware that handles decompression before the SuperTokens middleware."; diff --git a/lib/ts/framework/constants.ts b/lib/ts/framework/constants.ts index 2569cf8ec..acd184dec 100644 --- a/lib/ts/framework/constants.ts +++ b/lib/ts/framework/constants.ts @@ -15,4 +15,5 @@ export const COOKIE_HEADER = "Set-Cookie"; // Define error message for brotli decompression not being supported -export const BROTLI_DECOMPRESSION_ERROR_MESSAGE = "Brotli decompression not implement, use a middleware instead"; +export const BROTLI_DECOMPRESSION_ERROR_MESSAGE = + "Brotli decompression not implement, Please add a middleware that handles decompression before the SuperTokens middleware."; From 5114804e8caf36101b3c707ef8582d89751e93ed Mon Sep 17 00:00:00 2001 From: Deepjyoti Barman Date: Thu, 5 Sep 2024 18:17:46 +0530 Subject: [PATCH 31/32] Fix a typo regarding boxPrimitives check --- lib/build/framework/custom/nodeHeaders.js | 2 +- lib/ts/framework/custom/nodeHeaders.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/build/framework/custom/nodeHeaders.js b/lib/build/framework/custom/nodeHeaders.js index fec293524..88f417cd1 100644 --- a/lib/build/framework/custom/nodeHeaders.js +++ b/lib/build/framework/custom/nodeHeaders.js @@ -60,7 +60,7 @@ class Headers extends URLSearchParams { } else if (init == null) { // eslint-disable-line no-eq-null, eqeqeq // No op - } else if (typeof init === "object" && utils_1.isBoxedPrimitive(init)) { + } else if (typeof init === "object" && !utils_1.isBoxedPrimitive(init)) { const method = init[Symbol.iterator]; // eslint-disable-next-line no-eq-null, eqeqeq if (method == null) { diff --git a/lib/ts/framework/custom/nodeHeaders.ts b/lib/ts/framework/custom/nodeHeaders.ts index ff1dd7e96..c7849388b 100644 --- a/lib/ts/framework/custom/nodeHeaders.ts +++ b/lib/ts/framework/custom/nodeHeaders.ts @@ -64,7 +64,7 @@ export default class Headers extends URLSearchParams { } else if (init == null) { // eslint-disable-line no-eq-null, eqeqeq // No op - } else if (typeof init === "object" && isBoxedPrimitive(init)) { + } else if (typeof init === "object" && !isBoxedPrimitive(init)) { const method = init[Symbol.iterator]; // eslint-disable-next-line no-eq-null, eqeqeq if (method == null) { From d74b20d05f8dc7da85d29aec926352314cbfaae8 Mon Sep 17 00:00:00 2001 From: Deepjyoti Barman Date: Thu, 5 Sep 2024 18:43:30 +0530 Subject: [PATCH 32/32] Update changelog with details of changes --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 46f2fc22d..ecd4faafb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [unreleased] +## [20.0.6] - 2024-09-05 + +- Add edge compatibility for custom frameworks and Next.JS + ## [20.0.5] - 2024-09-02 - Optional form fields are now truly optional, can be omitted from the payload.