@nghiavuive/random-image 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,74 @@
1
+ # random-image
2
+
3
+ A generic utility library to fetch random images from various providers like Unsplash and Pexels.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install random-image
9
+ ```
10
+
11
+ ## Usage
12
+
13
+ You need to obtain API keys from the respective providers:
14
+ - [Unsplash Developers](https://unsplash.com/developers)
15
+ - [Pexels API](https://www.pexels.com/api/)
16
+
17
+ ```typescript
18
+ import { RandomImage, UnsplashProvider, PexelsProvider } from 'random-image';
19
+
20
+ // Using Unsplash
21
+ const unsplash = new UnsplashProvider('YOUR_UNSPLASH_ACCESS_KEY');
22
+ const fetcher = new RandomImage(unsplash);
23
+
24
+ fetcher.getRandom({
25
+ width: 1920,
26
+ height: 1080,
27
+ query: 'nature'
28
+ }).then(image => {
29
+ console.log(image.url); // URL to the image
30
+ console.log(image.author); // Photographer's name
31
+ });
32
+
33
+ // Using Pexels
34
+ const pexels = new PexelsProvider('YOUR_PEXELS_API_KEY');
35
+ const pexelsFetcher = new RandomImage(pexels);
36
+
37
+ pexelsFetcher.getRandom({
38
+ width: 800,
39
+ height: 600,
40
+ query: 'cats'
41
+ }).then(image => {
42
+ console.log(image.url);
43
+ });
44
+ ```
45
+
46
+ ## API
47
+
48
+ ### `RandomImage`
49
+ The main class to interact with.
50
+
51
+ ```typescript
52
+ class RandomImage {
53
+ constructor(provider: ImageProvider);
54
+ getRandom(options: ImageOptions): Promise<ImageResult>;
55
+ }
56
+ ```
57
+
58
+ ### `ImageOptions`
59
+ - `width` (number): Desired width of the image.
60
+ - `height` (number): Desired height of the image.
61
+ - `quality` (number): Quality (0-100) if supported.
62
+ - `query` (string): Search query (e.g. "nature", "city").
63
+
64
+ ### `ImageResult`
65
+ - `url` (string): Direct URL to the image.
66
+ - `width` (number): Width of the image.
67
+ - `height` (number): Height of the image.
68
+ - `author` (string): Name of the photographer.
69
+ - `authorUrl` (string): URL to photographer's profile.
70
+ - `originalUrl` (string): URL to the original photo page.
71
+
72
+ ## License
73
+
74
+ ISC
@@ -0,0 +1,42 @@
1
+ interface ImageOptions {
2
+ width?: number;
3
+ height?: number;
4
+ quality?: number;
5
+ query?: string;
6
+ }
7
+ interface ImageResult {
8
+ url: string;
9
+ width: number;
10
+ height: number;
11
+ author: string;
12
+ authorUrl?: string;
13
+ originalUrl: string;
14
+ }
15
+ interface ImageProvider {
16
+ fetchRandomImage(options: ImageOptions): Promise<ImageResult>;
17
+ }
18
+
19
+ declare class UnsplashProvider implements ImageProvider {
20
+ private accessKey;
21
+ constructor(accessKey: string);
22
+ fetchRandomImage(options: ImageOptions): Promise<ImageResult>;
23
+ }
24
+
25
+ declare class PexelsProvider implements ImageProvider {
26
+ private apiKey;
27
+ constructor(apiKey: string);
28
+ fetchRandomImage(options: ImageOptions): Promise<ImageResult>;
29
+ }
30
+
31
+ declare class RandomImage {
32
+ private provider;
33
+ constructor(provider: ImageProvider);
34
+ /**
35
+ * Fetches a random image based on the provided options.
36
+ * @param options - Configuration options for the image (width, height, query, etc.)
37
+ * @returns A promise that resolves to an ImageResult object.
38
+ */
39
+ getRandom(options?: ImageOptions): Promise<ImageResult>;
40
+ }
41
+
42
+ export { type ImageOptions, type ImageProvider, type ImageResult, PexelsProvider, RandomImage, UnsplashProvider };
@@ -0,0 +1,42 @@
1
+ interface ImageOptions {
2
+ width?: number;
3
+ height?: number;
4
+ quality?: number;
5
+ query?: string;
6
+ }
7
+ interface ImageResult {
8
+ url: string;
9
+ width: number;
10
+ height: number;
11
+ author: string;
12
+ authorUrl?: string;
13
+ originalUrl: string;
14
+ }
15
+ interface ImageProvider {
16
+ fetchRandomImage(options: ImageOptions): Promise<ImageResult>;
17
+ }
18
+
19
+ declare class UnsplashProvider implements ImageProvider {
20
+ private accessKey;
21
+ constructor(accessKey: string);
22
+ fetchRandomImage(options: ImageOptions): Promise<ImageResult>;
23
+ }
24
+
25
+ declare class PexelsProvider implements ImageProvider {
26
+ private apiKey;
27
+ constructor(apiKey: string);
28
+ fetchRandomImage(options: ImageOptions): Promise<ImageResult>;
29
+ }
30
+
31
+ declare class RandomImage {
32
+ private provider;
33
+ constructor(provider: ImageProvider);
34
+ /**
35
+ * Fetches a random image based on the provided options.
36
+ * @param options - Configuration options for the image (width, height, query, etc.)
37
+ * @returns A promise that resolves to an ImageResult object.
38
+ */
39
+ getRandom(options?: ImageOptions): Promise<ImageResult>;
40
+ }
41
+
42
+ export { type ImageOptions, type ImageProvider, type ImageResult, PexelsProvider, RandomImage, UnsplashProvider };
package/dist/index.js ADDED
@@ -0,0 +1,129 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/index.ts
21
+ var index_exports = {};
22
+ __export(index_exports, {
23
+ PexelsProvider: () => PexelsProvider,
24
+ RandomImage: () => RandomImage,
25
+ UnsplashProvider: () => UnsplashProvider
26
+ });
27
+ module.exports = __toCommonJS(index_exports);
28
+
29
+ // src/providers/unsplash.ts
30
+ var UnsplashProvider = class {
31
+ constructor(accessKey) {
32
+ this.accessKey = accessKey;
33
+ }
34
+ async fetchRandomImage(options) {
35
+ const params = new URLSearchParams();
36
+ if (options.query) params.append("query", options.query);
37
+ const url = `https://api.unsplash.com/photos/random?${params.toString()}`;
38
+ const response = await fetch(url, {
39
+ headers: {
40
+ Authorization: `Client-ID ${this.accessKey}`
41
+ }
42
+ });
43
+ if (!response.ok) {
44
+ throw new Error(`Unsplash API error: ${response.statusText}`);
45
+ }
46
+ const data = await response.json();
47
+ const photo = Array.isArray(data) ? data[0] : data;
48
+ const baseUrl = photo.urls.raw;
49
+ const sizeParams = new URLSearchParams();
50
+ if (options.width) sizeParams.append("w", options.width.toString());
51
+ if (options.height) sizeParams.append("h", options.height.toString());
52
+ if (options.quality) sizeParams.append("q", options.quality.toString());
53
+ const finalUrl = `${baseUrl}&${sizeParams.toString()}`;
54
+ return {
55
+ url: finalUrl,
56
+ width: options.width || photo.width,
57
+ height: options.height || photo.height,
58
+ author: photo.user.name,
59
+ authorUrl: photo.user.links.html,
60
+ originalUrl: photo.links.html
61
+ // Link to photo page
62
+ };
63
+ }
64
+ };
65
+
66
+ // src/providers/pexels.ts
67
+ var PexelsProvider = class {
68
+ constructor(apiKey) {
69
+ this.apiKey = apiKey;
70
+ }
71
+ async fetchRandomImage(options) {
72
+ const endpoint = options.query ? "https://api.pexels.com/v1/search" : "https://api.pexels.com/v1/curated";
73
+ const randomPage = Math.floor(Math.random() * 100) + 1;
74
+ const params = new URLSearchParams();
75
+ if (options.query) params.append("query", options.query);
76
+ params.append("per_page", "1");
77
+ params.append("page", randomPage.toString());
78
+ const response = await fetch(`${endpoint}?${params.toString()}`, {
79
+ headers: {
80
+ Authorization: this.apiKey
81
+ }
82
+ });
83
+ if (!response.ok) {
84
+ throw new Error(`Pexels API error: ${response.statusText}`);
85
+ }
86
+ const data = await response.json();
87
+ if (!data.photos || data.photos.length === 0) {
88
+ throw new Error("No images found on Pexels");
89
+ }
90
+ const photo = data.photos[0];
91
+ const baseUrl = photo.src.original;
92
+ const sizeParams = new URLSearchParams();
93
+ sizeParams.append("auto", "compress");
94
+ sizeParams.append("cs", "tinysrgb");
95
+ if (options.width) sizeParams.append("w", options.width.toString());
96
+ if (options.height) sizeParams.append("h", options.height.toString());
97
+ const finalUrl = `${baseUrl}?${sizeParams.toString()}`;
98
+ return {
99
+ url: finalUrl,
100
+ width: options.width || photo.width,
101
+ height: options.height || photo.height,
102
+ author: photo.photographer,
103
+ authorUrl: photo.photographer_url,
104
+ originalUrl: photo.url
105
+ };
106
+ }
107
+ };
108
+
109
+ // src/image-fetcher.ts
110
+ var RandomImage = class {
111
+ constructor(provider) {
112
+ this.provider = provider;
113
+ }
114
+ /**
115
+ * Fetches a random image based on the provided options.
116
+ * @param options - Configuration options for the image (width, height, query, etc.)
117
+ * @returns A promise that resolves to an ImageResult object.
118
+ */
119
+ async getRandom(options = {}) {
120
+ return this.provider.fetchRandomImage(options);
121
+ }
122
+ };
123
+ // Annotate the CommonJS export names for ESM import in node:
124
+ 0 && (module.exports = {
125
+ PexelsProvider,
126
+ RandomImage,
127
+ UnsplashProvider
128
+ });
129
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts","../src/providers/unsplash.ts","../src/providers/pexels.ts","../src/image-fetcher.ts"],"sourcesContent":["export * from './types';\nexport * from './providers/unsplash';\nexport * from './providers/pexels';\nexport * from './image-fetcher';\n","import { ImageProvider, ImageOptions, ImageResult } from '../types';\n\nexport class UnsplashProvider implements ImageProvider {\n private accessKey: string;\n\n constructor(accessKey: string) {\n this.accessKey = accessKey;\n }\n\n async fetchRandomImage(options: ImageOptions): Promise<ImageResult> {\n const params = new URLSearchParams();\n if (options.query) params.append('query', options.query);\n // Unsplash doesn't strictly support width/height for random photo selection in the same way for resizing via API query params on the /random endpoint directly for *fetching* the image content, \n // but we can request specific dimensions roughly or rely on the returned structure to pick a size.\n // However, the /photos/random endpoint returns a JSON with urls.raw, urls.full, etc.\n // We can append parameters to the returned URL for resizing.\n \n // Using fetching logic:\n const url = `https://api.unsplash.com/photos/random?${params.toString()}`;\n \n const response = await fetch(url, {\n headers: {\n Authorization: `Client-ID ${this.accessKey}`\n }\n });\n\n if (!response.ok) {\n throw new Error(`Unsplash API error: ${response.statusText}`);\n }\n\n const data = await response.json();\n \n // Handle single random photo (array if count param used, but here generic assumes one)\n const photo = Array.isArray(data) ? data[0] : data;\n\n // Construct resized URL\n // Unsplash uses Imgix. We can append parameters.\n const baseUrl = photo.urls.raw;\n const sizeParams = new URLSearchParams();\n if (options.width) sizeParams.append('w', options.width.toString());\n if (options.height) sizeParams.append('h', options.height.toString());\n if (options.quality) sizeParams.append('q', options.quality.toString());\n \n const finalUrl = `${baseUrl}&${sizeParams.toString()}`;\n\n return {\n url: finalUrl,\n width: options.width || photo.width,\n height: options.height || photo.height,\n author: photo.user.name,\n authorUrl: photo.user.links.html,\n originalUrl: photo.links.html // Link to photo page\n };\n }\n}\n","import { ImageProvider, ImageOptions, ImageResult } from '../types';\n\nexport class PexelsProvider implements ImageProvider {\n private apiKey: string;\n\n constructor(apiKey: string) {\n this.apiKey = apiKey;\n }\n\n async fetchRandomImage(options: ImageOptions): Promise<ImageResult> {\n // Pexels 'curated' or 'search'. \n // If query is present, use search. If not, use curated.\n // We need to randomize the result because Pexels search/curated returns a list.\n // We can use 'page' and 'per_page=1' with a random page number to simulate random? \n // Or just fetch one page and pick random?\n // Pexels API doesn't have a direct /random endpoint like Unsplash.\n // Efficient strategy: Search with 1 result per page, but randomize the page number.\n // Max page is tricky, maybe limit to top 100 results?\n \n const endpoint = options.query \n ? 'https://api.pexels.com/v1/search' \n : 'https://api.pexels.com/v1/curated';\n\n // Randomizing page number (1-100) to get a \"random\" image\n const randomPage = Math.floor(Math.random() * 100) + 1;\n \n const params = new URLSearchParams();\n if (options.query) params.append('query', options.query);\n params.append('per_page', '1');\n params.append('page', randomPage.toString());\n\n const response = await fetch(`${endpoint}?${params.toString()}`, {\n headers: {\n Authorization: this.apiKey\n }\n });\n\n if (!response.ok) {\n throw new Error(`Pexels API error: ${response.statusText}`);\n }\n\n const data = await response.json();\n \n if (!data.photos || data.photos.length === 0) {\n throw new Error('No images found on Pexels');\n }\n\n const photo = data.photos[0];\n\n // Pexels supports resizing via query params on the image url?\n // Pexels returns src object with original, large2x, large, medium, small, portrait, landscape, tiny.\n // Or we can modify the 'original' url.\n // Pexels docs say: https://images.pexels.com/photos/2014422/pexels-photo-2014422.jpeg?auto=compress&cs=tinysrgb&h=350\n \n const baseUrl = photo.src.original;\n const sizeParams = new URLSearchParams();\n sizeParams.append('auto', 'compress');\n sizeParams.append('cs', 'tinysrgb'); // Default pexels param\n if (options.width) sizeParams.append('w', options.width.toString());\n if (options.height) sizeParams.append('h', options.height.toString());\n \n // Note: Quality param is not standard in Pexels URL manipulation documented publicly as 'q', \n // but 'auto=compress' handles it. We can try adding it if needed or ignore. \n // I'll skip explicit q param mapping for now as it's not strictly 'quality=X'.\n\n const finalUrl = `${baseUrl}?${sizeParams.toString()}`;\n\n return {\n url: finalUrl,\n width: options.width || photo.width,\n height: options.height || photo.height,\n author: photo.photographer,\n authorUrl: photo.photographer_url,\n originalUrl: photo.url\n };\n }\n}\n","import { ImageProvider, ImageOptions, ImageResult } from './types';\n\nexport class RandomImage {\n private provider: ImageProvider;\n\n constructor(provider: ImageProvider) {\n this.provider = provider;\n }\n\n /**\n * Fetches a random image based on the provided options.\n * @param options - Configuration options for the image (width, height, query, etc.)\n * @returns A promise that resolves to an ImageResult object.\n */\n async getRandom(options: ImageOptions = {}): Promise<ImageResult> {\n return this.provider.fetchRandomImage(options);\n }\n}\n"],"mappings":"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","names":[]}
package/dist/index.mjs ADDED
@@ -0,0 +1,100 @@
1
+ // src/providers/unsplash.ts
2
+ var UnsplashProvider = class {
3
+ constructor(accessKey) {
4
+ this.accessKey = accessKey;
5
+ }
6
+ async fetchRandomImage(options) {
7
+ const params = new URLSearchParams();
8
+ if (options.query) params.append("query", options.query);
9
+ const url = `https://api.unsplash.com/photos/random?${params.toString()}`;
10
+ const response = await fetch(url, {
11
+ headers: {
12
+ Authorization: `Client-ID ${this.accessKey}`
13
+ }
14
+ });
15
+ if (!response.ok) {
16
+ throw new Error(`Unsplash API error: ${response.statusText}`);
17
+ }
18
+ const data = await response.json();
19
+ const photo = Array.isArray(data) ? data[0] : data;
20
+ const baseUrl = photo.urls.raw;
21
+ const sizeParams = new URLSearchParams();
22
+ if (options.width) sizeParams.append("w", options.width.toString());
23
+ if (options.height) sizeParams.append("h", options.height.toString());
24
+ if (options.quality) sizeParams.append("q", options.quality.toString());
25
+ const finalUrl = `${baseUrl}&${sizeParams.toString()}`;
26
+ return {
27
+ url: finalUrl,
28
+ width: options.width || photo.width,
29
+ height: options.height || photo.height,
30
+ author: photo.user.name,
31
+ authorUrl: photo.user.links.html,
32
+ originalUrl: photo.links.html
33
+ // Link to photo page
34
+ };
35
+ }
36
+ };
37
+
38
+ // src/providers/pexels.ts
39
+ var PexelsProvider = class {
40
+ constructor(apiKey) {
41
+ this.apiKey = apiKey;
42
+ }
43
+ async fetchRandomImage(options) {
44
+ const endpoint = options.query ? "https://api.pexels.com/v1/search" : "https://api.pexels.com/v1/curated";
45
+ const randomPage = Math.floor(Math.random() * 100) + 1;
46
+ const params = new URLSearchParams();
47
+ if (options.query) params.append("query", options.query);
48
+ params.append("per_page", "1");
49
+ params.append("page", randomPage.toString());
50
+ const response = await fetch(`${endpoint}?${params.toString()}`, {
51
+ headers: {
52
+ Authorization: this.apiKey
53
+ }
54
+ });
55
+ if (!response.ok) {
56
+ throw new Error(`Pexels API error: ${response.statusText}`);
57
+ }
58
+ const data = await response.json();
59
+ if (!data.photos || data.photos.length === 0) {
60
+ throw new Error("No images found on Pexels");
61
+ }
62
+ const photo = data.photos[0];
63
+ const baseUrl = photo.src.original;
64
+ const sizeParams = new URLSearchParams();
65
+ sizeParams.append("auto", "compress");
66
+ sizeParams.append("cs", "tinysrgb");
67
+ if (options.width) sizeParams.append("w", options.width.toString());
68
+ if (options.height) sizeParams.append("h", options.height.toString());
69
+ const finalUrl = `${baseUrl}?${sizeParams.toString()}`;
70
+ return {
71
+ url: finalUrl,
72
+ width: options.width || photo.width,
73
+ height: options.height || photo.height,
74
+ author: photo.photographer,
75
+ authorUrl: photo.photographer_url,
76
+ originalUrl: photo.url
77
+ };
78
+ }
79
+ };
80
+
81
+ // src/image-fetcher.ts
82
+ var RandomImage = class {
83
+ constructor(provider) {
84
+ this.provider = provider;
85
+ }
86
+ /**
87
+ * Fetches a random image based on the provided options.
88
+ * @param options - Configuration options for the image (width, height, query, etc.)
89
+ * @returns A promise that resolves to an ImageResult object.
90
+ */
91
+ async getRandom(options = {}) {
92
+ return this.provider.fetchRandomImage(options);
93
+ }
94
+ };
95
+ export {
96
+ PexelsProvider,
97
+ RandomImage,
98
+ UnsplashProvider
99
+ };
100
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/providers/unsplash.ts","../src/providers/pexels.ts","../src/image-fetcher.ts"],"sourcesContent":["import { ImageProvider, ImageOptions, ImageResult } from '../types';\n\nexport class UnsplashProvider implements ImageProvider {\n private accessKey: string;\n\n constructor(accessKey: string) {\n this.accessKey = accessKey;\n }\n\n async fetchRandomImage(options: ImageOptions): Promise<ImageResult> {\n const params = new URLSearchParams();\n if (options.query) params.append('query', options.query);\n // Unsplash doesn't strictly support width/height for random photo selection in the same way for resizing via API query params on the /random endpoint directly for *fetching* the image content, \n // but we can request specific dimensions roughly or rely on the returned structure to pick a size.\n // However, the /photos/random endpoint returns a JSON with urls.raw, urls.full, etc.\n // We can append parameters to the returned URL for resizing.\n \n // Using fetching logic:\n const url = `https://api.unsplash.com/photos/random?${params.toString()}`;\n \n const response = await fetch(url, {\n headers: {\n Authorization: `Client-ID ${this.accessKey}`\n }\n });\n\n if (!response.ok) {\n throw new Error(`Unsplash API error: ${response.statusText}`);\n }\n\n const data = await response.json();\n \n // Handle single random photo (array if count param used, but here generic assumes one)\n const photo = Array.isArray(data) ? data[0] : data;\n\n // Construct resized URL\n // Unsplash uses Imgix. We can append parameters.\n const baseUrl = photo.urls.raw;\n const sizeParams = new URLSearchParams();\n if (options.width) sizeParams.append('w', options.width.toString());\n if (options.height) sizeParams.append('h', options.height.toString());\n if (options.quality) sizeParams.append('q', options.quality.toString());\n \n const finalUrl = `${baseUrl}&${sizeParams.toString()}`;\n\n return {\n url: finalUrl,\n width: options.width || photo.width,\n height: options.height || photo.height,\n author: photo.user.name,\n authorUrl: photo.user.links.html,\n originalUrl: photo.links.html // Link to photo page\n };\n }\n}\n","import { ImageProvider, ImageOptions, ImageResult } from '../types';\n\nexport class PexelsProvider implements ImageProvider {\n private apiKey: string;\n\n constructor(apiKey: string) {\n this.apiKey = apiKey;\n }\n\n async fetchRandomImage(options: ImageOptions): Promise<ImageResult> {\n // Pexels 'curated' or 'search'. \n // If query is present, use search. If not, use curated.\n // We need to randomize the result because Pexels search/curated returns a list.\n // We can use 'page' and 'per_page=1' with a random page number to simulate random? \n // Or just fetch one page and pick random?\n // Pexels API doesn't have a direct /random endpoint like Unsplash.\n // Efficient strategy: Search with 1 result per page, but randomize the page number.\n // Max page is tricky, maybe limit to top 100 results?\n \n const endpoint = options.query \n ? 'https://api.pexels.com/v1/search' \n : 'https://api.pexels.com/v1/curated';\n\n // Randomizing page number (1-100) to get a \"random\" image\n const randomPage = Math.floor(Math.random() * 100) + 1;\n \n const params = new URLSearchParams();\n if (options.query) params.append('query', options.query);\n params.append('per_page', '1');\n params.append('page', randomPage.toString());\n\n const response = await fetch(`${endpoint}?${params.toString()}`, {\n headers: {\n Authorization: this.apiKey\n }\n });\n\n if (!response.ok) {\n throw new Error(`Pexels API error: ${response.statusText}`);\n }\n\n const data = await response.json();\n \n if (!data.photos || data.photos.length === 0) {\n throw new Error('No images found on Pexels');\n }\n\n const photo = data.photos[0];\n\n // Pexels supports resizing via query params on the image url?\n // Pexels returns src object with original, large2x, large, medium, small, portrait, landscape, tiny.\n // Or we can modify the 'original' url.\n // Pexels docs say: https://images.pexels.com/photos/2014422/pexels-photo-2014422.jpeg?auto=compress&cs=tinysrgb&h=350\n \n const baseUrl = photo.src.original;\n const sizeParams = new URLSearchParams();\n sizeParams.append('auto', 'compress');\n sizeParams.append('cs', 'tinysrgb'); // Default pexels param\n if (options.width) sizeParams.append('w', options.width.toString());\n if (options.height) sizeParams.append('h', options.height.toString());\n \n // Note: Quality param is not standard in Pexels URL manipulation documented publicly as 'q', \n // but 'auto=compress' handles it. We can try adding it if needed or ignore. \n // I'll skip explicit q param mapping for now as it's not strictly 'quality=X'.\n\n const finalUrl = `${baseUrl}?${sizeParams.toString()}`;\n\n return {\n url: finalUrl,\n width: options.width || photo.width,\n height: options.height || photo.height,\n author: photo.photographer,\n authorUrl: photo.photographer_url,\n originalUrl: photo.url\n };\n }\n}\n","import { ImageProvider, ImageOptions, ImageResult } from './types';\n\nexport class RandomImage {\n private provider: ImageProvider;\n\n constructor(provider: ImageProvider) {\n this.provider = provider;\n }\n\n /**\n * Fetches a random image based on the provided options.\n * @param options - Configuration options for the image (width, height, query, etc.)\n * @returns A promise that resolves to an ImageResult object.\n */\n async getRandom(options: ImageOptions = {}): Promise<ImageResult> {\n return this.provider.fetchRandomImage(options);\n }\n}\n"],"mappings":"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","names":[]}
package/package.json ADDED
@@ -0,0 +1,38 @@
1
+ {
2
+ "name": "@nghiavuive/random-image",
3
+ "version": "1.0.0",
4
+ "description": "",
5
+ "main": "./dist/index.js",
6
+ "module": "./dist/index.mjs",
7
+ "types": "./dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "import": "./dist/index.mjs",
12
+ "require": "./dist/index.js"
13
+ }
14
+ },
15
+ "files": [
16
+ "dist"
17
+ ],
18
+ "scripts": {
19
+ "build": "tsup",
20
+ "test": "vitest",
21
+ "dev": "tsup --watch",
22
+ "lint": "tsc --noEmit"
23
+ },
24
+ "keywords": [],
25
+ "author": "",
26
+ "license": "ISC",
27
+ "type": "commonjs",
28
+ "repository": {
29
+ "type": "git",
30
+ "url": "https://github.com/codengoo/random-image"
31
+ },
32
+ "devDependencies": {
33
+ "@types/node": "^25.2.0",
34
+ "tsup": "^8.5.1",
35
+ "typescript": "^5.9.3",
36
+ "vitest": "^4.0.18"
37
+ }
38
+ }