Socket
Socket
Sign inDemoInstall

@furystack/rest

Package Overview
Dependencies
Maintainers
1
Versions
145
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@furystack/rest - npm Package Compare versions

Comparing version 5.0.9 to 5.0.10

8

esm/deserialize-query-string.d.ts

@@ -1,3 +0,9 @@

export declare const tryDecodeQueryParam: (queryParam: any) => any;
/**
*
* Decoding steps: See the encoding steps in reverse order
* @param value The value to decode
* @returns The decoded value
*/
export declare const decode: <T>(value: string) => T;
export declare const deserializeQueryString: (fullQueryString: string) => any;
//# sourceMappingURL=deserialize-query-string.d.ts.map

51

esm/deserialize-query-string.js

@@ -1,43 +0,14 @@

export const tryDecodeQueryParam = (queryParam) => {
try {
return JSON.parse(decodeURIComponent(queryParam.toString()));
}
catch {
try {
return JSON.parse(queryParam.toString());
}
catch {
try {
return decodeURIComponent(queryParam.toString());
}
catch {
return queryParam;
}
}
}
};
/**
*
* Decoding steps: See the encoding steps in reverse order
* @param value The value to decode
* @returns The decoded value
*/
export const decode = (value) => JSON.parse(decodeURIComponent(escape(atob(decodeURIComponent(value)))));
export const deserializeQueryString = (fullQueryString) => {
const queryString = fullQueryString?.replace?.('?', ''); // trim starting ?
if (!queryString) {
return {};
}
const entries = queryString
.split('&')
.map((value) => value.split('='))
.filter(([key, value]) => key?.length && value?.length); // filter out empty keys
const dedupedValues = entries
.reduce((prev, current) => {
const currentKey = current[0];
const currentValue = tryDecodeQueryParam(current[1]);
const existing = prev.find(([key]) => key === currentKey);
if (existing) {
existing[1] instanceof Array ? existing[1].push(currentValue) : (existing[1] = currentValue);
return [...prev];
}
const newValue = [currentKey, currentKey.includes('[]') ? [currentValue] : currentValue];
return [...prev, newValue];
}, [])
.map(([key, value]) => [key.replace('[]', ''), value]);
return Object.fromEntries(dedupedValues);
const params = [...new URLSearchParams(fullQueryString).entries()]
.filter(([key, value]) => key && value)
.map(([key, value]) => [key, decode(value)]);
return Object.fromEntries(params);
};
//# sourceMappingURL=deserialize-query-string.js.map

@@ -1,3 +0,13 @@

export declare const serializeValue: ([key, value]: [key: string, value: any]) => string;
export declare const serializeToQueryString: <T extends object>(query: T) => string;
/**
* Serialize steps:
* 1. Stringify the value (even primitives, ensure type safety), e.g.: { foo: 'bar😉' } => '{"foo":"bar😉"}'
* 2. Encode as an URI Component, e.g.: ''{"foo":"bar😉"}'' => '%7B%22foo%22%3A%22bar%F0%9F%98%89%22%7D'
* 3. Unescape the URI Component, e.g.: '%7B%22foo%22%3A%22bar%F0%9F%98%89%22%7D' => '{"foo":"barð\x9F\x98\x89"}' - This and the first encodeURIComponent is needed because btoa only supports ASCII characters. We also don't want to encode the whole JSON string to keep a reasonable string length
* 4. Encode the string as base64, e.g.: '{"foo":"barð\x9F\x98\x89"}' => 'eyJmb28iOiJiYXLwn5iJIn0='
* 5. Encode as an URL Param: 'eyJmb28iOiJiYXLwn5iJIn0=' => 'eyJmb28iOiJiYXLwn5iJIn0%3D'
* @param value The value to encode
* @returns The encoded value that can be used as an URL search parameter
*/
export declare const serializeValue: (value: any) => string;
export declare const serializeToQueryString: <T extends object>(queryObject: T) => string;
//# sourceMappingURL=serialize-to-query-string.d.ts.map

@@ -1,18 +0,17 @@

