2
0

🐛 (httpReq) Properly parse big ints

Closes #1486
This commit is contained in:
Baptiste Arnaud
2024-05-01 08:46:01 +02:00
parent aee006a14b
commit 7efb79d581
2 changed files with 30 additions and 1 deletions

View File

@ -28,6 +28,7 @@ import {
} from '@typebot.io/schemas/features/blocks/integrations/webhook/constants' } from '@typebot.io/schemas/features/blocks/integrations/webhook/constants'
import { env } from '@typebot.io/env' import { env } from '@typebot.io/env'
import { parseAnswers } from '@typebot.io/results/parseAnswers' import { parseAnswers } from '@typebot.io/results/parseAnswers'
import { JSONParse } from '@typebot.io/lib/JSONParse'
type ParsedWebhook = ExecutableHttpRequest & { type ParsedWebhook = ExecutableHttpRequest & {
basicAuth: { username?: string; password?: string } basicAuth: { username?: string; password?: string }
@ -326,7 +327,7 @@ export const convertKeyValueTableToObject = (
// eslint-disable-next-line @typescript-eslint/no-explicit-any // eslint-disable-next-line @typescript-eslint/no-explicit-any
const safeJsonParse = (json: unknown): { data: any; isJson: boolean } => { const safeJsonParse = (json: unknown): { data: any; isJson: boolean } => {
try { try {
return { data: JSON.parse(json as string), isJson: true } return { data: JSONParse(json as string), isJson: true }
} catch (err) { } catch (err) {
return { data: json, isJson: false } return { data: json, isJson: false }
} }

28
packages/lib/JSONParse.ts Normal file
View File

@ -0,0 +1,28 @@
// Taken from https://github.com/Ivan-Korolenko/json-with-bigint/blob/main/json-with-bigint.js
/*
Function to parse JSON
If JSON has values presented in a lib's custom format (strings with digits and "n" character at the end), we just parse them to BigInt values (for backward compatibility with previous versions of the lib)
If JSON has values greater than Number.MAX_SAFE_INTEGER, we convert those values to our custom format, then parse them to BigInt values.
Other types of values are not affected and parsed as native JSON.parse() would parse them.
Big numbers are found and marked using RegEx with these conditions:
- Before the match there is ": OR ":[ OR ":[anyNumberOf(anyCharacters) with no \ before them
- The match itself has more than 16 digits OR (16 digits and any digit of the number is greater than that of the Number.MAX_SAFE_INTEGER). And it may have a - sign at the start
- After the match there is , OR } without " after it OR ] without " after it
*/
export const JSONParse = (json: string) => {
const numbersBiggerThanMaxInt =
/(?<=[^\\]":[\[]?|[^\\]":\[.*)(-?\d{17,}|-?(?:[9](?:[1-9]07199254740991|0[1-9]7199254740991|00[8-9]199254740991|007[2-9]99254740991|007199[3-9]54740991|0071992[6-9]4740991|00719925[5-9]740991|007199254[8-9]40991|0071992547[5-9]0991|00719925474[1-9]991|00719925474099[2-9])))(?=,|\}[^"]|\][^"])/g
const serializedData = json.replace(numbersBiggerThanMaxInt, `"$1n"`)
return JSON.parse(serializedData, (_, value) => {
const isCustomFormatBigInt =
typeof value === 'string' && Boolean(value.match(/^-?\d+n$/))
if (isCustomFormatBigInt)
return BigInt(value.substring(0, value.length - 1))
return value
})
}