payload 3.87.1 → 3.88.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/collections/operations/find.d.ts.map +1 -1
- package/dist/collections/operations/find.js +8 -1
- package/dist/collections/operations/find.js.map +1 -1
- package/dist/collections/operations/findDistinct.d.ts.map +1 -1
- package/dist/collections/operations/findDistinct.js +7 -0
- package/dist/collections/operations/findDistinct.js.map +1 -1
- package/dist/collections/operations/findVersions.d.ts.map +1 -1
- package/dist/collections/operations/findVersions.js +8 -0
- package/dist/collections/operations/findVersions.js.map +1 -1
- package/dist/collections/operations/update.d.ts.map +1 -1
- package/dist/collections/operations/update.js +8 -1
- package/dist/collections/operations/update.js.map +1 -1
- package/dist/database/queryValidation/validateQueryPaths.d.ts.map +1 -1
- package/dist/database/queryValidation/validateQueryPaths.js +8 -1
- package/dist/database/queryValidation/validateQueryPaths.js.map +1 -1
- package/dist/database/queryValidation/validateSortQuery.d.ts +23 -0
- package/dist/database/queryValidation/validateSortQuery.d.ts.map +1 -0
- package/dist/database/queryValidation/validateSortQuery.js +54 -0
- package/dist/database/queryValidation/validateSortQuery.js.map +1 -0
- package/dist/database/sanitizeJoinQuery.d.ts.map +1 -1
- package/dist/database/sanitizeJoinQuery.js +6 -0
- package/dist/database/sanitizeJoinQuery.js.map +1 -1
- package/dist/globals/operations/findVersions.d.ts.map +1 -1
- package/dist/globals/operations/findVersions.js +8 -0
- package/dist/globals/operations/findVersions.js.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/uploads/fetchAPI-multipart/isEligibleRequest.js +1 -2
- package/dist/uploads/fetchAPI-multipart/isEligibleRequest.js.map +1 -1
- package/dist/uploads/fetchAPI-multipart/isEligibleRequest.spec.js +27 -0
- package/dist/uploads/fetchAPI-multipart/isEligibleRequest.spec.js.map +1 -1
- package/dist/utilities/getSafeRedirect.d.ts.map +1 -1
- package/dist/utilities/getSafeRedirect.js +16 -9
- package/dist/utilities/getSafeRedirect.js.map +1 -1
- package/dist/utilities/getSafeRedirect.spec.js +76 -2
- package/dist/utilities/getSafeRedirect.spec.js.map +1 -1
- package/dist/versions/drafts/appendVersionToQueryKey.js +1 -3
- package/dist/versions/drafts/appendVersionToQueryKey.js.map +1 -1
- package/dist/versions/drafts/appendVersionToQueryKey.spec.js +28 -0
- package/dist/versions/drafts/appendVersionToQueryKey.spec.js.map +1 -0
- package/package.json +2 -2
|
@@ -2,23 +2,30 @@ export const getSafeRedirect = ({ allowAbsoluteUrls = false, fallbackTo = '/', r
|
|
|
2
2
|
if (typeof redirectTo !== 'string') {
|
|
3
3
|
return fallbackTo;
|
|
4
4
|
}
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
const redirectPath = redirectTo.trim();
|
|
6
|
+
const hasControlCharacters = [
|
|
7
|
+
...redirectPath
|
|
8
|
+
].some((character)=>{
|
|
9
|
+
const code = character.charCodeAt(0);
|
|
10
|
+
return code <= 31 || code === 127;
|
|
11
|
+
});
|
|
12
|
+
const hasAmbiguousPathPrefix = /^\/%(?:25)*(?:09|0a|0d|2f|5c)/i.test(redirectPath);
|
|
13
|
+
let parsedRedirect;
|
|
7
14
|
try {
|
|
8
|
-
|
|
15
|
+
parsedRedirect = new URL(redirectPath, 'http://localhost');
|
|
9
16
|
} catch {
|
|
10
|
-
return fallbackTo
|
|
11
|
-
;
|
|
17
|
+
return fallbackTo;
|
|
12
18
|
}
|
|
13
|
-
const isSafeRedirect = // Must start with a single forward slash (e.g., "/admin")
|
|
14
|
-
redirectPath.startsWith('/') && //
|
|
19
|
+
const isSafeRedirect = !hasControlCharacters && !hasAmbiguousPathPrefix && // Must start with a single forward slash (e.g., "/admin")
|
|
20
|
+
redirectPath.startsWith('/') && // Must resolve to the same origin after URL parser normalization
|
|
21
|
+
parsedRedirect.origin === 'http://localhost' && // Prevent protocol-relative URLs (e.g., "//example.com")
|
|
15
22
|
!redirectPath.startsWith('//') && // Prevent encoded slashes that could resolve to protocol-relative
|
|
16
23
|
!redirectPath.startsWith('/%2F') && // Prevent backslash-based escape attempts (e.g., "/\\/example.com", "/\\\\example.com", "/\\example.com")
|
|
17
24
|
!redirectPath.startsWith('/\\/') && !redirectPath.startsWith('/\\\\') && !redirectPath.startsWith('/\\') && // Prevent javascript-based schemes (e.g., "/javascript:alert(1)")
|
|
18
25
|
!redirectPath.toLowerCase().startsWith('/javascript:') && // Prevent attempts to redirect to full URLs using "/http:" or "/https:"
|
|
19
26
|
!redirectPath.toLowerCase().startsWith('/http');
|
|
20
|
-
const isAbsoluteSafeRedirect = allowAbsoluteUrls && // Must be a valid absolute URL with http or https
|
|
21
|
-
/^https?:\/\/\S+$/i.test(redirectPath);
|
|
27
|
+
const isAbsoluteSafeRedirect = allowAbsoluteUrls && !hasControlCharacters && // Must be a valid absolute URL with http or https
|
|
28
|
+
/^https?:\/\/\S+$/i.test(redirectPath) && (parsedRedirect.protocol === 'http:' || parsedRedirect.protocol === 'https:');
|
|
22
29
|
return isSafeRedirect || isAbsoluteSafeRedirect ? redirectPath : fallbackTo;
|
|
23
30
|
};
|
|
24
31
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/utilities/getSafeRedirect.ts"],"sourcesContent":["export const getSafeRedirect = ({\n allowAbsoluteUrls = false,\n fallbackTo = '/',\n redirectTo,\n}: {\n allowAbsoluteUrls?: boolean\n fallbackTo?: string\n redirectTo: string | string[]\n}): string => {\n if (typeof redirectTo !== 'string') {\n return fallbackTo\n }\n\n
|
|
1
|
+
{"version":3,"sources":["../../src/utilities/getSafeRedirect.ts"],"sourcesContent":["export const getSafeRedirect = ({\n allowAbsoluteUrls = false,\n fallbackTo = '/',\n redirectTo,\n}: {\n allowAbsoluteUrls?: boolean\n fallbackTo?: string\n redirectTo: string | string[]\n}): string => {\n if (typeof redirectTo !== 'string') {\n return fallbackTo\n }\n\n const redirectPath = redirectTo.trim()\n\n const hasControlCharacters = [...redirectPath].some((character) => {\n const code = character.charCodeAt(0)\n return code <= 31 || code === 127\n })\n const hasAmbiguousPathPrefix = /^\\/%(?:25)*(?:09|0a|0d|2f|5c)/i.test(redirectPath)\n\n let parsedRedirect: URL\n try {\n parsedRedirect = new URL(redirectPath, 'http://localhost')\n } catch {\n return fallbackTo\n }\n\n const isSafeRedirect =\n !hasControlCharacters &&\n !hasAmbiguousPathPrefix &&\n // Must start with a single forward slash (e.g., \"/admin\")\n redirectPath.startsWith('/') &&\n // Must resolve to the same origin after URL parser normalization\n parsedRedirect.origin === 'http://localhost' &&\n // Prevent protocol-relative URLs (e.g., \"//example.com\")\n !redirectPath.startsWith('//') &&\n // Prevent encoded slashes that could resolve to protocol-relative\n !redirectPath.startsWith('/%2F') &&\n // Prevent backslash-based escape attempts (e.g., \"/\\\\/example.com\", \"/\\\\\\\\example.com\", \"/\\\\example.com\")\n !redirectPath.startsWith('/\\\\/') &&\n !redirectPath.startsWith('/\\\\\\\\') &&\n !redirectPath.startsWith('/\\\\') &&\n // Prevent javascript-based schemes (e.g., \"/javascript:alert(1)\")\n !redirectPath.toLowerCase().startsWith('/javascript:') &&\n // Prevent attempts to redirect to full URLs using \"/http:\" or \"/https:\"\n !redirectPath.toLowerCase().startsWith('/http')\n\n const isAbsoluteSafeRedirect =\n allowAbsoluteUrls &&\n !hasControlCharacters &&\n // Must be a valid absolute URL with http or https\n /^https?:\\/\\/\\S+$/i.test(redirectPath) &&\n (parsedRedirect.protocol === 'http:' || parsedRedirect.protocol === 'https:')\n\n return isSafeRedirect || isAbsoluteSafeRedirect ? redirectPath : fallbackTo\n}\n"],"names":["getSafeRedirect","allowAbsoluteUrls","fallbackTo","redirectTo","redirectPath","trim","hasControlCharacters","some","character","code","charCodeAt","hasAmbiguousPathPrefix","test","parsedRedirect","URL","isSafeRedirect","startsWith","origin","toLowerCase","isAbsoluteSafeRedirect","protocol"],"mappings":"AAAA,OAAO,MAAMA,kBAAkB,CAAC,EAC9BC,oBAAoB,KAAK,EACzBC,aAAa,GAAG,EAChBC,UAAU,EAKX;IACC,IAAI,OAAOA,eAAe,UAAU;QAClC,OAAOD;IACT;IAEA,MAAME,eAAeD,WAAWE,IAAI;IAEpC,MAAMC,uBAAuB;WAAIF;KAAa,CAACG,IAAI,CAAC,CAACC;QACnD,MAAMC,OAAOD,UAAUE,UAAU,CAAC;QAClC,OAAOD,QAAQ,MAAMA,SAAS;IAChC;IACA,MAAME,yBAAyB,iCAAiCC,IAAI,CAACR;IAErE,IAAIS;IACJ,IAAI;QACFA,iBAAiB,IAAIC,IAAIV,cAAc;IACzC,EAAE,OAAM;QACN,OAAOF;IACT;IAEA,MAAMa,iBACJ,CAACT,wBACD,CAACK,0BACD,0DAA0D;IAC1DP,aAAaY,UAAU,CAAC,QACxB,iEAAiE;IACjEH,eAAeI,MAAM,KAAK,sBAC1B,yDAAyD;IACzD,CAACb,aAAaY,UAAU,CAAC,SACzB,kEAAkE;IAClE,CAACZ,aAAaY,UAAU,CAAC,WACzB,0GAA0G;IAC1G,CAACZ,aAAaY,UAAU,CAAC,WACzB,CAACZ,aAAaY,UAAU,CAAC,YACzB,CAACZ,aAAaY,UAAU,CAAC,UACzB,kEAAkE;IAClE,CAACZ,aAAac,WAAW,GAAGF,UAAU,CAAC,mBACvC,wEAAwE;IACxE,CAACZ,aAAac,WAAW,GAAGF,UAAU,CAAC;IAEzC,MAAMG,yBACJlB,qBACA,CAACK,wBACD,kDAAkD;IAClD,oBAAoBM,IAAI,CAACR,iBACxBS,CAAAA,eAAeO,QAAQ,KAAK,WAAWP,eAAeO,QAAQ,KAAK,QAAO;IAE7E,OAAOL,kBAAkBI,yBAAyBf,eAAeF;AACnE,EAAC"}
|
|
@@ -39,6 +39,30 @@ describe('getSafeRedirect', ()=>{
|
|
|
39
39
|
fallbackTo: fallback
|
|
40
40
|
})).toBe(fallback);
|
|
41
41
|
});
|
|
42
|
+
it.each([
|
|
43
|
+
'redirect=%2F%09%2Fexample.invalid',
|
|
44
|
+
'redirect=%2F%0D%2Fexample.invalid',
|
|
45
|
+
'redirect=%2F%0A%2Fexample.invalid'
|
|
46
|
+
])('should use the fallback when a path resolves outside the current origin: %s', (query)=>{
|
|
47
|
+
const redirectTo = new URLSearchParams(query).get('redirect');
|
|
48
|
+
expect(redirectTo).not.toBeNull();
|
|
49
|
+
expect(getSafeRedirect({
|
|
50
|
+
redirectTo: redirectTo,
|
|
51
|
+
fallbackTo: fallback
|
|
52
|
+
})).toBe(fallback);
|
|
53
|
+
});
|
|
54
|
+
it.each([
|
|
55
|
+
'/%2509/example.invalid',
|
|
56
|
+
'/%250D/example.invalid',
|
|
57
|
+
'/%250A/example.invalid',
|
|
58
|
+
'/%255Cexample.invalid',
|
|
59
|
+
'/%252fexample.invalid'
|
|
60
|
+
])('should use the fallback for ambiguous encoded path prefixes: %s', (input)=>{
|
|
61
|
+
expect(getSafeRedirect({
|
|
62
|
+
redirectTo: input,
|
|
63
|
+
fallbackTo: fallback
|
|
64
|
+
})).toBe(fallback);
|
|
65
|
+
});
|
|
42
66
|
// Unsafe redirect patterns
|
|
43
67
|
it.each([
|
|
44
68
|
'//example.com',
|
|
@@ -72,13 +96,63 @@ describe('getSafeRedirect', ()=>{
|
|
|
72
96
|
fallbackTo: fallback
|
|
73
97
|
})).toBe(fallback);
|
|
74
98
|
});
|
|
75
|
-
|
|
76
|
-
it('should return fallback on invalid encoding', ()=>{
|
|
99
|
+
it('should return fallback when the input is not a path or URL', ()=>{
|
|
77
100
|
expect(getSafeRedirect({
|
|
78
101
|
redirectTo: '%E0%A4%A',
|
|
79
102
|
fallbackTo: fallback
|
|
80
103
|
})).toBe(fallback);
|
|
81
104
|
});
|
|
105
|
+
it('should preserve an accepted local redirect', ()=>{
|
|
106
|
+
const redirectTo = '/dashboard?tab=overview#details';
|
|
107
|
+
expect(getSafeRedirect({
|
|
108
|
+
redirectTo,
|
|
109
|
+
fallbackTo: fallback
|
|
110
|
+
})).toBe(redirectTo);
|
|
111
|
+
});
|
|
112
|
+
it('should preserve a parsed navigation target byte-for-byte', ()=>{
|
|
113
|
+
const redirectTo = new URLSearchParams('redirect=%2Foauth%2Fcallback%3Fcode%3DA%252FB%26state%3Dopaque%253D%23done').get('redirect');
|
|
114
|
+
expect(redirectTo).toBe('/oauth/callback?code=A%2FB&state=opaque%3D#done');
|
|
115
|
+
expect(getSafeRedirect({
|
|
116
|
+
redirectTo: redirectTo,
|
|
117
|
+
fallbackTo: fallback
|
|
118
|
+
})).toBe('/oauth/callback?code=A%2FB&state=opaque%3D#done');
|
|
119
|
+
});
|
|
120
|
+
it.each([
|
|
121
|
+
[
|
|
122
|
+
'https://example.invalid/path?code=A%252FB#done',
|
|
123
|
+
'https://example.invalid/path?code=A%252FB#done'
|
|
124
|
+
],
|
|
125
|
+
[
|
|
126
|
+
'http://example.invalid/dashboard',
|
|
127
|
+
'http://example.invalid/dashboard'
|
|
128
|
+
]
|
|
129
|
+
])('should preserve an HTTP absolute redirect when enabled: %s', (input, expected)=>{
|
|
130
|
+
expect(getSafeRedirect({
|
|
131
|
+
allowAbsoluteUrls: true,
|
|
132
|
+
redirectTo: input,
|
|
133
|
+
fallbackTo: fallback
|
|
134
|
+
})).toBe(expected);
|
|
135
|
+
});
|
|
136
|
+
it.each([
|
|
137
|
+
[
|
|
138
|
+
'https://example.invalid/path',
|
|
139
|
+
false
|
|
140
|
+
],
|
|
141
|
+
[
|
|
142
|
+
'mailto:user@example.invalid',
|
|
143
|
+
true
|
|
144
|
+
],
|
|
145
|
+
[
|
|
146
|
+
'//example.invalid/path',
|
|
147
|
+
true
|
|
148
|
+
]
|
|
149
|
+
])('should use the fallback without an explicitly enabled HTTP(S) URL: %s', (input, allowAbsoluteUrls)=>{
|
|
150
|
+
expect(getSafeRedirect({
|
|
151
|
+
allowAbsoluteUrls,
|
|
152
|
+
redirectTo: input,
|
|
153
|
+
fallbackTo: fallback
|
|
154
|
+
})).toBe(fallback);
|
|
155
|
+
});
|
|
82
156
|
});
|
|
83
157
|
|
|
84
158
|
//# sourceMappingURL=getSafeRedirect.spec.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/utilities/getSafeRedirect.spec.ts"],"sourcesContent":["import { describe, it, expect } from 'vitest'\nimport { getSafeRedirect } from './getSafeRedirect'\n\nconst fallback = '/admin' // default fallback if the input is unsafe or invalid\n\ndescribe('getSafeRedirect', () => {\n // Valid - safe redirect paths\n it.each([['/dashboard'], ['/admin/settings'], ['/projects?id=123'], ['/hello-world']])(\n 'should allow safe relative path: %s',\n (input) => {\n // If the input is a clean relative path, it should be returned as-is\n expect(getSafeRedirect({ redirectTo: input, fallbackTo: fallback })).toBe(input)\n },\n )\n\n // Invalid types or empty inputs\n it.each(['', null, undefined, 123, {}, []])(\n 'should fallback on invalid or non-string input: %s',\n (input) => {\n // If the input is not a valid string, it should return the fallback\n expect(getSafeRedirect({ redirectTo: input as any, fallbackTo: fallback })).toBe(fallback)\n },\n )\n\n // Unsafe redirect patterns\n it.each([\n '//example.com', // protocol-relative URL\n '/javascript:alert(1)', // JavaScript scheme\n '/JavaScript:alert(1)', // case-insensitive JavaScript\n '/http://unknown.com', // disguised external redirect\n '/https://unknown.com', // disguised external redirect\n '/%2Funknown.com', // encoded slash — could resolve to //\n '/\\\\/unknown.com', // escaped slash\n '/\\\\\\\\unknown.com', // double escaped slashes\n '/\\\\unknown.com', // single escaped slash\n '%2F%2Funknown.com', // fully encoded protocol-relative path\n '%2Fjavascript:alert(1)', // encoded JavaScript scheme\n ])('should block unsafe redirect: %s', (input) => {\n // All of these should return the fallback because they’re unsafe\n expect(getSafeRedirect({ redirectTo: input, fallbackTo: fallback })).toBe(fallback)\n })\n\n // Input with extra spaces should still be properly handled\n it('should trim whitespace before evaluating', () => {\n // A valid path with surrounding spaces should still be accepted\n expect(getSafeRedirect({ redirectTo: ' /dashboard ', fallbackTo: fallback })).toBe(\n '/dashboard',\n )\n\n // An unsafe path with spaces should still be rejected\n expect(getSafeRedirect({ redirectTo: ' //example.com ', fallbackTo: fallback })).toBe(\n fallback,\n )\n })\n\n
|
|
1
|
+
{"version":3,"sources":["../../src/utilities/getSafeRedirect.spec.ts"],"sourcesContent":["import { describe, it, expect } from 'vitest'\nimport { getSafeRedirect } from './getSafeRedirect'\n\nconst fallback = '/admin' // default fallback if the input is unsafe or invalid\n\ndescribe('getSafeRedirect', () => {\n // Valid - safe redirect paths\n it.each([['/dashboard'], ['/admin/settings'], ['/projects?id=123'], ['/hello-world']])(\n 'should allow safe relative path: %s',\n (input) => {\n // If the input is a clean relative path, it should be returned as-is\n expect(getSafeRedirect({ redirectTo: input, fallbackTo: fallback })).toBe(input)\n },\n )\n\n // Invalid types or empty inputs\n it.each(['', null, undefined, 123, {}, []])(\n 'should fallback on invalid or non-string input: %s',\n (input) => {\n // If the input is not a valid string, it should return the fallback\n expect(getSafeRedirect({ redirectTo: input as any, fallbackTo: fallback })).toBe(fallback)\n },\n )\n\n it.each([\n 'redirect=%2F%09%2Fexample.invalid',\n 'redirect=%2F%0D%2Fexample.invalid',\n 'redirect=%2F%0A%2Fexample.invalid',\n ])('should use the fallback when a path resolves outside the current origin: %s', (query) => {\n const redirectTo = new URLSearchParams(query).get('redirect')\n\n expect(redirectTo).not.toBeNull()\n expect(getSafeRedirect({ redirectTo: redirectTo!, fallbackTo: fallback })).toBe(fallback)\n })\n\n it.each([\n '/%2509/example.invalid',\n '/%250D/example.invalid',\n '/%250A/example.invalid',\n '/%255Cexample.invalid',\n '/%252fexample.invalid',\n ])('should use the fallback for ambiguous encoded path prefixes: %s', (input) => {\n expect(getSafeRedirect({ redirectTo: input, fallbackTo: fallback })).toBe(fallback)\n })\n\n // Unsafe redirect patterns\n it.each([\n '//example.com', // protocol-relative URL\n '/javascript:alert(1)', // JavaScript scheme\n '/JavaScript:alert(1)', // case-insensitive JavaScript\n '/http://unknown.com', // disguised external redirect\n '/https://unknown.com', // disguised external redirect\n '/%2Funknown.com', // encoded slash — could resolve to //\n '/\\\\/unknown.com', // escaped slash\n '/\\\\\\\\unknown.com', // double escaped slashes\n '/\\\\unknown.com', // single escaped slash\n '%2F%2Funknown.com', // fully encoded protocol-relative path\n '%2Fjavascript:alert(1)', // encoded JavaScript scheme\n ])('should block unsafe redirect: %s', (input) => {\n // All of these should return the fallback because they’re unsafe\n expect(getSafeRedirect({ redirectTo: input, fallbackTo: fallback })).toBe(fallback)\n })\n\n // Input with extra spaces should still be properly handled\n it('should trim whitespace before evaluating', () => {\n // A valid path with surrounding spaces should still be accepted\n expect(getSafeRedirect({ redirectTo: ' /dashboard ', fallbackTo: fallback })).toBe(\n '/dashboard',\n )\n\n // An unsafe path with spaces should still be rejected\n expect(getSafeRedirect({ redirectTo: ' //example.com ', fallbackTo: fallback })).toBe(\n fallback,\n )\n })\n\n it('should return fallback when the input is not a path or URL', () => {\n expect(getSafeRedirect({ redirectTo: '%E0%A4%A', fallbackTo: fallback })).toBe(fallback)\n })\n\n it('should preserve an accepted local redirect', () => {\n const redirectTo = '/dashboard?tab=overview#details'\n\n expect(getSafeRedirect({ redirectTo, fallbackTo: fallback })).toBe(redirectTo)\n })\n\n it('should preserve a parsed navigation target byte-for-byte', () => {\n const redirectTo = new URLSearchParams(\n 'redirect=%2Foauth%2Fcallback%3Fcode%3DA%252FB%26state%3Dopaque%253D%23done',\n ).get('redirect')\n\n expect(redirectTo).toBe('/oauth/callback?code=A%2FB&state=opaque%3D#done')\n expect(getSafeRedirect({ redirectTo: redirectTo!, fallbackTo: fallback })).toBe(\n '/oauth/callback?code=A%2FB&state=opaque%3D#done',\n )\n })\n\n it.each([\n [\n 'https://example.invalid/path?code=A%252FB#done',\n 'https://example.invalid/path?code=A%252FB#done',\n ],\n ['http://example.invalid/dashboard', 'http://example.invalid/dashboard'],\n ])('should preserve an HTTP absolute redirect when enabled: %s', (input, expected) => {\n expect(\n getSafeRedirect({\n allowAbsoluteUrls: true,\n redirectTo: input,\n fallbackTo: fallback,\n }),\n ).toBe(expected)\n })\n\n it.each([\n ['https://example.invalid/path', false],\n ['mailto:user@example.invalid', true],\n ['//example.invalid/path', true],\n ])(\n 'should use the fallback without an explicitly enabled HTTP(S) URL: %s',\n (input, allowAbsoluteUrls) => {\n expect(getSafeRedirect({ allowAbsoluteUrls, redirectTo: input, fallbackTo: fallback })).toBe(\n fallback,\n )\n },\n )\n})\n"],"names":["describe","it","expect","getSafeRedirect","fallback","each","input","redirectTo","fallbackTo","toBe","undefined","query","URLSearchParams","get","not","toBeNull","expected","allowAbsoluteUrls"],"mappings":"AAAA,SAASA,QAAQ,EAAEC,EAAE,EAAEC,MAAM,QAAQ,SAAQ;AAC7C,SAASC,eAAe,QAAQ,oBAAmB;AAEnD,MAAMC,WAAW,SAAS,qDAAqD;;AAE/EJ,SAAS,mBAAmB;IAC1B,8BAA8B;IAC9BC,GAAGI,IAAI,CAAC;QAAC;YAAC;SAAa;QAAE;YAAC;SAAkB;QAAE;YAAC;SAAmB;QAAE;YAAC;SAAe;KAAC,EACnF,uCACA,CAACC;QACC,qEAAqE;QACrEJ,OAAOC,gBAAgB;YAAEI,YAAYD;YAAOE,YAAYJ;QAAS,IAAIK,IAAI,CAACH;IAC5E;IAGF,gCAAgC;IAChCL,GAAGI,IAAI,CAAC;QAAC;QAAI;QAAMK;QAAW;QAAK,CAAC;QAAG,EAAE;KAAC,EACxC,sDACA,CAACJ;QACC,oEAAoE;QACpEJ,OAAOC,gBAAgB;YAAEI,YAAYD;YAAcE,YAAYJ;QAAS,IAAIK,IAAI,CAACL;IACnF;IAGFH,GAAGI,IAAI,CAAC;QACN;QACA;QACA;KACD,EAAE,+EAA+E,CAACM;QACjF,MAAMJ,aAAa,IAAIK,gBAAgBD,OAAOE,GAAG,CAAC;QAElDX,OAAOK,YAAYO,GAAG,CAACC,QAAQ;QAC/Bb,OAAOC,gBAAgB;YAAEI,YAAYA;YAAaC,YAAYJ;QAAS,IAAIK,IAAI,CAACL;IAClF;IAEAH,GAAGI,IAAI,CAAC;QACN;QACA;QACA;QACA;QACA;KACD,EAAE,mEAAmE,CAACC;QACrEJ,OAAOC,gBAAgB;YAAEI,YAAYD;YAAOE,YAAYJ;QAAS,IAAIK,IAAI,CAACL;IAC5E;IAEA,2BAA2B;IAC3BH,GAAGI,IAAI,CAAC;QACN;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;KACD,EAAE,oCAAoC,CAACC;QACtC,iEAAiE;QACjEJ,OAAOC,gBAAgB;YAAEI,YAAYD;YAAOE,YAAYJ;QAAS,IAAIK,IAAI,CAACL;IAC5E;IAEA,2DAA2D;IAC3DH,GAAG,4CAA4C;QAC7C,gEAAgE;QAChEC,OAAOC,gBAAgB;YAAEI,YAAY;YAAoBC,YAAYJ;QAAS,IAAIK,IAAI,CACpF;QAGF,sDAAsD;QACtDP,OAAOC,gBAAgB;YAAEI,YAAY;YAAuBC,YAAYJ;QAAS,IAAIK,IAAI,CACvFL;IAEJ;IAEAH,GAAG,8DAA8D;QAC/DC,OAAOC,gBAAgB;YAAEI,YAAY;YAAYC,YAAYJ;QAAS,IAAIK,IAAI,CAACL;IACjF;IAEAH,GAAG,8CAA8C;QAC/C,MAAMM,aAAa;QAEnBL,OAAOC,gBAAgB;YAAEI;YAAYC,YAAYJ;QAAS,IAAIK,IAAI,CAACF;IACrE;IAEAN,GAAG,4DAA4D;QAC7D,MAAMM,aAAa,IAAIK,gBACrB,8EACAC,GAAG,CAAC;QAENX,OAAOK,YAAYE,IAAI,CAAC;QACxBP,OAAOC,gBAAgB;YAAEI,YAAYA;YAAaC,YAAYJ;QAAS,IAAIK,IAAI,CAC7E;IAEJ;IAEAR,GAAGI,IAAI,CAAC;QACN;YACE;YACA;SACD;QACD;YAAC;YAAoC;SAAmC;KACzE,EAAE,8DAA8D,CAACC,OAAOU;QACvEd,OACEC,gBAAgB;YACdc,mBAAmB;YACnBV,YAAYD;YACZE,YAAYJ;QACd,IACAK,IAAI,CAACO;IACT;IAEAf,GAAGI,IAAI,CAAC;QACN;YAAC;YAAgC;SAAM;QACvC;YAAC;YAA+B;SAAK;QACrC;YAAC;YAA0B;SAAK;KACjC,EACC,yEACA,CAACC,OAAOW;QACNf,OAAOC,gBAAgB;YAAEc;YAAmBV,YAAYD;YAAOE,YAAYJ;QAAS,IAAIK,IAAI,CAC1FL;IAEJ;AAEJ"}
|
|
@@ -1,11 +1,9 @@
|
|
|
1
1
|
export const appendVersionToQueryKey = (query = {})=>{
|
|
2
2
|
return Object.entries(query).reduce((res, [key, val])=>{
|
|
3
3
|
if ([
|
|
4
|
-
'AND',
|
|
5
4
|
'and',
|
|
6
|
-
'OR',
|
|
7
5
|
'or'
|
|
8
|
-
].includes(key) && Array.isArray(val)) {
|
|
6
|
+
].includes(key.toLowerCase()) && Array.isArray(val)) {
|
|
9
7
|
return {
|
|
10
8
|
...res,
|
|
11
9
|
[key.toLowerCase()]: val.map((subQuery)=>appendVersionToQueryKey(subQuery))
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/versions/drafts/appendVersionToQueryKey.ts"],"sourcesContent":["import type { Where } from '../../types/index.js'\n\nexport const appendVersionToQueryKey = (query: Where = {}): Where => {\n return Object.entries(query).reduce((res, [key, val]) => {\n if (['
|
|
1
|
+
{"version":3,"sources":["../../../src/versions/drafts/appendVersionToQueryKey.ts"],"sourcesContent":["import type { Where } from '../../types/index.js'\n\nexport const appendVersionToQueryKey = (query: Where = {}): Where => {\n return Object.entries(query).reduce((res, [key, val]) => {\n if (['and', 'or'].includes(key.toLowerCase()) && Array.isArray(val)) {\n return {\n ...res,\n [key.toLowerCase()]: val.map((subQuery) => appendVersionToQueryKey(subQuery)),\n }\n }\n\n if (key !== 'id') {\n return {\n ...res,\n [`version.${key}`]: val,\n }\n }\n\n return {\n ...res,\n parent: val,\n }\n }, {})\n}\n"],"names":["appendVersionToQueryKey","query","Object","entries","reduce","res","key","val","includes","toLowerCase","Array","isArray","map","subQuery","parent"],"mappings":"AAEA,OAAO,MAAMA,0BAA0B,CAACC,QAAe,CAAC,CAAC;IACvD,OAAOC,OAAOC,OAAO,CAACF,OAAOG,MAAM,CAAC,CAACC,KAAK,CAACC,KAAKC,IAAI;QAClD,IAAI;YAAC;YAAO;SAAK,CAACC,QAAQ,CAACF,IAAIG,WAAW,OAAOC,MAAMC,OAAO,CAACJ,MAAM;YACnE,OAAO;gBACL,GAAGF,GAAG;gBACN,CAACC,IAAIG,WAAW,GAAG,EAAEF,IAAIK,GAAG,CAAC,CAACC,WAAab,wBAAwBa;YACrE;QACF;QAEA,IAAIP,QAAQ,MAAM;YAChB,OAAO;gBACL,GAAGD,GAAG;gBACN,CAAC,CAAC,QAAQ,EAAEC,KAAK,CAAC,EAAEC;YACtB;QACF;QAEA,OAAO;YACL,GAAGF,GAAG;YACNS,QAAQP;QACV;IACF,GAAG,CAAC;AACN,EAAC"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
import { appendVersionToQueryKey } from './appendVersionToQueryKey.js';
|
|
3
|
+
describe('appendVersionToQueryKey', ()=>{
|
|
4
|
+
it.each([
|
|
5
|
+
'aNd',
|
|
6
|
+
'oR'
|
|
7
|
+
])('should preserve case-insensitive %s conditions when prefixing version fields', (logicalOperator)=>{
|
|
8
|
+
expect(appendVersionToQueryKey({
|
|
9
|
+
[logicalOperator]: [
|
|
10
|
+
{
|
|
11
|
+
title: {
|
|
12
|
+
equals: 'example'
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
]
|
|
16
|
+
})).toStrictEqual({
|
|
17
|
+
[logicalOperator.toLowerCase()]: [
|
|
18
|
+
{
|
|
19
|
+
'version.title': {
|
|
20
|
+
equals: 'example'
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
]
|
|
24
|
+
});
|
|
25
|
+
});
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
//# sourceMappingURL=appendVersionToQueryKey.spec.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/versions/drafts/appendVersionToQueryKey.spec.ts"],"sourcesContent":["import { describe, expect, it } from 'vitest'\n\nimport { appendVersionToQueryKey } from './appendVersionToQueryKey.js'\n\ndescribe('appendVersionToQueryKey', () => {\n it.each(['aNd', 'oR'])(\n 'should preserve case-insensitive %s conditions when prefixing version fields',\n (logicalOperator) => {\n expect(\n appendVersionToQueryKey({\n [logicalOperator]: [\n {\n title: {\n equals: 'example',\n },\n },\n ],\n }),\n ).toStrictEqual({\n [logicalOperator.toLowerCase()]: [\n {\n 'version.title': {\n equals: 'example',\n },\n },\n ],\n })\n },\n )\n})\n"],"names":["describe","expect","it","appendVersionToQueryKey","each","logicalOperator","title","equals","toStrictEqual","toLowerCase"],"mappings":"AAAA,SAASA,QAAQ,EAAEC,MAAM,EAAEC,EAAE,QAAQ,SAAQ;AAE7C,SAASC,uBAAuB,QAAQ,+BAA8B;AAEtEH,SAAS,2BAA2B;IAClCE,GAAGE,IAAI,CAAC;QAAC;QAAO;KAAK,EACnB,gFACA,CAACC;QACCJ,OACEE,wBAAwB;YACtB,CAACE,gBAAgB,EAAE;gBACjB;oBACEC,OAAO;wBACLC,QAAQ;oBACV;gBACF;aACD;QACH,IACAC,aAAa,CAAC;YACd,CAACH,gBAAgBI,WAAW,GAAG,EAAE;gBAC/B;oBACE,iBAAiB;wBACfF,QAAQ;oBACV;gBACF;aACD;QACH;IACF;AAEJ"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "payload",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.88.0",
|
|
4
4
|
"description": "Node, React, Headless CMS and Application Framework built on Next.js",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"admin panel",
|
|
@@ -115,7 +115,7 @@
|
|
|
115
115
|
"undici": "7.29.0",
|
|
116
116
|
"uuid": "13.0.2",
|
|
117
117
|
"ws": "^8.16.0",
|
|
118
|
-
"@payloadcms/translations": "3.
|
|
118
|
+
"@payloadcms/translations": "3.88.0"
|
|
119
119
|
},
|
|
120
120
|
"devDependencies": {
|
|
121
121
|
"@hyrious/esbuild-plugin-commonjs": "0.2.6",
|