export const serializeValue = ([key, value]) => {
if (typeof value === 'object') {
if (value instanceof Array) {
if (!value.some((v) => typeof v === 'object')) {
return value.map((val) => `${key}[]=${encodeURIComponent(val)}`).join('&');
}
}
return `${key}=${encodeURIComponent(JSON.stringify(value))}`;
}
return `${key}=${encodeURIComponent(value)}`;
};
export const serializeToQueryString = (query) => {
return Object.entries(query)
/**
* Serialize steps:
* 1. Stringify the value (even primitives, ensure type safety), e.g.: { foo: 'bar😉' } => '{"foo":"bar😉"}'
* 2. Encode as an URI Component, e.g.: ''{"foo":"bar😉"}'' => '%7B%22foo%22%3A%22bar%F0%9F%98%89%22%7D'
* 3. Unescape the URI Component, e.g.: '%7B%22foo%22%3A%22bar%F0%9F%98%89%22%7D' => '{"foo":"barð\x9F\x98\x89"}' - This and the first encodeURIComponent is needed because btoa only supports ASCII characters. We also don't want to encode the whole JSON string to keep a reasonable string length
* 4. Encode the string as base64, e.g.: '{"foo":"barð\x9F\x98\x89"}' => 'eyJmb28iOiJiYXLwn5iJIn0='
* 5. Encode as an URL Param: 'eyJmb28iOiJiYXLwn5iJIn0=' => 'eyJmb28iOiJiYXLwn5iJIn0%3D'
* @param value The value to encode
* @returns The encoded value that can be used as an URL search parameter
*/
export const serializeValue = (value) => encodeURIComponent(btoa(unescape(encodeURIComponent(JSON.stringify(value)))));
export const serializeToQueryString = (queryObject) => {
return new URLSearchParams(Object.fromEntries(Object.entries(queryObject)
.filter(([, value]) => value !== undefined)
.map(serializeValue)
.join('&');
.map(([key, value]) => [key, serializeValue(value)]))).toString();
};
//# sourceMappingURL=serialize-to-query-string.js.map
{
"name": "@furystack/rest",
"version": "5.0.9",
"version": "5.0.10",
"description": "Generic REST package",

@@ -5,0 +5,0 @@ "type": "module",

import { deserializeQueryString } from './deserialize-query-string'
import { serializeToQueryString } from './serialize-to-query-string'
import { serializeToQueryString, serializeValue } from './serialize-to-query-string'
import { describe, it, expect } from 'vitest'
describe('deserializeQueryString', () => {
it('Should serialize a null value', () => {
it('Should deserialize a null value', () => {
expect(deserializeQueryString(null as any)).toEqual({})
})
it('Should serialize an undefined value', () => {
it('Should deserialize an undefined value', () => {
expect(deserializeQueryString(undefined as any)).toEqual({})
})
it('Should serialize an empty string value', () => {
it('Should deserialize an empty string value', () => {
expect(deserializeQueryString('')).toEqual({})
})
it('Should serialize a string value with no keys / values', () => {
it('Should deserialize a string value with no keys / values', () => {
expect(deserializeQueryString('?')).toEqual({})
})
it('Should serialize a string with given value but empty key', () => {
it('Should deserialize a string with given value but empty key', () => {
expect(deserializeQueryString('?=alma')).toEqual({})
})
it('Should serialize a string with given key but empty value', () => {
it('Should deserialize a string with given key but empty value', () => {
expect(deserializeQueryString('?alma=')).toEqual({})
})
it('Should serialize a list of primitive values', () => {
expect(deserializeQueryString('?foo=value&bar=2&baz=false')).toEqual({ foo: 'value', bar: 2, baz: false })
it('Should deserialize a list of primitive values', () => {
expect(
deserializeQueryString(`?foo=${serializeValue('value')}&bar=${serializeValue(2)}&baz=${serializeValue(false)}`),
).toEqual({
foo: 'value',
bar: 2,
baz: false,
})
})
it('Should serialize an array', () => {
expect(deserializeQueryString('?foo[]=value&foo[]=2&foo[]=false')).toEqual({ foo: ['value', 2, false] })
})
it('Should override a value if not specified as an array', () => {
expect(deserializeQueryString('?foo=value&foo=2&foo=false&foo=bar')).toEqual({ foo: 'bar' })
expect(
deserializeQueryString(
`?foo=${serializeValue('value')}&foo=${serializeValue(2)}&foo=${serializeValue(false)}&foo=${serializeValue(
'bar',
)}`,
),
).toEqual({ foo: 'bar' })
})

@@ -63,4 +71,4 @@

it('Should deserialize escaped values', () => {
expect(deserializeQueryString('?alma=asd%2F*-%40')).toEqual({ alma: 'asd/*-@' })
expect(deserializeQueryString(`?alma=${serializeValue('asd/*-@?')}`)).toEqual({ alma: 'asd/*-@?' })
})
})

@@ -1,50 +0,15 @@

export const tryDecodeQueryParam = (queryParam: any) => {
try {
return JSON.parse(decodeURIComponent((queryParam as any).toString()))
} catch {
try {
return JSON.parse(queryParam.toString())
} catch {
try {
return decodeURIComponent(queryParam.toString())
} catch {
return queryParam
}
}
}
}
/**
*
* Decoding steps: See the encoding steps in reverse order
* @param value The value to decode
* @returns The decoded value
*/
export const decode = <T>(value: string) => JSON.parse(decodeURIComponent(escape(atob(decodeURIComponent(value))))) as T
export const deserializeQueryString = (fullQueryString: string) => {
const queryString = fullQueryString?.replace?.('?', '') // trim starting ?
const params = [...new URLSearchParams(fullQueryString).entries()]
.filter(([key, value]) => key && value)
.map(([key, value]) => [key, decode(value)])
if (!queryString) {
return {}
}
const entries = queryString
.split('&')
.map((value) => value.split('='))
.filter(([key, value]) => key?.length && value?.length) // filter out empty keys
const dedupedValues = entries
.reduce(
(prev, current) => {
const currentKey = current[0]
const currentValue = tryDecodeQueryParam(current[1])
const existing = prev.find(([key]) => key === currentKey)
if (existing) {
existing[1] instanceof Array ? existing[1].push(currentValue) : (existing[1] = currentValue)
return [...prev]
}
const newValue = [currentKey, currentKey.includes('[]') ? [currentValue] : currentValue] as [
string,
string | string[],
]
return [...prev, newValue]
},
[] as Array<[string, string | string[]]>,
)
.map(([key, value]) => [key.replace('[]', ''), value])
return Object.fromEntries(dedupedValues)
return Object.fromEntries(params)
}

@@ -6,16 +6,20 @@ import { serializeToQueryString } from './serialize-to-query-string'

it('Should serialize primitive values', () => {
expect(serializeToQueryString({ a: 1, b: false, c: 'foo', d: 0, e: null })).toBe('a=1&b=false&c=foo&d=0&e=null')
expect(serializeToQueryString({ a: 1, b: false, c: 'foo', d: 0, e: null })).toMatchInlineSnapshot(
'"a=MQ%253D%253D&b=ZmFsc2U%253D&c=ImZvbyI%253D&d=MA%253D%253D&e=bnVsbA%253D%253D"',
)
})
it('Should exclude explicit undefined', () => {
expect(serializeToQueryString({ a: 1, b: false, c: 'foo', d: undefined })).toBe('a=1&b=false&c=foo')
expect(serializeToQueryString({ a: 1, b: false, c: 'foo', d: undefined })).toMatchInlineSnapshot(
'"a=MQ%253D%253D&b=ZmFsc2U%253D&c=ImZvbyI%253D"',
)
})
it('Should serialize primitive arrays', () => {
expect(serializeToQueryString({ array: [1, 2, 3, 4] })).toBe('array[]=1&array[]=2&array[]=3&array[]=4')
expect(serializeToQueryString({ array: [1, 2, 3, 4] })).toMatchInlineSnapshot('"array=WzEsMiwzLDRd"')
})
it('Should serialize objects', () => {
expect(serializeToQueryString({ foo: { a: 1, b: 'value' } })).toBe(
`foo=${encodeURIComponent('{"a":1,"b":"value"}')}`,
expect(serializeToQueryString({ foo: { a: 1, b: 'value' } })).toMatchInlineSnapshot(
'"foo=eyJhIjoxLCJiIjoidmFsdWUifQ%253D%253D"',
)

@@ -26,4 +30,4 @@ })

const array = [1, 2, 3, { foo: 1 }]
expect(serializeToQueryString({ array })).toBe(`array=${encodeURIComponent(JSON.stringify(array))}`)
expect(serializeToQueryString({ array })).toMatchInlineSnapshot('"array=WzEsMiwzLHsiZm9vIjoxfV0%253D"')
})
})

@@ -1,18 +0,22 @@

export const serializeValue = ([key, value]: [key: string, value: any]) => {
if (typeof value === 'object') {
if (value instanceof Array) {
if (!value.some((v) => typeof v === 'object')) {
return value.map((val) => `${key}[]=${encodeURIComponent(val)}`).join('&')
}
}
return `${key}=${encodeURIComponent(JSON.stringify(value))}`
}
return `${key}=${encodeURIComponent(value)}`
}
/**
* Serialize steps:
* 1. Stringify the value (even primitives, ensure type safety), e.g.: { foo: 'bar😉' } => '{"foo":"bar😉"}'
* 2. Encode as an URI Component, e.g.: ''{"foo":"bar😉"}'' => '%7B%22foo%22%3A%22bar%F0%9F%98%89%22%7D'
* 3. Unescape the URI Component, e.g.: '%7B%22foo%22%3A%22bar%F0%9F%98%89%22%7D' => '{"foo":"barð\x9F\x98\x89"}' - This and the first encodeURIComponent is needed because btoa only supports ASCII characters. We also don't want to encode the whole JSON string to keep a reasonable string length
* 4. Encode the string as base64, e.g.: '{"foo":"barð\x9F\x98\x89"}' => 'eyJmb28iOiJiYXLwn5iJIn0='
* 5. Encode as an URL Param: 'eyJmb28iOiJiYXLwn5iJIn0=' => 'eyJmb28iOiJiYXLwn5iJIn0%3D'
* @param value The value to encode
* @returns The encoded value that can be used as an URL search parameter
*/
export const serializeValue = (value: any) =>
encodeURIComponent(btoa(unescape(encodeURIComponent(JSON.stringify(value)))))
export const serializeToQueryString = <T extends object>(query: T): string => {
return Object.entries(query)
.filter(([, value]) => value !== undefined)
.map(serializeValue)
.join('&')
export const serializeToQueryString = <T extends object>(queryObject: T): string => {
return new URLSearchParams(
Object.fromEntries(
Object.entries(queryObject)
.filter(([, value]) => value !== undefined)
.map(([key, value]) => [key, serializeValue(value)]),
),
).toString()
}

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc