From 8d23a4da9ca976d18d3ef5c7b81430b75f05bacf Mon Sep 17 00:00:00 2001 From: hanoak <92684191+hanoak@users.noreply.github.com> Date: Mon, 17 Aug 2026 15:54:52 +0530 Subject: [PATCH 1/3] feat: add types for photo search filter params (orientation, size, color, locale) --- src/generatePhotoEndpoints.ts | 3 ++- src/types.ts | 7 +++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/generatePhotoEndpoints.ts b/src/generatePhotoEndpoints.ts index 0fe22d5..6765204 100644 --- a/src/generatePhotoEndpoints.ts +++ b/src/generatePhotoEndpoints.ts @@ -2,6 +2,7 @@ import createFetchWrapper from "./createFetchWrapper"; import { Photo, PaginationParams, + PhotoFilterParams, ErrorResponse, Photos, PhotosWithTotalResults, @@ -18,7 +19,7 @@ export default function generatePhotoEndpoints(apiKey: string) { return { search( - params: PaginationParams & { query: string } + params: PaginationParams & PhotoFilterParams & { query: string } ): Promise { return fetchWrapper(`/search`, params); }, diff --git a/src/types.ts b/src/types.ts index 013c7a8..56b6e8f 100644 --- a/src/types.ts +++ b/src/types.ts @@ -11,6 +11,13 @@ export interface PaginationParams extends Params { page?: number; } +export interface PhotoFilterParams extends Params { + orientation?: "landscape" | "portrait" | "square"; + size?: "large" | "medium" | "small"; + color?: string; + locale?: string; +} + export interface VideoFilterParams extends Params { min_width?: number; max_width?: number; From 8faea88f7ad0e12bb338f272d1313e2de83d9483 Mon Sep 17 00:00:00 2001 From: hanoak <92684191+hanoak@users.noreply.github.com> Date: Mon, 17 Aug 2026 16:33:01 +0530 Subject: [PATCH 2/3] feat: expose response headers (rate-limit info) on all endpoint results --- src/createFetchWrapper.ts | 11 +++++++++-- src/generateCollectionEndpoints.ts | 26 +++++++++++++++++++------- src/generatePhotoEndpoints.ts | 20 ++++++++++++++------ src/generateVideoEndpoints.ts | 7 ++++--- src/types.ts | 6 +++++- 5 files changed, 51 insertions(+), 19 deletions(-) diff --git a/src/createFetchWrapper.ts b/src/createFetchWrapper.ts index b124a6d..56dac29 100644 --- a/src/createFetchWrapper.ts +++ b/src/createFetchWrapper.ts @@ -24,12 +24,19 @@ export default function createFetchWrapper(apiKey: string, type: AllowedTypes) { return (path: string, params?: T) => fetch(`${baseUrl}${path}?${stringifyParams(params || {})}`, options).then( - (response) => { + async (response) => { if (!response.ok) { throw new Error(response.statusText); } - return response.json(); + const json = await response.json(); + + Object.defineProperty(json, "headers", { + value: response.headers, + enumerable: false, + }); + + return json; } ); } diff --git a/src/generateCollectionEndpoints.ts b/src/generateCollectionEndpoints.ts index 64e0865..de68817 100644 --- a/src/generateCollectionEndpoints.ts +++ b/src/generateCollectionEndpoints.ts @@ -1,26 +1,38 @@ import createFetchWrapper from "./createFetchWrapper"; -import { Collection, PaginationParams, ErrorResponse, Medium } from "./types"; +import { + Collection, + PaginationParams, + ErrorResponse, + Medium, + WithHeaders, +} from "./types"; -type AllReturn = +type AllReturn = ( | { page: number; per_page: number; collections: Collection[]; } - | ErrorResponse; + | ErrorResponse +) & + WithHeaders; -type MediaReturn = +type MediaReturn = ( | { page: number; per_page: number; total_results: number; media: (Medium & { type: "Video" | "Photo" })[]; } - | ErrorResponse; + | ErrorResponse +) & + WithHeaders; -type FeaturedReturn = +type FeaturedReturn = ( | { page: number; per_page: number; collections: Collection[] } - | ErrorResponse; + | ErrorResponse +) & + WithHeaders; export default function generateCollectionEndpoints(apiKey: string) { const fetchWrapper = createFetchWrapper(apiKey, "collections"); diff --git a/src/generatePhotoEndpoints.ts b/src/generatePhotoEndpoints.ts index 6765204..2a4022e 100644 --- a/src/generatePhotoEndpoints.ts +++ b/src/generatePhotoEndpoints.ts @@ -6,13 +6,14 @@ import { ErrorResponse, Photos, PhotosWithTotalResults, + WithHeaders, } from "./types"; import { isPhotos } from "./typeCheckers"; -type SearchReturn = PhotosWithTotalResults | ErrorResponse; -type CuratedReturn = Photos | ErrorResponse; -type ShowReturn = Photo | ErrorResponse; -type RandomReturn = Photo | ErrorResponse; +type SearchReturn = (PhotosWithTotalResults | ErrorResponse) & WithHeaders; +type CuratedReturn = (Photos | ErrorResponse) & WithHeaders; +type ShowReturn = (Photo | ErrorResponse) & WithHeaders; +type RandomReturn = (Photo | ErrorResponse) & WithHeaders; export default function generatePhotoEndpoints(apiKey: string) { const fetchWrapper = createFetchWrapper(apiKey, "photo"); @@ -34,10 +35,17 @@ export default function generatePhotoEndpoints(apiKey: string) { const response = await this.curated({ page: randomPage, per_page: 1 }); if (isPhotos(response)) { - return response.photos[0] as RandomReturn; + const photo = response.photos[0]; + + Object.defineProperty(photo, "headers", { + value: response.headers, + enumerable: false, + }); + + return photo as RandomReturn; } - return response as ErrorResponse; + return response as RandomReturn; }, }; } diff --git a/src/generateVideoEndpoints.ts b/src/generateVideoEndpoints.ts index f842e4f..45db30e 100644 --- a/src/generateVideoEndpoints.ts +++ b/src/generateVideoEndpoints.ts @@ -5,11 +5,12 @@ import { Video, Videos, VideoFilterParams, + WithHeaders, } from "./types"; -type SearchReturn = Videos | ErrorResponse; -type PopularReturn = Videos | ErrorResponse; -type ShowReturn = Video; +type SearchReturn = (Videos | ErrorResponse) & WithHeaders; +type PopularReturn = (Videos | ErrorResponse) & WithHeaders; +type ShowReturn = Video & WithHeaders; export default function generatePhotoEndpoints(apiKey: string) { const fetchWrapper = createFetchWrapper(apiKey, "video"); diff --git a/src/types.ts b/src/types.ts index 56b6e8f..cdb56a2 100644 --- a/src/types.ts +++ b/src/types.ts @@ -2,6 +2,10 @@ export interface ErrorResponse { error: string; } +export interface WithHeaders { + headers: Headers; +} + export interface Params { [key: string]: string | number | undefined; } @@ -25,7 +29,7 @@ export interface VideoFilterParams extends Params { max_duration?: number; } -interface PaginationObject { +export interface PaginationObject { url?: string; page: number; per_page: number; From ce256068e0752d4422046952456a9adc3ace038a Mon Sep 17 00:00:00 2001 From: hanoak <92684191+hanoak@users.noreply.github.com> Date: Mon, 17 Aug 2026 16:39:42 +0530 Subject: [PATCH 3/3] fix: remove User-Agent header causing CORS failures in Firefox/Safari --- src/createFetchWrapper.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/createFetchWrapper.ts b/src/createFetchWrapper.ts index 56dac29..b3c58fd 100644 --- a/src/createFetchWrapper.ts +++ b/src/createFetchWrapper.ts @@ -15,7 +15,6 @@ export default function createFetchWrapper(apiKey: string, type: AllowedTypes) { headers: { Accept: "application/json", "Content-Type": "application/json", - "User-Agent": "Pexels/JavaScript", Authorization: apiKey, }, };