Launch Week Day 4: Introducing Data Exports.Learn More
Socket
Book a DemoSign in
Socket

unsplash-js

Package Overview
Dependencies
Maintainers
2
Versions
54
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

unsplash-js - npm Package Compare versions

Comparing version
6.3.0
to
7.0.0-beta.1
+5
dist/beacon.d.ts
export declare const trackNonHotLinkedPhotoView: ({ appId }: {
appId: string;
}) => ({ photoId, }: {
photoId: string | string[];
}) => Promise<Response>;
import { AnyJson, NonEmptyArray } from './typescript';
export declare type Errors = NonEmptyArray<string>;
export declare type ErrorSource = 'api' | 'decoding';
export declare const getErrorForBadStatusCode: (jsonResponse: AnyJson) => {
errors: Errors;
source: ErrorSource;
};
export declare class DecodingError {
readonly message: string;
constructor(message: string);
}
import { HandleResponse } from './response';
declare type FeedResponse<T> = {
results: T[];
total: number;
};
export declare const handleFeedResponse: <T>() => HandleResponse<FeedResponse<T>>;
export {};
/** Takes a dictionary containing nullish values and returns a dictionary of all the defined
* (non-nullish) values.
*/
export declare const compactDefined: <A>(obj: Record<string, A | null | undefined>) => Record<string, A>;
/**
* copied from `fp-ts`
* https://github.com/gcanti/fp-ts/blob/70190b5a03ddc2d31b4708c75c6dfad81d0bfa21/perf/function/flow.t¡s
*/
export declare function flow<A extends Array<unknown>, B>(ab: (...a: A) => B): (...a: A) => B;
export declare function flow<A extends Array<unknown>, B, C>(ab: (...a: A) => B, bc: (b: B) => C): (...a: A) => C;
export declare function flow<A extends Array<unknown>, B, C, D>(ab: (...a: A) => B, bc: (b: B) => C, cd: (b: C) => D): (...a: A) => D;
import { AnyJson } from './typescript';
/**
* Note: restrict the type of JSON to `AnyJson` so that `any` doesn't leak downstream.
*/
export declare const getJsonResponse: (response: Response) => Promise<AnyJson>;
import { PaginationParams } from '../types/request';
export declare const getCollections: (collectionIds?: string[] | undefined) => {
collections: string;
} | {
collections?: undefined;
};
export declare const getFeedParams: ({ page, perPage, orderBy }: PaginationParams) => Record<string, number | import("../types/request").OrderBy>;
import { ApiResponse, HandleResponse } from './response';
import { OmitStrict } from './typescript';
import { BuildUrlParams } from './url';
declare type FetchParams = Pick<RequestInit, 'method'>;
/**
* The params generated by the library
*/
declare type BaseRequestParams = BuildUrlParams & FetchParams & Pick<RequestInit, 'headers'>;
/**
* Additional fetch options provided by the user on a per-call basis
*/
declare type AdditionalPerFetchParams = Omit<RequestInit, keyof FetchParams>;
export declare type CompleteRequestParams = BaseRequestParams & AdditionalPerFetchParams;
declare type HandleRequest<Args> = (a: Args, additionalFetchOptions?: AdditionalPerFetchParams) => CompleteRequestParams;
/**
* helper used to type-check the arguments, and add default params for all requests
*/
export declare const createRequestHandler: <Args>(fn: (a: Args) => BaseRequestParams) => HandleRequest<Args>;
/**
* Variant of `createRequestHandler` used when the args object is entirely optional.
* We cannot combine this with `createRequestHandler` because it is impossible to make the function
* parameter conditionally nullable or non-nullable.
*/
export declare const createRequestHandlerOptional: <Args>(fn: (a?: Args | undefined) => BaseRequestParams) => (a?: Args | undefined, additionalFetchOptions?: Pick<RequestInit, "body" | "cache" | "credentials" | "headers" | "integrity" | "keepalive" | "mode" | "redirect" | "referrer" | "referrerPolicy" | "signal" | "window"> | undefined) => CompleteRequestParams;
/**
* Initial parameters that apply to all calls
*/
declare type InitParams = {
apiVersion?: string;
} & OmitStrict<RequestInit, 'method' | 'body'> & ({
accessKey: string;
apiUrl?: never;
} | {
apiUrl: string;
accessKey?: never;
});
declare type RequestGenerator<Args, ResponseType> = {
handleRequest: HandleRequest<Args>;
handleResponse: HandleResponse<ResponseType>;
};
declare type GeneratedRequestFunction<Args, ResponseType> = (...a: Parameters<HandleRequest<Args>>) => Promise<ApiResponse<ResponseType>>;
declare type InitMakeRequest = (args: InitParams) => <Args, ResponseType>(handlers: RequestGenerator<Args, ResponseType>) => GeneratedRequestFunction<Args, ResponseType>;
export declare const initMakeRequest: InitMakeRequest;
export {};
import { Errors, ErrorSource } from './errors';
export declare type ApiResponse<T> = {
type: 'success';
response: T;
errors?: never;
status: number;
} | {
type: 'error';
source: ErrorSource;
response?: never;
errors: Errors;
status: number;
};
export declare type HandleResponse<T> = (args: {
response: Response;
}) => Promise<T>;
export declare const handleFetchResponse: <ResponseType_1>(handleResponse: HandleResponse<ResponseType_1>) => (response: Response) => Promise<ApiResponse<ResponseType_1>>;
export declare const castResponse: <T>() => HandleResponse<T>;
export declare type AnyJson = boolean | number | string | null | JsonArray | JsonMap;
export declare type JsonMap = {
[key: string]: AnyJson;
};
export declare type JsonArray = Array<AnyJson>;
export declare const checkIsString: Refinement<unknown, string>;
/**
* https://github.com/Microsoft/TypeScript/issues/12215#issuecomment-377567046
*/
export declare type OmitStrict<T, K extends keyof T> = Omit<T, K>;
/**
* Unlike TypeScript's `NonNullable`, this does _not_ include `undefined`
*/
export declare type Nullable<T> = T | null;
export declare const isDefined: <T>(x: T | null | undefined) => x is T;
export declare type NonEmptyArray<T> = [T, ...T[]];
declare type Refinement<A, B extends A> = (a: A) => a is B;
export declare function getRefinement<A, B extends A>(getB: (a: A) => Nullable<B>): Refinement<A, B>;
export declare const checkIsNonEmptyArray: <T>(a: T[]) => a is NonEmptyArray<T>;
export {};
declare type Query = {
[index: string]: string | number | boolean;
};
export declare type BuildUrlParams = {
pathname: string;
query: Query;
};
export declare const buildUrl: ({ pathname, query }: BuildUrlParams) => (apiBaseUrl: string) => string;
export declare const parseQueryAndPathname: (url: string) => {
query: Query;
pathname: string | undefined;
};
export {};
import * as search from './methods/search';
export declare const createApi: (args: ({
apiVersion?: string | undefined;
} & Pick<RequestInit, "cache" | "credentials" | "headers" | "integrity" | "keepalive" | "mode" | "redirect" | "referrer" | "referrerPolicy" | "signal" | "window"> & {
accessKey: string;
apiUrl?: undefined;
}) | ({
apiVersion?: string | undefined;
} & Pick<RequestInit, "cache" | "credentials" | "headers" | "integrity" | "keepalive" | "mode" | "redirect" | "referrer" | "referrerPolicy" | "signal" | "window"> & {
apiUrl: string;
accessKey?: undefined;
})) => {
photos: {
get: (a: {
photoId: string;
}, additionalFetchOptions?: Pick<RequestInit, "body" | "cache" | "credentials" | "headers" | "integrity" | "keepalive" | "mode" | "redirect" | "referrer" | "referrerPolicy" | "signal" | "window"> | undefined) => Promise<import("./helpers/response").ApiResponse<any>>;
list: (a: import("./types/request").PaginationParams | undefined, additionalFetchOptions?: Pick<RequestInit, "body" | "cache" | "credentials" | "headers" | "integrity" | "keepalive" | "mode" | "redirect" | "referrer" | "referrerPolicy" | "signal" | "window"> | undefined) => Promise<import("./helpers/response").ApiResponse<{
results: any[];
total: number;
}>>;
getStats: (a: {
photoId: string;
}, additionalFetchOptions?: Pick<RequestInit, "body" | "cache" | "credentials" | "headers" | "integrity" | "keepalive" | "mode" | "redirect" | "referrer" | "referrerPolicy" | "signal" | "window"> | undefined) => Promise<import("./helpers/response").ApiResponse<any>>;
getRandom: (a: ({
collectionIds?: string[] | undefined;
featured?: boolean | undefined;
username?: string | undefined;
query?: string | undefined;
count?: number | undefined;
} & import("./types/request").OrientationParam) | undefined, additionalFetchOptions?: Pick<RequestInit, "body" | "cache" | "credentials" | "headers" | "integrity" | "keepalive" | "mode" | "redirect" | "referrer" | "referrerPolicy" | "signal" | "window"> | undefined) => Promise<import("./helpers/response").ApiResponse<any>>;
trackDownload: (a: {
downloadLocation: string;
}, additionalFetchOptions?: Pick<RequestInit, "body" | "cache" | "credentials" | "headers" | "integrity" | "keepalive" | "mode" | "redirect" | "referrer" | "referrerPolicy" | "signal" | "window"> | undefined) => Promise<import("./helpers/response").ApiResponse<any>>;
};
users: {
getPhotos: (a: {
stats?: boolean | undefined;
} & import("./types/request").OrientationParam & {
username: string;
} & import("./types/request").PaginationParams, additionalFetchOptions?: Pick<RequestInit, "body" | "cache" | "credentials" | "headers" | "integrity" | "keepalive" | "mode" | "redirect" | "referrer" | "referrerPolicy" | "signal" | "window"> | undefined) => Promise<import("./helpers/response").ApiResponse<{
results: any[];
total: number;
}>>;
getCollections: (a: {
username: string;
} & import("./types/request").PaginationParams, additionalFetchOptions?: Pick<RequestInit, "body" | "cache" | "credentials" | "headers" | "integrity" | "keepalive" | "mode" | "redirect" | "referrer" | "referrerPolicy" | "signal" | "window"> | undefined) => Promise<import("./helpers/response").ApiResponse<{
results: any[];
total: number;
}>>;
getLikes: (a: import("./types/request").OrientationParam & {
username: string;
} & import("./types/request").PaginationParams, additionalFetchOptions?: Pick<RequestInit, "body" | "cache" | "credentials" | "headers" | "integrity" | "keepalive" | "mode" | "redirect" | "referrer" | "referrerPolicy" | "signal" | "window"> | undefined) => Promise<import("./helpers/response").ApiResponse<{
results: any[];
total: number;
}>>;
get: (a: {
username: string;
}, additionalFetchOptions?: Pick<RequestInit, "body" | "cache" | "credentials" | "headers" | "integrity" | "keepalive" | "mode" | "redirect" | "referrer" | "referrerPolicy" | "signal" | "window"> | undefined) => Promise<import("./helpers/response").ApiResponse<any>>;
};
search: {
getCollections: (a: search.SearchParams, additionalFetchOptions?: Pick<RequestInit, "body" | "cache" | "credentials" | "headers" | "integrity" | "keepalive" | "mode" | "redirect" | "referrer" | "referrerPolicy" | "signal" | "window"> | undefined) => Promise<import("./helpers/response").ApiResponse<any>>;
getPhotos: (a: {
query: string;
} & Pick<import("./types/request").PaginationParams, "page" | "perPage"> & import("./types/request").OrientationParam & {
orderBy?: "relevant" | "latest" | undefined;
color?: "white" | "black" | "yellow" | "orange" | "red" | "purple" | "magenta" | "green" | "teal" | "blue" | "black_and_white" | undefined;
lang?: import("./methods/search/types").Language | undefined;
contentFilter?: "high" | "low" | undefined;
collectionIds?: string[] | undefined;
}, additionalFetchOptions?: Pick<RequestInit, "body" | "cache" | "credentials" | "headers" | "integrity" | "keepalive" | "mode" | "redirect" | "referrer" | "referrerPolicy" | "signal" | "window"> | undefined) => Promise<import("./helpers/response").ApiResponse<any>>;
getUsers: (a: search.SearchParams, additionalFetchOptions?: Pick<RequestInit, "body" | "cache" | "credentials" | "headers" | "integrity" | "keepalive" | "mode" | "redirect" | "referrer" | "referrerPolicy" | "signal" | "window"> | undefined) => Promise<import("./helpers/response").ApiResponse<any>>;
};
collections: {
getPhotos: (a: {
collectionId: string;
} & import("./types/request").PaginationParams & import("./types/request").OrientationParam, additionalFetchOptions?: Pick<RequestInit, "body" | "cache" | "credentials" | "headers" | "integrity" | "keepalive" | "mode" | "redirect" | "referrer" | "referrerPolicy" | "signal" | "window"> | undefined) => Promise<import("./helpers/response").ApiResponse<{
results: any[];
total: number;
}>>;
get: (a: {
collectionId: string;
}, additionalFetchOptions?: Pick<RequestInit, "body" | "cache" | "credentials" | "headers" | "integrity" | "keepalive" | "mode" | "redirect" | "referrer" | "referrerPolicy" | "signal" | "window"> | undefined) => Promise<import("./helpers/response").ApiResponse<any>>;
list: (a: Pick<import("./types/request").PaginationParams, "page" | "perPage"> | undefined, additionalFetchOptions?: Pick<RequestInit, "body" | "cache" | "credentials" | "headers" | "integrity" | "keepalive" | "mode" | "redirect" | "referrer" | "referrerPolicy" | "signal" | "window"> | undefined) => Promise<import("./helpers/response").ApiResponse<{
results: any[];
total: number;
}>>;
getRelated: (a: {
collectionId: string;
}, additionalFetchOptions?: Pick<RequestInit, "body" | "cache" | "credentials" | "headers" | "integrity" | "keepalive" | "mode" | "redirect" | "referrer" | "referrerPolicy" | "signal" | "window"> | undefined) => Promise<import("./helpers/response").ApiResponse<any>>;
};
};
'use strict'
if (process.env.NODE_ENV === 'production') {
module.exports = require('./unsplash-js.cjs.production.min.js')
} else {
module.exports = require('./unsplash-js.cjs.development.js')
}
import { OrientationParam, PaginationParams } from '../../types/request';
declare type CollectionId = {
collectionId: string;
};
export declare const getPhotos: {
handleRequest: (a: CollectionId & PaginationParams & OrientationParam, additionalFetchOptions?: Pick<RequestInit, "headers" | "body" | "cache" | "credentials" | "integrity" | "keepalive" | "mode" | "redirect" | "referrer" | "referrerPolicy" | "signal" | "window"> | undefined) => import("../../helpers/request").CompleteRequestParams;
handleResponse: import("../../helpers/response").HandleResponse<{
results: any[];
total: number;
}>;
};
export declare const get: {
handleRequest: (a: CollectionId, additionalFetchOptions?: Pick<RequestInit, "headers" | "body" | "cache" | "credentials" | "integrity" | "keepalive" | "mode" | "redirect" | "referrer" | "referrerPolicy" | "signal" | "window"> | undefined) => import("../../helpers/request").CompleteRequestParams;
handleResponse: import("../../helpers/response").HandleResponse<any>;
};
export declare const list: {
handleRequest: (a?: Pick<PaginationParams, "page" | "perPage"> | undefined, additionalFetchOptions?: Pick<RequestInit, "headers" | "body" | "cache" | "credentials" | "integrity" | "keepalive" | "mode" | "redirect" | "referrer" | "referrerPolicy" | "signal" | "window"> | undefined) => import("../../helpers/request").CompleteRequestParams;
handleResponse: import("../../helpers/response").HandleResponse<{
results: any[];
total: number;
}>;
};
export declare const getRelated: {
handleRequest: (a: CollectionId, additionalFetchOptions?: Pick<RequestInit, "headers" | "body" | "cache" | "credentials" | "integrity" | "keepalive" | "mode" | "redirect" | "referrer" | "referrerPolicy" | "signal" | "window"> | undefined) => import("../../helpers/request").CompleteRequestParams;
handleResponse: import("../../helpers/response").HandleResponse<any>;
};
export {};
import { OrientationParam, PaginationParams } from '../../types/request';
declare type PhotoId = {
photoId: string;
};
export declare const list: {
handleRequest: (a?: PaginationParams | undefined, additionalFetchOptions?: Pick<RequestInit, "headers" | "body" | "cache" | "credentials" | "integrity" | "keepalive" | "mode" | "redirect" | "referrer" | "referrerPolicy" | "signal" | "window"> | undefined) => import("../../helpers/request").CompleteRequestParams;
handleResponse: import("../../helpers/response").HandleResponse<{
results: any[];
total: number;
}>;
};
export declare const get: {
handleRequest: (a: PhotoId, additionalFetchOptions?: Pick<RequestInit, "headers" | "body" | "cache" | "credentials" | "integrity" | "keepalive" | "mode" | "redirect" | "referrer" | "referrerPolicy" | "signal" | "window"> | undefined) => import("../../helpers/request").CompleteRequestParams;
handleResponse: import("../../helpers/response").HandleResponse<any>;
};
export declare const getStats: {
handleRequest: (a: PhotoId, additionalFetchOptions?: Pick<RequestInit, "headers" | "body" | "cache" | "credentials" | "integrity" | "keepalive" | "mode" | "redirect" | "referrer" | "referrerPolicy" | "signal" | "window"> | undefined) => import("../../helpers/request").CompleteRequestParams;
handleResponse: import("../../helpers/response").HandleResponse<any>;
};
export declare const getRandom: {
handleRequest: (a?: ({
collectionIds?: string[] | undefined;
featured?: boolean | undefined;
username?: string | undefined;
query?: string | undefined;
count?: number | undefined;
} & OrientationParam) | undefined, additionalFetchOptions?: Pick<RequestInit, "headers" | "body" | "cache" | "credentials" | "integrity" | "keepalive" | "mode" | "redirect" | "referrer" | "referrerPolicy" | "signal" | "window"> | undefined) => import("../../helpers/request").CompleteRequestParams;
handleResponse: import("../../helpers/response").HandleResponse<any>;
};
export declare const trackDownload: {
handleRequest: (a: {
downloadLocation: string;
}, additionalFetchOptions?: Pick<RequestInit, "headers" | "body" | "cache" | "credentials" | "integrity" | "keepalive" | "mode" | "redirect" | "referrer" | "referrerPolicy" | "signal" | "window"> | undefined) => import("../../helpers/request").CompleteRequestParams;
handleResponse: import("../../helpers/response").HandleResponse<any>;
};
export {};
import { OrientationParam, PaginationParams } from '../../types/request';
import { ColorId, ContentFilter, Language, SearchOrderBy } from './types';
export declare type SearchParams = {
query: string;
} & Pick<PaginationParams, 'page' | 'perPage'>;
declare type SearchPhotosParams = SearchParams & OrientationParam & {
/**
* API defaults to `"relevant"` if no value is provided
*/
orderBy?: SearchOrderBy;
color?: ColorId;
/**
* API defaults to `en` (English) if no value is provided
*/
lang?: Language;
/**
* API defaults to `"low"` if no value is provided
*/
contentFilter?: ContentFilter;
collectionIds?: string[];
};
export declare const getPhotos: {
handleRequest: (a: SearchPhotosParams, additionalFetchOptions?: Pick<RequestInit, "headers" | "body" | "cache" | "credentials" | "integrity" | "keepalive" | "mode" | "redirect" | "referrer" | "referrerPolicy" | "signal" | "window"> | undefined) => import("../../helpers/request").CompleteRequestParams;
handleResponse: import("../../helpers/response").HandleResponse<any>;
};
export declare const getCollections: {
handleRequest: (a: SearchParams, additionalFetchOptions?: Pick<RequestInit, "headers" | "body" | "cache" | "credentials" | "integrity" | "keepalive" | "mode" | "redirect" | "referrer" | "referrerPolicy" | "signal" | "window"> | undefined) => import("../../helpers/request").CompleteRequestParams;
handleResponse: import("../../helpers/response").HandleResponse<any>;
};
export declare const getUsers: {
handleRequest: (a: SearchParams, additionalFetchOptions?: Pick<RequestInit, "headers" | "body" | "cache" | "credentials" | "integrity" | "keepalive" | "mode" | "redirect" | "referrer" | "referrerPolicy" | "signal" | "window"> | undefined) => import("../../helpers/request").CompleteRequestParams;
handleResponse: import("../../helpers/response").HandleResponse<any>;
};
export {};
export declare type SearchOrderBy = 'relevant' | 'latest';
export declare type ColorId = 'white' | 'black' | 'yellow' | 'orange' | 'red' | 'purple' | 'magenta' | 'green' | 'teal' | 'blue' | 'black_and_white';
export declare type ContentFilter = 'high' | 'low';
export declare enum Language {
Afrikaans = "af",
Amharic = "am",
Arabic = "ar",
Azerbaijani = "az",
Belarusian = "be",
Bulgarian = "bg",
Bengali = "bn",
Bosnian = "bs",
Catalan = "ca",
Cebuano = "ceb",
Corsican = "co",
Czech = "cs",
Welsh = "cy",
Danish = "da",
German = "de",
Greek = "el",
English = "en",
Esperanto = "eo",
Spanish = "es",
Estonian = "et",
Basque = "eu",
Persian = "fa",
Finnish = "fi",
French = "fr",
Frisian = "fy",
Irish = "ga",
ScotsGaelic = "gd",
Galician = "gl",
Gujarati = "gu",
Hausa = "ha",
Hawaiian = "haw",
Hindi = "hi",
Hmong = "hmn",
Croatian = "hr",
HaitianCreole = "ht",
Hungarian = "hu",
Armenian = "hy",
Indonesian = "id",
Igbo = "ig",
Icelandic = "is",
Italian = "it",
Hebrew = "iw",
Japanese = "ja",
Javanese = "jw",
Georgian = "ka",
Kazakh = "kk",
Khmer = "km",
Kannada = "kn",
Korean = "ko",
Kurdish = "ku",
Kyrgyz = "ky",
Latin = "la",
Luxembourgish = "lb",
Lao = "lo",
Lithuanian = "lt",
Latvian = "lv",
Malagasy = "mg",
Maori = "mi",
Macedonian = "mk",
Malayalam = "ml",
Mongolian = "mn",
Marathi = "mr",
Malay = "ms",
Maltese = "mt",
Myanmar = "my",
Nepali = "ne",
Dutch = "nl",
Norwegian = "no",
Nyanja = "ny",
Oriya = "or",
Punjabi = "pa",
Polish = "pl",
Pashto = "ps",
Portuguese = "pt",
Romanian = "ro",
Russian = "ru",
Kinyarwanda = "rw",
Sindhi = "sd",
Sinhala = "si",
Slovak = "sk",
Slovenian = "sl",
Samoan = "sm",
Shona = "sn",
Somali = "so",
Albanian = "sq",
Serbian = "sr",
Sesotho = "st",
Sundanese = "su",
Swedish = "sv",
Swahili = "sw",
Tamil = "ta",
Telugu = "te",
Tajik = "tg",
Thai = "th",
Turkmen = "tk",
Filipino = "tl",
Turkish = "tr",
Tatar = "tt",
Uighur = "ug",
Ukrainian = "uk",
Urdu = "ur",
Uzbek = "uz",
Vietnamese = "vi",
Xhosa = "xh",
Yiddish = "yi",
Yoruba = "yo",
ChineseSimplified = "zh",
ChineseTraditional = "zh-TW",
Zulu = "zu"
}
import { OrientationParam, PaginationParams } from '../../types/request';
declare type UserName = {
username: string;
};
export declare const get: {
handleRequest: (a: UserName, additionalFetchOptions?: Pick<RequestInit, "headers" | "body" | "cache" | "credentials" | "integrity" | "keepalive" | "mode" | "redirect" | "referrer" | "referrerPolicy" | "signal" | "window"> | undefined) => import("../../helpers/request").CompleteRequestParams;
handleResponse: import("../../helpers/response").HandleResponse<any>;
};
export declare const getPhotos: {
handleRequest: (a: {
stats?: boolean | undefined;
} & OrientationParam & UserName & PaginationParams, additionalFetchOptions?: Pick<RequestInit, "headers" | "body" | "cache" | "credentials" | "integrity" | "keepalive" | "mode" | "redirect" | "referrer" | "referrerPolicy" | "signal" | "window"> | undefined) => import("../../helpers/request").CompleteRequestParams;
handleResponse: import("../../helpers/response").HandleResponse<{
results: any[];
total: number;
}>;
};
export declare const getLikes: {
handleRequest: (a: OrientationParam & UserName & PaginationParams, additionalFetchOptions?: Pick<RequestInit, "headers" | "body" | "cache" | "credentials" | "integrity" | "keepalive" | "mode" | "redirect" | "referrer" | "referrerPolicy" | "signal" | "window"> | undefined) => import("../../helpers/request").CompleteRequestParams;
handleResponse: import("../../helpers/response").HandleResponse<{
results: any[];
total: number;
}>;
};
export declare const getCollections: {
handleRequest: (a: UserName & PaginationParams, additionalFetchOptions?: Pick<RequestInit, "headers" | "body" | "cache" | "credentials" | "integrity" | "keepalive" | "mode" | "redirect" | "referrer" | "referrerPolicy" | "signal" | "window"> | undefined) => import("../../helpers/request").CompleteRequestParams;
handleResponse: import("../../helpers/response").HandleResponse<{
results: any[];
total: number;
}>;
};
export {};
export declare enum OrderBy {
LATEST = "latest",
POPULAR = "popular",
OLDEST = "oldest"
}
declare type Orientation = 'landscape' | 'portrait' | 'squarish';
export declare type OrientationParam = {
orientation?: Orientation;
};
export declare type PaginationParams = {
/**
* API defaults to `10` if no value is provided
*/
perPage?: number;
/**
* API defaults to `1` if no value is provided
*/
page?: number;
/**
* API defaults to `"latest"` if no value is provided
*/
orderBy?: OrderBy;
};
export {};
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
var ContentTypeHelpers = require('content-type');
function _extends() {
_extends = Object.assign || function (target) {
for (var i = 1; i < arguments.length; i++) {
var source = arguments[i];
for (var key in source) {
if (Object.prototype.hasOwnProperty.call(source, key)) {
target[key] = source[key];
}
}
}
return target;
};
return _extends.apply(this, arguments);
}
function _objectWithoutPropertiesLoose(source, excluded) {
if (source == null) return {};
var target = {};
var sourceKeys = Object.keys(source);
var key, i;
for (i = 0; i < sourceKeys.length; i++) {
key = sourceKeys[i];
if (excluded.indexOf(key) >= 0) continue;
target[key] = source[key];
}
return target;
}
var checkIsString = /*#__PURE__*/getRefinement(function (value) {
return typeof value === 'string' ? value : null;
});
var isDefined = function isDefined(x) {
return x !== null && x !== undefined;
};
function getRefinement(getB) {
return function (a) {
return isDefined(getB(a));
};
}
var checkIsNonEmptyArray = function checkIsNonEmptyArray(a) {
return a.length > 0;
};
/** Takes a dictionary containing nullish values and returns a dictionary of all the defined
* (non-nullish) values.
*/
var compactDefined = function compactDefined(obj) {
return Object.keys(obj).reduce(function (acc, key) {
var _ref;
var value = obj[key];
return _extends({}, acc, isDefined(value) ? (_ref = {}, _ref[key] = value, _ref) : {});
}, {});
};
function flow() {
for (var _len = arguments.length, fns = new Array(_len), _key = 0; _key < _len; _key++) {
fns[_key] = arguments[_key];
}
var len = fns.length - 1;
return function () {
for (var _len2 = arguments.length, x = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
x[_key2] = arguments[_key2];
}
var y = fns[0].apply(this, x);
for (var i = 1; i <= len; i++) {
y = fns[i].call(this, y);
}
return y;
};
}
var checkIsObject = /*#__PURE__*/getRefinement(function (response) {
return isDefined(response) && typeof response === 'object' && !Array.isArray(response) ? response : null;
});
var checkIsErrors = /*#__PURE__*/getRefinement(function (errors) {
return Array.isArray(errors) && errors.every(checkIsString) && checkIsNonEmptyArray(errors) ? errors : null;
});
var checkIsApiError = /*#__PURE__*/getRefinement(function (response) {
return checkIsObject(response) && 'errors' in response && checkIsErrors(response.errors) ? {
errors: response.errors
} : null;
});
var getErrorForBadStatusCode = function getErrorForBadStatusCode(jsonResponse) {
if (checkIsApiError(jsonResponse)) {
return {
errors: jsonResponse.errors,
source: 'api'
};
} else {
return {
errors: ['Responded with a status code outside the 2xx range, and the response body is not recognisable.'],
source: 'decoding'
};
}
};
var DecodingError = function DecodingError(message) {
this.message = message;
};
var CONTENT_TYPE_RESPONSE_HEADER = 'content-type';
var CONTENT_TYPE_JSON = 'application/json';
var checkIsJsonResponse = function checkIsJsonResponse(response) {
var contentTypeHeader = response.headers.get(CONTENT_TYPE_RESPONSE_HEADER);
return isDefined(contentTypeHeader) && ContentTypeHelpers.parse(contentTypeHeader).type === CONTENT_TYPE_JSON;
};
/**
* Note: restrict the type of JSON to `AnyJson` so that `any` doesn't leak downstream.
*/
var getJsonResponse = function getJsonResponse(response) {
if (checkIsJsonResponse(response)) {
return response.json()["catch"](function (_err) {
throw new DecodingError('unable to parse JSON response.');
});
} else {
throw new DecodingError('expected JSON response from server.');
}
};
var handleFetchResponse = function handleFetchResponse(handleResponse) {
return function (response) {
return (response.ok ? handleResponse({
response: response
}).then(function (handledResponse) {
return {
type: 'success',
status: response.status,
response: handledResponse
};
}) : getJsonResponse(response).then(function (jsonResponse) {
return _extends({
type: 'error',
status: response.status
}, getErrorForBadStatusCode(jsonResponse));
}))["catch"](function (error) {
/**
* We want to separate expected decoding errors from unknown ones. We do so by throwing a custom
* `DecodingError` whenever we encounter one within `handleFetchResponse` and catch them all
* here. This allows us to easily handle all of these errors at once. Unexpected errors are not
* caught, so that they bubble up and fail loudly.
*
* Note: Ideally we'd use an Either type, but this does the job without introducing dependencies
* like `fp-ts`.
*/
if (error instanceof DecodingError) {
return {
type: 'error',
source: 'decoding',
status: response.status,
errors: [error.message]
};
} else {
throw error;
}
});
};
};
var castResponse = function castResponse() {
return function (_ref) {
var response = _ref.response;
return getJsonResponse(response);
};
};
var addQueryToUrl = function addQueryToUrl(query) {
return function (url) {
Object.keys(query).forEach(function (queryKey) {
return url.searchParams.set(queryKey, query[queryKey].toString());
});
};
};
var buildUrl = function buildUrl(_ref) {
var pathname = _ref.pathname,
query = _ref.query;
return function (apiBaseUrl) {
var url = new URL(pathname, apiBaseUrl);
addQueryToUrl(query)(url);
return url.toString();
};
};
var parseQueryAndPathname = function parseQueryAndPathname(url) {
var _URL = new URL(url),
pathname = _URL.pathname,
searchParams = _URL.searchParams;
var query = {};
searchParams.forEach(function (value, key) {
query[key] = value;
});
return {
query: query,
pathname: pathname === '/' ? undefined : pathname
};
};
/**
* helper used to type-check the arguments, and add default params for all requests
*/
var createRequestHandler = function createRequestHandler(fn) {
return function (a, additionalFetchOptions) {
if (additionalFetchOptions === void 0) {
additionalFetchOptions = {};
}
var _fn = fn(a),
headers = _fn.headers,
query = _fn.query,
baseReqParams = _objectWithoutPropertiesLoose(_fn, ["headers", "query"]);
return _extends({}, baseReqParams, additionalFetchOptions, {
query: query,
headers: _extends({}, headers, additionalFetchOptions.headers)
});
};
};
/**
* Variant of `createRequestHandler` used when the args object is entirely optional.
* We cannot combine this with `createRequestHandler` because it is impossible to make the function
* parameter conditionally nullable or non-nullable.
*/
var createRequestHandlerOptional = function createRequestHandlerOptional(fn) {
return createRequestHandler(fn);
};
var initMakeRequest = function initMakeRequest(_ref) {
var accessKey = _ref.accessKey,
_ref$apiVersion = _ref.apiVersion,
apiVersion = _ref$apiVersion === void 0 ? 'v1' : _ref$apiVersion,
_ref$apiUrl = _ref.apiUrl,
apiUrl = _ref$apiUrl === void 0 ? 'https://api.unsplash.com' : _ref$apiUrl,
generalHeaders = _ref.headers,
generalFetchOptions = _objectWithoutPropertiesLoose(_ref, ["accessKey", "apiVersion", "apiUrl", "headers"]);
return function (_ref2) {
var handleResponse = _ref2.handleResponse,
handleRequest = _ref2.handleRequest;
return flow(handleRequest, function (_ref3) {
var pathname = _ref3.pathname,
query = _ref3.query,
_ref3$method = _ref3.method,
method = _ref3$method === void 0 ? 'GET' : _ref3$method,
endpointHeaders = _ref3.headers,
body = _ref3.body,
signal = _ref3.signal;
var url = buildUrl({
pathname: pathname,
query: query
})(apiUrl);
var fetchOptions = _extends({
method: method,
headers: _extends({}, generalHeaders, endpointHeaders, {
'Accept-Version': apiVersion
}, isDefined(accessKey) ? {
Authorization: "Client-ID " + accessKey
} : {}),
body: body,
signal: signal
}, generalFetchOptions);
return fetch(url, fetchOptions).then(handleFetchResponse(handleResponse));
});
};
};
var TOTAL_RESPONSE_HEADER = 'x-total';
var getTotalFromApiFeedResponse = function getTotalFromApiFeedResponse(response) {
var totalsStr = response.headers.get(TOTAL_RESPONSE_HEADER);
if (isDefined(totalsStr)) {
var total = parseInt(totalsStr);
if (Number.isInteger(total)) {
return total;
} else {
throw new DecodingError("expected " + TOTAL_RESPONSE_HEADER + " header to be valid integer.");
}
} else {
throw new DecodingError("expected " + TOTAL_RESPONSE_HEADER + " header to exist.");
}
};
var handleFeedResponse = function handleFeedResponse() {
return function (_ref) {
var response = _ref.response;
return castResponse()({
response: response
}).then(function (results) {
return {
results: results,
total: getTotalFromApiFeedResponse(response)
};
});
};
};
var getCollections = function getCollections(collectionIds) {
return isDefined(collectionIds) ? {
collections: collectionIds.join()
} : {};
};
var getFeedParams = function getFeedParams(_ref) {
var page = _ref.page,
perPage = _ref.perPage,
orderBy = _ref.orderBy;
return compactDefined({
per_page: perPage,
order_by: orderBy,
page: page
});
};
var COLLECTIONS_PATH_PREFIX = '/collections';
var getPhotos = {
handleRequest: /*#__PURE__*/createRequestHandler(function (_ref) {
var collectionId = _ref.collectionId,
orientation = _ref.orientation,
paginationParams = _objectWithoutPropertiesLoose(_ref, ["collectionId", "orientation"]);
return {
pathname: COLLECTIONS_PATH_PREFIX + "/" + collectionId + "/photos",
query: compactDefined(_extends({}, getFeedParams(paginationParams), {
orientation: orientation
}))
};
}),
handleResponse: /*#__PURE__*/handleFeedResponse()
};
var get = {
handleRequest: /*#__PURE__*/createRequestHandler(function (_ref2) {
var collectionId = _ref2.collectionId;
return {
pathname: COLLECTIONS_PATH_PREFIX + "/" + collectionId,
query: {}
};
}),
handleResponse: /*#__PURE__*/castResponse()
};
var list = {
handleRequest: /*#__PURE__*/createRequestHandlerOptional(function (paginationParams) {
if (paginationParams === void 0) {
paginationParams = {};
}
return {
pathname: COLLECTIONS_PATH_PREFIX,
query: getFeedParams(paginationParams)
};
}),
handleResponse: /*#__PURE__*/handleFeedResponse()
};
var getRelated = {
handleRequest: /*#__PURE__*/createRequestHandler(function (_ref3) {
var collectionId = _ref3.collectionId;
return {
pathname: COLLECTIONS_PATH_PREFIX + "/" + collectionId + "/related",
query: {}
};
}),
handleResponse: /*#__PURE__*/castResponse()
};
var PHOTOS_PATH_PREFIX = '/photos';
var list$1 = {
handleRequest: /*#__PURE__*/createRequestHandlerOptional(function (feedParams) {
if (feedParams === void 0) {
feedParams = {};
}
return {
pathname: PHOTOS_PATH_PREFIX,
query: compactDefined(getFeedParams(feedParams))
};
}),
handleResponse: /*#__PURE__*/handleFeedResponse()
};
var get$1 = {
handleRequest: /*#__PURE__*/createRequestHandler(function (_ref) {
var photoId = _ref.photoId;
return {
pathname: PHOTOS_PATH_PREFIX + "/" + photoId,
query: {}
};
}),
handleResponse: /*#__PURE__*/castResponse()
};
var getStats = {
handleRequest: /*#__PURE__*/createRequestHandler(function (_ref2) {
var photoId = _ref2.photoId;
return {
pathname: PHOTOS_PATH_PREFIX + "/" + photoId + "/statistics",
query: {}
};
}),
handleResponse: /*#__PURE__*/castResponse()
};
var getRandom = {
handleRequest: /*#__PURE__*/createRequestHandlerOptional(function (_temp) {
var _ref3 = _temp === void 0 ? {} : _temp,
collectionIds = _ref3.collectionIds,
queryParams = _objectWithoutPropertiesLoose(_ref3, ["collectionIds"]);
return {
pathname: PHOTOS_PATH_PREFIX + "/random",
query: compactDefined(_extends({}, queryParams, getCollections(collectionIds))),
headers: {
/**
* Avoid response caching
*/
'cache-control': 'no-cache'
}
};
}),
handleResponse: /*#__PURE__*/castResponse()
};
var trackDownload = {
handleRequest: /*#__PURE__*/createRequestHandler(function (_ref4) {
var downloadLocation = _ref4.downloadLocation;
var _parseQueryAndPathnam = parseQueryAndPathname(downloadLocation),
pathname = _parseQueryAndPathnam.pathname,
query = _parseQueryAndPathnam.query;
if (!isDefined(pathname)) {
throw new Error('Could not parse pathname from url.');
}
return {
pathname: pathname,
query: compactDefined(query)
};
}),
handleResponse: /*#__PURE__*/castResponse()
};
var SEARCH_PATH_PREFIX = "/search";
var getPhotos$1 = {
handleRequest: /*#__PURE__*/createRequestHandler(function (_ref) {
var query = _ref.query,
page = _ref.page,
perPage = _ref.perPage,
orderBy = _ref.orderBy,
collectionIds = _ref.collectionIds,
lang = _ref.lang,
contentFilter = _ref.contentFilter,
filters = _objectWithoutPropertiesLoose(_ref, ["query", "page", "perPage", "orderBy", "collectionIds", "lang", "contentFilter"]);
return {
pathname: SEARCH_PATH_PREFIX + "/photos",
query: compactDefined(_extends({
query: query,
content_filter: contentFilter,
lang: lang,
order_by: orderBy
}, getFeedParams({
page: page,
perPage: perPage
}), getCollections(collectionIds), filters))
};
}),
handleResponse: /*#__PURE__*/castResponse()
};
var getCollections$1 = {
handleRequest: /*#__PURE__*/createRequestHandler(function (_ref2) {
var query = _ref2.query,
paginationParams = _objectWithoutPropertiesLoose(_ref2, ["query"]);
return {
pathname: SEARCH_PATH_PREFIX + "/collections",
query: _extends({
query: query
}, getFeedParams(paginationParams))
};
}),
handleResponse: /*#__PURE__*/castResponse()
};
var getUsers = {
handleRequest: /*#__PURE__*/createRequestHandler(function (_ref3) {
var query = _ref3.query,
paginationParams = _objectWithoutPropertiesLoose(_ref3, ["query"]);
return {
pathname: SEARCH_PATH_PREFIX + "/users",
query: _extends({
query: query
}, getFeedParams(paginationParams))
};
}),
handleResponse: /*#__PURE__*/castResponse()
};
var USERS_PATH_PREFIX = '/users';
var get$2 = {
handleRequest: /*#__PURE__*/createRequestHandler(function (_ref) {
var username = _ref.username;
return {
pathname: USERS_PATH_PREFIX + "/" + username,
query: {}
};
}),
handleResponse: /*#__PURE__*/castResponse()
};
var getPhotos$2 = {
handleRequest: /*#__PURE__*/createRequestHandler(function (_ref2) {
var username = _ref2.username,
stats = _ref2.stats,
orientation = _ref2.orientation,
paginationParams = _objectWithoutPropertiesLoose(_ref2, ["username", "stats", "orientation"]);
return {
pathname: USERS_PATH_PREFIX + "/" + username + "/photos",
query: compactDefined(_extends({}, getFeedParams(paginationParams), {
orientation: orientation,
stats: stats
}))
};
}),
handleResponse: /*#__PURE__*/handleFeedResponse()
};
var getLikes = {
handleRequest: /*#__PURE__*/createRequestHandler(function (_ref3) {
var username = _ref3.username,
orientation = _ref3.orientation,
paginationParams = _objectWithoutPropertiesLoose(_ref3, ["username", "orientation"]);
return {
pathname: USERS_PATH_PREFIX + "/" + username + "/likes",
query: compactDefined(_extends({}, getFeedParams(paginationParams), {
orientation: orientation
}))
};
}),
handleResponse: /*#__PURE__*/handleFeedResponse()
};
var getCollections$2 = {
handleRequest: /*#__PURE__*/createRequestHandler(function (_ref4) {
var username = _ref4.username,
paginationParams = _objectWithoutPropertiesLoose(_ref4, ["username"]);
return {
pathname: USERS_PATH_PREFIX + "/" + username + "/collections",
query: getFeedParams(paginationParams)
};
}),
handleResponse: /*#__PURE__*/handleFeedResponse()
};
var createApi = /*#__PURE__*/flow(initMakeRequest, function (makeRequest) {
return {
photos: {
get: makeRequest(get$1),
list: makeRequest(list$1),
getStats: makeRequest(getStats),
getRandom: makeRequest(getRandom),
trackDownload: makeRequest(trackDownload)
},
users: {
getPhotos: makeRequest(getPhotos$2),
getCollections: makeRequest(getCollections$2),
getLikes: makeRequest(getLikes),
get: makeRequest(get$2)
},
search: {
getCollections: makeRequest(getCollections$1),
getPhotos: makeRequest(getPhotos$1),
getUsers: makeRequest(getUsers)
},
collections: {
getPhotos: makeRequest(getPhotos),
get: makeRequest(get),
list: makeRequest(list),
getRelated: makeRequest(getRelated)
}
};
});
exports.createApi = createApi;
//# sourceMappingURL=unsplash-js.cjs.development.js.map
{"version":3,"file":"unsplash-js.cjs.development.js","sources":["../src/helpers/typescript.ts","../src/helpers/fp.ts","../src/helpers/errors.ts","../src/helpers/json.ts","../src/helpers/response.ts","../src/helpers/url.ts","../src/helpers/request.ts","../src/helpers/feed.ts","../src/helpers/query.ts","../src/methods/collections/index.ts","../src/methods/photos/index.ts","../src/methods/search/index.ts","../src/methods/users/index.ts","../src/index.ts"],"sourcesContent":["// Copied from https://github.com/Microsoft/TypeScript/issues/1897#issuecomment-338650717\nexport type AnyJson = boolean | number | string | null | JsonArray | JsonMap;\nexport type JsonMap = { [key: string]: AnyJson };\nexport type JsonArray = Array<AnyJson>;\n\nexport const checkIsString = getRefinement(\n (value: unknown): Nullable<string> => (typeof value === 'string' ? value : null),\n);\n\n/**\n * https://github.com/Microsoft/TypeScript/issues/12215#issuecomment-377567046\n */\nexport type OmitStrict<T, K extends keyof T> = Omit<T, K>;\n\n/**\n * Unlike TypeScript's `NonNullable`, this does _not_ include `undefined`\n */\nexport type Nullable<T> = T | null;\n\nexport const isDefined = <T>(x: T | null | undefined): x is T => x !== null && x !== undefined;\n\nexport type NonEmptyArray<T> = [T, ...T[]];\n\ntype Refinement<A, B extends A> = (a: A) => a is B;\nexport function getRefinement<A, B extends A>(getB: (a: A) => Nullable<B>): Refinement<A, B> {\n return (a: A): a is B => isDefined(getB(a));\n}\n\nexport const checkIsNonEmptyArray = <T>(a: T[]): a is NonEmptyArray<T> => a.length > 0;\n","import { isDefined } from './typescript';\n\n/** Takes a dictionary containing nullish values and returns a dictionary of all the defined\n * (non-nullish) values.\n */\nexport const compactDefined = <A>(obj: Record<string, A | null | undefined>) =>\n Object.keys(obj).reduce<Record<string, A>>((acc, key) => {\n const value = obj[key];\n return {\n ...acc,\n ...(isDefined(value) ? { [key]: value } : {}),\n };\n }, {});\n\n/**\n * copied from `fp-ts`\n * https://github.com/gcanti/fp-ts/blob/70190b5a03ddc2d31b4708c75c6dfad81d0bfa21/perf/function/flow.t¡s\n */\nexport function flow<A extends Array<unknown>, B>(ab: (...a: A) => B): (...a: A) => B;\nexport function flow<A extends Array<unknown>, B, C>(\n ab: (...a: A) => B,\n bc: (b: B) => C,\n): (...a: A) => C;\nexport function flow<A extends Array<unknown>, B, C, D>(\n ab: (...a: A) => B,\n bc: (b: B) => C,\n cd: (b: C) => D,\n): (...a: A) => D;\nexport function flow(...fns: Array<Function>): Function {\n const len = fns.length - 1;\n return function(this: any, ...x: Array<any>) {\n let y = fns[0].apply(this, x);\n for (let i = 1; i <= len; i++) {\n y = fns[i].call(this, y);\n }\n return y;\n };\n}\n","import {\n AnyJson,\n checkIsString,\n getRefinement,\n isDefined,\n checkIsNonEmptyArray,\n JsonMap,\n NonEmptyArray,\n Nullable,\n} from './typescript';\n\nexport type Errors = NonEmptyArray<string>;\nexport type ErrorSource = 'api' | 'decoding';\n\nconst checkIsObject = getRefinement(\n (response: AnyJson): Nullable<JsonMap> =>\n isDefined(response) && typeof response === 'object' && !Array.isArray(response)\n ? response\n : null,\n);\n\nconst checkIsErrors = getRefinement(\n (errors: AnyJson): Nullable<Errors> =>\n Array.isArray(errors) && errors.every(checkIsString) && checkIsNonEmptyArray(errors)\n ? errors\n : null,\n);\n\nconst checkIsApiError = getRefinement(\n (response: AnyJson): Nullable<{ errors: Errors }> =>\n checkIsObject(response) && 'errors' in response && checkIsErrors(response.errors)\n ? { errors: response.errors }\n : null,\n);\n\nexport const getErrorForBadStatusCode = (\n jsonResponse: AnyJson,\n): { errors: Errors; source: ErrorSource } => {\n if (checkIsApiError(jsonResponse)) {\n return { errors: jsonResponse.errors, source: 'api' };\n } else {\n return {\n errors: [\n 'Responded with a status code outside the 2xx range, and the response body is not recognisable.',\n ],\n source: 'decoding',\n };\n }\n};\n\nexport class DecodingError {\n constructor(readonly message: string) {}\n}\n","import * as ContentTypeHelpers from 'content-type';\nimport { DecodingError } from './errors';\nimport { AnyJson, isDefined } from './typescript';\n\nconst CONTENT_TYPE_RESPONSE_HEADER = 'content-type';\nconst CONTENT_TYPE_JSON = 'application/json';\nconst checkIsJsonResponse = (response: Response) => {\n const contentTypeHeader = response.headers.get(CONTENT_TYPE_RESPONSE_HEADER);\n\n return (\n isDefined(contentTypeHeader) &&\n ContentTypeHelpers.parse(contentTypeHeader).type === CONTENT_TYPE_JSON\n );\n};\n\n/**\n * Note: restrict the type of JSON to `AnyJson` so that `any` doesn't leak downstream.\n */\nexport const getJsonResponse = (response: Response): Promise<AnyJson> => {\n if (checkIsJsonResponse(response)) {\n return response.json().catch(_err => {\n throw new DecodingError('unable to parse JSON response.');\n });\n } else {\n throw new DecodingError('expected JSON response from server.');\n }\n};\n","import { Errors, ErrorSource, getErrorForBadStatusCode, DecodingError } from './errors';\nimport { getJsonResponse } from './json';\n\nexport type ApiResponse<T> =\n | {\n type: 'success';\n response: T;\n errors?: never;\n status: number;\n }\n | {\n type: 'error';\n source: ErrorSource;\n response?: never;\n errors: Errors;\n status: number;\n };\n\nexport type HandleResponse<T> = (args: { response: Response }) => Promise<T>;\n\nexport const handleFetchResponse = <ResponseType>(handleResponse: HandleResponse<ResponseType>) => (\n response: Response,\n): Promise<ApiResponse<ResponseType>> =>\n (response.ok\n ? handleResponse({ response }).then(\n (handledResponse): ApiResponse<ResponseType> => ({\n type: 'success',\n status: response.status,\n response: handledResponse,\n }),\n )\n : getJsonResponse(response).then(\n (jsonResponse): ApiResponse<ResponseType> => ({\n type: 'error',\n status: response.status,\n ...getErrorForBadStatusCode(jsonResponse),\n }),\n )\n ).catch(error => {\n /**\n * We want to separate expected decoding errors from unknown ones. We do so by throwing a custom\n * `DecodingError` whenever we encounter one within `handleFetchResponse` and catch them all\n * here. This allows us to easily handle all of these errors at once. Unexpected errors are not\n * caught, so that they bubble up and fail loudly.\n *\n * Note: Ideally we'd use an Either type, but this does the job without introducing dependencies\n * like `fp-ts`.\n */\n if (error instanceof DecodingError) {\n return {\n type: 'error',\n source: 'decoding',\n status: response.status,\n errors: [error.message],\n };\n } else {\n throw error;\n }\n });\n\nexport const castResponse = <T>(): HandleResponse<T> => ({ response }) =>\n (getJsonResponse(response) as unknown) as Promise<T>;\n","type Query = {\n [index: string]: string | number | boolean;\n};\n\nexport type BuildUrlParams = {\n pathname: string;\n query: Query;\n};\n\nconst addQueryToUrl = (query: Query) => (url: URL) => {\n Object.keys(query).forEach(queryKey =>\n url.searchParams.set(queryKey, query[queryKey].toString()),\n );\n};\n\nexport const buildUrl = ({ pathname, query }: BuildUrlParams) => (apiBaseUrl: string) => {\n const url = new URL(pathname, apiBaseUrl);\n addQueryToUrl(query)(url);\n return url.toString();\n};\n\nexport const parseQueryAndPathname = (url: string) => {\n const { pathname, searchParams } = new URL(url);\n\n const query: Query = {};\n\n searchParams.forEach((value, key) => {\n query[key] = value;\n });\n\n return { query, pathname: pathname === '/' ? undefined : pathname };\n};\n","import { flow } from './fp';\nimport { ApiResponse, handleFetchResponse, HandleResponse } from './response';\nimport { isDefined, OmitStrict } from './typescript';\nimport { buildUrl, BuildUrlParams } from './url';\n\ntype FetchParams = Pick<RequestInit, 'method'>;\n/**\n * The params generated by the library\n */\ntype BaseRequestParams = BuildUrlParams &\n FetchParams &\n // `headers` is not part of FetchParams because we want to allow headers in the additional params as well\n Pick<RequestInit, 'headers'>;\n\n/**\n * Additional fetch options provided by the user on a per-call basis\n */\ntype AdditionalPerFetchParams = Omit<RequestInit, keyof FetchParams>;\nexport type CompleteRequestParams = BaseRequestParams & AdditionalPerFetchParams;\ntype HandleRequest<Args> = (\n a: Args,\n additionalFetchOptions?: AdditionalPerFetchParams,\n) => CompleteRequestParams;\n\n/**\n * helper used to type-check the arguments, and add default params for all requests\n */\nexport const createRequestHandler = <Args>(\n fn: (a: Args) => BaseRequestParams,\n): HandleRequest<Args> => (a, additionalFetchOptions = {}) => {\n const { headers, query, ...baseReqParams } = fn(a);\n\n return {\n ...baseReqParams,\n ...additionalFetchOptions,\n query,\n headers: {\n ...headers,\n ...additionalFetchOptions.headers,\n },\n };\n};\n\n/**\n * Variant of `createRequestHandler` used when the args object is entirely optional.\n * We cannot combine this with `createRequestHandler` because it is impossible to make the function\n * parameter conditionally nullable or non-nullable.\n */\nexport const createRequestHandlerOptional = <Args>(\n fn: (a?: Args) => BaseRequestParams,\n): ((a?: Args, additionalFetchOptions?: AdditionalPerFetchParams) => CompleteRequestParams) =>\n createRequestHandler(fn);\n\n/**\n * Initial parameters that apply to all calls\n */\ntype InitParams = {\n apiVersion?: string;\n} & OmitStrict<RequestInit, 'method' | 'body'> &\n ({ accessKey: string; apiUrl?: never } | { apiUrl: string; accessKey?: never });\n\ntype RequestGenerator<Args, ResponseType> = {\n handleRequest: HandleRequest<Args>;\n handleResponse: HandleResponse<ResponseType>;\n};\n\ntype GeneratedRequestFunction<Args, ResponseType> = (\n ...a: Parameters<HandleRequest<Args>>\n) => Promise<ApiResponse<ResponseType>>;\n\ntype InitMakeRequest = (\n args: InitParams,\n) => <Args, ResponseType>(\n handlers: RequestGenerator<Args, ResponseType>,\n) => GeneratedRequestFunction<Args, ResponseType>;\n\nexport const initMakeRequest: InitMakeRequest = ({\n accessKey,\n apiVersion = 'v1',\n apiUrl = 'https://api.unsplash.com',\n headers: generalHeaders,\n ...generalFetchOptions\n}) => ({ handleResponse, handleRequest }) =>\n flow(\n handleRequest,\n ({ pathname, query, method = 'GET', headers: endpointHeaders, body, signal }) => {\n const url = buildUrl({ pathname, query })(apiUrl);\n\n const fetchOptions: RequestInit = {\n method,\n headers: {\n ...generalHeaders,\n ...endpointHeaders,\n 'Accept-Version': apiVersion,\n ...(isDefined(accessKey) ? { Authorization: `Client-ID ${accessKey}` } : {}),\n },\n body,\n signal,\n ...generalFetchOptions,\n };\n\n return fetch(url, fetchOptions).then(handleFetchResponse(handleResponse));\n },\n );\n","import { DecodingError } from './errors';\nimport { HandleResponse, castResponse } from './response';\nimport { isDefined } from './typescript';\n\nconst TOTAL_RESPONSE_HEADER = 'x-total';\nconst getTotalFromApiFeedResponse = (response: Response) => {\n const totalsStr = response.headers.get(TOTAL_RESPONSE_HEADER);\n if (isDefined(totalsStr)) {\n const total = parseInt(totalsStr);\n if (Number.isInteger(total)) {\n return total;\n } else {\n throw new DecodingError(`expected ${TOTAL_RESPONSE_HEADER} header to be valid integer.`);\n }\n } else {\n throw new DecodingError(`expected ${TOTAL_RESPONSE_HEADER} header to exist.`);\n }\n};\n\ntype FeedResponse<T> = {\n results: T[];\n total: number;\n};\n\nexport const handleFeedResponse = <T>(): HandleResponse<FeedResponse<T>> => ({ response }) =>\n castResponse<T[]>()({ response }).then(results => ({\n results,\n total: getTotalFromApiFeedResponse(response),\n }));\n","import { PaginationParams } from '../types/request';\nimport { compactDefined } from './fp';\nimport { isDefined } from './typescript';\n\nexport const getCollections = (collectionIds?: string[]) =>\n isDefined(collectionIds) ? { collections: collectionIds.join() } : {};\n\nexport const getFeedParams = ({ page, perPage, orderBy }: PaginationParams) =>\n compactDefined({\n per_page: perPage,\n order_by: orderBy,\n page,\n });\n","import { handleFeedResponse } from '../../helpers/feed';\nimport { compactDefined } from '../../helpers/fp';\nimport * as Query from '../../helpers/query';\nimport { createRequestHandler, createRequestHandlerOptional } from '../../helpers/request';\nimport { castResponse } from '../../helpers/response';\nimport { OrientationParam, PaginationParams } from '../../types/request';\n\ntype CollectionId = {\n collectionId: string;\n};\n\nconst COLLECTIONS_PATH_PREFIX = '/collections';\n\nexport const getPhotos = {\n handleRequest: createRequestHandler(\n ({\n collectionId,\n orientation,\n ...paginationParams\n }: CollectionId & PaginationParams & OrientationParam) => ({\n pathname: `${COLLECTIONS_PATH_PREFIX}/${collectionId}/photos`,\n query: compactDefined({ ...Query.getFeedParams(paginationParams), orientation }),\n }),\n ),\n handleResponse: handleFeedResponse<any>(),\n};\n\nexport const get = {\n handleRequest: createRequestHandler(({ collectionId }: CollectionId) => ({\n pathname: `${COLLECTIONS_PATH_PREFIX}/${collectionId}`,\n query: {},\n })),\n handleResponse: castResponse<any>(),\n};\n\nexport const list = {\n handleRequest: createRequestHandlerOptional(\n (paginationParams: Pick<PaginationParams, 'page' | 'perPage'> = {}) => ({\n pathname: COLLECTIONS_PATH_PREFIX,\n query: Query.getFeedParams(paginationParams),\n }),\n ),\n handleResponse: handleFeedResponse<any>(),\n};\n\nexport const getRelated = {\n handleRequest: createRequestHandler(({ collectionId }: CollectionId) => ({\n pathname: `${COLLECTIONS_PATH_PREFIX}/${collectionId}/related`,\n query: {},\n })),\n handleResponse: castResponse<any>(),\n};\n","import { handleFeedResponse } from '../../helpers/feed';\nimport { compactDefined } from '../../helpers/fp';\nimport * as Query from '../../helpers/query';\nimport { createRequestHandler, createRequestHandlerOptional } from '../../helpers/request';\nimport { castResponse } from '../../helpers/response';\nimport { isDefined } from '../../helpers/typescript';\nimport { parseQueryAndPathname } from '../../helpers/url';\nimport { OrientationParam, PaginationParams } from '../../types/request';\n\ntype PhotoId = {\n photoId: string;\n};\n\nconst PHOTOS_PATH_PREFIX = '/photos';\n\nexport const list = {\n handleRequest: createRequestHandlerOptional((feedParams: PaginationParams = {}) => ({\n pathname: PHOTOS_PATH_PREFIX,\n query: compactDefined(Query.getFeedParams(feedParams)),\n })),\n handleResponse: handleFeedResponse<any>(),\n};\n\nexport const get = {\n handleRequest: createRequestHandler(({ photoId }: PhotoId) => ({\n pathname: `${PHOTOS_PATH_PREFIX}/${photoId}`,\n query: {},\n })),\n handleResponse: castResponse<any>(),\n};\n\nexport const getStats = {\n handleRequest: createRequestHandler(({ photoId }: PhotoId) => ({\n pathname: `${PHOTOS_PATH_PREFIX}/${photoId}/statistics`,\n query: {},\n })),\n handleResponse: castResponse<any>(),\n};\n\nexport const getRandom = {\n handleRequest: createRequestHandlerOptional(\n ({\n collectionIds,\n ...queryParams\n }: {\n collectionIds?: string[];\n featured?: boolean;\n username?: string;\n query?: string;\n count?: number;\n } & OrientationParam = {}) => ({\n pathname: `${PHOTOS_PATH_PREFIX}/random`,\n query: compactDefined({\n ...queryParams,\n ...Query.getCollections(collectionIds),\n }),\n headers: {\n /**\n * Avoid response caching\n */\n 'cache-control': 'no-cache',\n },\n }),\n ),\n handleResponse: castResponse<any>(),\n};\n\nexport const trackDownload = {\n handleRequest: createRequestHandler(({ downloadLocation }: { downloadLocation: string }) => {\n const { pathname, query } = parseQueryAndPathname(downloadLocation);\n\n if (!isDefined(pathname)) {\n throw new Error('Could not parse pathname from url.');\n }\n return { pathname, query: compactDefined(query) };\n }),\n handleResponse: castResponse<any>(),\n};\n","import { compactDefined } from '../../helpers/fp';\nimport * as Query from '../../helpers/query';\nimport { createRequestHandler } from '../../helpers/request';\nimport { castResponse } from '../../helpers/response';\nimport { OrientationParam, PaginationParams } from '../../types/request';\nimport { ColorId, ContentFilter, Language, SearchOrderBy } from './types';\n\nexport type SearchParams = {\n query: string;\n} & Pick<PaginationParams, 'page' | 'perPage'>;\n\nconst SEARCH_PATH_PREFIX = `/search`;\n\ntype SearchPhotosParams = SearchParams &\n OrientationParam & {\n /**\n * API defaults to `\"relevant\"` if no value is provided\n */\n orderBy?: SearchOrderBy;\n color?: ColorId;\n /**\n * API defaults to `en` (English) if no value is provided\n */\n lang?: Language;\n /**\n * API defaults to `\"low\"` if no value is provided\n */\n contentFilter?: ContentFilter;\n collectionIds?: string[];\n };\n\nexport const getPhotos = {\n handleRequest: createRequestHandler(\n ({\n query,\n page,\n perPage,\n orderBy,\n collectionIds,\n lang,\n contentFilter,\n ...filters\n }: SearchPhotosParams) => ({\n pathname: `${SEARCH_PATH_PREFIX}/photos`,\n query: compactDefined({\n query,\n content_filter: contentFilter,\n lang,\n order_by: orderBy,\n ...Query.getFeedParams({ page, perPage }),\n ...Query.getCollections(collectionIds),\n ...filters,\n }),\n }),\n ),\n handleResponse: castResponse<any>(),\n};\n\nexport const getCollections = {\n handleRequest: createRequestHandler(({ query, ...paginationParams }: SearchParams) => ({\n pathname: `${SEARCH_PATH_PREFIX}/collections`,\n query: { query, ...Query.getFeedParams(paginationParams) },\n })),\n handleResponse: castResponse<any>(),\n};\n\nexport const getUsers = {\n handleRequest: createRequestHandler(({ query, ...paginationParams }: SearchParams) => ({\n pathname: `${SEARCH_PATH_PREFIX}/users`,\n query: { query, ...Query.getFeedParams(paginationParams) },\n })),\n handleResponse: castResponse<any>(),\n};\n","import { handleFeedResponse } from '../../helpers/feed';\nimport { compactDefined } from '../../helpers/fp';\nimport * as Query from '../../helpers/query';\nimport { createRequestHandler } from '../../helpers/request';\nimport { castResponse } from '../../helpers/response';\nimport { OrientationParam, PaginationParams } from '../../types/request';\n\ntype UserName = {\n username: string;\n};\n\nconst USERS_PATH_PREFIX = '/users';\n\nexport const get = {\n handleRequest: createRequestHandler(({ username }: UserName) => ({\n pathname: `${USERS_PATH_PREFIX}/${username}`,\n query: {},\n })),\n handleResponse: castResponse<any>(),\n};\n\nexport const getPhotos = {\n handleRequest: createRequestHandler(\n ({\n username,\n stats,\n orientation,\n ...paginationParams\n }: {\n stats?: boolean;\n } & OrientationParam &\n UserName &\n PaginationParams) => ({\n pathname: `${USERS_PATH_PREFIX}/${username}/photos`,\n query: compactDefined({\n ...Query.getFeedParams(paginationParams),\n orientation,\n stats,\n }),\n }),\n ),\n handleResponse: handleFeedResponse<any>(),\n};\n\nexport const getLikes = {\n handleRequest: createRequestHandler(\n ({\n username,\n orientation,\n ...paginationParams\n }: OrientationParam & UserName & PaginationParams) => ({\n pathname: `${USERS_PATH_PREFIX}/${username}/likes`,\n query: compactDefined({\n ...Query.getFeedParams(paginationParams),\n orientation,\n }),\n }),\n ),\n handleResponse: handleFeedResponse<any>(),\n};\nexport const getCollections = {\n handleRequest: createRequestHandler(\n ({ username, ...paginationParams }: UserName & PaginationParams) => ({\n pathname: `${USERS_PATH_PREFIX}/${username}/collections`,\n query: Query.getFeedParams(paginationParams),\n }),\n ),\n handleResponse: handleFeedResponse<any>(),\n};\n","import { flow } from './helpers/fp';\nimport { initMakeRequest } from './helpers/request';\nimport * as collections from './methods/collections';\nimport * as photos from './methods/photos';\nimport * as search from './methods/search';\nimport * as users from './methods/users';\n\nexport const createApi = flow(initMakeRequest, makeRequest => ({\n photos: {\n get: makeRequest(photos.get),\n list: makeRequest(photos.list),\n getStats: makeRequest(photos.getStats),\n getRandom: makeRequest(photos.getRandom),\n trackDownload: makeRequest(photos.trackDownload),\n },\n users: {\n getPhotos: makeRequest(users.getPhotos),\n getCollections: makeRequest(users.getCollections),\n getLikes: makeRequest(users.getLikes),\n get: makeRequest(users.get),\n },\n search: {\n getCollections: makeRequest(search.getCollections),\n getPhotos: makeRequest(search.getPhotos),\n getUsers: makeRequest(search.getUsers),\n },\n collections: {\n getPhotos: makeRequest(collections.getPhotos),\n get: makeRequest(collections.get),\n list: makeRequest(collections.list),\n getRelated: makeRequest(collections.getRelated),\n },\n}));\n"],"names":["checkIsString","getRefinement","value","isDefined","x","undefined","getB","a","checkIsNonEmptyArray","length","compactDefined","obj","Object","keys","reduce","acc","key","flow","fns","len","y","apply","i","call","checkIsObject","response","Array","isArray","checkIsErrors","errors","every","checkIsApiError","getErrorForBadStatusCode","jsonResponse","source","DecodingError","message","CONTENT_TYPE_RESPONSE_HEADER","CONTENT_TYPE_JSON","checkIsJsonResponse","contentTypeHeader","headers","get","ContentTypeHelpers","type","getJsonResponse","json","_err","handleFetchResponse","handleResponse","ok","then","handledResponse","status","error","castResponse","addQueryToUrl","query","url","forEach","queryKey","searchParams","set","toString","buildUrl","pathname","apiBaseUrl","URL","parseQueryAndPathname","createRequestHandler","fn","additionalFetchOptions","baseReqParams","createRequestHandlerOptional","initMakeRequest","accessKey","apiVersion","apiUrl","generalHeaders","generalFetchOptions","handleRequest","method","endpointHeaders","body","signal","fetchOptions","Authorization","fetch","TOTAL_RESPONSE_HEADER","getTotalFromApiFeedResponse","totalsStr","total","parseInt","Number","isInteger","handleFeedResponse","results","getCollections","collectionIds","collections","join","getFeedParams","page","perPage","orderBy","per_page","order_by","COLLECTIONS_PATH_PREFIX","getPhotos","collectionId","orientation","paginationParams","Query","list","getRelated","PHOTOS_PATH_PREFIX","feedParams","photoId","getStats","getRandom","queryParams","trackDownload","downloadLocation","Error","SEARCH_PATH_PREFIX","lang","contentFilter","filters","content_filter","getUsers","USERS_PATH_PREFIX","username","stats","getLikes","createApi","makeRequest","photos","users","search"],"mappings":"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"}
"use strict";Object.defineProperty(exports,"__esModule",{value:!0});var e=require("content-type");function n(){return(n=Object.assign||function(e){for(var n=1;n<arguments.length;n++){var t=arguments[n];for(var r in t)Object.prototype.hasOwnProperty.call(t,r)&&(e[r]=t[r])}return e}).apply(this,arguments)}function t(e,n){if(null==e)return{};var t,r,o={},a=Object.keys(e);for(r=0;r<a.length;r++)n.indexOf(t=a[r])>=0||(o[t]=e[t]);return o}var r=a((function(e){return"string"==typeof e?e:null})),o=function(e){return null!=e};function a(e){return function(n){return o(e(n))}}var s=function(e){return Object.keys(e).reduce((function(t,r){var a,s=e[r];return n({},t,o(s)?((a={})[r]=s,a):{})}),{})};function u(){for(var e=arguments.length,n=new Array(e),t=0;t<e;t++)n[t]=arguments[t];var r=n.length-1;return function(){for(var e=arguments.length,t=new Array(e),o=0;o<e;o++)t[o]=arguments[o];for(var a=n[0].apply(this,t),s=1;s<=r;s++)a=n[s].call(this,a);return a}}var i=a((function(e){return o(e)&&"object"==typeof e&&!Array.isArray(e)?e:null})),c=a((function(e){return Array.isArray(e)&&e.every(r)&&e.length>0?e:null})),l=a((function(e){return i(e)&&"errors"in e&&c(e.errors)?{errors:e.errors}:null})),h=function(e){this.message=e},p=function(n){if(function(n){var t=n.headers.get("content-type");return o(t)&&"application/json"===e.parse(t).type}(n))return n.json().catch((function(e){throw new h("unable to parse JSON response.")}));throw new h("expected JSON response from server.")},d=function(){return function(e){return p(e.response)}},f=function(e){return function(r,o){void 0===o&&(o={});var a=e(r),s=a.headers,u=a.query;return n({},t(a,["headers","query"]),o,{query:u,headers:n({},s,o.headers)})}},y=function(e){return f(e)},q=function(e){var r=e.accessKey,a=e.apiVersion,s=void 0===a?"v1":a,i=e.apiUrl,c=void 0===i?"https://api.unsplash.com":i,d=e.headers,f=t(e,["accessKey","apiVersion","apiUrl","headers"]);return function(e){var t=e.handleResponse;return u(e.handleRequest,(function(e){var a=e.method,u=void 0===a?"GET":a,i=e.headers,y=e.body,q=e.signal,g=function(e){var n=e.pathname,t=e.query;return function(e){var r=new URL(n,e);return function(e){return function(n){Object.keys(e).forEach((function(t){return n.searchParams.set(t,e[t].toString())}))}}(t)(r),r.toString()}}({pathname:e.pathname,query:e.query})(c),v=n({method:u,headers:n({},d,i,{"Accept-Version":s},o(r)?{Authorization:"Client-ID "+r}:{}),body:y,signal:q},f);return fetch(g,v).then(function(e){return function(t){return(t.ok?e({response:t}).then((function(e){return{type:"success",status:t.status,response:e}})):p(t).then((function(e){return n({type:"error",status:t.status},function(e){return l(e)?{errors:e.errors,source:"api"}:{errors:["Responded with a status code outside the 2xx range, and the response body is not recognisable."],source:"decoding"}}(e))}))).catch((function(e){if(e instanceof h)return{type:"error",source:"decoding",status:t.status,errors:[e.message]};throw e}))}}(t))}))}},g=function(e){var n=e.headers.get("x-total");if(o(n)){var t=parseInt(n);if(Number.isInteger(t))return t;throw new h("expected x-total header to be valid integer.")}throw new h("expected x-total header to exist.")},v=function(){return function(e){var n=e.response;return d()({response:n}).then((function(e){return{results:e,total:g(n)}}))}},m=function(e){return o(e)?{collections:e.join()}:{}},R=function(e){return s({per_page:e.perPage,order_by:e.orderBy,page:e.page})},w={handleRequest:f((function(e){var r=e.collectionId,o=e.orientation,a=t(e,["collectionId","orientation"]);return{pathname:"/collections/"+r+"/photos",query:s(n({},R(a),{orientation:o}))}})),handleResponse:v()},b={handleRequest:f((function(e){return{pathname:"/collections/"+e.collectionId,query:{}}})),handleResponse:d()},I={handleRequest:y((function(e){return void 0===e&&(e={}),{pathname:"/collections",query:R(e)}})),handleResponse:v()},x={handleRequest:f((function(e){return{pathname:"/collections/"+e.collectionId+"/related",query:{}}})),handleResponse:d()},P={handleRequest:y((function(e){return void 0===e&&(e={}),{pathname:"/photos",query:s(R(e))}})),handleResponse:v()},j={handleRequest:f((function(e){return{pathname:"/photos/"+e.photoId,query:{}}})),handleResponse:d()},O={handleRequest:f((function(e){return{pathname:"/photos/"+e.photoId+"/statistics",query:{}}})),handleResponse:d()},A={handleRequest:y((function(e){var r=void 0===e?{}:e,o=r.collectionIds,a=t(r,["collectionIds"]);return{pathname:"/photos/random",query:s(n({},a,m(o))),headers:{"cache-control":"no-cache"}}})),handleResponse:d()},k={handleRequest:f((function(e){var n=function(e){var n=new URL(e),t=n.pathname,r={};return n.searchParams.forEach((function(e,n){r[n]=e})),{query:r,pathname:"/"===t?void 0:t}}(e.downloadLocation),t=n.pathname,r=n.query;if(!o(t))throw new Error("Could not parse pathname from url.");return{pathname:t,query:s(r)}})),handleResponse:d()},_={handleRequest:f((function(e){var r=e.query,o=e.page,a=e.perPage,u=e.orderBy,i=e.collectionIds,c=e.lang,l=e.contentFilter,h=t(e,["query","page","perPage","orderBy","collectionIds","lang","contentFilter"]);return{pathname:"/search/photos",query:s(n({query:r,content_filter:l,lang:c,order_by:u},R({page:o,perPage:a}),m(i),h))}})),handleResponse:d()},S={handleRequest:f((function(e){var r=e.query,o=t(e,["query"]);return{pathname:"/search/collections",query:n({query:r},R(o))}})),handleResponse:d()},U={handleRequest:f((function(e){var r=e.query,o=t(e,["query"]);return{pathname:"/search/users",query:n({query:r},R(o))}})),handleResponse:d()},C={handleRequest:f((function(e){return{pathname:"/users/"+e.username,query:{}}})),handleResponse:d()},E={handleRequest:f((function(e){var r=e.username,o=e.stats,a=e.orientation,u=t(e,["username","stats","orientation"]);return{pathname:"/users/"+r+"/photos",query:s(n({},R(u),{orientation:a,stats:o}))}})),handleResponse:v()},L={handleRequest:f((function(e){var r=e.username,o=e.orientation,a=t(e,["username","orientation"]);return{pathname:"/users/"+r+"/likes",query:s(n({},R(a),{orientation:o}))}})),handleResponse:v()},B={handleRequest:f((function(e){var n=e.username,r=t(e,["username"]);return{pathname:"/users/"+n+"/collections",query:R(r)}})),handleResponse:v()};exports.createApi=u(q,(function(e){return{photos:{get:e(j),list:e(P),getStats:e(O),getRandom:e(A),trackDownload:e(k)},users:{getPhotos:e(E),getCollections:e(B),getLikes:e(L),get:e(C)},search:{getCollections:e(S),getPhotos:e(_),getUsers:e(U)},collections:{getPhotos:e(w),get:e(b),list:e(I),getRelated:e(x)}}}));
//# sourceMappingURL=unsplash-js.cjs.production.min.js.map
{"version":3,"file":"unsplash-js.cjs.production.min.js","sources":["../src/helpers/typescript.ts","../src/helpers/fp.ts","../src/helpers/errors.ts","../src/helpers/json.ts","../src/helpers/response.ts","../src/helpers/request.ts","../src/helpers/url.ts","../src/helpers/feed.ts","../src/helpers/query.ts","../src/methods/collections/index.ts","../src/methods/photos/index.ts","../src/methods/search/index.ts","../src/methods/users/index.ts","../src/index.ts"],"sourcesContent":["// Copied from https://github.com/Microsoft/TypeScript/issues/1897#issuecomment-338650717\nexport type AnyJson = boolean | number | string | null | JsonArray | JsonMap;\nexport type JsonMap = { [key: string]: AnyJson };\nexport type JsonArray = Array<AnyJson>;\n\nexport const checkIsString = getRefinement(\n (value: unknown): Nullable<string> => (typeof value === 'string' ? value : null),\n);\n\n/**\n * https://github.com/Microsoft/TypeScript/issues/12215#issuecomment-377567046\n */\nexport type OmitStrict<T, K extends keyof T> = Omit<T, K>;\n\n/**\n * Unlike TypeScript's `NonNullable`, this does _not_ include `undefined`\n */\nexport type Nullable<T> = T | null;\n\nexport const isDefined = <T>(x: T | null | undefined): x is T => x !== null && x !== undefined;\n\nexport type NonEmptyArray<T> = [T, ...T[]];\n\ntype Refinement<A, B extends A> = (a: A) => a is B;\nexport function getRefinement<A, B extends A>(getB: (a: A) => Nullable<B>): Refinement<A, B> {\n return (a: A): a is B => isDefined(getB(a));\n}\n\nexport const checkIsNonEmptyArray = <T>(a: T[]): a is NonEmptyArray<T> => a.length > 0;\n","import { isDefined } from './typescript';\n\n/** Takes a dictionary containing nullish values and returns a dictionary of all the defined\n * (non-nullish) values.\n */\nexport const compactDefined = <A>(obj: Record<string, A | null | undefined>) =>\n Object.keys(obj).reduce<Record<string, A>>((acc, key) => {\n const value = obj[key];\n return {\n ...acc,\n ...(isDefined(value) ? { [key]: value } : {}),\n };\n }, {});\n\n/**\n * copied from `fp-ts`\n * https://github.com/gcanti/fp-ts/blob/70190b5a03ddc2d31b4708c75c6dfad81d0bfa21/perf/function/flow.t¡s\n */\nexport function flow<A extends Array<unknown>, B>(ab: (...a: A) => B): (...a: A) => B;\nexport function flow<A extends Array<unknown>, B, C>(\n ab: (...a: A) => B,\n bc: (b: B) => C,\n): (...a: A) => C;\nexport function flow<A extends Array<unknown>, B, C, D>(\n ab: (...a: A) => B,\n bc: (b: B) => C,\n cd: (b: C) => D,\n): (...a: A) => D;\nexport function flow(...fns: Array<Function>): Function {\n const len = fns.length - 1;\n return function(this: any, ...x: Array<any>) {\n let y = fns[0].apply(this, x);\n for (let i = 1; i <= len; i++) {\n y = fns[i].call(this, y);\n }\n return y;\n };\n}\n","import {\n AnyJson,\n checkIsString,\n getRefinement,\n isDefined,\n checkIsNonEmptyArray,\n JsonMap,\n NonEmptyArray,\n Nullable,\n} from './typescript';\n\nexport type Errors = NonEmptyArray<string>;\nexport type ErrorSource = 'api' | 'decoding';\n\nconst checkIsObject = getRefinement(\n (response: AnyJson): Nullable<JsonMap> =>\n isDefined(response) && typeof response === 'object' && !Array.isArray(response)\n ? response\n : null,\n);\n\nconst checkIsErrors = getRefinement(\n (errors: AnyJson): Nullable<Errors> =>\n Array.isArray(errors) && errors.every(checkIsString) && checkIsNonEmptyArray(errors)\n ? errors\n : null,\n);\n\nconst checkIsApiError = getRefinement(\n (response: AnyJson): Nullable<{ errors: Errors }> =>\n checkIsObject(response) && 'errors' in response && checkIsErrors(response.errors)\n ? { errors: response.errors }\n : null,\n);\n\nexport const getErrorForBadStatusCode = (\n jsonResponse: AnyJson,\n): { errors: Errors; source: ErrorSource } => {\n if (checkIsApiError(jsonResponse)) {\n return { errors: jsonResponse.errors, source: 'api' };\n } else {\n return {\n errors: [\n 'Responded with a status code outside the 2xx range, and the response body is not recognisable.',\n ],\n source: 'decoding',\n };\n }\n};\n\nexport class DecodingError {\n constructor(readonly message: string) {}\n}\n","import * as ContentTypeHelpers from 'content-type';\nimport { DecodingError } from './errors';\nimport { AnyJson, isDefined } from './typescript';\n\nconst CONTENT_TYPE_RESPONSE_HEADER = 'content-type';\nconst CONTENT_TYPE_JSON = 'application/json';\nconst checkIsJsonResponse = (response: Response) => {\n const contentTypeHeader = response.headers.get(CONTENT_TYPE_RESPONSE_HEADER);\n\n return (\n isDefined(contentTypeHeader) &&\n ContentTypeHelpers.parse(contentTypeHeader).type === CONTENT_TYPE_JSON\n );\n};\n\n/**\n * Note: restrict the type of JSON to `AnyJson` so that `any` doesn't leak downstream.\n */\nexport const getJsonResponse = (response: Response): Promise<AnyJson> => {\n if (checkIsJsonResponse(response)) {\n return response.json().catch(_err => {\n throw new DecodingError('unable to parse JSON response.');\n });\n } else {\n throw new DecodingError('expected JSON response from server.');\n }\n};\n","import { Errors, ErrorSource, getErrorForBadStatusCode, DecodingError } from './errors';\nimport { getJsonResponse } from './json';\n\nexport type ApiResponse<T> =\n | {\n type: 'success';\n response: T;\n errors?: never;\n status: number;\n }\n | {\n type: 'error';\n source: ErrorSource;\n response?: never;\n errors: Errors;\n status: number;\n };\n\nexport type HandleResponse<T> = (args: { response: Response }) => Promise<T>;\n\nexport const handleFetchResponse = <ResponseType>(handleResponse: HandleResponse<ResponseType>) => (\n response: Response,\n): Promise<ApiResponse<ResponseType>> =>\n (response.ok\n ? handleResponse({ response }).then(\n (handledResponse): ApiResponse<ResponseType> => ({\n type: 'success',\n status: response.status,\n response: handledResponse,\n }),\n )\n : getJsonResponse(response).then(\n (jsonResponse): ApiResponse<ResponseType> => ({\n type: 'error',\n status: response.status,\n ...getErrorForBadStatusCode(jsonResponse),\n }),\n )\n ).catch(error => {\n /**\n * We want to separate expected decoding errors from unknown ones. We do so by throwing a custom\n * `DecodingError` whenever we encounter one within `handleFetchResponse` and catch them all\n * here. This allows us to easily handle all of these errors at once. Unexpected errors are not\n * caught, so that they bubble up and fail loudly.\n *\n * Note: Ideally we'd use an Either type, but this does the job without introducing dependencies\n * like `fp-ts`.\n */\n if (error instanceof DecodingError) {\n return {\n type: 'error',\n source: 'decoding',\n status: response.status,\n errors: [error.message],\n };\n } else {\n throw error;\n }\n });\n\nexport const castResponse = <T>(): HandleResponse<T> => ({ response }) =>\n (getJsonResponse(response) as unknown) as Promise<T>;\n","import { flow } from './fp';\nimport { ApiResponse, handleFetchResponse, HandleResponse } from './response';\nimport { isDefined, OmitStrict } from './typescript';\nimport { buildUrl, BuildUrlParams } from './url';\n\ntype FetchParams = Pick<RequestInit, 'method'>;\n/**\n * The params generated by the library\n */\ntype BaseRequestParams = BuildUrlParams &\n FetchParams &\n // `headers` is not part of FetchParams because we want to allow headers in the additional params as well\n Pick<RequestInit, 'headers'>;\n\n/**\n * Additional fetch options provided by the user on a per-call basis\n */\ntype AdditionalPerFetchParams = Omit<RequestInit, keyof FetchParams>;\nexport type CompleteRequestParams = BaseRequestParams & AdditionalPerFetchParams;\ntype HandleRequest<Args> = (\n a: Args,\n additionalFetchOptions?: AdditionalPerFetchParams,\n) => CompleteRequestParams;\n\n/**\n * helper used to type-check the arguments, and add default params for all requests\n */\nexport const createRequestHandler = <Args>(\n fn: (a: Args) => BaseRequestParams,\n): HandleRequest<Args> => (a, additionalFetchOptions = {}) => {\n const { headers, query, ...baseReqParams } = fn(a);\n\n return {\n ...baseReqParams,\n ...additionalFetchOptions,\n query,\n headers: {\n ...headers,\n ...additionalFetchOptions.headers,\n },\n };\n};\n\n/**\n * Variant of `createRequestHandler` used when the args object is entirely optional.\n * We cannot combine this with `createRequestHandler` because it is impossible to make the function\n * parameter conditionally nullable or non-nullable.\n */\nexport const createRequestHandlerOptional = <Args>(\n fn: (a?: Args) => BaseRequestParams,\n): ((a?: Args, additionalFetchOptions?: AdditionalPerFetchParams) => CompleteRequestParams) =>\n createRequestHandler(fn);\n\n/**\n * Initial parameters that apply to all calls\n */\ntype InitParams = {\n apiVersion?: string;\n} & OmitStrict<RequestInit, 'method' | 'body'> &\n ({ accessKey: string; apiUrl?: never } | { apiUrl: string; accessKey?: never });\n\ntype RequestGenerator<Args, ResponseType> = {\n handleRequest: HandleRequest<Args>;\n handleResponse: HandleResponse<ResponseType>;\n};\n\ntype GeneratedRequestFunction<Args, ResponseType> = (\n ...a: Parameters<HandleRequest<Args>>\n) => Promise<ApiResponse<ResponseType>>;\n\ntype InitMakeRequest = (\n args: InitParams,\n) => <Args, ResponseType>(\n handlers: RequestGenerator<Args, ResponseType>,\n) => GeneratedRequestFunction<Args, ResponseType>;\n\nexport const initMakeRequest: InitMakeRequest = ({\n accessKey,\n apiVersion = 'v1',\n apiUrl = 'https://api.unsplash.com',\n headers: generalHeaders,\n ...generalFetchOptions\n}) => ({ handleResponse, handleRequest }) =>\n flow(\n handleRequest,\n ({ pathname, query, method = 'GET', headers: endpointHeaders, body, signal }) => {\n const url = buildUrl({ pathname, query })(apiUrl);\n\n const fetchOptions: RequestInit = {\n method,\n headers: {\n ...generalHeaders,\n ...endpointHeaders,\n 'Accept-Version': apiVersion,\n ...(isDefined(accessKey) ? { Authorization: `Client-ID ${accessKey}` } : {}),\n },\n body,\n signal,\n ...generalFetchOptions,\n };\n\n return fetch(url, fetchOptions).then(handleFetchResponse(handleResponse));\n },\n );\n","type Query = {\n [index: string]: string | number | boolean;\n};\n\nexport type BuildUrlParams = {\n pathname: string;\n query: Query;\n};\n\nconst addQueryToUrl = (query: Query) => (url: URL) => {\n Object.keys(query).forEach(queryKey =>\n url.searchParams.set(queryKey, query[queryKey].toString()),\n );\n};\n\nexport const buildUrl = ({ pathname, query }: BuildUrlParams) => (apiBaseUrl: string) => {\n const url = new URL(pathname, apiBaseUrl);\n addQueryToUrl(query)(url);\n return url.toString();\n};\n\nexport const parseQueryAndPathname = (url: string) => {\n const { pathname, searchParams } = new URL(url);\n\n const query: Query = {};\n\n searchParams.forEach((value, key) => {\n query[key] = value;\n });\n\n return { query, pathname: pathname === '/' ? undefined : pathname };\n};\n","import { DecodingError } from './errors';\nimport { HandleResponse, castResponse } from './response';\nimport { isDefined } from './typescript';\n\nconst TOTAL_RESPONSE_HEADER = 'x-total';\nconst getTotalFromApiFeedResponse = (response: Response) => {\n const totalsStr = response.headers.get(TOTAL_RESPONSE_HEADER);\n if (isDefined(totalsStr)) {\n const total = parseInt(totalsStr);\n if (Number.isInteger(total)) {\n return total;\n } else {\n throw new DecodingError(`expected ${TOTAL_RESPONSE_HEADER} header to be valid integer.`);\n }\n } else {\n throw new DecodingError(`expected ${TOTAL_RESPONSE_HEADER} header to exist.`);\n }\n};\n\ntype FeedResponse<T> = {\n results: T[];\n total: number;\n};\n\nexport const handleFeedResponse = <T>(): HandleResponse<FeedResponse<T>> => ({ response }) =>\n castResponse<T[]>()({ response }).then(results => ({\n results,\n total: getTotalFromApiFeedResponse(response),\n }));\n","import { PaginationParams } from '../types/request';\nimport { compactDefined } from './fp';\nimport { isDefined } from './typescript';\n\nexport const getCollections = (collectionIds?: string[]) =>\n isDefined(collectionIds) ? { collections: collectionIds.join() } : {};\n\nexport const getFeedParams = ({ page, perPage, orderBy }: PaginationParams) =>\n compactDefined({\n per_page: perPage,\n order_by: orderBy,\n page,\n });\n","import { handleFeedResponse } from '../../helpers/feed';\nimport { compactDefined } from '../../helpers/fp';\nimport * as Query from '../../helpers/query';\nimport { createRequestHandler, createRequestHandlerOptional } from '../../helpers/request';\nimport { castResponse } from '../../helpers/response';\nimport { OrientationParam, PaginationParams } from '../../types/request';\n\ntype CollectionId = {\n collectionId: string;\n};\n\nconst COLLECTIONS_PATH_PREFIX = '/collections';\n\nexport const getPhotos = {\n handleRequest: createRequestHandler(\n ({\n collectionId,\n orientation,\n ...paginationParams\n }: CollectionId & PaginationParams & OrientationParam) => ({\n pathname: `${COLLECTIONS_PATH_PREFIX}/${collectionId}/photos`,\n query: compactDefined({ ...Query.getFeedParams(paginationParams), orientation }),\n }),\n ),\n handleResponse: handleFeedResponse<any>(),\n};\n\nexport const get = {\n handleRequest: createRequestHandler(({ collectionId }: CollectionId) => ({\n pathname: `${COLLECTIONS_PATH_PREFIX}/${collectionId}`,\n query: {},\n })),\n handleResponse: castResponse<any>(),\n};\n\nexport const list = {\n handleRequest: createRequestHandlerOptional(\n (paginationParams: Pick<PaginationParams, 'page' | 'perPage'> = {}) => ({\n pathname: COLLECTIONS_PATH_PREFIX,\n query: Query.getFeedParams(paginationParams),\n }),\n ),\n handleResponse: handleFeedResponse<any>(),\n};\n\nexport const getRelated = {\n handleRequest: createRequestHandler(({ collectionId }: CollectionId) => ({\n pathname: `${COLLECTIONS_PATH_PREFIX}/${collectionId}/related`,\n query: {},\n })),\n handleResponse: castResponse<any>(),\n};\n","import { handleFeedResponse } from '../../helpers/feed';\nimport { compactDefined } from '../../helpers/fp';\nimport * as Query from '../../helpers/query';\nimport { createRequestHandler, createRequestHandlerOptional } from '../../helpers/request';\nimport { castResponse } from '../../helpers/response';\nimport { isDefined } from '../../helpers/typescript';\nimport { parseQueryAndPathname } from '../../helpers/url';\nimport { OrientationParam, PaginationParams } from '../../types/request';\n\ntype PhotoId = {\n photoId: string;\n};\n\nconst PHOTOS_PATH_PREFIX = '/photos';\n\nexport const list = {\n handleRequest: createRequestHandlerOptional((feedParams: PaginationParams = {}) => ({\n pathname: PHOTOS_PATH_PREFIX,\n query: compactDefined(Query.getFeedParams(feedParams)),\n })),\n handleResponse: handleFeedResponse<any>(),\n};\n\nexport const get = {\n handleRequest: createRequestHandler(({ photoId }: PhotoId) => ({\n pathname: `${PHOTOS_PATH_PREFIX}/${photoId}`,\n query: {},\n })),\n handleResponse: castResponse<any>(),\n};\n\nexport const getStats = {\n handleRequest: createRequestHandler(({ photoId }: PhotoId) => ({\n pathname: `${PHOTOS_PATH_PREFIX}/${photoId}/statistics`,\n query: {},\n })),\n handleResponse: castResponse<any>(),\n};\n\nexport const getRandom = {\n handleRequest: createRequestHandlerOptional(\n ({\n collectionIds,\n ...queryParams\n }: {\n collectionIds?: string[];\n featured?: boolean;\n username?: string;\n query?: string;\n count?: number;\n } & OrientationParam = {}) => ({\n pathname: `${PHOTOS_PATH_PREFIX}/random`,\n query: compactDefined({\n ...queryParams,\n ...Query.getCollections(collectionIds),\n }),\n headers: {\n /**\n * Avoid response caching\n */\n 'cache-control': 'no-cache',\n },\n }),\n ),\n handleResponse: castResponse<any>(),\n};\n\nexport const trackDownload = {\n handleRequest: createRequestHandler(({ downloadLocation }: { downloadLocation: string }) => {\n const { pathname, query } = parseQueryAndPathname(downloadLocation);\n\n if (!isDefined(pathname)) {\n throw new Error('Could not parse pathname from url.');\n }\n return { pathname, query: compactDefined(query) };\n }),\n handleResponse: castResponse<any>(),\n};\n","import { compactDefined } from '../../helpers/fp';\nimport * as Query from '../../helpers/query';\nimport { createRequestHandler } from '../../helpers/request';\nimport { castResponse } from '../../helpers/response';\nimport { OrientationParam, PaginationParams } from '../../types/request';\nimport { ColorId, ContentFilter, Language, SearchOrderBy } from './types';\n\nexport type SearchParams = {\n query: string;\n} & Pick<PaginationParams, 'page' | 'perPage'>;\n\nconst SEARCH_PATH_PREFIX = `/search`;\n\ntype SearchPhotosParams = SearchParams &\n OrientationParam & {\n /**\n * API defaults to `\"relevant\"` if no value is provided\n */\n orderBy?: SearchOrderBy;\n color?: ColorId;\n /**\n * API defaults to `en` (English) if no value is provided\n */\n lang?: Language;\n /**\n * API defaults to `\"low\"` if no value is provided\n */\n contentFilter?: ContentFilter;\n collectionIds?: string[];\n };\n\nexport const getPhotos = {\n handleRequest: createRequestHandler(\n ({\n query,\n page,\n perPage,\n orderBy,\n collectionIds,\n lang,\n contentFilter,\n ...filters\n }: SearchPhotosParams) => ({\n pathname: `${SEARCH_PATH_PREFIX}/photos`,\n query: compactDefined({\n query,\n content_filter: contentFilter,\n lang,\n order_by: orderBy,\n ...Query.getFeedParams({ page, perPage }),\n ...Query.getCollections(collectionIds),\n ...filters,\n }),\n }),\n ),\n handleResponse: castResponse<any>(),\n};\n\nexport const getCollections = {\n handleRequest: createRequestHandler(({ query, ...paginationParams }: SearchParams) => ({\n pathname: `${SEARCH_PATH_PREFIX}/collections`,\n query: { query, ...Query.getFeedParams(paginationParams) },\n })),\n handleResponse: castResponse<any>(),\n};\n\nexport const getUsers = {\n handleRequest: createRequestHandler(({ query, ...paginationParams }: SearchParams) => ({\n pathname: `${SEARCH_PATH_PREFIX}/users`,\n query: { query, ...Query.getFeedParams(paginationParams) },\n })),\n handleResponse: castResponse<any>(),\n};\n","import { handleFeedResponse } from '../../helpers/feed';\nimport { compactDefined } from '../../helpers/fp';\nimport * as Query from '../../helpers/query';\nimport { createRequestHandler } from '../../helpers/request';\nimport { castResponse } from '../../helpers/response';\nimport { OrientationParam, PaginationParams } from '../../types/request';\n\ntype UserName = {\n username: string;\n};\n\nconst USERS_PATH_PREFIX = '/users';\n\nexport const get = {\n handleRequest: createRequestHandler(({ username }: UserName) => ({\n pathname: `${USERS_PATH_PREFIX}/${username}`,\n query: {},\n })),\n handleResponse: castResponse<any>(),\n};\n\nexport const getPhotos = {\n handleRequest: createRequestHandler(\n ({\n username,\n stats,\n orientation,\n ...paginationParams\n }: {\n stats?: boolean;\n } & OrientationParam &\n UserName &\n PaginationParams) => ({\n pathname: `${USERS_PATH_PREFIX}/${username}/photos`,\n query: compactDefined({\n ...Query.getFeedParams(paginationParams),\n orientation,\n stats,\n }),\n }),\n ),\n handleResponse: handleFeedResponse<any>(),\n};\n\nexport const getLikes = {\n handleRequest: createRequestHandler(\n ({\n username,\n orientation,\n ...paginationParams\n }: OrientationParam & UserName & PaginationParams) => ({\n pathname: `${USERS_PATH_PREFIX}/${username}/likes`,\n query: compactDefined({\n ...Query.getFeedParams(paginationParams),\n orientation,\n }),\n }),\n ),\n handleResponse: handleFeedResponse<any>(),\n};\nexport const getCollections = {\n handleRequest: createRequestHandler(\n ({ username, ...paginationParams }: UserName & PaginationParams) => ({\n pathname: `${USERS_PATH_PREFIX}/${username}/collections`,\n query: Query.getFeedParams(paginationParams),\n }),\n ),\n handleResponse: handleFeedResponse<any>(),\n};\n","import { flow } from './helpers/fp';\nimport { initMakeRequest } from './helpers/request';\nimport * as collections from './methods/collections';\nimport * as photos from './methods/photos';\nimport * as search from './methods/search';\nimport * as users from './methods/users';\n\nexport const createApi = flow(initMakeRequest, makeRequest => ({\n photos: {\n get: makeRequest(photos.get),\n list: makeRequest(photos.list),\n getStats: makeRequest(photos.getStats),\n getRandom: makeRequest(photos.getRandom),\n trackDownload: makeRequest(photos.trackDownload),\n },\n users: {\n getPhotos: makeRequest(users.getPhotos),\n getCollections: makeRequest(users.getCollections),\n getLikes: makeRequest(users.getLikes),\n get: makeRequest(users.get),\n },\n search: {\n getCollections: makeRequest(search.getCollections),\n getPhotos: makeRequest(search.getPhotos),\n getUsers: makeRequest(search.getUsers),\n },\n collections: {\n getPhotos: makeRequest(collections.getPhotos),\n get: makeRequest(collections.get),\n list: makeRequest(collections.list),\n getRelated: makeRequest(collections.getRelated),\n },\n}));\n"],"names":["checkIsString","getRefinement","value","isDefined","x","getB","a","compactDefined","obj","Object","keys","reduce","acc","key","flow","fns","len","length","y","apply","this","i","call","checkIsObject","response","Array","isArray","checkIsErrors","errors","every","checkIsApiError","DecodingError","message","getJsonResponse","contentTypeHeader","headers","get","ContentTypeHelpers","type","checkIsJsonResponse","json","_err","castResponse","createRequestHandler","fn","additionalFetchOptions","query","createRequestHandlerOptional","initMakeRequest","accessKey","apiVersion","apiUrl","generalHeaders","generalFetchOptions","handleResponse","handleRequest","method","endpointHeaders","body","signal","url","pathname","apiBaseUrl","URL","forEach","queryKey","searchParams","set","toString","addQueryToUrl","buildUrl","fetchOptions","Authorization","fetch","then","ok","handledResponse","status","jsonResponse","source","getErrorForBadStatusCode","error","handleFetchResponse","getTotalFromApiFeedResponse","totalsStr","total","parseInt","Number","isInteger","handleFeedResponse","results","getCollections","collectionIds","collections","join","getFeedParams","per_page","perPage","order_by","orderBy","page","getPhotos","collectionId","orientation","paginationParams","COLLECTIONS_PATH_PREFIX","Query","list","getRelated","feedParams","PHOTOS_PATH_PREFIX","photoId","getStats","getRandom","queryParams","trackDownload","undefined","parseQueryAndPathname","downloadLocation","Error","lang","contentFilter","filters","SEARCH_PATH_PREFIX","content_filter","getUsers","USERS_PATH_PREFIX","username","stats","getLikes","makeRequest","photos","users","search"],"mappings":"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"}
import { parse } from 'content-type';
function _extends() {
_extends = Object.assign || function (target) {
for (var i = 1; i < arguments.length; i++) {
var source = arguments[i];
for (var key in source) {
if (Object.prototype.hasOwnProperty.call(source, key)) {
target[key] = source[key];
}
}
}
return target;
};
return _extends.apply(this, arguments);
}
function _objectWithoutPropertiesLoose(source, excluded) {
if (source == null) return {};
var target = {};
var sourceKeys = Object.keys(source);
var key, i;
for (i = 0; i < sourceKeys.length; i++) {
key = sourceKeys[i];
if (excluded.indexOf(key) >= 0) continue;
target[key] = source[key];
}
return target;
}
var checkIsString = /*#__PURE__*/getRefinement(function (value) {
return typeof value === 'string' ? value : null;
});
var isDefined = function isDefined(x) {
return x !== null && x !== undefined;
};
function getRefinement(getB) {
return function (a) {
return isDefined(getB(a));
};
}
var checkIsNonEmptyArray = function checkIsNonEmptyArray(a) {
return a.length > 0;
};
/** Takes a dictionary containing nullish values and returns a dictionary of all the defined
* (non-nullish) values.
*/
var compactDefined = function compactDefined(obj) {
return Object.keys(obj).reduce(function (acc, key) {
var _ref;
var value = obj[key];
return _extends({}, acc, isDefined(value) ? (_ref = {}, _ref[key] = value, _ref) : {});
}, {});
};
function flow() {
for (var _len = arguments.length, fns = new Array(_len), _key = 0; _key < _len; _key++) {
fns[_key] = arguments[_key];
}
var len = fns.length - 1;
return function () {
for (var _len2 = arguments.length, x = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
x[_key2] = arguments[_key2];
}
var y = fns[0].apply(this, x);
for (var i = 1; i <= len; i++) {
y = fns[i].call(this, y);
}
return y;
};
}
var checkIsObject = /*#__PURE__*/getRefinement(function (response) {
return isDefined(response) && typeof response === 'object' && !Array.isArray(response) ? response : null;
});
var checkIsErrors = /*#__PURE__*/getRefinement(function (errors) {
return Array.isArray(errors) && errors.every(checkIsString) && checkIsNonEmptyArray(errors) ? errors : null;
});
var checkIsApiError = /*#__PURE__*/getRefinement(function (response) {
return checkIsObject(response) && 'errors' in response && checkIsErrors(response.errors) ? {
errors: response.errors
} : null;
});
var getErrorForBadStatusCode = function getErrorForBadStatusCode(jsonResponse) {
if (checkIsApiError(jsonResponse)) {
return {
errors: jsonResponse.errors,
source: 'api'
};
} else {
return {
errors: ['Responded with a status code outside the 2xx range, and the response body is not recognisable.'],
source: 'decoding'
};
}
};
var DecodingError = function DecodingError(message) {
this.message = message;
};
var CONTENT_TYPE_RESPONSE_HEADER = 'content-type';
var CONTENT_TYPE_JSON = 'application/json';
var checkIsJsonResponse = function checkIsJsonResponse(response) {
var contentTypeHeader = response.headers.get(CONTENT_TYPE_RESPONSE_HEADER);
return isDefined(contentTypeHeader) && parse(contentTypeHeader).type === CONTENT_TYPE_JSON;
};
/**
* Note: restrict the type of JSON to `AnyJson` so that `any` doesn't leak downstream.
*/
var getJsonResponse = function getJsonResponse(response) {
if (checkIsJsonResponse(response)) {
return response.json()["catch"](function (_err) {
throw new DecodingError('unable to parse JSON response.');
});
} else {
throw new DecodingError('expected JSON response from server.');
}
};
var handleFetchResponse = function handleFetchResponse(handleResponse) {
return function (response) {
return (response.ok ? handleResponse({
response: response
}).then(function (handledResponse) {
return {
type: 'success',
status: response.status,
response: handledResponse
};
}) : getJsonResponse(response).then(function (jsonResponse) {
return _extends({
type: 'error',
status: response.status
}, getErrorForBadStatusCode(jsonResponse));
}))["catch"](function (error) {
/**
* We want to separate expected decoding errors from unknown ones. We do so by throwing a custom
* `DecodingError` whenever we encounter one within `handleFetchResponse` and catch them all
* here. This allows us to easily handle all of these errors at once. Unexpected errors are not
* caught, so that they bubble up and fail loudly.
*
* Note: Ideally we'd use an Either type, but this does the job without introducing dependencies
* like `fp-ts`.
*/
if (error instanceof DecodingError) {
return {
type: 'error',
source: 'decoding',
status: response.status,
errors: [error.message]
};
} else {
throw error;
}
});
};
};
var castResponse = function castResponse() {
return function (_ref) {
var response = _ref.response;
return getJsonResponse(response);
};
};
var addQueryToUrl = function addQueryToUrl(query) {
return function (url) {
Object.keys(query).forEach(function (queryKey) {
return url.searchParams.set(queryKey, query[queryKey].toString());
});
};
};
var buildUrl = function buildUrl(_ref) {
var pathname = _ref.pathname,
query = _ref.query;
return function (apiBaseUrl) {
var url = new URL(pathname, apiBaseUrl);
addQueryToUrl(query)(url);
return url.toString();
};
};
var parseQueryAndPathname = function parseQueryAndPathname(url) {
var _URL = new URL(url),
pathname = _URL.pathname,
searchParams = _URL.searchParams;
var query = {};
searchParams.forEach(function (value, key) {
query[key] = value;
});
return {
query: query,
pathname: pathname === '/' ? undefined : pathname
};
};
/**
* helper used to type-check the arguments, and add default params for all requests
*/
var createRequestHandler = function createRequestHandler(fn) {
return function (a, additionalFetchOptions) {
if (additionalFetchOptions === void 0) {
additionalFetchOptions = {};
}
var _fn = fn(a),
headers = _fn.headers,
query = _fn.query,
baseReqParams = _objectWithoutPropertiesLoose(_fn, ["headers", "query"]);
return _extends({}, baseReqParams, additionalFetchOptions, {
query: query,
headers: _extends({}, headers, additionalFetchOptions.headers)
});
};
};
/**
* Variant of `createRequestHandler` used when the args object is entirely optional.
* We cannot combine this with `createRequestHandler` because it is impossible to make the function
* parameter conditionally nullable or non-nullable.
*/
var createRequestHandlerOptional = function createRequestHandlerOptional(fn) {
return createRequestHandler(fn);
};
var initMakeRequest = function initMakeRequest(_ref) {
var accessKey = _ref.accessKey,
_ref$apiVersion = _ref.apiVersion,
apiVersion = _ref$apiVersion === void 0 ? 'v1' : _ref$apiVersion,
_ref$apiUrl = _ref.apiUrl,
apiUrl = _ref$apiUrl === void 0 ? 'https://api.unsplash.com' : _ref$apiUrl,
generalHeaders = _ref.headers,
generalFetchOptions = _objectWithoutPropertiesLoose(_ref, ["accessKey", "apiVersion", "apiUrl", "headers"]);
return function (_ref2) {
var handleResponse = _ref2.handleResponse,
handleRequest = _ref2.handleRequest;
return flow(handleRequest, function (_ref3) {
var pathname = _ref3.pathname,
query = _ref3.query,
_ref3$method = _ref3.method,
method = _ref3$method === void 0 ? 'GET' : _ref3$method,
endpointHeaders = _ref3.headers,
body = _ref3.body,
signal = _ref3.signal;
var url = buildUrl({
pathname: pathname,
query: query
})(apiUrl);
var fetchOptions = _extends({
method: method,
headers: _extends({}, generalHeaders, endpointHeaders, {
'Accept-Version': apiVersion
}, isDefined(accessKey) ? {
Authorization: "Client-ID " + accessKey
} : {}),
body: body,
signal: signal
}, generalFetchOptions);
return fetch(url, fetchOptions).then(handleFetchResponse(handleResponse));
});
};
};
var TOTAL_RESPONSE_HEADER = 'x-total';
var getTotalFromApiFeedResponse = function getTotalFromApiFeedResponse(response) {
var totalsStr = response.headers.get(TOTAL_RESPONSE_HEADER);
if (isDefined(totalsStr)) {
var total = parseInt(totalsStr);
if (Number.isInteger(total)) {
return total;
} else {
throw new DecodingError("expected " + TOTAL_RESPONSE_HEADER + " header to be valid integer.");
}
} else {
throw new DecodingError("expected " + TOTAL_RESPONSE_HEADER + " header to exist.");
}
};
var handleFeedResponse = function handleFeedResponse() {
return function (_ref) {
var response = _ref.response;
return castResponse()({
response: response
}).then(function (results) {
return {
results: results,
total: getTotalFromApiFeedResponse(response)
};
});
};
};
var getCollections = function getCollections(collectionIds) {
return isDefined(collectionIds) ? {
collections: collectionIds.join()
} : {};
};
var getFeedParams = function getFeedParams(_ref) {
var page = _ref.page,
perPage = _ref.perPage,
orderBy = _ref.orderBy;
return compactDefined({
per_page: perPage,
order_by: orderBy,
page: page
});
};
var COLLECTIONS_PATH_PREFIX = '/collections';
var getPhotos = {
handleRequest: /*#__PURE__*/createRequestHandler(function (_ref) {
var collectionId = _ref.collectionId,
orientation = _ref.orientation,
paginationParams = _objectWithoutPropertiesLoose(_ref, ["collectionId", "orientation"]);
return {
pathname: COLLECTIONS_PATH_PREFIX + "/" + collectionId + "/photos",
query: compactDefined(_extends({}, getFeedParams(paginationParams), {
orientation: orientation
}))
};
}),
handleResponse: /*#__PURE__*/handleFeedResponse()
};
var get = {
handleRequest: /*#__PURE__*/createRequestHandler(function (_ref2) {
var collectionId = _ref2.collectionId;
return {
pathname: COLLECTIONS_PATH_PREFIX + "/" + collectionId,
query: {}
};
}),
handleResponse: /*#__PURE__*/castResponse()
};
var list = {
handleRequest: /*#__PURE__*/createRequestHandlerOptional(function (paginationParams) {
if (paginationParams === void 0) {
paginationParams = {};
}
return {
pathname: COLLECTIONS_PATH_PREFIX,
query: getFeedParams(paginationParams)
};
}),
handleResponse: /*#__PURE__*/handleFeedResponse()
};
var getRelated = {
handleRequest: /*#__PURE__*/createRequestHandler(function (_ref3) {
var collectionId = _ref3.collectionId;
return {
pathname: COLLECTIONS_PATH_PREFIX + "/" + collectionId + "/related",
query: {}
};
}),
handleResponse: /*#__PURE__*/castResponse()
};
var PHOTOS_PATH_PREFIX = '/photos';
var list$1 = {
handleRequest: /*#__PURE__*/createRequestHandlerOptional(function (feedParams) {
if (feedParams === void 0) {
feedParams = {};
}
return {
pathname: PHOTOS_PATH_PREFIX,
query: compactDefined(getFeedParams(feedParams))
};
}),
handleResponse: /*#__PURE__*/handleFeedResponse()
};
var get$1 = {
handleRequest: /*#__PURE__*/createRequestHandler(function (_ref) {
var photoId = _ref.photoId;
return {
pathname: PHOTOS_PATH_PREFIX + "/" + photoId,
query: {}
};
}),
handleResponse: /*#__PURE__*/castResponse()
};
var getStats = {
handleRequest: /*#__PURE__*/createRequestHandler(function (_ref2) {
var photoId = _ref2.photoId;
return {
pathname: PHOTOS_PATH_PREFIX + "/" + photoId + "/statistics",
query: {}
};
}),
handleResponse: /*#__PURE__*/castResponse()
};
var getRandom = {
handleRequest: /*#__PURE__*/createRequestHandlerOptional(function (_temp) {
var _ref3 = _temp === void 0 ? {} : _temp,
collectionIds = _ref3.collectionIds,
queryParams = _objectWithoutPropertiesLoose(_ref3, ["collectionIds"]);
return {
pathname: PHOTOS_PATH_PREFIX + "/random",
query: compactDefined(_extends({}, queryParams, getCollections(collectionIds))),
headers: {
/**
* Avoid response caching
*/
'cache-control': 'no-cache'
}
};
}),
handleResponse: /*#__PURE__*/castResponse()
};
var trackDownload = {
handleRequest: /*#__PURE__*/createRequestHandler(function (_ref4) {
var downloadLocation = _ref4.downloadLocation;
var _parseQueryAndPathnam = parseQueryAndPathname(downloadLocation),
pathname = _parseQueryAndPathnam.pathname,
query = _parseQueryAndPathnam.query;
if (!isDefined(pathname)) {
throw new Error('Could not parse pathname from url.');
}
return {
pathname: pathname,
query: compactDefined(query)
};
}),
handleResponse: /*#__PURE__*/castResponse()
};
var SEARCH_PATH_PREFIX = "/search";
var getPhotos$1 = {
handleRequest: /*#__PURE__*/createRequestHandler(function (_ref) {
var query = _ref.query,
page = _ref.page,
perPage = _ref.perPage,
orderBy = _ref.orderBy,
collectionIds = _ref.collectionIds,
lang = _ref.lang,
contentFilter = _ref.contentFilter,
filters = _objectWithoutPropertiesLoose(_ref, ["query", "page", "perPage", "orderBy", "collectionIds", "lang", "contentFilter"]);
return {
pathname: SEARCH_PATH_PREFIX + "/photos",
query: compactDefined(_extends({
query: query,
content_filter: contentFilter,
lang: lang,
order_by: orderBy
}, getFeedParams({
page: page,
perPage: perPage
}), getCollections(collectionIds), filters))
};
}),
handleResponse: /*#__PURE__*/castResponse()
};
var getCollections$1 = {
handleRequest: /*#__PURE__*/createRequestHandler(function (_ref2) {
var query = _ref2.query,
paginationParams = _objectWithoutPropertiesLoose(_ref2, ["query"]);
return {
pathname: SEARCH_PATH_PREFIX + "/collections",
query: _extends({
query: query
}, getFeedParams(paginationParams))
};
}),
handleResponse: /*#__PURE__*/castResponse()
};
var getUsers = {
handleRequest: /*#__PURE__*/createRequestHandler(function (_ref3) {
var query = _ref3.query,
paginationParams = _objectWithoutPropertiesLoose(_ref3, ["query"]);
return {
pathname: SEARCH_PATH_PREFIX + "/users",
query: _extends({
query: query
}, getFeedParams(paginationParams))
};
}),
handleResponse: /*#__PURE__*/castResponse()
};
var USERS_PATH_PREFIX = '/users';
var get$2 = {
handleRequest: /*#__PURE__*/createRequestHandler(function (_ref) {
var username = _ref.username;
return {
pathname: USERS_PATH_PREFIX + "/" + username,
query: {}
};
}),
handleResponse: /*#__PURE__*/castResponse()
};
var getPhotos$2 = {
handleRequest: /*#__PURE__*/createRequestHandler(function (_ref2) {
var username = _ref2.username,
stats = _ref2.stats,
orientation = _ref2.orientation,
paginationParams = _objectWithoutPropertiesLoose(_ref2, ["username", "stats", "orientation"]);
return {
pathname: USERS_PATH_PREFIX + "/" + username + "/photos",
query: compactDefined(_extends({}, getFeedParams(paginationParams), {
orientation: orientation,
stats: stats
}))
};
}),
handleResponse: /*#__PURE__*/handleFeedResponse()
};
var getLikes = {
handleRequest: /*#__PURE__*/createRequestHandler(function (_ref3) {
var username = _ref3.username,
orientation = _ref3.orientation,
paginationParams = _objectWithoutPropertiesLoose(_ref3, ["username", "orientation"]);
return {
pathname: USERS_PATH_PREFIX + "/" + username + "/likes",
query: compactDefined(_extends({}, getFeedParams(paginationParams), {
orientation: orientation
}))
};
}),
handleResponse: /*#__PURE__*/handleFeedResponse()
};
var getCollections$2 = {
handleRequest: /*#__PURE__*/createRequestHandler(function (_ref4) {
var username = _ref4.username,
paginationParams = _objectWithoutPropertiesLoose(_ref4, ["username"]);
return {
pathname: USERS_PATH_PREFIX + "/" + username + "/collections",
query: getFeedParams(paginationParams)
};
}),
handleResponse: /*#__PURE__*/handleFeedResponse()
};
var createApi = /*#__PURE__*/flow(initMakeRequest, function (makeRequest) {
return {
photos: {
get: makeRequest(get$1),
list: makeRequest(list$1),
getStats: makeRequest(getStats),
getRandom: makeRequest(getRandom),
trackDownload: makeRequest(trackDownload)
},
users: {
getPhotos: makeRequest(getPhotos$2),
getCollections: makeRequest(getCollections$2),
getLikes: makeRequest(getLikes),
get: makeRequest(get$2)
},
search: {
getCollections: makeRequest(getCollections$1),
getPhotos: makeRequest(getPhotos$1),
getUsers: makeRequest(getUsers)
},
collections: {
getPhotos: makeRequest(getPhotos),
get: makeRequest(get),
list: makeRequest(list),
getRelated: makeRequest(getRelated)
}
};
});
export { createApi };
//# sourceMappingURL=unsplash-js.esm.js.map
{"version":3,"file":"unsplash-js.esm.js","sources":["../src/helpers/typescript.ts","../src/helpers/fp.ts","../src/helpers/errors.ts","../src/helpers/json.ts","../src/helpers/response.ts","../src/helpers/url.ts","../src/helpers/request.ts","../src/helpers/feed.ts","../src/helpers/query.ts","../src/methods/collections/index.ts","../src/methods/photos/index.ts","../src/methods/search/index.ts","../src/methods/users/index.ts","../src/index.ts"],"sourcesContent":["// Copied from https://github.com/Microsoft/TypeScript/issues/1897#issuecomment-338650717\nexport type AnyJson = boolean | number | string | null | JsonArray | JsonMap;\nexport type JsonMap = { [key: string]: AnyJson };\nexport type JsonArray = Array<AnyJson>;\n\nexport const checkIsString = getRefinement(\n (value: unknown): Nullable<string> => (typeof value === 'string' ? value : null),\n);\n\n/**\n * https://github.com/Microsoft/TypeScript/issues/12215#issuecomment-377567046\n */\nexport type OmitStrict<T, K extends keyof T> = Omit<T, K>;\n\n/**\n * Unlike TypeScript's `NonNullable`, this does _not_ include `undefined`\n */\nexport type Nullable<T> = T | null;\n\nexport const isDefined = <T>(x: T | null | undefined): x is T => x !== null && x !== undefined;\n\nexport type NonEmptyArray<T> = [T, ...T[]];\n\ntype Refinement<A, B extends A> = (a: A) => a is B;\nexport function getRefinement<A, B extends A>(getB: (a: A) => Nullable<B>): Refinement<A, B> {\n return (a: A): a is B => isDefined(getB(a));\n}\n\nexport const checkIsNonEmptyArray = <T>(a: T[]): a is NonEmptyArray<T> => a.length > 0;\n","import { isDefined } from './typescript';\n\n/** Takes a dictionary containing nullish values and returns a dictionary of all the defined\n * (non-nullish) values.\n */\nexport const compactDefined = <A>(obj: Record<string, A | null | undefined>) =>\n Object.keys(obj).reduce<Record<string, A>>((acc, key) => {\n const value = obj[key];\n return {\n ...acc,\n ...(isDefined(value) ? { [key]: value } : {}),\n };\n }, {});\n\n/**\n * copied from `fp-ts`\n * https://github.com/gcanti/fp-ts/blob/70190b5a03ddc2d31b4708c75c6dfad81d0bfa21/perf/function/flow.t¡s\n */\nexport function flow<A extends Array<unknown>, B>(ab: (...a: A) => B): (...a: A) => B;\nexport function flow<A extends Array<unknown>, B, C>(\n ab: (...a: A) => B,\n bc: (b: B) => C,\n): (...a: A) => C;\nexport function flow<A extends Array<unknown>, B, C, D>(\n ab: (...a: A) => B,\n bc: (b: B) => C,\n cd: (b: C) => D,\n): (...a: A) => D;\nexport function flow(...fns: Array<Function>): Function {\n const len = fns.length - 1;\n return function(this: any, ...x: Array<any>) {\n let y = fns[0].apply(this, x);\n for (let i = 1; i <= len; i++) {\n y = fns[i].call(this, y);\n }\n return y;\n };\n}\n","import {\n AnyJson,\n checkIsString,\n getRefinement,\n isDefined,\n checkIsNonEmptyArray,\n JsonMap,\n NonEmptyArray,\n Nullable,\n} from './typescript';\n\nexport type Errors = NonEmptyArray<string>;\nexport type ErrorSource = 'api' | 'decoding';\n\nconst checkIsObject = getRefinement(\n (response: AnyJson): Nullable<JsonMap> =>\n isDefined(response) && typeof response === 'object' && !Array.isArray(response)\n ? response\n : null,\n);\n\nconst checkIsErrors = getRefinement(\n (errors: AnyJson): Nullable<Errors> =>\n Array.isArray(errors) && errors.every(checkIsString) && checkIsNonEmptyArray(errors)\n ? errors\n : null,\n);\n\nconst checkIsApiError = getRefinement(\n (response: AnyJson): Nullable<{ errors: Errors }> =>\n checkIsObject(response) && 'errors' in response && checkIsErrors(response.errors)\n ? { errors: response.errors }\n : null,\n);\n\nexport const getErrorForBadStatusCode = (\n jsonResponse: AnyJson,\n): { errors: Errors; source: ErrorSource } => {\n if (checkIsApiError(jsonResponse)) {\n return { errors: jsonResponse.errors, source: 'api' };\n } else {\n return {\n errors: [\n 'Responded with a status code outside the 2xx range, and the response body is not recognisable.',\n ],\n source: 'decoding',\n };\n }\n};\n\nexport class DecodingError {\n constructor(readonly message: string) {}\n}\n","import * as ContentTypeHelpers from 'content-type';\nimport { DecodingError } from './errors';\nimport { AnyJson, isDefined } from './typescript';\n\nconst CONTENT_TYPE_RESPONSE_HEADER = 'content-type';\nconst CONTENT_TYPE_JSON = 'application/json';\nconst checkIsJsonResponse = (response: Response) => {\n const contentTypeHeader = response.headers.get(CONTENT_TYPE_RESPONSE_HEADER);\n\n return (\n isDefined(contentTypeHeader) &&\n ContentTypeHelpers.parse(contentTypeHeader).type === CONTENT_TYPE_JSON\n );\n};\n\n/**\n * Note: restrict the type of JSON to `AnyJson` so that `any` doesn't leak downstream.\n */\nexport const getJsonResponse = (response: Response): Promise<AnyJson> => {\n if (checkIsJsonResponse(response)) {\n return response.json().catch(_err => {\n throw new DecodingError('unable to parse JSON response.');\n });\n } else {\n throw new DecodingError('expected JSON response from server.');\n }\n};\n","import { Errors, ErrorSource, getErrorForBadStatusCode, DecodingError } from './errors';\nimport { getJsonResponse } from './json';\n\nexport type ApiResponse<T> =\n | {\n type: 'success';\n response: T;\n errors?: never;\n status: number;\n }\n | {\n type: 'error';\n source: ErrorSource;\n response?: never;\n errors: Errors;\n status: number;\n };\n\nexport type HandleResponse<T> = (args: { response: Response }) => Promise<T>;\n\nexport const handleFetchResponse = <ResponseType>(handleResponse: HandleResponse<ResponseType>) => (\n response: Response,\n): Promise<ApiResponse<ResponseType>> =>\n (response.ok\n ? handleResponse({ response }).then(\n (handledResponse): ApiResponse<ResponseType> => ({\n type: 'success',\n status: response.status,\n response: handledResponse,\n }),\n )\n : getJsonResponse(response).then(\n (jsonResponse): ApiResponse<ResponseType> => ({\n type: 'error',\n status: response.status,\n ...getErrorForBadStatusCode(jsonResponse),\n }),\n )\n ).catch(error => {\n /**\n * We want to separate expected decoding errors from unknown ones. We do so by throwing a custom\n * `DecodingError` whenever we encounter one within `handleFetchResponse` and catch them all\n * here. This allows us to easily handle all of these errors at once. Unexpected errors are not\n * caught, so that they bubble up and fail loudly.\n *\n * Note: Ideally we'd use an Either type, but this does the job without introducing dependencies\n * like `fp-ts`.\n */\n if (error instanceof DecodingError) {\n return {\n type: 'error',\n source: 'decoding',\n status: response.status,\n errors: [error.message],\n };\n } else {\n throw error;\n }\n });\n\nexport const castResponse = <T>(): HandleResponse<T> => ({ response }) =>\n (getJsonResponse(response) as unknown) as Promise<T>;\n","type Query = {\n [index: string]: string | number | boolean;\n};\n\nexport type BuildUrlParams = {\n pathname: string;\n query: Query;\n};\n\nconst addQueryToUrl = (query: Query) => (url: URL) => {\n Object.keys(query).forEach(queryKey =>\n url.searchParams.set(queryKey, query[queryKey].toString()),\n );\n};\n\nexport const buildUrl = ({ pathname, query }: BuildUrlParams) => (apiBaseUrl: string) => {\n const url = new URL(pathname, apiBaseUrl);\n addQueryToUrl(query)(url);\n return url.toString();\n};\n\nexport const parseQueryAndPathname = (url: string) => {\n const { pathname, searchParams } = new URL(url);\n\n const query: Query = {};\n\n searchParams.forEach((value, key) => {\n query[key] = value;\n });\n\n return { query, pathname: pathname === '/' ? undefined : pathname };\n};\n","import { flow } from './fp';\nimport { ApiResponse, handleFetchResponse, HandleResponse } from './response';\nimport { isDefined, OmitStrict } from './typescript';\nimport { buildUrl, BuildUrlParams } from './url';\n\ntype FetchParams = Pick<RequestInit, 'method'>;\n/**\n * The params generated by the library\n */\ntype BaseRequestParams = BuildUrlParams &\n FetchParams &\n // `headers` is not part of FetchParams because we want to allow headers in the additional params as well\n Pick<RequestInit, 'headers'>;\n\n/**\n * Additional fetch options provided by the user on a per-call basis\n */\ntype AdditionalPerFetchParams = Omit<RequestInit, keyof FetchParams>;\nexport type CompleteRequestParams = BaseRequestParams & AdditionalPerFetchParams;\ntype HandleRequest<Args> = (\n a: Args,\n additionalFetchOptions?: AdditionalPerFetchParams,\n) => CompleteRequestParams;\n\n/**\n * helper used to type-check the arguments, and add default params for all requests\n */\nexport const createRequestHandler = <Args>(\n fn: (a: Args) => BaseRequestParams,\n): HandleRequest<Args> => (a, additionalFetchOptions = {}) => {\n const { headers, query, ...baseReqParams } = fn(a);\n\n return {\n ...baseReqParams,\n ...additionalFetchOptions,\n query,\n headers: {\n ...headers,\n ...additionalFetchOptions.headers,\n },\n };\n};\n\n/**\n * Variant of `createRequestHandler` used when the args object is entirely optional.\n * We cannot combine this with `createRequestHandler` because it is impossible to make the function\n * parameter conditionally nullable or non-nullable.\n */\nexport const createRequestHandlerOptional = <Args>(\n fn: (a?: Args) => BaseRequestParams,\n): ((a?: Args, additionalFetchOptions?: AdditionalPerFetchParams) => CompleteRequestParams) =>\n createRequestHandler(fn);\n\n/**\n * Initial parameters that apply to all calls\n */\ntype InitParams = {\n apiVersion?: string;\n} & OmitStrict<RequestInit, 'method' | 'body'> &\n ({ accessKey: string; apiUrl?: never } | { apiUrl: string; accessKey?: never });\n\ntype RequestGenerator<Args, ResponseType> = {\n handleRequest: HandleRequest<Args>;\n handleResponse: HandleResponse<ResponseType>;\n};\n\ntype GeneratedRequestFunction<Args, ResponseType> = (\n ...a: Parameters<HandleRequest<Args>>\n) => Promise<ApiResponse<ResponseType>>;\n\ntype InitMakeRequest = (\n args: InitParams,\n) => <Args, ResponseType>(\n handlers: RequestGenerator<Args, ResponseType>,\n) => GeneratedRequestFunction<Args, ResponseType>;\n\nexport const initMakeRequest: InitMakeRequest = ({\n accessKey,\n apiVersion = 'v1',\n apiUrl = 'https://api.unsplash.com',\n headers: generalHeaders,\n ...generalFetchOptions\n}) => ({ handleResponse, handleRequest }) =>\n flow(\n handleRequest,\n ({ pathname, query, method = 'GET', headers: endpointHeaders, body, signal }) => {\n const url = buildUrl({ pathname, query })(apiUrl);\n\n const fetchOptions: RequestInit = {\n method,\n headers: {\n ...generalHeaders,\n ...endpointHeaders,\n 'Accept-Version': apiVersion,\n ...(isDefined(accessKey) ? { Authorization: `Client-ID ${accessKey}` } : {}),\n },\n body,\n signal,\n ...generalFetchOptions,\n };\n\n return fetch(url, fetchOptions).then(handleFetchResponse(handleResponse));\n },\n );\n","import { DecodingError } from './errors';\nimport { HandleResponse, castResponse } from './response';\nimport { isDefined } from './typescript';\n\nconst TOTAL_RESPONSE_HEADER = 'x-total';\nconst getTotalFromApiFeedResponse = (response: Response) => {\n const totalsStr = response.headers.get(TOTAL_RESPONSE_HEADER);\n if (isDefined(totalsStr)) {\n const total = parseInt(totalsStr);\n if (Number.isInteger(total)) {\n return total;\n } else {\n throw new DecodingError(`expected ${TOTAL_RESPONSE_HEADER} header to be valid integer.`);\n }\n } else {\n throw new DecodingError(`expected ${TOTAL_RESPONSE_HEADER} header to exist.`);\n }\n};\n\ntype FeedResponse<T> = {\n results: T[];\n total: number;\n};\n\nexport const handleFeedResponse = <T>(): HandleResponse<FeedResponse<T>> => ({ response }) =>\n castResponse<T[]>()({ response }).then(results => ({\n results,\n total: getTotalFromApiFeedResponse(response),\n }));\n","import { PaginationParams } from '../types/request';\nimport { compactDefined } from './fp';\nimport { isDefined } from './typescript';\n\nexport const getCollections = (collectionIds?: string[]) =>\n isDefined(collectionIds) ? { collections: collectionIds.join() } : {};\n\nexport const getFeedParams = ({ page, perPage, orderBy }: PaginationParams) =>\n compactDefined({\n per_page: perPage,\n order_by: orderBy,\n page,\n });\n","import { handleFeedResponse } from '../../helpers/feed';\nimport { compactDefined } from '../../helpers/fp';\nimport * as Query from '../../helpers/query';\nimport { createRequestHandler, createRequestHandlerOptional } from '../../helpers/request';\nimport { castResponse } from '../../helpers/response';\nimport { OrientationParam, PaginationParams } from '../../types/request';\n\ntype CollectionId = {\n collectionId: string;\n};\n\nconst COLLECTIONS_PATH_PREFIX = '/collections';\n\nexport const getPhotos = {\n handleRequest: createRequestHandler(\n ({\n collectionId,\n orientation,\n ...paginationParams\n }: CollectionId & PaginationParams & OrientationParam) => ({\n pathname: `${COLLECTIONS_PATH_PREFIX}/${collectionId}/photos`,\n query: compactDefined({ ...Query.getFeedParams(paginationParams), orientation }),\n }),\n ),\n handleResponse: handleFeedResponse<any>(),\n};\n\nexport const get = {\n handleRequest: createRequestHandler(({ collectionId }: CollectionId) => ({\n pathname: `${COLLECTIONS_PATH_PREFIX}/${collectionId}`,\n query: {},\n })),\n handleResponse: castResponse<any>(),\n};\n\nexport const list = {\n handleRequest: createRequestHandlerOptional(\n (paginationParams: Pick<PaginationParams, 'page' | 'perPage'> = {}) => ({\n pathname: COLLECTIONS_PATH_PREFIX,\n query: Query.getFeedParams(paginationParams),\n }),\n ),\n handleResponse: handleFeedResponse<any>(),\n};\n\nexport const getRelated = {\n handleRequest: createRequestHandler(({ collectionId }: CollectionId) => ({\n pathname: `${COLLECTIONS_PATH_PREFIX}/${collectionId}/related`,\n query: {},\n })),\n handleResponse: castResponse<any>(),\n};\n","import { handleFeedResponse } from '../../helpers/feed';\nimport { compactDefined } from '../../helpers/fp';\nimport * as Query from '../../helpers/query';\nimport { createRequestHandler, createRequestHandlerOptional } from '../../helpers/request';\nimport { castResponse } from '../../helpers/response';\nimport { isDefined } from '../../helpers/typescript';\nimport { parseQueryAndPathname } from '../../helpers/url';\nimport { OrientationParam, PaginationParams } from '../../types/request';\n\ntype PhotoId = {\n photoId: string;\n};\n\nconst PHOTOS_PATH_PREFIX = '/photos';\n\nexport const list = {\n handleRequest: createRequestHandlerOptional((feedParams: PaginationParams = {}) => ({\n pathname: PHOTOS_PATH_PREFIX,\n query: compactDefined(Query.getFeedParams(feedParams)),\n })),\n handleResponse: handleFeedResponse<any>(),\n};\n\nexport const get = {\n handleRequest: createRequestHandler(({ photoId }: PhotoId) => ({\n pathname: `${PHOTOS_PATH_PREFIX}/${photoId}`,\n query: {},\n })),\n handleResponse: castResponse<any>(),\n};\n\nexport const getStats = {\n handleRequest: createRequestHandler(({ photoId }: PhotoId) => ({\n pathname: `${PHOTOS_PATH_PREFIX}/${photoId}/statistics`,\n query: {},\n })),\n handleResponse: castResponse<any>(),\n};\n\nexport const getRandom = {\n handleRequest: createRequestHandlerOptional(\n ({\n collectionIds,\n ...queryParams\n }: {\n collectionIds?: string[];\n featured?: boolean;\n username?: string;\n query?: string;\n count?: number;\n } & OrientationParam = {}) => ({\n pathname: `${PHOTOS_PATH_PREFIX}/random`,\n query: compactDefined({\n ...queryParams,\n ...Query.getCollections(collectionIds),\n }),\n headers: {\n /**\n * Avoid response caching\n */\n 'cache-control': 'no-cache',\n },\n }),\n ),\n handleResponse: castResponse<any>(),\n};\n\nexport const trackDownload = {\n handleRequest: createRequestHandler(({ downloadLocation }: { downloadLocation: string }) => {\n const { pathname, query } = parseQueryAndPathname(downloadLocation);\n\n if (!isDefined(pathname)) {\n throw new Error('Could not parse pathname from url.');\n }\n return { pathname, query: compactDefined(query) };\n }),\n handleResponse: castResponse<any>(),\n};\n","import { compactDefined } from '../../helpers/fp';\nimport * as Query from '../../helpers/query';\nimport { createRequestHandler } from '../../helpers/request';\nimport { castResponse } from '../../helpers/response';\nimport { OrientationParam, PaginationParams } from '../../types/request';\nimport { ColorId, ContentFilter, Language, SearchOrderBy } from './types';\n\nexport type SearchParams = {\n query: string;\n} & Pick<PaginationParams, 'page' | 'perPage'>;\n\nconst SEARCH_PATH_PREFIX = `/search`;\n\ntype SearchPhotosParams = SearchParams &\n OrientationParam & {\n /**\n * API defaults to `\"relevant\"` if no value is provided\n */\n orderBy?: SearchOrderBy;\n color?: ColorId;\n /**\n * API defaults to `en` (English) if no value is provided\n */\n lang?: Language;\n /**\n * API defaults to `\"low\"` if no value is provided\n */\n contentFilter?: ContentFilter;\n collectionIds?: string[];\n };\n\nexport const getPhotos = {\n handleRequest: createRequestHandler(\n ({\n query,\n page,\n perPage,\n orderBy,\n collectionIds,\n lang,\n contentFilter,\n ...filters\n }: SearchPhotosParams) => ({\n pathname: `${SEARCH_PATH_PREFIX}/photos`,\n query: compactDefined({\n query,\n content_filter: contentFilter,\n lang,\n order_by: orderBy,\n ...Query.getFeedParams({ page, perPage }),\n ...Query.getCollections(collectionIds),\n ...filters,\n }),\n }),\n ),\n handleResponse: castResponse<any>(),\n};\n\nexport const getCollections = {\n handleRequest: createRequestHandler(({ query, ...paginationParams }: SearchParams) => ({\n pathname: `${SEARCH_PATH_PREFIX}/collections`,\n query: { query, ...Query.getFeedParams(paginationParams) },\n })),\n handleResponse: castResponse<any>(),\n};\n\nexport const getUsers = {\n handleRequest: createRequestHandler(({ query, ...paginationParams }: SearchParams) => ({\n pathname: `${SEARCH_PATH_PREFIX}/users`,\n query: { query, ...Query.getFeedParams(paginationParams) },\n })),\n handleResponse: castResponse<any>(),\n};\n","import { handleFeedResponse } from '../../helpers/feed';\nimport { compactDefined } from '../../helpers/fp';\nimport * as Query from '../../helpers/query';\nimport { createRequestHandler } from '../../helpers/request';\nimport { castResponse } from '../../helpers/response';\nimport { OrientationParam, PaginationParams } from '../../types/request';\n\ntype UserName = {\n username: string;\n};\n\nconst USERS_PATH_PREFIX = '/users';\n\nexport const get = {\n handleRequest: createRequestHandler(({ username }: UserName) => ({\n pathname: `${USERS_PATH_PREFIX}/${username}`,\n query: {},\n })),\n handleResponse: castResponse<any>(),\n};\n\nexport const getPhotos = {\n handleRequest: createRequestHandler(\n ({\n username,\n stats,\n orientation,\n ...paginationParams\n }: {\n stats?: boolean;\n } & OrientationParam &\n UserName &\n PaginationParams) => ({\n pathname: `${USERS_PATH_PREFIX}/${username}/photos`,\n query: compactDefined({\n ...Query.getFeedParams(paginationParams),\n orientation,\n stats,\n }),\n }),\n ),\n handleResponse: handleFeedResponse<any>(),\n};\n\nexport const getLikes = {\n handleRequest: createRequestHandler(\n ({\n username,\n orientation,\n ...paginationParams\n }: OrientationParam & UserName & PaginationParams) => ({\n pathname: `${USERS_PATH_PREFIX}/${username}/likes`,\n query: compactDefined({\n ...Query.getFeedParams(paginationParams),\n orientation,\n }),\n }),\n ),\n handleResponse: handleFeedResponse<any>(),\n};\nexport const getCollections = {\n handleRequest: createRequestHandler(\n ({ username, ...paginationParams }: UserName & PaginationParams) => ({\n pathname: `${USERS_PATH_PREFIX}/${username}/collections`,\n query: Query.getFeedParams(paginationParams),\n }),\n ),\n handleResponse: handleFeedResponse<any>(),\n};\n","import { flow } from './helpers/fp';\nimport { initMakeRequest } from './helpers/request';\nimport * as collections from './methods/collections';\nimport * as photos from './methods/photos';\nimport * as search from './methods/search';\nimport * as users from './methods/users';\n\nexport const createApi = flow(initMakeRequest, makeRequest => ({\n photos: {\n get: makeRequest(photos.get),\n list: makeRequest(photos.list),\n getStats: makeRequest(photos.getStats),\n getRandom: makeRequest(photos.getRandom),\n trackDownload: makeRequest(photos.trackDownload),\n },\n users: {\n getPhotos: makeRequest(users.getPhotos),\n getCollections: makeRequest(users.getCollections),\n getLikes: makeRequest(users.getLikes),\n get: makeRequest(users.get),\n },\n search: {\n getCollections: makeRequest(search.getCollections),\n getPhotos: makeRequest(search.getPhotos),\n getUsers: makeRequest(search.getUsers),\n },\n collections: {\n getPhotos: makeRequest(collections.getPhotos),\n get: makeRequest(collections.get),\n list: makeRequest(collections.list),\n getRelated: makeRequest(collections.getRelated),\n },\n}));\n"],"names":["checkIsString","getRefinement","value","isDefined","x","undefined","getB","a","checkIsNonEmptyArray","length","compactDefined","obj","Object","keys","reduce","acc","key","flow","fns","len","y","apply","i","call","checkIsObject","response","Array","isArray","checkIsErrors","errors","every","checkIsApiError","getErrorForBadStatusCode","jsonResponse","source","DecodingError","message","CONTENT_TYPE_RESPONSE_HEADER","CONTENT_TYPE_JSON","checkIsJsonResponse","contentTypeHeader","headers","get","ContentTypeHelpers","type","getJsonResponse","json","_err","handleFetchResponse","handleResponse","ok","then","handledResponse","status","error","castResponse","addQueryToUrl","query","url","forEach","queryKey","searchParams","set","toString","buildUrl","pathname","apiBaseUrl","URL","parseQueryAndPathname","createRequestHandler","fn","additionalFetchOptions","baseReqParams","createRequestHandlerOptional","initMakeRequest","accessKey","apiVersion","apiUrl","generalHeaders","generalFetchOptions","handleRequest","method","endpointHeaders","body","signal","fetchOptions","Authorization","fetch","TOTAL_RESPONSE_HEADER","getTotalFromApiFeedResponse","totalsStr","total","parseInt","Number","isInteger","handleFeedResponse","results","getCollections","collectionIds","collections","join","getFeedParams","page","perPage","orderBy","per_page","order_by","COLLECTIONS_PATH_PREFIX","getPhotos","collectionId","orientation","paginationParams","Query","list","getRelated","PHOTOS_PATH_PREFIX","feedParams","photoId","getStats","getRandom","queryParams","trackDownload","downloadLocation","Error","SEARCH_PATH_PREFIX","lang","contentFilter","filters","content_filter","getUsers","USERS_PATH_PREFIX","username","stats","getLikes","createApi","makeRequest","photos","users","search"],"mappings":"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"}
export const trackNonHotLinkedPhotoView = ({ appId }: { appId: string }) => ({
photoId,
}: {
photoId: string | string[];
}) => {
const ids = !Array.isArray(photoId) ? [photoId] : photoId;
if (ids.length > 20) {
throw new Error(
'You cannot track more than 20 photos at once. Please try again with fewer photos.',
);
}
return fetch(`views.unsplash.com/v?photo_id=${ids.join()}&app_id=${appId}`);
};
import {
AnyJson,
checkIsString,
getRefinement,
isDefined,
checkIsNonEmptyArray,
JsonMap,
NonEmptyArray,
Nullable,
} from './typescript';
export type Errors = NonEmptyArray<string>;
export type ErrorSource = 'api' | 'decoding';
const checkIsObject = getRefinement(
(response: AnyJson): Nullable<JsonMap> =>
isDefined(response) && typeof response === 'object' && !Array.isArray(response)
? response
: null,
);
const checkIsErrors = getRefinement(
(errors: AnyJson): Nullable<Errors> =>
Array.isArray(errors) && errors.every(checkIsString) && checkIsNonEmptyArray(errors)
? errors
: null,
);
const checkIsApiError = getRefinement(
(response: AnyJson): Nullable<{ errors: Errors }> =>
checkIsObject(response) && 'errors' in response && checkIsErrors(response.errors)
? { errors: response.errors }
: null,
);
export const getErrorForBadStatusCode = (
jsonResponse: AnyJson,
): { errors: Errors; source: ErrorSource } => {
if (checkIsApiError(jsonResponse)) {
return { errors: jsonResponse.errors, source: 'api' };
} else {
return {
errors: [
'Responded with a status code outside the 2xx range, and the response body is not recognisable.',
],
source: 'decoding',
};
}
};
export class DecodingError {
constructor(readonly message: string) {}
}
import { DecodingError } from './errors';
import { HandleResponse, castResponse } from './response';
import { isDefined } from './typescript';
const TOTAL_RESPONSE_HEADER = 'x-total';
const getTotalFromApiFeedResponse = (response: Response) => {
const totalsStr = response.headers.get(TOTAL_RESPONSE_HEADER);
if (isDefined(totalsStr)) {
const total = parseInt(totalsStr);
if (Number.isInteger(total)) {
return total;
} else {
throw new DecodingError(`expected ${TOTAL_RESPONSE_HEADER} header to be valid integer.`);
}
} else {
throw new DecodingError(`expected ${TOTAL_RESPONSE_HEADER} header to exist.`);
}
};
type FeedResponse<T> = {
results: T[];
total: number;
};
export const handleFeedResponse = <T>(): HandleResponse<FeedResponse<T>> => ({ response }) =>
castResponse<T[]>()({ response }).then(results => ({
results,
total: getTotalFromApiFeedResponse(response),
}));
import { isDefined } from './typescript';
/** Takes a dictionary containing nullish values and returns a dictionary of all the defined
* (non-nullish) values.
*/
export const compactDefined = <A>(obj: Record<string, A | null | undefined>) =>
Object.keys(obj).reduce<Record<string, A>>((acc, key) => {
const value = obj[key];
return {
...acc,
...(isDefined(value) ? { [key]: value } : {}),
};
}, {});
/**
* copied from `fp-ts`
* https://github.com/gcanti/fp-ts/blob/70190b5a03ddc2d31b4708c75c6dfad81d0bfa21/perf/function/flow.t¡s
*/
export function flow<A extends Array<unknown>, B>(ab: (...a: A) => B): (...a: A) => B;
export function flow<A extends Array<unknown>, B, C>(
ab: (...a: A) => B,
bc: (b: B) => C,
): (...a: A) => C;
export function flow<A extends Array<unknown>, B, C, D>(
ab: (...a: A) => B,
bc: (b: B) => C,
cd: (b: C) => D,
): (...a: A) => D;
export function flow(...fns: Array<Function>): Function {
const len = fns.length - 1;
return function(this: any, ...x: Array<any>) {
let y = fns[0].apply(this, x);
for (let i = 1; i <= len; i++) {
y = fns[i].call(this, y);
}
return y;
};
}
import * as ContentTypeHelpers from 'content-type';
import { DecodingError } from './errors';
import { AnyJson, isDefined } from './typescript';
const CONTENT_TYPE_RESPONSE_HEADER = 'content-type';
const CONTENT_TYPE_JSON = 'application/json';
const checkIsJsonResponse = (response: Response) => {
const contentTypeHeader = response.headers.get(CONTENT_TYPE_RESPONSE_HEADER);
return (
isDefined(contentTypeHeader) &&
ContentTypeHelpers.parse(contentTypeHeader).type === CONTENT_TYPE_JSON
);
};
/**
* Note: restrict the type of JSON to `AnyJson` so that `any` doesn't leak downstream.
*/
export const getJsonResponse = (response: Response): Promise<AnyJson> => {
if (checkIsJsonResponse(response)) {
return response.json().catch(_err => {
throw new DecodingError('unable to parse JSON response.');
});
} else {
throw new DecodingError('expected JSON response from server.');
}
};
import { PaginationParams } from '../types/request';
import { compactDefined } from './fp';
import { isDefined } from './typescript';
export const getCollections = (collectionIds?: string[]) =>
isDefined(collectionIds) ? { collections: collectionIds.join() } : {};
export const getFeedParams = ({ page, perPage, orderBy }: PaginationParams) =>
compactDefined({
per_page: perPage,
order_by: orderBy,
page,
});
import { flow } from './fp';
import { ApiResponse, handleFetchResponse, HandleResponse } from './response';
import { isDefined, OmitStrict } from './typescript';
import { buildUrl, BuildUrlParams } from './url';
type FetchParams = Pick<RequestInit, 'method'>;
/**
* The params generated by the library
*/
type BaseRequestParams = BuildUrlParams &
FetchParams &
// `headers` is not part of FetchParams because we want to allow headers in the additional params as well
Pick<RequestInit, 'headers'>;
/**
* Additional fetch options provided by the user on a per-call basis
*/
type AdditionalPerFetchParams = Omit<RequestInit, keyof FetchParams>;
export type CompleteRequestParams = BaseRequestParams & AdditionalPerFetchParams;
type HandleRequest<Args> = (
a: Args,
additionalFetchOptions?: AdditionalPerFetchParams,
) => CompleteRequestParams;
/**
* helper used to type-check the arguments, and add default params for all requests
*/
export const createRequestHandler = <Args>(
fn: (a: Args) => BaseRequestParams,
): HandleRequest<Args> => (a, additionalFetchOptions = {}) => {
const { headers, query, ...baseReqParams } = fn(a);
return {
...baseReqParams,
...additionalFetchOptions,
query,
headers: {
...headers,
...additionalFetchOptions.headers,
},
};
};
/**
* Variant of `createRequestHandler` used when the args object is entirely optional.
* We cannot combine this with `createRequestHandler` because it is impossible to make the function
* parameter conditionally nullable or non-nullable.
*/
export const createRequestHandlerOptional = <Args>(
fn: (a?: Args) => BaseRequestParams,
): ((a?: Args, additionalFetchOptions?: AdditionalPerFetchParams) => CompleteRequestParams) =>
createRequestHandler(fn);
/**
* Initial parameters that apply to all calls
*/
type InitParams = {
apiVersion?: string;
} & OmitStrict<RequestInit, 'method' | 'body'> &
({ accessKey: string; apiUrl?: never } | { apiUrl: string; accessKey?: never });
type RequestGenerator<Args, ResponseType> = {
handleRequest: HandleRequest<Args>;
handleResponse: HandleResponse<ResponseType>;
};
type GeneratedRequestFunction<Args, ResponseType> = (
...a: Parameters<HandleRequest<Args>>
) => Promise<ApiResponse<ResponseType>>;
type InitMakeRequest = (
args: InitParams,
) => <Args, ResponseType>(
handlers: RequestGenerator<Args, ResponseType>,
) => GeneratedRequestFunction<Args, ResponseType>;
export const initMakeRequest: InitMakeRequest = ({
accessKey,
apiVersion = 'v1',
apiUrl = 'https://api.unsplash.com',
headers: generalHeaders,
...generalFetchOptions
}) => ({ handleResponse, handleRequest }) =>
flow(
handleRequest,
({ pathname, query, method = 'GET', headers: endpointHeaders, body, signal }) => {
const url = buildUrl({ pathname, query })(apiUrl);
const fetchOptions: RequestInit = {
method,
headers: {
...generalHeaders,
...endpointHeaders,
'Accept-Version': apiVersion,
...(isDefined(accessKey) ? { Authorization: `Client-ID ${accessKey}` } : {}),
},
body,
signal,
...generalFetchOptions,
};
return fetch(url, fetchOptions).then(handleFetchResponse(handleResponse));
},
);
import { Errors, ErrorSource, getErrorForBadStatusCode, DecodingError } from './errors';
import { getJsonResponse } from './json';
export type ApiResponse<T> =
| {
type: 'success';
response: T;
errors?: never;
status: number;
}
| {
type: 'error';
source: ErrorSource;
response?: never;
errors: Errors;
status: number;
};
export type HandleResponse<T> = (args: { response: Response }) => Promise<T>;
export const handleFetchResponse = <ResponseType>(handleResponse: HandleResponse<ResponseType>) => (
response: Response,
): Promise<ApiResponse<ResponseType>> =>
(response.ok
? handleResponse({ response }).then(
(handledResponse): ApiResponse<ResponseType> => ({
type: 'success',
status: response.status,
response: handledResponse,
}),
)
: getJsonResponse(response).then(
(jsonResponse): ApiResponse<ResponseType> => ({
type: 'error',
status: response.status,
...getErrorForBadStatusCode(jsonResponse),
}),
)
).catch(error => {
/**
* We want to separate expected decoding errors from unknown ones. We do so by throwing a custom
* `DecodingError` whenever we encounter one within `handleFetchResponse` and catch them all
* here. This allows us to easily handle all of these errors at once. Unexpected errors are not
* caught, so that they bubble up and fail loudly.
*
* Note: Ideally we'd use an Either type, but this does the job without introducing dependencies
* like `fp-ts`.
*/
if (error instanceof DecodingError) {
return {
type: 'error',
source: 'decoding',
status: response.status,
errors: [error.message],
};
} else {
throw error;
}
});
export const castResponse = <T>(): HandleResponse<T> => ({ response }) =>
(getJsonResponse(response) as unknown) as Promise<T>;
// Copied from https://github.com/Microsoft/TypeScript/issues/1897#issuecomment-338650717
export type AnyJson = boolean | number | string | null | JsonArray | JsonMap;
export type JsonMap = { [key: string]: AnyJson };
export type JsonArray = Array<AnyJson>;
export const checkIsString = getRefinement(
(value: unknown): Nullable<string> => (typeof value === 'string' ? value : null),
);
/**
* https://github.com/Microsoft/TypeScript/issues/12215#issuecomment-377567046
*/
export type OmitStrict<T, K extends keyof T> = Omit<T, K>;
/**
* Unlike TypeScript's `NonNullable`, this does _not_ include `undefined`
*/
export type Nullable<T> = T | null;
export const isDefined = <T>(x: T | null | undefined): x is T => x !== null && x !== undefined;
export type NonEmptyArray<T> = [T, ...T[]];
type Refinement<A, B extends A> = (a: A) => a is B;
export function getRefinement<A, B extends A>(getB: (a: A) => Nullable<B>): Refinement<A, B> {
return (a: A): a is B => isDefined(getB(a));
}
export const checkIsNonEmptyArray = <T>(a: T[]): a is NonEmptyArray<T> => a.length > 0;
type Query = {
[index: string]: string | number | boolean;
};
export type BuildUrlParams = {
pathname: string;
query: Query;
};
const addQueryToUrl = (query: Query) => (url: URL) => {
Object.keys(query).forEach(queryKey =>
url.searchParams.set(queryKey, query[queryKey].toString()),
);
};
export const buildUrl = ({ pathname, query }: BuildUrlParams) => (apiBaseUrl: string) => {
const url = new URL(pathname, apiBaseUrl);
addQueryToUrl(query)(url);
return url.toString();
};
export const parseQueryAndPathname = (url: string) => {
const { pathname, searchParams } = new URL(url);
const query: Query = {};
searchParams.forEach((value, key) => {
query[key] = value;
});
return { query, pathname: pathname === '/' ? undefined : pathname };
};
import { flow } from './helpers/fp';
import { initMakeRequest } from './helpers/request';
import * as collections from './methods/collections';
import * as photos from './methods/photos';
import * as search from './methods/search';
import * as users from './methods/users';
export const createApi = flow(initMakeRequest, makeRequest => ({
photos: {
get: makeRequest(photos.get),
list: makeRequest(photos.list),
getStats: makeRequest(photos.getStats),
getRandom: makeRequest(photos.getRandom),
trackDownload: makeRequest(photos.trackDownload),
},
users: {
getPhotos: makeRequest(users.getPhotos),
getCollections: makeRequest(users.getCollections),
getLikes: makeRequest(users.getLikes),
get: makeRequest(users.get),
},
search: {
getCollections: makeRequest(search.getCollections),
getPhotos: makeRequest(search.getPhotos),
getUsers: makeRequest(search.getUsers),
},
collections: {
getPhotos: makeRequest(collections.getPhotos),
get: makeRequest(collections.get),
list: makeRequest(collections.list),
getRelated: makeRequest(collections.getRelated),
},
}));
import { handleFeedResponse } from '../../helpers/feed';
import { compactDefined } from '../../helpers/fp';
import * as Query from '../../helpers/query';
import { createRequestHandler, createRequestHandlerOptional } from '../../helpers/request';
import { castResponse } from '../../helpers/response';
import { OrientationParam, PaginationParams } from '../../types/request';
type CollectionId = {
collectionId: string;
};
const COLLECTIONS_PATH_PREFIX = '/collections';
export const getPhotos = {
handleRequest: createRequestHandler(
({
collectionId,
orientation,
...paginationParams
}: CollectionId & PaginationParams & OrientationParam) => ({
pathname: `${COLLECTIONS_PATH_PREFIX}/${collectionId}/photos`,
query: compactDefined({ ...Query.getFeedParams(paginationParams), orientation }),
}),
),
handleResponse: handleFeedResponse<any>(),
};
export const get = {
handleRequest: createRequestHandler(({ collectionId }: CollectionId) => ({
pathname: `${COLLECTIONS_PATH_PREFIX}/${collectionId}`,
query: {},
})),
handleResponse: castResponse<any>(),
};
export const list = {
handleRequest: createRequestHandlerOptional(
(paginationParams: Pick<PaginationParams, 'page' | 'perPage'> = {}) => ({
pathname: COLLECTIONS_PATH_PREFIX,
query: Query.getFeedParams(paginationParams),
}),
),
handleResponse: handleFeedResponse<any>(),
};
export const getRelated = {
handleRequest: createRequestHandler(({ collectionId }: CollectionId) => ({
pathname: `${COLLECTIONS_PATH_PREFIX}/${collectionId}/related`,
query: {},
})),
handleResponse: castResponse<any>(),
};
import { handleFeedResponse } from '../../helpers/feed';
import { compactDefined } from '../../helpers/fp';
import * as Query from '../../helpers/query';
import { createRequestHandler, createRequestHandlerOptional } from '../../helpers/request';
import { castResponse } from '../../helpers/response';
import { isDefined } from '../../helpers/typescript';
import { parseQueryAndPathname } from '../../helpers/url';
import { OrientationParam, PaginationParams } from '../../types/request';
type PhotoId = {
photoId: string;
};
const PHOTOS_PATH_PREFIX = '/photos';
export const list = {
handleRequest: createRequestHandlerOptional((feedParams: PaginationParams = {}) => ({
pathname: PHOTOS_PATH_PREFIX,
query: compactDefined(Query.getFeedParams(feedParams)),
})),
handleResponse: handleFeedResponse<any>(),
};
export const get = {
handleRequest: createRequestHandler(({ photoId }: PhotoId) => ({
pathname: `${PHOTOS_PATH_PREFIX}/${photoId}`,
query: {},
})),
handleResponse: castResponse<any>(),
};
export const getStats = {
handleRequest: createRequestHandler(({ photoId }: PhotoId) => ({
pathname: `${PHOTOS_PATH_PREFIX}/${photoId}/statistics`,
query: {},
})),
handleResponse: castResponse<any>(),
};
export const getRandom = {
handleRequest: createRequestHandlerOptional(
({
collectionIds,
...queryParams
}: {
collectionIds?: string[];
featured?: boolean;
username?: string;
query?: string;
count?: number;
} & OrientationParam = {}) => ({
pathname: `${PHOTOS_PATH_PREFIX}/random`,
query: compactDefined({
...queryParams,
...Query.getCollections(collectionIds),
}),
headers: {
/**
* Avoid response caching
*/
'cache-control': 'no-cache',
},
}),
),
handleResponse: castResponse<any>(),
};
export const trackDownload = {
handleRequest: createRequestHandler(({ downloadLocation }: { downloadLocation: string }) => {
const { pathname, query } = parseQueryAndPathname(downloadLocation);
if (!isDefined(pathname)) {
throw new Error('Could not parse pathname from url.');
}
return { pathname, query: compactDefined(query) };
}),
handleResponse: castResponse<any>(),
};
import { compactDefined } from '../../helpers/fp';
import * as Query from '../../helpers/query';
import { createRequestHandler } from '../../helpers/request';
import { castResponse } from '../../helpers/response';
import { OrientationParam, PaginationParams } from '../../types/request';
import { ColorId, ContentFilter, Language, SearchOrderBy } from './types';
export type SearchParams = {
query: string;
} & Pick<PaginationParams, 'page' | 'perPage'>;
const SEARCH_PATH_PREFIX = `/search`;
type SearchPhotosParams = SearchParams &
OrientationParam & {
/**
* API defaults to `"relevant"` if no value is provided
*/
orderBy?: SearchOrderBy;
color?: ColorId;
/**
* API defaults to `en` (English) if no value is provided
*/
lang?: Language;
/**
* API defaults to `"low"` if no value is provided
*/
contentFilter?: ContentFilter;
collectionIds?: string[];
};
export const getPhotos = {
handleRequest: createRequestHandler(
({
query,
page,
perPage,
orderBy,
collectionIds,
lang,
contentFilter,
...filters
}: SearchPhotosParams) => ({
pathname: `${SEARCH_PATH_PREFIX}/photos`,
query: compactDefined({
query,
content_filter: contentFilter,
lang,
order_by: orderBy,
...Query.getFeedParams({ page, perPage }),
...Query.getCollections(collectionIds),
...filters,
}),
}),
),
handleResponse: castResponse<any>(),
};
export const getCollections = {
handleRequest: createRequestHandler(({ query, ...paginationParams }: SearchParams) => ({
pathname: `${SEARCH_PATH_PREFIX}/collections`,
query: { query, ...Query.getFeedParams(paginationParams) },
})),
handleResponse: castResponse<any>(),
};
export const getUsers = {
handleRequest: createRequestHandler(({ query, ...paginationParams }: SearchParams) => ({
pathname: `${SEARCH_PATH_PREFIX}/users`,
query: { query, ...Query.getFeedParams(paginationParams) },
})),
handleResponse: castResponse<any>(),
};
export type SearchOrderBy = 'relevant' | 'latest';
export type ColorId =
| 'white'
| 'black'
| 'yellow'
| 'orange'
| 'red'
| 'purple'
| 'magenta'
| 'green'
| 'teal'
| 'blue'
| 'black_and_white';
export type ContentFilter = 'high' | 'low';
export enum Language {
Afrikaans = 'af',
Amharic = 'am',
Arabic = 'ar',
Azerbaijani = 'az',
Belarusian = 'be',
Bulgarian = 'bg',
Bengali = 'bn',
Bosnian = 'bs',
Catalan = 'ca',
Cebuano = 'ceb',
Corsican = 'co',
Czech = 'cs',
Welsh = 'cy',
Danish = 'da',
German = 'de',
Greek = 'el',
English = 'en',
Esperanto = 'eo',
Spanish = 'es',
Estonian = 'et',
Basque = 'eu',
Persian = 'fa',
Finnish = 'fi',
French = 'fr',
Frisian = 'fy',
Irish = 'ga',
ScotsGaelic = 'gd',
Galician = 'gl',
Gujarati = 'gu',
Hausa = 'ha',
Hawaiian = 'haw',
Hindi = 'hi',
Hmong = 'hmn',
Croatian = 'hr',
HaitianCreole = 'ht',
Hungarian = 'hu',
Armenian = 'hy',
Indonesian = 'id',
Igbo = 'ig',
Icelandic = 'is',
Italian = 'it',
Hebrew = 'iw',
Japanese = 'ja',
Javanese = 'jw',
Georgian = 'ka',
Kazakh = 'kk',
Khmer = 'km',
Kannada = 'kn',
Korean = 'ko',
Kurdish = 'ku',
Kyrgyz = 'ky',
Latin = 'la',
Luxembourgish = 'lb',
Lao = 'lo',
Lithuanian = 'lt',
Latvian = 'lv',
Malagasy = 'mg',
Maori = 'mi',
Macedonian = 'mk',
Malayalam = 'ml',
Mongolian = 'mn',
Marathi = 'mr',
Malay = 'ms',
Maltese = 'mt',
Myanmar = 'my',
Nepali = 'ne',
Dutch = 'nl',
Norwegian = 'no',
Nyanja = 'ny',
Oriya = 'or',
Punjabi = 'pa',
Polish = 'pl',
Pashto = 'ps',
Portuguese = 'pt',
Romanian = 'ro',
Russian = 'ru',
Kinyarwanda = 'rw',
Sindhi = 'sd',
Sinhala = 'si',
Slovak = 'sk',
Slovenian = 'sl',
Samoan = 'sm',
Shona = 'sn',
Somali = 'so',
Albanian = 'sq',
Serbian = 'sr',
Sesotho = 'st',
Sundanese = 'su',
Swedish = 'sv',
Swahili = 'sw',
Tamil = 'ta',
Telugu = 'te',
Tajik = 'tg',
Thai = 'th',
Turkmen = 'tk',
Filipino = 'tl',
Turkish = 'tr',
Tatar = 'tt',
Uighur = 'ug',
Ukrainian = 'uk',
Urdu = 'ur',
Uzbek = 'uz',
Vietnamese = 'vi',
Xhosa = 'xh',
Yiddish = 'yi',
Yoruba = 'yo',
ChineseSimplified = 'zh',
ChineseTraditional = 'zh-TW',
Zulu = 'zu',
}
import { handleFeedResponse } from '../../helpers/feed';
import { compactDefined } from '../../helpers/fp';
import * as Query from '../../helpers/query';
import { createRequestHandler } from '../../helpers/request';
import { castResponse } from '../../helpers/response';
import { OrientationParam, PaginationParams } from '../../types/request';
type UserName = {
username: string;
};
const USERS_PATH_PREFIX = '/users';
export const get = {
handleRequest: createRequestHandler(({ username }: UserName) => ({
pathname: `${USERS_PATH_PREFIX}/${username}`,
query: {},
})),
handleResponse: castResponse<any>(),
};
export const getPhotos = {
handleRequest: createRequestHandler(
({
username,
stats,
orientation,
...paginationParams
}: {
stats?: boolean;
} & OrientationParam &
UserName &
PaginationParams) => ({
pathname: `${USERS_PATH_PREFIX}/${username}/photos`,
query: compactDefined({
...Query.getFeedParams(paginationParams),
orientation,
stats,
}),
}),
),
handleResponse: handleFeedResponse<any>(),
};
export const getLikes = {
handleRequest: createRequestHandler(
({
username,
orientation,
...paginationParams
}: OrientationParam & UserName & PaginationParams) => ({
pathname: `${USERS_PATH_PREFIX}/${username}/likes`,
query: compactDefined({
...Query.getFeedParams(paginationParams),
orientation,
}),
}),
),
handleResponse: handleFeedResponse<any>(),
};
export const getCollections = {
handleRequest: createRequestHandler(
({ username, ...paginationParams }: UserName & PaginationParams) => ({
pathname: `${USERS_PATH_PREFIX}/${username}/collections`,
query: Query.getFeedParams(paginationParams),
}),
),
handleResponse: handleFeedResponse<any>(),
};
export enum OrderBy {
LATEST = 'latest',
POPULAR = 'popular',
OLDEST = 'oldest',
}
type Orientation = 'landscape' | 'portrait' | 'squarish';
export type OrientationParam = {
orientation?: Orientation;
};
export type PaginationParams = {
/**
* API defaults to `10` if no value is provided
*/
perPage?: number;
/**
* API defaults to `1` if no value is provided
*/
page?: number;
/**
* API defaults to `"latest"` if no value is provided
*/
orderBy?: OrderBy;
};
+104
-26
# Changelog
## 7.0.0
This version includes a total TypeScript rewrite of the library, with many breaking changes. If upgrading from a previous version, read carefully. You will not be able to upgrade to v7 without making the necessary adjustments.
### Breaking Changes
- Replaces the `Unsplash` `class` with a named `createApi` function:
```ts
// before
import Unsplash from 'unsplash-js';
const unsplash = new Unsplash({ accessKey: 'MY_ACCESS_KEY' });
// after
import { createApi } from 'unsplash-js';
const unsplash = createApi({ accessKey: 'MY_ACCESS_KEY' });
// or
import Unsplash from 'unsplash-js';
const unsplash = Unsplash.createApi({ accessKey: 'MY_ACCESS_KEY' });
```
- Removes user authentication features from the library. This means that the `createApi` function does not recieve `secret`, `callbackUrl` or `bearerToken`.
* Removes the following API methods (primarily due to removal of user authentication):
- `photos`:
- ❌ `likePhoto`
- ❌ `unlikePhoto`
- ❌ `downloadPhoto` (deprecated in 6.3, replaced with `trackDownload`)
- `users`:
- ❌ `statistics`
- `collections`:
- ❌ `createCollection`
- ❌ `updateCollection`
- ❌ `deleteCollection`
- ❌ `addPhotoToCollection`
- ❌ `removePhotoFromCollection`
- `auth`:
- ❌ `getAuthenticationUrl`
- ❌ `userAuthentication`
- ❌ `setBearerToken`
- `currentUser`:
- ❌ `profile`
- ❌ `updateProfile`
- ❌ `toJson` (the library now takes care of converting the response to JSON).
* Renames all of the remaining API methods:
- `search`:
- ⚠️ `photos` --> `getPhotos`
- ⚠️ `users` --> `getUsers`
- ⚠️ `collections` --> `getCollections`
- `photos`:
- ⚠️ `listPhotos` --> `list`
- ⚠️ `getPhoto` --> `get`
- ⚠️ `getRandomPhoto` --> `getRandom`
- ⚠️ `getPhotoStats` --> `getStats`
- `users`:
- ⚠️ `profile` --> `get`
- ⚠️ `photos` --> `getPhotos`
- ⚠️ `likes` --> `getLikes`
- ⚠️ `collections` --> `getCollections`
- `collections`:
- ⚠️ `listCollections` --> `list`
- ⚠️ `getCollection` --> `get`
- ⚠️ `getCollectionPhotos` --> `getPhotos`
- ⚠️ `listRelatedCollections` --> `listRelated`
- Changes the format of the parameters for **all** API methods. They are now all named parameters within the first argument, instead of multiple arguments. Check the TypeScript types and the [Arguments](./README.md#Arguments) section of the docs for the new parameters format.
- Changes the format of the responses for **all** API methods. The JSON is now parsed and returned, removing the need for the `toJson` helper. Feeds have the "x-total" header added to the response. The library now also performs error-handling: expected errors are returned instead of thrown, along with a description of their source. Check the TypeScript types and the [Response](./README.md#Response) section of the docs for the new response format.
### Changes
- TypeScript support! Everything is now accurately typed (except responses which we plan to add types for soon).
- You can now provide fetch options on a per-call basis using the second parameter. See [Arguments](./README.md#Arguments).
## 6.3.0

@@ -7,3 +83,3 @@

- Deprecate `photos.photoDownload` in favor of `photos.trackDownload` to better clarify method usage. `photoDownload` will continue to be supported until version 7.0.
- Deprecate `photos.downloadPhoto` in favor of `photos.trackDownload` to better clarify method usage. `downloadPhoto` will continue to be supported until version 7.0.

@@ -17,3 +93,3 @@ ## 6.2.0

```js
unsplash.search.photos("nature", 1, 10, { lang: "en" });
unsplash.search.photos('nature', 1, 10, { lang: 'en' });
```

@@ -24,6 +100,6 @@

```js
unsplash.search.photos("nature", 1, 10, {
orientation: "landscape",
color: "green", // new
orderBy: "relevant" // new
unsplash.search.photos('nature', 1, 10, {
orientation: 'landscape',
color: 'green', // new
orderBy: 'relevant', // new
});

@@ -35,3 +111,3 @@ ```

```js
unsplash.search.photos("nature", 1, 10, { contentFilter: "high" });
unsplash.search.photos('nature', 1, 10, { contentFilter: 'high' });
```

@@ -50,6 +126,7 @@

- To better clarify the use of `accessKey` when initializing, `applicationId` has been renamed to `accessKey`:
```js
// previously
const unsplash = new Unsplash({
applicationId: "{APP_ACCESS_KEY}"
applicationId: '{APP_ACCESS_KEY}',
});

@@ -59,5 +136,6 @@

const unsplash = new Unsplash({
accessKey: "{APP_ACCESS_KEY}"
accessKey: '{APP_ACCESS_KEY}',
});
```
- `unsplash.photos.getPhotoStats` now uses the `/photos/:id/statistics` endpoint ([changelog reference](https://changelog.unsplash.com/deprecations/2017/10/05/existing-deprecations.html))

@@ -68,3 +146,3 @@

```js
unsplash.search.photos("nature", 1, 10, { orientation: "landscape", collections: [1,2] })
unsplash.search.photos('nature', 1, 10, { orientation: 'landscape', collections: [1, 2] });
```

@@ -76,19 +154,19 @@

| Removed Method | Replacement | Reason |
|---|---|---|
| `unsplash.search.all` | None | This endpoint is undocumented publicly and is highly likely to change in the future. Therefore, we don't recommend anyone use this functionality in their applications. |
| `unsplash.photos.listCuratedPhotos` | None | Curated photos were [deprecated in 2017](https://changelog.unsplash.com/deprecations/2018/09/27/curated-collections-deprecation.html), [removed in 2019](https://changelog.unsplash.com/deprecations/2019/09/23/curated-collections-removal.html) |
| `unsplash.photos.searchPhotos` | `unsplash.search.photos` | Replaced by [the new search endpoints in 2017](https://changelog.unsplash.com/deprecations/2017/10/05/existing-deprecations.html) |
| `unsplash.photos.uploadPhoto` | None | Removed for legal compatibility |
| `unsplash.collections.listFeaturedCollections` | `unsplash.collections.listCollections` | Redundant endpoint |
| `unsplash.collections.listCuratedCollections` | None | Curated collections were replaced by collections. [Deprecated in 2017](https://changelog.unsplash.com/deprecations/2018/09/27/curated-collections-deprecation.html), [removed in 2019](https://changelog.unsplash.com/deprecations/2019/09/23/curated-collections-removal.html) |
| `unsplash.collections.getCuratedCollection` | `unsplash.collections.getCollection` | Curated collections were replaced by collections. [Deprecated in 2017](https://changelog.unsplash.com/deprecations/2018/09/27/curated-collections-deprecation.html), [removed in 2019](https://changelog.unsplash.com/deprecations/2019/09/23/curated-collections-removal.html) |
| Removed Method | Replacement | Reason |
| ------------------------------------------------- | ------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `unsplash.search.all` | None | This endpoint is undocumented publicly and is highly likely to change in the future. Therefore, we don't recommend anyone use this functionality in their applications. |
| `unsplash.photos.listCuratedPhotos` | None | Curated photos were [deprecated in 2017](https://changelog.unsplash.com/deprecations/2018/09/27/curated-collections-deprecation.html), [removed in 2019](https://changelog.unsplash.com/deprecations/2019/09/23/curated-collections-removal.html) |
| `unsplash.photos.searchPhotos` | `unsplash.search.photos` | Replaced by [the new search endpoints in 2017](https://changelog.unsplash.com/deprecations/2017/10/05/existing-deprecations.html) |
| `unsplash.photos.uploadPhoto` | None | Removed for legal compatibility |
| `unsplash.collections.listFeaturedCollections` | `unsplash.collections.listCollections` | Redundant endpoint |
| `unsplash.collections.listCuratedCollections` | None | Curated collections were replaced by collections. [Deprecated in 2017](https://changelog.unsplash.com/deprecations/2018/09/27/curated-collections-deprecation.html), [removed in 2019](https://changelog.unsplash.com/deprecations/2019/09/23/curated-collections-removal.html) |
| `unsplash.collections.getCuratedCollection` | `unsplash.collections.getCollection` | Curated collections were replaced by collections. [Deprecated in 2017](https://changelog.unsplash.com/deprecations/2018/09/27/curated-collections-deprecation.html), [removed in 2019](https://changelog.unsplash.com/deprecations/2019/09/23/curated-collections-removal.html) |
| `unsplash.collections.getCuratedCollectionPhotos` | `unsplash.collections.getCollectionPhotos` | Curated collections were replaced by collections. [Deprecated in 2017](https://changelog.unsplash.com/deprecations/2018/09/27/curated-collections-deprecation.html), [removed in 2019](https://changelog.unsplash.com/deprecations/2019/09/23/curated-collections-removal.html) |
| `unsplash.categories.*` | None | [Categories were deprecated in 2017](https://changelog.unsplash.com/deprecations/2017/10/05/existing-deprecations.html) and [removed from the API in 2017](https://changelog.unsplash.com/deprecations/2018/04/20/categories-eol.html) |
| `unsplash.categories.*` | None | [Categories were deprecated in 2017](https://changelog.unsplash.com/deprecations/2017/10/05/existing-deprecations.html) and [removed from the API in 2017](https://changelog.unsplash.com/deprecations/2018/04/20/categories-eol.html) |
| Removed Parameter | Method | Reason |
|---|---|---|
| `category` | `unsplash.photos.getRandomPhoto` | [Categories were deprecated in 2017](https://changelog.unsplash.com/deprecations/2017/10/05/existing-deprecations.html) and [removed from the API in 2017](https://changelog.unsplash.com/deprecations/2018/04/20/categories-eol.html) |
| `w` | `unsplash.photos.getPhoto`, `unsplash.photos.getRandomPhoto` | [Deprecated in favor of dynamic image URLs](https://changelog.unsplash.com/2019/03/19/image-resizing.html) |
| `h` | `unsplash.photos.getPhoto`, `unsplash.photos.getRandomPhoto` | [Deprecated in favor of dynamic image URLs](https://changelog.unsplash.com/2019/03/19/image-resizing.html) |
| `crop` | `unsplash.photos.getPhoto` | [Deprecated in favor of dynamic image URLs](https://changelog.unsplash.com/2019/03/19/image-resizing.html) |
| Removed Parameter | Method | Reason |
| ----------------- | ------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `category` | `unsplash.photos.getRandomPhoto` | [Categories were deprecated in 2017](https://changelog.unsplash.com/deprecations/2017/10/05/existing-deprecations.html) and [removed from the API in 2017](https://changelog.unsplash.com/deprecations/2018/04/20/categories-eol.html) |
| `w` | `unsplash.photos.getPhoto`, `unsplash.photos.getRandomPhoto` | [Deprecated in favor of dynamic image URLs](https://changelog.unsplash.com/2019/03/19/image-resizing.html) |
| `h` | `unsplash.photos.getPhoto`, `unsplash.photos.getRandomPhoto` | [Deprecated in favor of dynamic image URLs](https://changelog.unsplash.com/2019/03/19/image-resizing.html) |
| `crop` | `unsplash.photos.getPhoto` | [Deprecated in favor of dynamic image URLs](https://changelog.unsplash.com/2019/03/19/image-resizing.html) |

@@ -1,4 +0,4 @@

The MIT License (MIT)
MIT License
Copyright (c) 2015 Naoufal Kadhom
Copyright (c) 2020 Unsplash

@@ -22,2 +22,1 @@ Permission is hereby granted, free of charge, to any person obtaining a copy

SOFTWARE.
+55
-37
{
"name": "unsplash-js",
"version": "6.3.0",
"version": "7.0.0-beta.1",
"description": "A JavaScript wrapper for the Unsplash API",
"main": "lib/unsplash.js",
"main": "dist/index.js",
"typings": "dist/index.d.ts",
"files": [
"dist",
"src"
],
"engines": {
"node": ">=10"
},
"scripts": {
"build": "npm run build:lib && npm run build:umd && npm run build:umd:min && npm run build:examples",
"build:examples": "cp dist/unsplash.min.js examples/umd/public/unsplash.min.js",
"build:lib": "babel src --out-dir lib",
"build:umd": "webpack src/unsplash.js dist/unsplash.js --config webpack.config.development.js",
"build:umd:min": "webpack src/unsplash.js dist/unsplash.min.js --config webpack.config.production.js",
"build:watch": "babel src --watch --out-dir lib",
"lint": "eslint src",
"test": "npm run lint && npm run test:node",
"test:node": "mocha --compilers js:babel-core/register --require test/setup --recursive",
"test:watch": "npm test -- --watch",
"prepublish": "npm run build",
"publish:major": "npm run build && npm version major",
"publish:minor": "npm run build && npm version minor",
"publish:patch": "npm run build && npm version patch"
"start": "tsdx watch",
"build": "tsdx build",
"test": "tsdx test",
"lint": "tsdx lint",
"prepare": "tsdx build",
"size": "size-limit",
"analyze": "size-limit --why"
},
"resolutions": {
"typescript": "^4.0.5",
"@typescript-eslint/eslint-plugin": "^4.6.1",
"@typescript-eslint/parser": "^4.8.2"
},
"peerDependencies": {},
"husky": {
"hooks": {
"pre-commit": "tsdx lint"
}
},
"prettier": {
"printWidth": 100,
"semi": true,
"singleQuote": true,
"trailingComma": "all"
},
"module": "dist/unsplash-js.esm.js",
"size-limit": [
{
"path": "dist/unsplash-js.cjs.production.min.js",
"limit": "5 KB"
},
{
"path": "dist/unsplash-js.esm.js",
"limit": "5 KB"
}
],
"devDependencies": {
"@size-limit/preset-small-lib": "^4.9.0",
"husky": "^4.3.0",
"rollup-plugin-analyzer": "^3.3.0",
"size-limit": "^4.9.0",
"tsdx": "^0.14.1",
"tslib": "^2.0.3"
},
"repository": {

@@ -40,25 +77,6 @@ "type": "git",

"homepage": "https://github.com/unsplash/unsplash-js#readme",
"devDependencies": {
"babel": "6.3.26",
"babel-cli": "6.26.0",
"babel-core": "6.26.3",
"babel-eslint": "5.0.0-beta10",
"babel-loader": "6.2.1",
"babel-plugin-transform-class-properties": "6.4.0",
"babel-plugin-transform-object-assign": "6.3.13",
"babel-preset-es2015": "6.3.13",
"eslint": "1.10.2",
"expect": "1.12.2",
"istanbul": "0.4.2",
"mocha": "2.3.3",
"mockery": "1.4.0",
"node-fetch": "2.6.0",
"webpack": "1.12.14"
},
"dependencies": {
"form-urlencoded": "1.2.0",
"lodash.get": "4.4.2",
"querystring": "0.2.0",
"url-parse": "1.4.5"
"@types/content-type": "^1.1.3",
"content-type": "^1.0.4"
}
}
+367
-616
# Unsplash
[![npm](https://img.shields.io/npm/v/unsplash-js.svg?style=flat-square)](https://www.npmjs.com/package/unsplash-js)
[![Travis](https://img.shields.io/travis/unsplash/unsplash-js/master.svg?style=flat-square)](https://travis-ci.org/unsplash/unsplash-js/branches)
A server-side Javascript wrapper for working with the [Unsplash API](https://unsplash.com/developers).
Official Javascript wrapper for the [Unsplash API](https://unsplash.com/developers).
Before using the Unsplash API, you need to [register as a developer](https://unsplash.com/developers) and read the [API Guidelines](https://help.unsplash.com/api-guidelines/unsplash-api-guidelines).
## Quick start
Quick links to methods you're likely to care about:
- [Get a list of new photos](#photos-all) 🎉
- [Get a random photo](#photo-random) 🎑
- [Trigger a photo download](#track-download) 📡
- [Search for a photo by keyword](#search-photos) 🕵️‍♂️
**Note:** Every application must abide by the [API Guidelines](https://help.unsplash.com/api-guidelines/unsplash-api-guidelines). Specifically, remember to [hotlink images](https://help.unsplash.com/api-guidelines/more-on-each-guideline/guideline-hotlinking-images), [attribute photographers](https://help.unsplash.com/api-guidelines/more-on-each-guideline/guideline-attribution), and [trigger a download when appropriate](https://help.unsplash.com/api-guidelines/more-on-each-guideline/guideline-triggering-a-download).
## Documentation
- [Installation](https://github.com/unsplash/unsplash-js#installation)
- [Dependencies](https://github.com/unsplash/unsplash-js#dependencies)
- [Usage](https://github.com/unsplash/unsplash-js#usage)
- [Instance Methods](https://github.com/unsplash/unsplash-js#instance-methods)
- [Helpers](https://github.com/unsplash/unsplash-js#helpers)
- [Installation](#installation)
- [Dependencies](#dependencies)
- [Usage](#usage)
- [Types](#types)
- [Instance Methods](#instance-methods)
## Installation
```bash
$ npm i --save unsplash-js
```
## Dependencies
This library depends on [fetch](https://fetch.spec.whatwg.org/) to make requests to the Unsplash API. For environments that don't support fetch, you'll need to provide a [polyfill](https://github.com/bitinn/node-fetch).
# OR
```js
// ES Modules syntax
import fetch from 'node-fetch';
global.fetch = fetch;
// require syntax
const fetch = require('node-fetch');
global.fetch = fetch;
$ yarn add unsplash-js
```
Note: we recommend using a version of `node-fetch` higher than `2.4.0` to benefit from Brotli compression.
## Dependencies
## Usage
### Fetch
If you're using `unsplash-js` publicly in the browser, you'll need to proxy your requests through your server to sign the requests with the Access Key and/or Secret Key to abide by the [API Guideline](https://help.unsplash.com/articles/2511245-unsplash-api-guidelines) to keep keys confidential.
This library depends on [fetch](https://fetch.spec.whatwg.org/) to make requests to the Unsplash API. For environments that don't support fetch, you'll need to provide polyfills of your choosing. Here are the ones we recommend:
### Creating an instance
To create an instance, simply provide an _Object_ with your `accessKey`:
- node implementation: [node-fetch](https://github.com/bitinn/node-fetch)
- browser polyfill: [whatwg-fetch](https://github.com/github/fetch)
```js
// ES Modules syntax
import Unsplash, { toJson } from 'unsplash-js';
// require syntax
const Unsplash = require('unsplash-js').default;
const toJson = require('unsplash-js').toJson;
```ts
// server
import fetch from 'node-fetch';
global.fetch = fetch;
const unsplash = new Unsplash({ accessKey: APP_ACCESS_KEY });
const unsplash = new Unsplash({
accessKey: APP_ACCESS_KEY,
// Optionally you can also configure a custom header to be sent with every request
headers: {
"X-Custom-Header": "foo"
},
// Optionally if using a node-fetch polyfill or a version of fetch which supports the timeout option, you can configure the request timeout for all requests
timeout: 500 // values set in ms
});
// browser
import 'whatwg-fetch';
```
_Credentials can be obtained from [Unsplash Developers](https://unsplash.com/developers)._
Note: we recommend using a version of `node-fetch` higher than `2.4.0` to benefit from Brotli compression.
---
### URL
### Error handling
```js
unsplash.users.profile("naoufal")
.catch(err => {
// Your flawless error handling code
});
```
This library also depends on the WHATWG URL interface:
---
- MDN [docs](https://developer.mozilla.org/en-US/docs/Web/API/URL) for browsers.
- NodeJS [docs](https://nodejs.org/api/url.html).
## Instance Methods
Make sure to polyfill this interface if targetting older environments that do not implement it (i.e. Internet Explorer or a Node version older than [v8](https://nodejs.org/es/blog/release/v8.0.0/#say-hello-to-the-whatwg-url-parser))
- [Search](https://github.com/unsplash/unsplash-js#search)
- [Photos](https://github.com/unsplash/unsplash-js#photos)
- [Users](https://github.com/unsplash/unsplash-js#users)
- [Collections](https://github.com/unsplash/unsplash-js#collections)
- [User Authorization](https://github.com/unsplash/unsplash-js#user-authorization)
- [Current User](https://github.com/unsplash/unsplash-js#current-user)
## Usage
All the instance methods below make use of the `toJson` helper method described [below](https://github.com/unsplash/unsplash-js#tojsonres)
### Creating an instance
---
To create an instance, simply provide an _Object_ with your `accessKey`.
<div id="search" />
NOTE: If you're using `unsplash-js` publicly in the browser, you'll need to proxy your requests through your server to sign the requests with the Access Key to abide by the [API Guideline](https://help.unsplash.com/articles/2511245-unsplash-api-guidelines) to keep keys confidential. We provide an `apiUrl` property that lets you do so. You should only need to provide _one_ of those two values in any given scenario.
<div id="search-photos" />
```ts
import { createApi } from 'unsplash-js';
### search.photos(keyword, page, per_page, options)
Get a list of photos matching the keyword. [See endpoint docs 🚀](https://unsplash.com/documentation#search-photos)
// on your node server
const serverApi = createApi({
accessKey: 'MY_ACCESS_KEY',
//...other fetch options
});
__Arguments__
| Argument | Type | Optional/Required | Default |
|---|---|---|---|
|__`keyword`__|_string_|Required||
|__`page`__|_number_|Optional|1|
|__`per_page`__|_number_|Optional|10|
|__`options`__|_object_|Optional||
|__`options.orientation`__|_string_|Optional||
|__`options.contentFilter`__|_string_|Optional|"low"|
|__`options.color`__|_string_|Optional||
|__`options.orderBy`__|_string_|Optional|"relevant"|
|__`options.collections`__|_array_|Optional||
|__`options.lang`__|_string_|Optional|"en"|
See the [API documentation for the possible option values](https://unsplash.com/documentation#parameters-16).
__Example__
```js
unsplash.search.photos("dogs", 1, 10, { orientation: "portrait", color: "green" })
.then(toJson)
.then(json => {
// Your code
});
// in the browser
const browserApi = createApi({
apiUrl: 'https://mywebsite.com/unsplash-proxy',
//...other fetch options
});
```
### search.users(keyword, page, per_page)
Get a list of users matching the keyword. [See endpoint docs 🚀](https://unsplash.com/documentation#search-users)
### Making a request
__Arguments__
#### Arguments
| Argument | Type | Opt/Required | Default |
|---|---|---|---|
|__`keyword`__|_string_|Required||
|__`page`__|_number_|Optional|1|
|__`per_page`__|_number_|Optional|10|
All methods have 2 arguments: the first one includes all of the specific parameters for that particular endpoint, while the second allows you to pass down any additional options that you want to provide to `fetch`. On top of that, the `createApi` constructor can receive `fetch` options to be added to _every_ request:
```ts
const unsplash = createApi({
accessKey: 'MY_ACCESS_KEY',
// `fetch` options to be sent with every request
headers: { 'X-Custom-Header': 'foo' },
});
__Example__
```js
unsplash.search.users("steve", 1)
.then(toJson)
.then(json => {
// Your code
});
unsplash.photos.get(
{ photoId: '123' },
// `fetch` options to be sent only with _this_ request
{ headers: { 'X-Custom-Header-2': 'bar' } },
);
```
### search.collections(keyword, page, per_page)
Get a list of collections matching the keyword. [See endpoint docs 🚀](https://unsplash.com/documentation#search-collections)
Example: if you would like to implement [request abortion](https://developer.mozilla.org/en-US/docs/Web/API/AbortController), you can do so like this:
__Arguments__
```ts
const unsplash = createApi({
accessKey: 'MY_ACCESS_KEY',
});
| Argument | Type | Opt/Required | Default |
|---|---|---|---|
|__`keyword`__|_string_|Required||
|__`page`__|_number_|Optional|1|
|__`per_page`__|_number_|Optional|10|
const controller = new AbortController();
const signal = controller.signal;
unsplash.photos.get({ photoId: '123' }, { signal }).catch(err => {
if (err.name === 'AbortError') {
console.log('Fetch aborted');
}
});
__Example__
```js
unsplash.search.collections("dogs", 1)
.then(toJson)
.then(json => {
// Your code
});
controller.abort();
```
---
#### Response
<div id="photos" />
When making a request using this SDK, there are 2 possible outcomes to a request.
<div id="photos-all" />
- Error: we return a `result.errors` object containing an array of strings (each one representing one error) and `result.source` describing the origin of the error (e.g. `api`, `decoding`). Typically, you will only have on item in this array.
- Success: we return a `result.response` object containing the data.
- If the request is for a page from a feed, then `result.response.results` will contain the JSON received from API, and `result.response.total` will contain the [`X-total` header value](https://unsplash.com/documentation#per-page-and-total) indicating the total number of items in the feed (not just the page you asked for).
- If the request is something other than a feed, then `result.response` will contain the JSON received from API
### photos.listPhotos(page, perPage, orderBy)
Get a single page from the list of all photos. [See endpoint docs 🚀](https://unsplash.com/documentation#list-photos)
You can inspect which one you have by reading the `result.type` value or checking the contents of `result.errors`/`result.success`
__Arguments__
```ts
const unsplash = createApi({ accessKey: 'MY_ACCESS_KEY' });
| Argument | Type | Opt/Required | Default |
|---|---|---|
|__`page`__|_number_|Optional|1|
|__`perPage`__|_number_|Optional|10|
|__`orderBy`__|_string_|Optional|`latest`|
// non-feed example
unsplash.photos.get({ photoId: 'foo' }).then(result => {
if (result.errors) {
// handle error here
console.log('error occurred: ', result.errors[0]);
} else {
// handle success here
const photo = result.response;
console.log(photo);
}
});
__Example__
```js
unsplash.photos.listPhotos(2, 15, "latest")
.then(toJson)
.then(json => {
// Your code
});
```
---
// feed example
unsplash.users.getPhotos({ username: 'foo' }).then(result => {
if (result.errors) {
// handle error here
console.log('error occurred: ', result.errors[0]);
} else {
const feed = result.response;
### photos.getPhoto(id)
Retrieve a single photo. [See endpoint docs 🚀](https://unsplash.com/documentation#get-a-photo)
// extract total and results array from response
const { total, results } = feed;
__Arguments__
| Argument | Type | Opt/Required |
|---|---|---|
|__`id`__|_string_|Required|
__Example__
```js
unsplash.photos.getPhoto("mtNweauBsMQ")
.then(toJson)
.then(json => {
// Your code
});
// handle success here
console.log(`received ${results.length} photos out of ${total}`);
console.log('first photo: ', results[0]);
}
});
```
---
### photos.getPhotoStats(id)
Retrieve a single photo's stats. [See endpoint docs 🚀](https://unsplash.com/documentation#get-a-photos-statistics)
NOTE: you can also pattern-match on `result.type` whose value will be `error` or `success`:
__Arguments__
| Argument | Type | Opt/Required |
|---|---|---|
|__`id`__|_string_|Required|
__Example__
```js
unsplash.photos.getPhotoStats("mtNweauBsMQ")
.then(toJson)
.then(json => {
// Your code
});
```ts
unsplash.photos.get({ photoId: 'foo' }).then(result => {
switch (result.type) {
case 'error':
console.log('error occurred: ', result.errors[0]);
case 'success':
const photo = result.response;
console.log(photo);
}
});
```
---
<div id="photo-random" />
## Types
### photos.getRandomPhoto({ query, username, featured })
Retrieve a single random photo, given optional filters. [See endpoint docs 🚀](https://unsplash.com/documentation#get-a-random-photo)
This library is written in TypeScript. This means that even if you are writing plain JavaScript, you can still get useful and accurate type information. We highly recommend that you setup your environment (using an IDE such as [VSCode](https://code.visualstudio.com/)) to fully benefit from this information:
When using this function, It is recommended to double check the types of the parameters,
in particular for the parameters of type Array<number>.
![](./vscode-screenshot2.png)
![](./vscode-screenshot.png)
__Arguments__
## Instance Methods
Argument 1:
_An Object containing the follow keys:_
NOTE: All of the method arguments described here are in the first parameter. See the [arguments](#Arguments) section for more information.
| Argument | Type | Opt/Required |
|---|---|---|
|__`query`__|_string_|Optional|
|__`username`__|_string_|Optional|
|__`featured`__|_boolean_|Optional|
|__`collections`__|_Array<number>_|Optional|
|__`count`__|_string_|Optional|
- [Search](https://github.com/unsplash/unsplash-js#search)
- [Photos](https://github.com/unsplash/unsplash-js#photos)
- [Users](https://github.com/unsplash/unsplash-js#users)
- [Collections](https://github.com/unsplash/unsplash-js#collections)
__Example__
```js
unsplash.photos.getRandomPhoto({ username: "naoufal" })
.then(toJson)
.then(json => {
// Your code
});
```
---
### photos.likePhoto(id)
Like a photo on behalf of the logged-in user. This requires the `write_likes` scope. [See endpoint docs 🚀](https://unsplash.com/documentation#like-a-photo)
<div id="search" />
__Arguments__
<div id="search-photos" />
| Argument | Type | Opt/Required |
|---|---|---|
|__`id`__|_string_|Required|
### search.getPhotos(arguments, additionalFetchOptions)
__Example__
```js
unsplash.photos.likePhoto("mtNweauBsMQ")
.then(toJson)
.then(json => {
// Your code
});
```
---
Get a list of photos matching the query. [See endpoint docs 🚀](https://unsplash.com/documentation#search-photos)
### photos.unlikePhoto(id)
Remove a user’s like of a photo. [See endpoint docs 🚀](https://unsplash.com/documentation#unlike-a-photo)
**Arguments**
__Arguments__
| Argument | Type | Optional/Required | Default |
| ------------------- | -------- | ----------------- | ---------- |
| **`query`** | _string_ | Required | |
| **`page`** | _number_ | Optional | 1 |
| **`perPage`** | _number_ | Optional | 10 |
| **`orientation`** | _string_ | Optional | |
| **`contentFilter`** | _string_ | Optional | "low" |
| **`color`** | _string_ | Optional | |
| **`orderBy`** | _string_ | Optional | "relevant" |
| **`collectionIds`** | _array_ | Optional | |
| **`lang`** | _string_ | Optional | "en" |
| Argument | Type | Opt/Required |
|---|---|---|
|__`id`__|_string_|Required|
**Example**
__Example__
```js
unsplash.photos.unlikePhoto("mtNweauBsMQ")
.then(toJson)
.then(json => {
// Your code
});
unsplash.search.getPhotos({
query: 'cat',
page: 1,
perPage: 10,
color: 'green',
orientation: 'portrait',
});
```
---
<div id="track-download" />
### search.getUsers(arguments, additionalFetchOptions)
### photos.trackDownload(photo)
Trigger a download of a photo as per the [download tracking requirement of API Guidelines](https://medium.com/unsplash/unsplash-api-guidelines-triggering-a-download-c39b24e99e02). [See endpoint docs 🚀](https://unsplash.com/documentation#track-a-photo-download)
Get a list of users matching the query. [See endpoint docs 🚀](https://unsplash.com/documentation#search-users)
*Note*: this accepts a photo JSON object, not a URL string or photo ID. See the example below for how to pair it with other calls to trigger it.
**Arguments**
__Arguments__
| Argument | Type | Opt/Required | Default |
| ------------- | -------- | ------------ | ------- |
| **`query`** | _string_ | Required | |
| **`page`** | _number_ | Optional | 1 |
| **`perPage`** | _number_ | Optional | 10 |
| Argument | Type | Opt/Required |
|---|---|---|
|__`photo`__|_json_|Required|
**Example**
__Example__
```js
unsplash.photos.getPhoto("mtNweauBsMQ")
.then(toJson)
.then(json => {
unsplash.photos.trackDownload(json);
});
// or if working with an array of photos
unsplash.search.photos("dogs", 1)
.then(toJson)
.then(json => {
unsplash.photos.trackDownload(json["results"][0]);
});
unsplash.search.getUsers({
query: 'cat',
page: 1,
perPage: 10,
});
```
---
### search.getCollections(arguments, additionalFetchOptions)
<div id="users" />
Get a list of collections matching the query. [See endpoint docs 🚀](https://unsplash.com/documentation#search-collections)
### users.profile(username)
Retrieve public details on a given user. [See endpoint docs 🚀](https://unsplash.com/documentation#get-a-users-public-profile)
**Arguments**
__Arguments__
| Argument | Type | Opt/Required | Default |
| ------------- | -------- | ------------ | ------- |
| **`query`** | _string_ | Required | |
| **`page`** | _number_ | Optional | 1 |
| **`perPage`** | _number_ | Optional | 10 |
| Argument | Type | Opt/Required |
|---|---|---|
|__`username`__|_string_|Required|
**Example**
__Example__
```js
unsplash.users.profile("naoufal")
.then(toJson)
.then(json => {
// Your code
});
unsplash.search.getCollections({
query: 'cat',
page: 1,
perPage: 10,
});
```
---
### users.statistics(username, resolution, quantity)
Retrieve statistics for a given user. [See endpoint docs 🚀](https://unsplash.com/documentation#get-a-users-statistics)
<div id="photos" />
__Arguments__
<div id="photos-all" />
| Argument | Type | Opt/Required | Notes | Default
|---|---|---|---|---|
|__`username`__|_string_|Required|
|__`resolution`__|_string_|Optional|Currently only `days`|`days`|
|__`quantity`__|_string_|Optional||30|
### photos.list(arguments, additionalFetchOptions)
Get a single page from the list of all photos. [See endpoint docs 🚀](https://unsplash.com/documentation#list-photos)
__Example__
```js
unsplash.users.statistics("naoufal", "days", 30)
.then(toJson)
.then(json => {
// Your code
});
```
---
**Arguments**
### users.photos(username, page, perPage, orderBy, options)
Get a list of photos uploaded by a user. [See endpoint docs 🚀](https://unsplash.com/documentation#list-a-users-photos)
| Argument | Type | Opt/Required | Default |
| ------------- | -------- | ------------ | -------- |
| **`page`** | _number_ | Optional | 1 |
| **`perPage`** | _number_ | Optional | 10 |
| **`orderBy`** | _string_ | Optional | `latest` |
__Arguments__
**Example**
| Argument | Type | Opt/Required | Notes | Default |
|---|---|---|---|---|
|__`username`__|_string_|Required|||
|__`page`__|_number_|Optional||1|
|__`perPage`__|_number_|Optional||10|
|__`orderBy`__|_string_|Optional|`latest`, `oldest`|`latest`|
|__`options`__|_object_|Optional|
|__`options.stats`__|_boolean_|Optional||`false`|
|__`options.orientation`__|_string_|Optional|`landscape`, `portrait`, `squarish`|
__Example__
```js
unsplash.users.photos("naoufal", 1, 10, "latest", { orientation: "landscape" })
.then(toJson)
.then(json => {
// Your code
});
unsplash.photos.list();
unsplash.photos.list({ page: 2, page: 15 });
```
---
### users.likes(username, page, perPage, orderBy, options)
Get a list of photos liked by a user. [See endpoint docs 🚀](https://unsplash.com/documentation#list-a-users-liked-photos)
### photos.get(arguments, additionalFetchOptions)
__Arguments__
Retrieve a single photo. [See endpoint docs 🚀](https://unsplash.com/documentation#get-a-photo)
| Argument | Type | Opt/Required | Notes | Default |
|---|---|---|---|
|__`username`__|_string_|Required||
|__`page`__|_number_|Optional||1|
|__`perPage`__|_number_|Optional||10|
|__`orderBy`__|_string_|Optional|`latest`, `oldest`|`latest`|
|__`options`__|_object_|Optional||
|__`options.orientation`__|_string_|Optional|`landscape`, `portrait`, `squarish`||
**Arguments**
__Example__
```js
unsplash.users.likes("naoufal", 2, 15, "latest", { orientation: "landscape" })
.then(toJson)
.then(json => {
// Your code
});
```
---
| Argument | Type | Opt/Required |
| ------------- | -------- | ------------ |
| **`photoId`** | _string_ | Required |
### users.collections(username, page, perPage, orderBy)
Get a list of collections created by the user. [See endpoint docs 🚀](https://unsplash.com/documentation#list-a-users-collections)
**Example**
__Arguments__
| Argument | Type | Opt/Required | Notes | Default |
|---|---|---|---|
|__`username`__|_string_|Required|||
|__`page`__|_number_|Optional||1|
|__`perPage`__|_number_|Optional||10|
|__`orderBy`__|_string_|Optional|`published` or `updated`|`updated`|
__Example__
```js
unsplash.users.collections("naoufal", 2, 15, "updated")
.then(toJson)
.then(json => {
// Your code
});
unsplash.photos.get({ photoId: 'mtNweauBsMQ' });
```
---
<div id="collections" />
### photos.getStats(arguments, additionalFetchOptions)
### collections.listCollections(page, perPage, orderBy)
Get a single page from the list of all collections. [See endpoint docs 🚀](https://unsplash.com/documentation#list-collections)
Retrieve a single photo's stats. [See endpoint docs 🚀](https://unsplash.com/documentation#get-a-photos-statistics)
__Arguments__
**Arguments**
| Argument | Type | Opt/Required | Notes | Default |
|---|---|---|---|
|__`page`__|_number_|Optional||1|
|__`perPage`__|_number_|Optional||10|
|__`orderBy`__|_string_|Optional|`latest`, `oldest`|`latest`|
| Argument | Type | Opt/Required |
| ------------- | -------- | ------------ |
| **`photoId`** | _string_ | Required |
__Example__
**Example**
```js
unsplash.collections.listCollections(1, 10, "latest")
.then(toJson)
.then(json => {
// Your code
});
unsplash.photos.getStats({ photoId: 'mtNweauBsMQ' });
```
---
### collections.getCollection(id)
Retrieve a single collection. To view a user’s private collections, the `read_collections` scope is required. [See endpoint docs 🚀](https://unsplash.com/documentation#get-a-collection)
<div id="photo-random" />
__Arguments__
### photos.getRandom(arguments, additionalFetchOptions)
| Argument | Type | Opt/Required |
|---|---|---|
|__`id`__|_number_|Required|
Retrieve a single random photo, given optional filters. [See endpoint docs 🚀](https://unsplash.com/documentation#get-a-random-photo). Note: if you provide a value for `count` greater than `1`, you will receive an array of photos. Otherwise, you will receive a single photo object.
**Arguments**
__Example__
```js
unsplash.collections.getCollection(123456)
.then(toJson)
.then(json => {
// Your code
});
```
---
| Argument | Type | Opt/Required |
| ------------------- | --------------- | ------------ |
| **`query`** | _string_ | Optional |
| **`username`** | _string_ | Optional |
| **`featured`** | _boolean_ | Optional |
| **`collectionIds`** | _Array<number>_ | Optional |
| **`count`** | _string_ | Optional |
### collections.getCollectionPhotos(id, page, perPage, orderBy, options)
Retrieve a collection’s photos. [See endpoint docs 🚀](https://unsplash.com/documentation#get-a-collections-photos)
**Example**
__Arguments__
| Argument | Type | Opt/Required | Notes | Default |
|---|---|---|---|
|__`id`__|_number_|Required|||
|__`page`__|_number_|Optional||1|
|__`perPage`__|_number_|Optional||10|
|__`orderBy`__|_string_|Optional|`latest`, `oldest`|`latest`|
|__`options`__|_object_|Optional|
|__`options.orientation`__|_string_|Optional| `landscape`, `portrait`, `squarish`|
__Example__
```js
unsplash.collections.getCollectionPhotos(123456, 1, 10, "latest")
.then(toJson)
.then(json => {
// Your code
});
unsplash.photos.getRandom();
unsplash.photos.getRandom({
count: 10,
});
unsplash.photos.getRandom({
collectionIds: ['abc123'],
featured: true,
username: 'naoufal',
query: 'dog',
count: 1,
});
```
---
### collections.createCollection(title, description, private)
Create a new collection. This requires the `write_collections` scope. [See endpoint docs 🚀](https://unsplash.com/documentation#create-a-new-collection)
<div id="track-download" />
__Arguments__
### photos.trackDownload(arguments, additionalFetchOptions)
| Argument | Type | Opt/Required |
|---|---|---|
|__`title`__|_string_|Required|
|__`description`__|_string_|Optional|
|__`private`__|_boolean_|Optional|
Trigger a download of a photo as per the [download tracking requirement of API Guidelines](https://medium.com/unsplash/unsplash-api-guidelines-triggering-a-download-c39b24e99e02). [See endpoint docs 🚀](https://unsplash.com/documentation#track-a-photo-download)
__Example__
```js
unsplash.collections.createCollection("Birds", "Wild birds from 'round the world", true)
.then(toJson)
.then(json => {
// Your code
});
```
---
**Arguments**
### collections.updateCollection(id, title, description, private)
Update an existing collection belonging to the logged-in user. This requires the `write_collections` scope. [See endpoint docs 🚀](https://unsplash.com/documentation#update-an-existing-collection)
| Argument | Type | Opt/Required |
| ---------------------- | -------- | ------------ |
| **`downloadLocation`** | _string_ | Required |
__Arguments__
**Example**
| Argument | Type | Opt/Required |
|---|---|---|
|__`id`__|_number_|Required|
|__`title`__|_string_|Optional|
|__`description`__|_string_|Optional|
|__`private`__|_boolean_|Optional|
```js
unsplash.photos.get({ photoId: 'mtNweauBsMQ' }).then(result => {
if (result.type === 'success') {
const photo = result.response;
unsplash.photos.trackDownload({
downloadLocation: photo.links.downloadLocation,
});
}
});
__Example__
```js
unsplash.collections.updateCollection(12345, "Wild Birds", "Wild birds from around the world", false)
.then(toJson)
.then(json => {
// Your code
});
// or if working with an array of photos
unsplash.search.photos({ query: 'dogs' }).then(result => {
if (result.type === 'success') {
const firstPhoto = result.response.results[0];
unsplash.photos.trackDownload({
downloadLocation: photo.links.downloadLocation,
});
}
});
```
---
### collections.deleteCollection(id)
Delete a collection belonging to the logged-in user. This requires the `write_collections` scope. [See endpoint docs 🚀](https://unsplash.com/documentation#delete-a-collection)
<div id="users" />
__Arguments__
### users.get(username)
| Argument | Type | Opt/Required |
|---|---|---|
|__`id`__|_number_|Required|
Retrieve public details on a given user. [See endpoint docs 🚀](https://unsplash.com/documentation#get-a-users-public-profile)
**Arguments**
__Example__
```js
unsplash.collections.deleteCollection(88)
.then(toJson)
.then(json => {
// Your code
});
```
---
| Argument | Type | Opt/Required |
| -------------- | -------- | ------------ |
| **`username`** | _string_ | Required |
### collections.addPhotoToCollection(collectionId, photoId)
Add a photo to one of the logged-in user’s collections. Requires the `write_collections` scope. [See endpoint docs 🚀](https://unsplash.com/documentation#add-a-photo-to-a-collection)
**Example**
__Arguments__
| Argument | Type | Opt/Required |
|---|---|---|
|__`collectionId`__|_number_|Required|
|__`photoId`__|_string_|Required|
__Example__
```js
unsplash.collections.addPhotoToCollection(88, 'abc1234')
.then(toJson)
.then(json => {
// Your code
});
unsplash.users.get({ username: 'naoufal' });
```
---
### collections.removePhotoFromCollection(collectionId, photoId)
Remove a photo from one of the logged-in user’s collections. Requires the `write_collections` scope. [See endpoint docs 🚀](https://unsplash.com/documentation#remove-a-photo-from-a-collection)
### users.getPhotos(arguments, additionalFetchOptions)
__Arguments__
Get a list of photos uploaded by a user. [See endpoint docs 🚀](https://unsplash.com/documentation#list-a-users-photos)
| Argument | Type | Opt/Required |
|---|---|---|
|__`collectionId`__|_number_|Required|
|__`photoId`__|_string_|Required|
**Arguments**
__Example__
```js
unsplash.collections.removePhotoFromCollection(88, 'abc1234')
.then(toJson)
.then(json => {
// Your code
});
```
---
| Argument | Type | Opt/Required | Notes | Default |
| ----------------- | --------- | ------------ | ----------------------------------- | -------- |
| **`username`** | _string_ | Required | | |
| **`page`** | _number_ | Optional | | 1 |
| **`perPage`** | _number_ | Optional | | 10 |
| **`orderBy`** | _string_ | Optional | `latest`, `oldest` | `latest` |
| **`stats`** | _boolean_ | Optional | | `false` |
| **`orientation`** | _string_ | Optional | `landscape`, `portrait`, `squarish` | |
### collections.listRelatedCollections(collectionId)
Lists collections related to the provided one. [See endpoint docs 🚀](https://unsplash.com/documentation#list-a-collections-related-collections)
**Example**
__Arguments__
| Argument | Type | Opt/Required |
|---|---|---|
|__`collectionId`__|_number_|Required|
__Example__
```js
unsplash.collections.listRelatedCollections(88)
.then(toJson)
.then(json => {
// Your code
});
unsplash.users.getPhotos({
username: 'naoufal',
page: 1,
perPage: 10,
orderBy: 'latest',
orientation: 'landscape',
});
```

@@ -648,186 +456,129 @@

<div id="user-authorization" />
### users.getLikes(arguments, additionalFetchOptions)
Note: Most endpoints do not need to be authenticated by an individual user to be accessed and can instead be accessed with [public authentication](https://unsplash.com/documentation#public-authentication). Endpoints that require user authentication will be explicitly marked with the required scopes.
Get a list of photos liked by a user. [See endpoint docs 🚀](https://unsplash.com/documentation#list-a-users-liked-photos)
When initializing an instance of Unsplash, you'll need to include your application's `secretKey` and `callbackUrl` as defined in the [API documentation](https://unsplash.com/documentation/user-authentication-workflow):
**Arguments**
```js
const unsplash = new Unsplash({
accessKey: "{APP_ACCESS_KEY}",
secret: "{APP_SECRET}",
callbackUrl: "{CALLBACK_URL}"
});
```
| Argument | Type | Opt/Required | Notes | Default |
| ----------------- | -------- | ------------ | ----------------------------------- | -------- |
| **`username`** | _string_ | Required | | |
| **`page`** | _number_ | Optional | | 1 |
| **`perPage`** | _number_ | Optional | | 10 |
| **`orderBy`** | _string_ | Optional | `latest`, `oldest` | `latest` |
| **`orientation`** | _string_ | Optional | `landscape`, `portrait`, `squarish` | |
If you already have a bearer token, you can also provide it to the constructor:
**Example**
```js
const unsplash = new Unsplash({
accessKey: "{APP_ACCESS_KEY}",
secret: "{APP_SECRET}",
callbackUrl: "{CALLBACK_URL}",
bearerToken: "{USER_BEARER_TOKEN}"
unsplash.users.getLikes({
username: 'naoufal',
page: 1,
perPage: 10,
orderBy: 'latest',
orientation: 'landscape',
});
```
Generate an authentication url with the scopes your app requires.
---
```js
const authenticationUrl = unsplash.auth.getAuthenticationUrl([
"public",
"read_user",
"write_user",
"read_photos",
"write_photos"
]);
```
### users.getCollections(arguments, additionalFetchOptions)
Now that you have an authentication url, you'll want to redirect the user to it.
Get a list of collections created by the user. [See endpoint docs 🚀](https://unsplash.com/documentation#list-a-users-collections)
```js
location.assign(authenticationUrl);
```
**Arguments**
After the user authorizes your app she'll be redirected to your callback url with a `code` querystring present. Request an access token using that code.
| Argument | Type | Opt/Required | Notes | Default |
| -------------- | -------- | ------------ | ----- | ------- |
| **`username`** | _string_ | Required | | |
| **`page`** | _number_ | Optional | | 1 |
| **`perPage`** | _number_ | Optional | | 10 |
**Example**
```js
// The OAuth code will be passed to your callback url as a querystring
unsplash.auth.userAuthentication(query.code)
.then(toJson)
.then(json => {
unsplash.auth.setBearerToken(json.access_token);
});
unsplash.users.getCollections({
username: 'naoufal',
page: 2,
perPage: 15,
});
```
_For more information on the authroization workflow, consult the [Unsplash API Documentation](https://unsplash.com/documentation/user-authentication-workflow)._
---
### auth.getAuthenticationUrl(scopes)
Build an OAuth url with requested scopes.
<div id="collections" />
__Arguments__
### collections.list(arguments, additionalFetchOptions)
| Argument | Type | Opt/Required | Default |
|---|---|---|---|
|__`scopes`__|_Array<string>_|Optional| `["public"]` |
Get a single page from the list of all collections. [See endpoint docs 🚀](https://unsplash.com/documentation#list-collections)
__Example__
```js
const authenticationUrl = unsplash.auth.getAuthenticationUrl([
"public",
"read_user",
"write_user",
"read_photos",
"write_photos"
]);
```
---
**Arguments**
### auth.userAuthentication(code)
Retrieve a user's access token.
| Argument | Type | Opt/Required | Notes | Default |
| ------------- | -------- | ------------ | ----- | ------- |
| **`page`** | _number_ | Optional | | 1 |
| **`perPage`** | _number_ | Optional | | 10 |
__Arguments__
**Example**
| Argument | Type | Opt/Required |
|---|---|---|
|__`code`__|_string_|Required|
__Example__
```js
unsplash.auth.userAuthentication("{OAUTH_CODE}")
.then(toJson)
.then(json => {
// Your code
});
unsplash.collections.list({ page: 1, perPage: 10 });
```
---
### auth.setBearerToken(accessToken)
Set a bearer token on the instance.
### collections.get(arguments, additionalFetchOptions)
__Arguments__
Retrieve a single collection. [See endpoint docs 🚀](https://unsplash.com/documentation#get-a-collection)
| Argument | Type | Opt/Required |
|---|---|---|
|__`accessToken`__|_string_|Required|
**Arguments**
__Example__
| Argument | Type | Opt/Required |
| ------------------ | -------- | ------------ |
| **`collectionId`** | _string_ | Required |
**Example**
```js
unsplash.auth.setBearerToken("{BEARER_TOKEN}");
unsplash.collections.get({ collectionId: 'abc123' });
```
---
<div id="current-user" />
### collections.getPhotos(arguments, additionalFetchOptions)
### currentUser.profile()
Get the user’s profile.
Retrieve a collection’s photos. [See endpoint docs 🚀](https://unsplash.com/documentation#get-a-collections-photos)
__Arguments__
**Arguments**
_N/A_
| Argument | Type | Opt/Required | Notes | Default |
| ------------------ | -------- | ------------ | ----------------------------------- | -------- |
| **`collectionId`** | _string_ | Required | | |
| **`page`** | _number_ | Optional | | 1 |
| **`perPage`** | _number_ | Optional | | 10 |
| **`orderBy`** | _string_ | Optional | `latest`, `oldest` | `latest` |
| **`orientation`** | _string_ | Optional | `landscape`, `portrait`, `squarish` | |
__Example__
**Example**
```js
unsplash.currentUser.profile()
.then(toJson)
.then(json => {
// Your code
});
unsplash.collections.getPhotos({ collectionId: 'abc123' });
```
---
### currentUser.updateProfile(options)
Update the current user’s profile.
### collections.getRelated(arguments, additionalFetchOptions)
__Arguments__
Lists collections related to the provided one. [See endpoint docs 🚀](https://unsplash.com/documentation#list-a-collections-related-collections)
| Argument | Type | Opt/Required |Notes|
|---|---|---|---|
|__`options`__|_Object_|Required|Object with the following optional keys: `username`, `firstName`, `lastName`, `email`, `url`, `location`, `bio`, `instagramUsername`|
**Arguments**
__Example__
```js
unsplash.currentUser.updateProfile({
username: "drizzy",
firstName: "Aubrey",
lastName: "Graham",
email: "drizzy@octobersveryown.com",
url: "http://octobersveryown.com",
location: "Toronto, Ontario, Canada",
bio: "Views from the 6",
instagramUsername: "champagnepapi"
})
.then(toJson)
.then(json => {
// Your code
});
```
---
| Argument | Type | Opt/Required |
| ------------------ | -------- | ------------ |
| **`collectionId`** | _string_ | Required |
## Helpers
**Example**
### toJson(res)
__Arguments__
| Argument | Type | Opt/Required |
|---|---|---|
|__`res`__|_Object_|Required|
__Example__
```js
import Unsplash, { toJson } from "unsplash-js";
const unsplash = new Unsplash({
accessKey: YOUR_ACCESS_KEY,
secret: YOUR_SECRET_KEY
});
unsplash.stats.total()
.then(toJson)
.then(json => {
// Your code
});
unsplash.collections.getRelated({ collectionId: 'abc123' });
```
{
"extends": "eslint:recommended",
"ecmaFeatures": {
"modules": true
},
"env": {
"browser": true,
"node": true,
"mocha": true
},
"parser": "babel-eslint",
"rules": {
"semi": [2, "always"],
"no-multiple-empty-lines": [2, {"max": 1}],
"quotes": [2, "double", "avoid-escape"],
"space-after-keywords": 2,
"space-in-parens": [2, "never"]
}
}
#### Steps to Reproduce
-
#### Observed Behaviour
-
> _Image or video please._
#### Expected Behaviour
-
#### Technical Notes
-
[
{ "name": "Priority: Critical", "color": "#e11d21" },
{ "name": "Status: Blocked", "color": "#e11d21" },
{ "name": "Status: On Hold", "color": "#e11d21" },
{ "name": "Status: In Progress", "color": "#fbca04" },
{ "name": "Status: Ready for Review", "color": "#bfe5bf" },
{ "name": "Type: Bug", "color": "#e11d21" },
{ "name": "Type: Maintenance", "color": "#fbca04" },
{ "name": "Type: Enhancement", "color": "#84b6eb" },
{ "name": "Type: Question", "color": "#cc317c" }
]
#### Overview
-
- Closes #
#### Todo
-
#### Screenshots/Videos (User Facing Changes)
> _Insert responsive image(s) and/or video(s)_
language: node_js
dist: trusty
node_js:
- "4.8"
script:
- npm run test

Sorry, the diff of this file is too big to display

!function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e():"function"==typeof define&&define.amd?define([],e):"object"==typeof exports?exports.Unsplash=e():t.Unsplash=e()}(this,function(){return function(t){function e(n){if(r[n])return r[n].exports;var o=r[n]={exports:{},id:n,loaded:!1};return t[n].call(o.exports,o,o.exports,e),o.loaded=!0,o.exports}var r={};return e.m=t,e.c=r,e.p="",e(0)}([function(t,e,r){"use strict";function n(t){return t&&t.__esModule?t:{"default":t}}function o(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function i(t){return"function"==typeof t.json?t.json():t}Object.defineProperty(e,"__esModule",{value:!0});var u=function(){function t(t,e){for(var r=0;r<e.length;r++){var n=e[r];n.enumerable=n.enumerable||!1,n.configurable=!0,"value"in n&&(n.writable=!0),Object.defineProperty(t,n.key,n)}}return function(e,r,n){return r&&t(e.prototype,r),n&&t(e,n),e}}();e.toJson=i;var s=r(1),a=r(2),c=r(4),l=n(c),h=r(6),f=n(h),p=r(10),d=n(p),v=r(7),y=n(v),_=r(5),g=n(_),m=r(8),b=n(m),j=r(9),q=n(j),O=function(){function t(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};o(this,t),this._apiUrl=e.apiUrl||s.API_URL,this._apiVersion=e.apiVersion||s.API_VERSION,this._accessKey=e.accessKey,this._secret=e.secret,this._callbackUrl=e.callbackUrl,this._bearerToken=e.bearerToken,this._headers=e.headers||{},this._timeout=e.timeout||0,this.auth=l["default"].bind(this)(),this.currentUser=f["default"].bind(this)(),this.users=d["default"].bind(this)(),this.photos=y["default"].bind(this)(),this.collections=g["default"].bind(this)(),this.search=b["default"].bind(this)(),this.stats=q["default"].bind(this)()}return u(t,[{key:"request",value:function(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},e=a.buildFetchOptions.bind(this)(t),r=e.url,n=e.options;return fetch(r,n)}}]),t}();e["default"]=O},function(t,e){"use strict";Object.defineProperty(e,"__esModule",{value:!0});e.API_URL="https://api.unsplash.com",e.API_VERSION="v1",e.OAUTH_AUTHORIZE_URL="https://unsplash.com/oauth/authorize",e.OAUTH_TOKEN_URL="https://unsplash.com/oauth/token"},function(t,e,r){"use strict";function n(t){return t&&t.__esModule?t:{"default":t}}function o(t){return(0,l["default"])(t)}function i(t){return(0,f["default"])(t,{},!0)}function u(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},e=t.method,r=t.query,n=t.oauth,i=t.body,u=n===!0?t.url:""+this._apiUrl+t.url,c=s({},this._headers,t.headers,{"Accept-Version":this._apiVersion,Authorization:this._bearerToken?"Bearer "+this._bearerToken:"Client-ID "+this._accessKey}),l=this._timeout;return i&&(c["Content-Type"]="application/x-www-form-urlencoded"),r&&(u=decodeURIComponent(u+"?"+(0,a.stringify)(r))),{url:u,options:{method:e,headers:c,timeout:l,body:"GET"!==e&&i?o(i):void 0}}}Object.defineProperty(e,"__esModule",{value:!0});var s=Object.assign||function(t){for(var e=1;e<arguments.length;e++){var r=arguments[e];for(var n in r)Object.prototype.hasOwnProperty.call(r,n)&&(t[n]=r[n])}return t};e.formUrlEncode=o,e.getUrlComponents=i,e.buildFetchOptions=u;var a=r(3),c=r(11),l=n(c),h=r(17),f=n(h)},function(t,e,r){"use strict";e.decode=e.parse=r(13),e.encode=e.stringify=r(14)},function(t,e,r){"use strict";function n(t){return t&&t.__esModule?t:{"default":t}}function o(){var t=this;return{getAuthenticationUrl:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:["public"],r=u["default"].stringify({client_id:t._accessKey,redirect_uri:t._callbackUrl,response_type:"code",scope:e.length>1?e.join("+"):e.toString()});return decodeURIComponent(s.OAUTH_AUTHORIZE_URL+"?"+r)},userAuthentication:function(e){var r=s.OAUTH_TOKEN_URL;return t.request({url:r,method:"POST",body:{client_id:t._accessKey,client_secret:t._secret,redirect_uri:t._callbackUrl,grant_type:"authorization_code",code:e},oauth:!0})},setBearerToken:function(e){e&&(t._bearerToken=e)}}}Object.defineProperty(e,"__esModule",{value:!0}),e["default"]=o;var i=r(3),u=n(i),s=r(1)},function(t,e){"use strict";function r(){var t=this;return{listCollections:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:1,r=arguments.length>1&&void 0!==arguments[1]?arguments[1]:10,n="/collections",o={per_page:r,page:e};return t.request({url:n,method:"GET",query:o})},getCollection:n.bind(this),getCollectionPhotos:o.bind(this),createCollection:i.bind(this,null),updateCollection:i.bind(this),deleteCollection:function(e){var r="/collections/"+e;return t.request({url:r,method:"DELETE"})},addPhotoToCollection:function(e,r){var n="/collections/"+e+"/add";return t.request({url:n,method:"POST",body:{photo_id:r}})},removePhotoFromCollection:function(e,r){var n="/collections/"+e+"/remove?photo_id="+r;return t.request({url:n,method:"DELETE"})},listRelatedCollections:function(e){var r="/collections/"+e+"/related";return t.request({url:r,method:"GET"})}}}function n(t){return this.request({url:"/collections/"+t,method:"GET"})}function o(t){var e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:1,r=arguments.length>2&&void 0!==arguments[2]?arguments[2]:10,n=arguments.length>3&&void 0!==arguments[3]?arguments[3]:"latest",o=arguments.length>4&&void 0!==arguments[4]?arguments[4]:{},i={per_page:r,order_by:n,orientation:o.orientation,page:e};return Object.keys(i).forEach(function(t){i[t]||delete i[t]}),this.request({url:"/collections/"+t+"/photos",method:"GET",query:i})}function i(t,e,r,n){var o=t?"/collections/"+t:"/collections",i={title:e,description:r,"private":n};return this.request({url:o,method:t?"PUT":"POST",body:i})}Object.defineProperty(e,"__esModule",{value:!0}),e["default"]=r},function(t,e){"use strict";function r(){var t=this;return{profile:function(){var e="/me";return t.request({url:e,method:"GET"})},updateProfile:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},r="/me",n=e.username,o=e.firstName,i=e.lastName,u=e.email,s=e.url,a=e.location,c=e.bio,l=e.instagramUsername,h={username:n,first_name:o,last_name:i,email:u,url:s,location:a,bio:c,instagram_username:l};return Object.keys(h).forEach(function(t){h[t]||delete h[t]}),t.request({url:r,method:"PUT",body:h})}}}Object.defineProperty(e,"__esModule",{value:!0}),e["default"]=r},function(t,e,r){"use strict";function n(t){return t&&t.__esModule?t:{"default":t}}function o(){var t=this;return{listPhotos:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:1,r=arguments.length>1&&void 0!==arguments[1]?arguments[1]:10,n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:"latest",o="/photos",i={page:e,per_page:r,order_by:n};return t.request({url:o,method:"GET",query:i})},getPhoto:function(e){var r="/photos/"+e;return t.request({url:r,method:"GET"})},getPhotoStats:function(e){var r="/photos/"+e+"/statistics";return t.request({url:r,method:"GET"})},getRandomPhoto:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},r="/photos/random",n=e.collections||[],o={featured:e.featured,username:e.username,orientation:e.orientation,collections:n.join(),query:e.query,c:e.cacheBuster||(new Date).getTime(),count:e.count};return Object.keys(o).forEach(function(t){o[t]||delete o[t]}),t.request({url:r,method:"GET",query:o})},likePhoto:function(e){if(!t._bearerToken)throw new Error("Requires a bearerToken to be set.");var r="/photos/"+e+"/like";return t.request({url:r,method:"POST"})},unlikePhoto:function(e){if(!t._bearerToken)throw new Error("Requires a bearerToken to be set.");var r="/photos/"+e+"/like";return t.request({url:r,method:"DELETE"})},downloadPhoto:i.bind(this),trackDownload:i.bind(this)}}function i(t){var e=(0,a["default"])(t,"links.download_location",void 0);if(void 0===e)throw new Error("Object received is not a photo. "+t);var r=(0,u.getUrlComponents)(e);return this.request({url:r.pathname,method:"GET",query:r.query})}Object.defineProperty(e,"__esModule",{value:!0}),e["default"]=o;var u=r(2),s=r(12),a=n(s)},function(t,e){"use strict";function r(){var t=this;return{photos:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:"",r=arguments.length>1&&void 0!==arguments[1]?arguments[1]:1,n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:10,o=arguments.length>3&&void 0!==arguments[3]?arguments[3]:{},i=o.collections||[],u={query:encodeURIComponent(e),per_page:n,orientation:o.orientation,content_filter:o.contentFilter,color:o.color,order_by:o.orderBy,lang:o.lang,collections:i.join(),page:r};return Object.keys(u).forEach(function(t){u[t]||"query"==t||delete u[t]}),t.request({url:"/search/photos",method:"GET",query:u})},users:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:"",r=arguments.length>1&&void 0!==arguments[1]?arguments[1]:1,n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:10,o={query:encodeURIComponent(e),per_page:n,page:r};return t.request({url:"/search/users",method:"GET",query:o})},collections:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:"",r=arguments.length>1&&void 0!==arguments[1]?arguments[1]:1,n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:10,o={query:encodeURIComponent(e),per_page:n,page:r};return t.request({url:"/search/collections",method:"GET",query:o})}}}Object.defineProperty(e,"__esModule",{value:!0}),e["default"]=r},function(t,e){"use strict";function r(){var t=this;return{total:function(){var e="/stats/total";return t.request({url:e,method:"GET"})}}}Object.defineProperty(e,"__esModule",{value:!0}),e["default"]=r},function(t,e){"use strict";function r(){var t=this;return{profile:function(e){var r="/users/"+e;return t.request({url:r,method:"GET"})},photos:function(e){var r=arguments.length>1&&void 0!==arguments[1]?arguments[1]:1,n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:10,o=arguments.length>3&&void 0!==arguments[3]?arguments[3]:"latest",i=arguments.length>4&&void 0!==arguments[4]?arguments[4]:{},u=i.stats||!1,s="/users/"+e+"/photos",a={page:r,per_page:n,order_by:o,orientation:i.orientation,stats:u};return Object.keys(a).forEach(function(t){a[t]||delete a[t]}),t.request({url:s,method:"GET",query:a})},likes:function(e){var r=arguments.length>1&&void 0!==arguments[1]?arguments[1]:1,n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:10,o=arguments.length>3&&void 0!==arguments[3]?arguments[3]:"latest",i=arguments.length>4&&void 0!==arguments[4]?arguments[4]:{},u="/users/"+e+"/likes",s={page:r,per_page:n,order_by:o,orientation:i.orientation};return Object.keys(s).forEach(function(t){s[t]||delete s[t]}),t.request({url:u,method:"GET",query:s})},collections:function(e){var r=arguments.length>1&&void 0!==arguments[1]?arguments[1]:1,n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:10,o=arguments.length>3&&void 0!==arguments[3]?arguments[3]:"published",i="/users/"+e+"/collections",u={page:r,per_page:n,order_by:o};return t.request({url:i,method:"GET",query:u})},statistics:function(e){var r=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"days",n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:30,o="/users/"+e+"/statistics",i={resolution:r,quantity:n};return t.request({url:o,method:"GET",query:i})}}}Object.defineProperty(e,"__esModule",{value:!0}),e["default"]=r},function(t,e){t.exports=function(t,e){function r(t){return String(t).replace(/[^ !'()~\*]*/g,encodeURIComponent).replace(/ /g,"+").replace(/[!'()~\*]/g,function(t){return"%"+t.charCodeAt().toString(16).slice(-2).toUpperCase()})}function n(t){var r=Object.keys(t);return e.sorted?r.sort():r}function o(t){return t.filter(function(t){return t}).join("&")}function i(t,e){return o(n(e).map(function(r){return s(t+"["+r+"]",e[r])}))}function u(t,e){return o(e.map(function(e){return s(t+"[]",e)}))}function s(t,n){var o=typeof n,s=null;return n===s?s=e.ignorenull?s:r(t)+"="+s:/string|number|boolean/.test(o)?s=r(t)+"="+r(n):Array.isArray(n)?s=u(t,n):"object"===o&&(s=i(t,n)),s}return e="object"==typeof e?e:{},o(n(t).map(function(e){return s(e,t[e])}))}},function(t,e){(function(e){function r(t,e){return null==t?void 0:t[e]}function n(t){var e=!1;if(null!=t&&"function"!=typeof t.toString)try{e=!!(t+"")}catch(r){}return e}function o(t){var e=-1,r=t?t.length:0;for(this.clear();++e<r;){var n=t[e];this.set(n[0],n[1])}}function i(){this.__data__=yt?yt(null):{}}function u(t){return this.has(t)&&delete this.__data__[t]}function s(t){var e=this.__data__;if(yt){var r=e[t];return r===z?void 0:r}return lt.call(e,t)?e[t]:void 0}function a(t){var e=this.__data__;return yt?void 0!==e[t]:lt.call(e,t)}function c(t,e){var r=this.__data__;return r[t]=yt&&void 0===e?z:e,this}function l(t){var e=-1,r=t?t.length:0;for(this.clear();++e<r;){var n=t[e];this.set(n[0],n[1])}}function h(){this.__data__=[]}function f(t){var e=this.__data__,r=q(e,t);if(r<0)return!1;var n=e.length-1;return r==n?e.pop():dt.call(e,r,1),!0}function p(t){var e=this.__data__,r=q(e,t);return r<0?void 0:e[r][1]}function d(t){return q(this.__data__,t)>-1}function v(t,e){var r=this.__data__,n=q(r,t);return n<0?r.push([t,e]):r[n][1]=e,this}function y(t){var e=-1,r=t?t.length:0;for(this.clear();++e<r;){var n=t[e];this.set(n[0],n[1])}}function _(){this.__data__={hash:new o,map:new(vt||l),string:new o}}function g(t){return U(this,t)["delete"](t)}function m(t){return U(this,t).get(t)}function b(t){return U(this,t).has(t)}function j(t,e){return U(this,t).set(t,e),this}function q(t,e){for(var r=t.length;r--;)if(G(t[r][0],e))return r;return-1}function O(t,e){e=C(e,t)?[e]:w(e);for(var r=0,n=e.length;null!=t&&r<n;)t=t[A(e[r++])];return r&&r==n?t:void 0}function E(t){if(!M(t)||x(t))return!1;var e=S(t)||n(t)?ft:tt;return e.test(R(t))}function T(t){if("string"==typeof t)return t;if(L(t))return gt?gt.call(t):"";var e=t+"";return"0"==e&&1/t==-D?"-0":e}function w(t){return bt(t)?t:mt(t)}function U(t,e){var r=t.__data__;return P(e)?r["string"==typeof e?"string":"hash"]:r.map}function k(t,e){var n=r(t,e);return E(n)?n:void 0}function C(t,e){if(bt(t))return!1;var r=typeof t;return!("number"!=r&&"symbol"!=r&&"boolean"!=r&&null!=t&&!L(t))||(J.test(t)||!Z.test(t)||null!=e&&t in Object(e))}function P(t){var e=typeof t;return"string"==e||"number"==e||"symbol"==e||"boolean"==e?"__proto__"!==t:null===t}function x(t){return!!at&&at in t}function A(t){if("string"==typeof t||L(t))return t;var e=t+"";return"0"==e&&1/t==-D?"-0":e}function R(t){if(null!=t){try{return ct.call(t)}catch(e){}try{return t+""}catch(e){}}return""}function I(t,e){if("function"!=typeof t||e&&"function"!=typeof e)throw new TypeError(K);var r=function(){var n=arguments,o=e?e.apply(this,n):n[0],i=r.cache;if(i.has(o))return i.get(o);var u=t.apply(this,n);return r.cache=i.set(o,u),u};return r.cache=new(I.Cache||y),r}function G(t,e){return t===e||t!==t&&e!==e}function S(t){var e=M(t)?ht.call(t):"";return e==H||e==V}function M(t){var e=typeof t;return!!t&&("object"==e||"function"==e)}function F(t){return!!t&&"object"==typeof t}function L(t){return"symbol"==typeof t||F(t)&&ht.call(t)==B}function N(t){return null==t?"":T(t)}function $(t,e,r){var n=null==t?void 0:O(t,e);return void 0===n?r:n}var K="Expected a function",z="__lodash_hash_undefined__",D=1/0,H="[object Function]",V="[object GeneratorFunction]",B="[object Symbol]",Z=/\.|\[(?:[^[\]]*|(["'])(?:(?!\1)[^\\]|\\.)*?\1)\]/,J=/^\w*$/,Q=/^\./,W=/[^.[\]]+|\[(?:(-?\d+(?:\.\d+)?)|(["'])((?:(?!\2)[^\\]|\\.)*?)\2)\]|(?=(?:\.|\[\])(?:\.|\[\]|$))/g,X=/[\\^$.*+?()[\]{}|]/g,Y=/\\(\\)?/g,tt=/^\[object .+?Constructor\]$/,et="object"==typeof e&&e&&e.Object===Object&&e,rt="object"==typeof self&&self&&self.Object===Object&&self,nt=et||rt||Function("return this")(),ot=Array.prototype,it=Function.prototype,ut=Object.prototype,st=nt["__core-js_shared__"],at=function(){var t=/[^.]+$/.exec(st&&st.keys&&st.keys.IE_PROTO||"");return t?"Symbol(src)_1."+t:""}(),ct=it.toString,lt=ut.hasOwnProperty,ht=ut.toString,ft=RegExp("^"+ct.call(lt).replace(X,"\\$&").replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g,"$1.*?")+"$"),pt=nt.Symbol,dt=ot.splice,vt=k(nt,"Map"),yt=k(Object,"create"),_t=pt?pt.prototype:void 0,gt=_t?_t.toString:void 0;o.prototype.clear=i,o.prototype["delete"]=u,o.prototype.get=s,o.prototype.has=a,o.prototype.set=c,l.prototype.clear=h,l.prototype["delete"]=f,l.prototype.get=p,l.prototype.has=d,l.prototype.set=v,y.prototype.clear=_,y.prototype["delete"]=g,y.prototype.get=m,y.prototype.has=b,y.prototype.set=j;var mt=I(function(t){t=N(t);var e=[];return Q.test(t)&&e.push(""),t.replace(W,function(t,r,n,o){e.push(n?o.replace(Y,"$1"):r||t)}),e});I.Cache=y;var bt=Array.isArray;t.exports=$}).call(e,function(){return this}())},function(t,e){"use strict";function r(t,e){return Object.prototype.hasOwnProperty.call(t,e)}t.exports=function(t,e,n,o){e=e||"&",n=n||"=";var i={};if("string"!=typeof t||0===t.length)return i;var u=/\+/g;t=t.split(e);var s=1e3;o&&"number"==typeof o.maxKeys&&(s=o.maxKeys);var a=t.length;s>0&&a>s&&(a=s);for(var c=0;c<a;++c){var l,h,f,p,d=t[c].replace(u,"%20"),v=d.indexOf(n);v>=0?(l=d.substr(0,v),h=d.substr(v+1)):(l=d,h=""),f=decodeURIComponent(l),p=decodeURIComponent(h),r(i,f)?Array.isArray(i[f])?i[f].push(p):i[f]=[i[f],p]:i[f]=p}return i}},function(t,e){"use strict";var r=function(t){switch(typeof t){case"string":return t;case"boolean":return t?"true":"false";case"number":return isFinite(t)?t:"";default:return""}};t.exports=function(t,e,n,o){return e=e||"&",n=n||"=",null===t&&(t=void 0),"object"==typeof t?Object.keys(t).map(function(o){var i=encodeURIComponent(r(o))+n;return Array.isArray(t[o])?t[o].map(function(t){return i+encodeURIComponent(r(t))}).join(e):i+encodeURIComponent(r(t[o]))}).join(e):o?encodeURIComponent(r(o))+n+encodeURIComponent(r(t)):""}},function(t,e){"use strict";function r(t){try{return decodeURIComponent(t.replace(/\+/g," "))}catch(e){return null}}function n(t){for(var e,n=/([^=?&]+)=?([^&]*)/g,o={};e=n.exec(t);){var i=r(e[1]),u=r(e[2]);null===i||null===u||i in o||(o[i]=u)}return o}function o(t,e){e=e||"";var r,n,o=[];"string"!=typeof e&&(e="?");for(n in t)if(u.call(t,n)){if(r=t[n],r||null!==r&&r!==i&&!isNaN(r)||(r=""),n=encodeURIComponent(n),r=encodeURIComponent(r),null===n||null===r)continue;o.push(n+"="+r)}return o.length?e+o.join("&"):""}var i,u=Object.prototype.hasOwnProperty;e.stringify=o,e.parse=n},function(t,e){"use strict";t.exports=function(t,e){if(e=e.split(":")[0],t=+t,!t)return!1;switch(e){case"http":case"ws":return 80!==t;case"https":case"wss":return 443!==t;case"ftp":return 21!==t;case"gopher":return 70!==t;case"file":return!1}return 0!==t}},function(t,e,r){(function(e){"use strict";function n(t){return(t||"").replace(v,"")}function o(t){var r;r="undefined"!=typeof window?window:"undefined"!=typeof e?e:"undefined"!=typeof self?self:{};var n=r.location||{};t=t||n;var o,i={},u=typeof t;if("blob:"===t.protocol)i=new s(unescape(t.pathname),{});else if("string"===u){i=new s(t,{});for(o in _)delete i[o]}else if("object"===u){for(o in t)o in _||(i[o]=t[o]);void 0===i.slashes&&(i.slashes=f.test(t.href))}return i}function i(t){t=n(t);var e=p.exec(t);return{protocol:e[1]?e[1].toLowerCase():"",slashes:!!e[2],rest:e[3]}}function u(t,e){if(""===t)return e;for(var r=(e||"/").split("/").slice(0,-1).concat(t.split("/")),n=r.length,o=r[n-1],i=!1,u=0;n--;)"."===r[n]?r.splice(n,1):".."===r[n]?(r.splice(n,1),u++):u&&(0===n&&(i=!0),r.splice(n,1),u--);return i&&r.unshift(""),"."!==o&&".."!==o||r.push(""),r.join("/")}function s(t,e,r){if(t=n(t),!(this instanceof s))return new s(t,e,r);var a,c,f,p,d,v,_=y.slice(),g=typeof e,m=this,b=0;for("object"!==g&&"string"!==g&&(r=e,e=null),r&&"function"!=typeof r&&(r=h.parse),e=o(e),c=i(t||""),a=!c.protocol&&!c.slashes,m.slashes=c.slashes||a&&e.slashes,m.protocol=c.protocol||e.protocol||"",t=c.rest,c.slashes||(_[3]=[/(.*)/,"pathname"]);b<_.length;b++)p=_[b],"function"!=typeof p?(f=p[0],v=p[1],f!==f?m[v]=t:"string"==typeof f?~(d=t.indexOf(f))&&("number"==typeof p[2]?(m[v]=t.slice(0,d),t=t.slice(d+p[2])):(m[v]=t.slice(d),t=t.slice(0,d))):(d=f.exec(t))&&(m[v]=d[1],t=t.slice(0,d.index)),m[v]=m[v]||(a&&p[3]?e[v]||"":""),p[4]&&(m[v]=m[v].toLowerCase())):t=p(t);r&&(m.query=r(m.query)),a&&e.slashes&&"/"!==m.pathname.charAt(0)&&(""!==m.pathname||""!==e.pathname)&&(m.pathname=u(m.pathname,e.pathname)),l(m.port,m.protocol)||(m.host=m.hostname,m.port=""),m.username=m.password="",m.auth&&(p=m.auth.split(":"),m.username=p[0]||"",m.password=p[1]||""),m.origin=m.protocol&&m.host&&"file:"!==m.protocol?m.protocol+"//"+m.host:"null",m.href=m.toString()}function a(t,e,r){var n=this;switch(t){case"query":"string"==typeof e&&e.length&&(e=(r||h.parse)(e)),n[t]=e;break;case"port":n[t]=e,l(e,n.protocol)?e&&(n.host=n.hostname+":"+e):(n.host=n.hostname,n[t]="");break;case"hostname":n[t]=e,n.port&&(e+=":"+n.port),n.host=e;break;case"host":n[t]=e,/:\d+$/.test(e)?(e=e.split(":"),n.port=e.pop(),n.hostname=e.join(":")):(n.hostname=e,n.port="");break;case"protocol":n.protocol=e.toLowerCase(),n.slashes=!r;break;case"pathname":case"hash":if(e){var o="pathname"===t?"/":"#";n[t]=e.charAt(0)!==o?o+e:e}else n[t]=e;break;default:n[t]=e}for(var i=0;i<y.length;i++){var u=y[i];u[4]&&(n[u[1]]=n[u[1]].toLowerCase())}return n.origin=n.protocol&&n.host&&"file:"!==n.protocol?n.protocol+"//"+n.host:"null",n.href=n.toString(),n}function c(t){t&&"function"==typeof t||(t=h.stringify);var e,r=this,n=r.protocol;n&&":"!==n.charAt(n.length-1)&&(n+=":");var o=n+(r.slashes?"//":"");return r.username&&(o+=r.username,r.password&&(o+=":"+r.password),o+="@"),o+=r.host+r.pathname,e="object"==typeof r.query?t(r.query):r.query,e&&(o+="?"!==e.charAt(0)?"?"+e:e),r.hash&&(o+=r.hash),o}var l=r(16),h=r(15),f=/^[A-Za-z][A-Za-z0-9+-.]*:\/\//,p=/^([a-z][a-z0-9.+-]*:)?(\/\/)?([\S\s]*)/i,d="[\\x09\\x0A\\x0B\\x0C\\x0D\\x20\\xA0\\u1680\\u180E\\u2000\\u2001\\u2002\\u2003\\u2004\\u2005\\u2006\\u2007\\u2008\\u2009\\u200A\\u202F\\u205F\\u3000\\u2028\\u2029\\uFEFF]",v=new RegExp("^"+d+"+"),y=[["#","hash"],["?","query"],function(t){return t.replace("\\","/")},["/","pathname"],["@","auth",1],[NaN,"host",void 0,1,1],[/:(\d+)$/,"port",void 0,1],[NaN,"hostname",void 0,1,1]],_={hash:1,query:1};s.prototype={set:a,toString:c},s.extractProtocol=i,s.location=o,s.trimLeft=n,s.qs=h,t.exports=s}).call(e,function(){return this}())}])});
import config from 'universal-config';
import Unsplash, { toJson } from 'unsplash-js';
const unsplash = new Unsplash({
accessKey: config.get('ACCESS_KEY')
});
users();
photos();
collections();
function users() {
console.log("\nUsers")
unsplash.users.profile('naoufal')
.then(toJson)
.then(json => {
console.log(json);
});
unsplash.users.photos("naoufal")
.then(toJson)
.then(json => {
console.log(json);
});
unsplash.users.likes("naoufal")
.then(toJson)
.then(json => {
console.log(json);
});
}
function photos() {
console.log("\nPhotos");
unsplash.photos.listPhotos(1, 10)
.then(toJson)
.then(json => {
console.log(json);
});
unsplash.photos.getPhoto("kZ8dyUT0h30")
.then(toJson)
.then(json => {
console.log(json);
});
unsplash.photos.getRandomPhoto({ featured: true })
.then(toJson)
.then(json => {
console.log(json.links.html);
});
}
function collections() {
console.log("\nCollections");
unsplash.collections.listCollections(1, 10)
.then(toJson)
.then(json => {
console.log(json);
});
unsplash.collections.getCollection(151165)
.then(toJson)
.then(json => {
console.log(json);
});
unsplash.collections.getCollectionPhotos(151165)
.then(toJson)
.then(json => {
console.log(json);
});
}
module.exports = {
ACCESS_KEY: process.env.ACCESS_KEY || '5f82c78e3722e13421afa7674623013d3c7bc0673f114e08d8f0aa12eeec9373',
SECRET: process.env.SECRET || 'b5906a7297749a82b7aead883d14468bb9368c84a2ee3733946a919d71d2c24b',
CALLBACK_URL: process.env.CALLBACK_URL || 'http://unsplash-js.herokuapp.com'
};
require('babel-register');
global.fetch = require('node-fetch');
require('./app');
{
"name": "unsplash-js-node-example",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "MIT",
"dependencies": {
"babel-register": "6.6.5",
"node-fetch": "1.5.0",
"universal-config": "0.1.0",
"unsplash-js": "../.."
}
}
<html>
<head>
<title>Unsplash UMD Example</title>
</head>
<body>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/fetch/0.10.1/fetch.min.js"></script>
<script src="/js/unsplash.min.js"></script>
<script src="/js/main.js"></script>
</body>
</html>
{
"name": "unsplash-js-umd-example",
"version": "1.0.0",
"description": "",
"main": "server.js",
"scripts": {
"start": "NODE_ENV=production node server.js"
},
"repository": {
"type": "git",
"url": "git+https://github.com/naoufal/unsplash.git"
},
"author": "Naoufal Kadhom",
"license": "MIT",
"bugs": {
"url": "https://github.com/naoufal/unsplash/issues"
},
"homepage": "https://github.com/naoufal/unsplash#readme",
"devDependencies": {
"express": "4.13.3"
}
}
var unsplash = new Unsplash({
accessKey: "{YOUR_ACCESS_KEY}",
secret: "{YOUR_SECRET}"
});
unsplash.users.profile("naoufal")
.then(Unsplash.toJson)
.then(function (json) {
console.log(json);
});
var express = require('express');
var app = express();
app.use('/js', express.static('public'));
app.get('/', function(req, res) {
res.sendFile(__dirname + '/index.html');
});
app.listen(3000, 'localhost', function(err) {
if (err) {
console.log(err);
}
console.log('Listening at localhost:3000');
});
<html>
<head>
<title>Unsplash Webpack Example</title>
</head>
<body>
<div id="root">
</div>
<script src="/static/bundle.js"></script>
</body>
</html>
require('es6-promise').polyfill();
require('whatwg-fetch');
require('./main');
import Unsplash, { toJson } from "unsplash-js";
let unsplash = new Unsplash({
accessKey: "{YOUR_ACCESS_KEY}",
secret: "{YOUR_SECRET}"
});
unsplash.users.profile("naoufal")
.then(toJson)
.then(json => {
console.log(json);
});
{
"name": "unsplash-js-webpack-example",
"version": "1.0.0",
"description": "",
"main": "server.js",
"scripts": {
"start": "NODE_ENV=production node server.js"
},
"repository": {
"type": "git",
"url": "git+https://github.com/naoufal/unsplash.git"
},
"author": "Naoufal Kadhom",
"license": "MIT",
"bugs": {
"url": "https://github.com/naoufal/unsplash/issues"
},
"homepage": "https://github.com/naoufal/unsplash#readme",
"devDependencies": {
"babel-core": "^6.4.0",
"babel-eslint": "5.0.0-beta6",
"babel-loader": "^6.2.1",
"babel-preset-es2015": "^6.3.13",
"es6-promise": "3.0.2",
"exports-loader": "0.6.2",
"imports-loader": "0.6.5",
"unsplash-js": "../..",
"webpack": "1.12.3",
"webpack-dev-server": "1.12.1",
"whatwg-fetch": "0.10.1"
}
}
var webpack = require('webpack');
var WebpackDevServer = require('webpack-dev-server');
var config = require('./webpack.config');
new WebpackDevServer(webpack(config), {
publicPath: config.output.publicPath,
hot: true,
historyApiFallback: true,
stats: {
colors: true
}
}).listen(3000, 'localhost', function (err) {
if (err) {
console.log(err);
}
console.log('Listening at localhost:3000');
});
var path = require("path");
var webpack = require("webpack");
module.exports = {
devtool: "eval",
entry: [
"webpack-dev-server/client?http://localhost:3000",
"webpack/hot/only-dev-server",
"./index"
],
output: {
path: path.join(__dirname, "dist"),
filename: "bundle.js",
publicPath: "/static/"
},
plugins: [
new webpack.HotModuleReplacementPlugin(),
new webpack.NoErrorsPlugin(),
new webpack.IgnorePlugin(/node-fetch/)
],
module: {
loaders: [{
test: /\.js$/,
loaders: ["babel-loader"],
exclude: /node_modules/,
include: __dirname
}]
}
};

Sorry, the diff of this file is too big to display

"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
var API_URL = exports.API_URL = "https://api.unsplash.com";
var API_VERSION = exports.API_VERSION = "v1";
var OAUTH_AUTHORIZE_URL = exports.OAUTH_AUTHORIZE_URL = "https://unsplash.com/oauth/authorize";
var OAUTH_TOKEN_URL = exports.OAUTH_TOKEN_URL = "https://unsplash.com/oauth/token";
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = auth;
var _querystring = require("querystring");
var _querystring2 = _interopRequireDefault(_querystring);
var _constants = require("../constants");
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function auth() {
var _this = this;
return {
getAuthenticationUrl: function getAuthenticationUrl() {
var scope = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : ["public"];
var querystrings = _querystring2.default.stringify({
client_id: _this._accessKey,
redirect_uri: _this._callbackUrl,
response_type: "code",
scope: scope.length > 1 ? scope.join("+") : scope.toString()
});
return decodeURIComponent(_constants.OAUTH_AUTHORIZE_URL + "?" + querystrings);
},
userAuthentication: function userAuthentication(code) {
var url = _constants.OAUTH_TOKEN_URL;
return _this.request({
url: url,
method: "POST",
body: {
client_id: _this._accessKey,
client_secret: _this._secret,
redirect_uri: _this._callbackUrl,
grant_type: "authorization_code",
code: code
},
oauth: true
});
},
setBearerToken: function setBearerToken(accessToken) {
if (accessToken) {
_this._bearerToken = accessToken;
}
}
};
}
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = collections;
function collections() {
var _this = this;
return {
listCollections: function listCollections() {
var page = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 1;
var perPage = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 10;
var url = "/collections";
var query = {
per_page: perPage,
page: page
};
return _this.request({
url: url,
method: "GET",
query: query
});
},
getCollection: collection.bind(this),
getCollectionPhotos: collectionPhotos.bind(this),
createCollection: createUpdateCollection.bind(this, null),
updateCollection: createUpdateCollection.bind(this),
deleteCollection: function deleteCollection(id) {
var url = "/collections/" + id;
return _this.request({
url: url,
method: "DELETE"
});
},
addPhotoToCollection: function addPhotoToCollection(collectionId, photoId) {
var url = "/collections/" + collectionId + "/add";
return _this.request({
url: url,
method: "POST",
body: {
photo_id: photoId
}
});
},
removePhotoFromCollection: function removePhotoFromCollection(collectionId, photoId) {
var url = "/collections/" + collectionId + "/remove?photo_id=" + photoId;
return _this.request({
url: url,
method: "DELETE"
});
},
listRelatedCollections: function listRelatedCollections(collectionId) {
var url = "/collections/" + collectionId + "/related";
return _this.request({
url: url,
method: "GET"
});
}
};
}
function collection(id) {
return this.request({
url: "/collections/" + id,
method: "GET"
});
}
function collectionPhotos(id) {
var page = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 1;
var perPage = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 10;
var orderBy = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : "latest";
var options = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : {};
var query = {
per_page: perPage,
order_by: orderBy,
orientation: options.orientation,
page: page
};
Object.keys(query).forEach(function (key) {
if (!query[key]) {
delete query[key];
}
});
return this.request({
url: "/collections/" + id + "/photos",
method: "GET",
query: query
});
}
function createUpdateCollection(id, title, description, isPrivate) {
var url = id ? "/collections/" + id : "/collections";
var body = {
title: title,
description: description,
"private": isPrivate
};
return this.request({
url: url,
method: id ? "PUT" : "POST",
body: body
});
}
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = currentUser;
function currentUser() {
var _this = this;
return {
profile: function profile() {
var url = "/me";
return _this.request({
url: url,
method: "GET"
});
},
updateProfile: function updateProfile() {
var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
var endpointUrl = "/me";
var username = options.username,
firstName = options.firstName,
lastName = options.lastName,
email = options.email,
url = options.url,
location = options.location,
bio = options.bio,
instagramUsername = options.instagramUsername;
var body = {
username: username,
first_name: firstName,
last_name: lastName,
email: email,
url: url,
location: location,
bio: bio,
instagram_username: instagramUsername
};
Object.keys(body).forEach(function (key) {
if (!body[key]) {
delete body[key];
}
});
return _this.request({
url: endpointUrl,
method: "PUT",
body: body
});
}
};
}
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = photos;
var _utils = require("../utils");
var _lodash = require("lodash.get");
var _lodash2 = _interopRequireDefault(_lodash);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function photos() {
var _this = this;
return {
listPhotos: function listPhotos() {
var page = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 1;
var perPage = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 10;
var orderBy = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : "latest";
var url = "/photos";
var query = {
page: page,
per_page: perPage,
order_by: orderBy
};
return _this.request({
url: url,
method: "GET",
query: query
});
},
getPhoto: function getPhoto(id) {
var url = "/photos/" + id;
return _this.request({
url: url,
method: "GET"
});
},
getPhotoStats: function getPhotoStats(id) {
var url = "/photos/" + id + "/statistics";
return _this.request({
url: url,
method: "GET"
});
},
getRandomPhoto: function getRandomPhoto() {
var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
var url = "/photos/random";
var collections = options.collections || [];
var query = {
featured: options.featured,
username: options.username,
orientation: options.orientation,
collections: collections.join(),
query: options.query,
c: options.cacheBuster || new Date().getTime(), // Avoid ajax response caching
count: options.count
};
Object.keys(query).forEach(function (key) {
if (!query[key]) {
delete query[key];
}
});
return _this.request({
url: url,
method: "GET",
query: query
});
},
likePhoto: function likePhoto(id) {
if (!_this._bearerToken) {
throw new Error("Requires a bearerToken to be set.");
}
var url = "/photos/" + id + "/like";
return _this.request({
url: url,
method: "POST"
});
},
unlikePhoto: function unlikePhoto(id) {
if (!_this._bearerToken) {
throw new Error("Requires a bearerToken to be set.");
}
var url = "/photos/" + id + "/like";
return _this.request({
url: url,
method: "DELETE"
});
},
// Deprecated in 6.2
downloadPhoto: track.bind(this),
trackDownload: track.bind(this)
};
}
function track(photo) {
var downloadLocation = (0, _lodash2.default)(photo, "links.download_location", undefined);
if (downloadLocation === undefined) {
throw new Error("Object received is not a photo. " + photo);
}
var urlComponents = (0, _utils.getUrlComponents)(downloadLocation);
return this.request({
url: urlComponents.pathname,
method: "GET",
query: urlComponents.query
});
}
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = search;
function search() {
var _this = this;
return {
photos: function photos() {
var keyword = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : "";
var page = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 1;
var perPage = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 10;
var options = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {};
var collections = options.collections || [];
var query = {
query: encodeURIComponent(keyword),
per_page: perPage,
orientation: options.orientation,
content_filter: options.contentFilter,
color: options.color,
order_by: options.orderBy,
lang: options.lang,
collections: collections.join(),
page: page
};
Object.keys(query).forEach(function (key) {
if (!query[key] && key != "query") {
delete query[key];
}
});
return _this.request({
url: "/search/photos",
method: "GET",
query: query
});
},
users: function users() {
var keyword = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : "";
var page = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 1;
var perPage = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 10;
var query = {
query: encodeURIComponent(keyword),
per_page: perPage,
page: page
};
return _this.request({
url: "/search/users",
method: "GET",
query: query
});
},
collections: function collections() {
var keyword = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : "";
var page = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 1;
var perPage = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 10;
var query = {
query: encodeURIComponent(keyword),
per_page: perPage,
page: page
};
return _this.request({
url: "/search/collections",
method: "GET",
query: query
});
}
};
}
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = stats;
function stats() {
var _this = this;
return {
total: function total() {
var url = "/stats/total";
return _this.request({
url: url,
method: "GET"
});
}
};
}
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = users;
function users() {
var _this = this;
return {
profile: function profile(username) {
var url = "/users/" + username;
return _this.request({
url: url,
method: "GET"
});
},
photos: function photos(username) {
var page = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 1;
var perPage = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 10;
var orderBy = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : "latest";
var options = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : {};
var stats = options.stats || false;
var url = "/users/" + username + "/photos";
var query = {
page: page,
per_page: perPage,
order_by: orderBy,
orientation: options.orientation,
stats: stats
};
Object.keys(query).forEach(function (key) {
if (!query[key]) {
delete query[key];
}
});
return _this.request({
url: url,
method: "GET",
query: query
});
},
likes: function likes(username) {
var page = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 1;
var perPage = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 10;
var orderBy = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : "latest";
var options = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : {};
var url = "/users/" + username + "/likes";
var query = {
page: page,
per_page: perPage,
order_by: orderBy,
orientation: options.orientation
};
Object.keys(query).forEach(function (key) {
if (!query[key]) {
delete query[key];
}
});
return _this.request({
url: url,
method: "GET",
query: query
});
},
collections: function collections(username) {
var page = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 1;
var perPage = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 10;
var orderBy = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : "published";
var url = "/users/" + username + "/collections";
var query = {
page: page,
per_page: perPage,
order_by: orderBy
};
return _this.request({
url: url,
method: "GET",
query: query
});
},
statistics: function statistics(username) {
var resolution = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : "days";
var quantity = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 30;
var url = "/users/" + username + "/statistics";
var query = {
resolution: resolution,
quantity: quantity
};
return _this.request({
url: url,
method: "GET",
query: query
});
}
};
}
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
exports.toJson = toJson;
var _constants = require("./constants");
var _utils = require("./utils");
var _auth = require("./methods/auth");
var _auth2 = _interopRequireDefault(_auth);
var _currentUser = require("./methods/currentUser");
var _currentUser2 = _interopRequireDefault(_currentUser);
var _users = require("./methods/users");
var _users2 = _interopRequireDefault(_users);
var _photos = require("./methods/photos");
var _photos2 = _interopRequireDefault(_photos);
var _collections = require("./methods/collections");
var _collections2 = _interopRequireDefault(_collections);
var _search = require("./methods/search");
var _search2 = _interopRequireDefault(_search);
var _stats = require("./methods/stats");
var _stats2 = _interopRequireDefault(_stats);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
var Unsplash = function () {
function Unsplash() {
var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
_classCallCheck(this, Unsplash);
this._apiUrl = options.apiUrl || _constants.API_URL;
this._apiVersion = options.apiVersion || _constants.API_VERSION;
this._accessKey = options.accessKey;
this._secret = options.secret;
this._callbackUrl = options.callbackUrl;
this._bearerToken = options.bearerToken;
this._headers = options.headers || {};
this._timeout = options.timeout || 0; // 0 defaults to the OS timeout behaviour.
this.auth = _auth2.default.bind(this)();
this.currentUser = _currentUser2.default.bind(this)();
this.users = _users2.default.bind(this)();
this.photos = _photos2.default.bind(this)();
this.collections = _collections2.default.bind(this)();
this.search = _search2.default.bind(this)();
this.stats = _stats2.default.bind(this)();
}
_createClass(Unsplash, [{
key: "request",
value: function request() {
var requestOptions = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
var _buildFetchOptions$bi = _utils.buildFetchOptions.bind(this)(requestOptions),
url = _buildFetchOptions$bi.url,
options = _buildFetchOptions$bi.options;
return fetch(url, options);
}
}]);
return Unsplash;
}();
exports.default = Unsplash;
function toJson(res) {
return typeof res.json === "function" ? res.json() : res;
}
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
exports.formUrlEncode = formUrlEncode;
exports.getUrlComponents = getUrlComponents;
exports.buildFetchOptions = buildFetchOptions;
var _querystring = require("querystring");
var _formUrlencoded = require("form-urlencoded");
var _formUrlencoded2 = _interopRequireDefault(_formUrlencoded);
var _urlParse = require("url-parse");
var _urlParse2 = _interopRequireDefault(_urlParse);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function formUrlEncode(body) {
return (0, _formUrlencoded2.default)(body);
}
function getUrlComponents(uri) {
return (0, _urlParse2.default)(uri, {}, true);
}
function buildFetchOptions() {
var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
var method = options.method,
query = options.query,
oauth = options.oauth,
body = options.body;
var url = oauth === true ? options.url : "" + this._apiUrl + options.url;
var headers = _extends({}, this._headers, options.headers, {
"Accept-Version": this._apiVersion,
"Authorization": this._bearerToken ? "Bearer " + this._bearerToken : "Client-ID " + this._accessKey
});
var timeout = this._timeout;
if (body) {
headers["Content-Type"] = "application/x-www-form-urlencoded";
}
if (query) {
url = decodeURIComponent(url + "?" + (0, _querystring.stringify)(query));
}
return {
url: url,
options: {
method: method,
headers: headers,
timeout: timeout,
body: method !== "GET" && body ? formUrlEncode(body) : undefined
}
};
}
module.exports = require('./src/unsplash');
export const API_URL = "https://api.unsplash.com";
export const API_VERSION = "v1";
export const OAUTH_AUTHORIZE_URL = "https://unsplash.com/oauth/authorize";
export const OAUTH_TOKEN_URL = "https://unsplash.com/oauth/token";
import querystring from "querystring";
import { OAUTH_AUTHORIZE_URL, OAUTH_TOKEN_URL } from "../constants";
export default function auth() {
return {
getAuthenticationUrl: (scope = ["public"]) => {
let querystrings = querystring.stringify({
client_id: this._accessKey,
redirect_uri: this._callbackUrl,
response_type: "code",
scope: scope.length > 1
? scope.join("+")
: scope.toString()
});
return decodeURIComponent(`${OAUTH_AUTHORIZE_URL}?${querystrings}`);
},
userAuthentication: (code) => {
const url = OAUTH_TOKEN_URL;
return this.request({
url,
method: "POST",
body: {
client_id: this._accessKey,
client_secret: this._secret,
redirect_uri: this._callbackUrl,
grant_type: "authorization_code",
code
},
oauth: true
});
},
setBearerToken: (accessToken) => {
if (accessToken) {
this._bearerToken = accessToken;
}
}
};
}
export default function collections() {
return {
listCollections: (page = 1, perPage = 10) => {
const url = "/collections";
const query = {
per_page: perPage,
page
};
return this.request({
url: url,
method: "GET",
query
});
},
getCollection: collection.bind(this),
getCollectionPhotos: collectionPhotos.bind(this),
createCollection: createUpdateCollection.bind(this, null),
updateCollection: createUpdateCollection.bind(this),
deleteCollection: (id) => {
const url = `/collections/${id}`;
return this.request({
url: url,
method: "DELETE"
});
},
addPhotoToCollection: (collectionId, photoId) => {
const url = `/collections/${collectionId}/add`;
return this.request({
url: url,
method: "POST",
body: {
photo_id: photoId
}
});
},
removePhotoFromCollection: (collectionId, photoId) => {
const url = `/collections/${collectionId}/remove?photo_id=${photoId}`;
return this.request({
url: url,
method: "DELETE"
});
},
listRelatedCollections: (collectionId) => {
const url = `/collections/${collectionId}/related`;
return this.request({
url: url,
method: "GET"
});
}
};
}
function collection(id) {
return this.request({
url: `/collections/${id}`,
method: "GET"
});
}
function collectionPhotos(
id,
page = 1,
perPage = 10,
orderBy = "latest",
options = {},
) {
const query = {
per_page: perPage,
order_by: orderBy,
orientation: options.orientation,
page
};
Object.keys(query).forEach(key => {
if (!query[key]) {
delete query[key];
}
});
return this.request({
url: `/collections/${id}/photos`,
method: "GET",
query
});
}
function createUpdateCollection(id, title, description, isPrivate) {
const url = id
? `/collections/${id}`
: "/collections";
const body = {
title,
description,
"private": isPrivate
};
return this.request({
url: url,
method: id
? "PUT"
: "POST",
body
});
}
export default function currentUser() {
return {
profile: () => {
const url = "/me";
return this.request({
url,
method: "GET"
});
},
updateProfile: (options = {}) => {
const endpointUrl = "/me";
let {
username,
firstName,
lastName,
email,
url,
location,
bio,
instagramUsername
} = options;
let body = {
username,
first_name: firstName,
last_name: lastName,
email,
url,
location,
bio,
instagram_username: instagramUsername
};
Object.keys(body).forEach(key => {
if (!body[key]) {
delete body[key];
}
});
return this.request({
url: endpointUrl,
method: "PUT",
body
});
}
};
}
import { getUrlComponents } from "../utils";
import get from "lodash.get";
export default function photos() {
return {
listPhotos: (page = 1, perPage = 10, orderBy = "latest") => {
const url = "/photos";
const query = {
page,
per_page: perPage,
order_by: orderBy
};
return this.request({
url,
method: "GET",
query
});
},
getPhoto: (id) => {
const url = `/photos/${id}`;
return this.request({
url,
method: "GET"
});
},
getPhotoStats: (id) => {
const url = `/photos/${id}/statistics`;
return this.request({
url,
method: "GET"
});
},
getRandomPhoto: (options = {}) => {
const url = "/photos/random";
const collections = options.collections || [];
const query = {
featured: options.featured,
username: options.username,
orientation: options.orientation,
collections: collections.join(),
query: options.query,
c: options.cacheBuster || new Date().getTime(), // Avoid ajax response caching
count: options.count
};
Object.keys(query).forEach(key => {
if (!query[key]) {
delete query[key];
}
});
return this.request({
url,
method: "GET",
query
});
},
likePhoto: (id) => {
if (!this._bearerToken) {
throw new Error("Requires a bearerToken to be set.");
}
const url = `/photos/${id}/like`;
return this.request({
url,
method: "POST"
});
},
unlikePhoto: (id) => {
if (!this._bearerToken) {
throw new Error("Requires a bearerToken to be set.");
}
const url = `/photos/${id}/like`;
return this.request({
url,
method: "DELETE"
});
},
// Deprecated in 6.2
downloadPhoto: track.bind(this),
trackDownload: track.bind(this)
};
}
function track(photo) {
const downloadLocation = get(photo, "links.download_location", undefined);
if (downloadLocation === undefined) {
throw new Error(`Object received is not a photo. ${photo}`);
}
const urlComponents = getUrlComponents(downloadLocation);
return this.request({
url: urlComponents.pathname,
method: "GET",
query: urlComponents.query
});
}
export default function search() {
return {
photos: (keyword = "", page = 1, perPage = 10, options = {}) => {
const collections = options.collections || [];
const query = {
query: encodeURIComponent(keyword),
per_page: perPage,
orientation: options.orientation,
content_filter: options.contentFilter,
color: options.color,
order_by: options.orderBy,
lang: options.lang,
collections: collections.join(),
page
};
Object.keys(query).forEach(key => {
if (!query[key] && key != "query") {
delete query[key];
}
});
return this.request({
url: "/search/photos",
method: "GET",
query
});
},
users: (keyword = "", page = 1, perPage = 10) => {
const query = {
query: encodeURIComponent(keyword),
per_page: perPage,
page
};
return this.request({
url: "/search/users",
method: "GET",
query
});
},
collections: (keyword = "", page = 1, perPage = 10) => {
const query = {
query: encodeURIComponent(keyword),
per_page: perPage,
page
};
return this.request({
url: "/search/collections",
method: "GET",
query
});
}
};
}
export default function stats() {
return {
total: () => {
const url = "/stats/total";
return this.request({
url,
method: "GET"
});
}
};
}
export default function users() {
return {
profile: (username) => {
const url = `/users/${username}`;
return this.request({
url,
method: "GET"
});
},
photos: (
username,
page = 1,
perPage = 10,
orderBy = "latest",
options = {}
) => {
const stats = options.stats || false;
const url = `/users/${username}/photos`;
const query = {
page,
per_page: perPage,
order_by: orderBy,
orientation: options.orientation,
stats
};
Object.keys(query).forEach(key => {
if (!query[key]) {
delete query[key];
}
});
return this.request({
url,
method: "GET",
query
});
},
likes: (username, page = 1, perPage = 10, orderBy = "latest", options = {}) => {
const url = `/users/${username}/likes`;
const query = {
page,
per_page: perPage,
order_by: orderBy,
orientation: options.orientation
};
Object.keys(query).forEach(key => {
if (!query[key]) {
delete query[key];
}
});
return this.request({
url,
method: "GET",
query
});
},
collections: (username, page = 1, perPage = 10, orderBy = "published") => {
const url = `/users/${username}/collections`;
const query = {
page,
per_page: perPage,
order_by: orderBy
};
return this.request({
url,
method: "GET",
query
});
},
statistics: (username, resolution = "days", quantity = 30) => {
const url = `/users/${username}/statistics`;
const query = {
resolution,
quantity
};
return this.request({
url,
method: "GET",
query
});
}
};
}
import { API_URL, API_VERSION } from "./constants";
import { buildFetchOptions } from "./utils";
import auth from "./methods/auth";
import currentUser from "./methods/currentUser";
import users from "./methods/users";
import photos from "./methods/photos";
import collections from "./methods/collections";
import search from "./methods/search";
import stats from "./methods/stats";
export default class Unsplash {
constructor(options = {}) {
this._apiUrl = options.apiUrl || API_URL;
this._apiVersion = options.apiVersion || API_VERSION;
this._accessKey = options.accessKey;
this._secret = options.secret;
this._callbackUrl = options.callbackUrl;
this._bearerToken = options.bearerToken;
this._headers = options.headers || {};
this._timeout = options.timeout || 0; // 0 defaults to the OS timeout behaviour.
this.auth = auth.bind(this)();
this.currentUser = currentUser.bind(this)();
this.users = users.bind(this)();
this.photos = photos.bind(this)();
this.collections = collections.bind(this)();
this.search = search.bind(this)();
this.stats = stats.bind(this)();
}
request(requestOptions = {}) {
var { url, options } = buildFetchOptions.bind(this)(requestOptions);
return fetch(url, options);
}
}
export function toJson(res) {
return typeof res.json === "function" ? res.json() : res;
}
import { stringify as qsStringify } from "querystring";
import formurlencoded from "form-urlencoded";
import parse from "url-parse";
export function formUrlEncode(body) {
return formurlencoded(body);
}
export function getUrlComponents(uri) {
return parse(uri, {}, true);
}
export function buildFetchOptions(options = {}) {
let { method, query, oauth, body } = options;
let url = (oauth === true)
? options.url
: `${this._apiUrl}${options.url}`;
let headers = Object.assign({}, this._headers, options.headers, {
"Accept-Version": this._apiVersion,
"Authorization": this._bearerToken
? `Bearer ${this._bearerToken}`
: `Client-ID ${this._accessKey}`
});
let timeout = this._timeout;
if (body) {
headers["Content-Type"] = "application/x-www-form-urlencoded";
}
if (query) {
url = decodeURIComponent(`${url}?${qsStringify(query)}`);
}
return {
url: url,
options: {
method,
headers,
timeout,
body: (method !== "GET") && body
? formUrlEncode(body)
: undefined
}
};
}
var context = require.context('./test', true, /-test\.js$/);
context.keys().forEach(context);
module.exports = context;
"use strict";
const webpack = require("webpack");
module.exports = {
output: {
library: "Unsplash",
libraryTarget: "umd"
},
module: {
loaders: [
{ test: /\.js$/, loaders: ["babel-loader"], exclude: /node_modules/ }
]
},
plugins: [
new webpack.DefinePlugin({
"process.browser": true
})
]
};
'use strict';
var webpack = require('webpack');
var baseConfig = require('./webpack.config.base');
var config = Object.create(baseConfig);
config.plugins = [
new webpack.optimize.OccurenceOrderPlugin(),
new webpack.DefinePlugin({
'process.env.NODE_ENV': JSON.stringify('development'),
'process.browser': true
})
];
module.exports = config;
'use strict';
var webpack = require('webpack');
var baseConfig = require('./webpack.config.base');
var config = Object.create(baseConfig);
config.plugins = [
new webpack.optimize.OccurenceOrderPlugin(),
new webpack.optimize.UglifyJsPlugin({
compress: {
warnings: false,
drop_console: true
}
}),
new webpack.DefinePlugin({
'process.env.NODE_ENV': JSON.stringify('production'),
'process.browser': true
})
];
module.exports = config;