nekosia.js 0.2.0 → 0.2.1
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/LICENSE +1 -1
- package/examples/dynamicCategoryFetch.js +4 -4
- package/examples/fetchCategoryImages.js +2 -2
- package/examples/fetchImages.js +7 -1
- package/index.js +4 -3
- package/package.json +4 -4
- package/services/https.js +4 -4
- package/test/api.test.js +95 -70
- package/test/integration.test.js +39 -3
- package/types/index.d.ts +4 -4
- package/types/tags.ts +3 -2
package/LICENSE
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
const { NekosiaAPI } = require('../index.js');
|
|
2
2
|
|
|
3
|
-
const
|
|
3
|
+
const fetch = async (category, options = {}) => {
|
|
4
4
|
try {
|
|
5
5
|
const response = await NekosiaAPI.fetchCategoryImages(category, options);
|
|
6
6
|
console.log(`${category.toUpperCase()}:`, response);
|
|
@@ -10,7 +10,7 @@ const fetchImages = async (category, options = {}) => {
|
|
|
10
10
|
};
|
|
11
11
|
|
|
12
12
|
(async () => {
|
|
13
|
-
await
|
|
14
|
-
await
|
|
15
|
-
await
|
|
13
|
+
await fetch('catgirl');
|
|
14
|
+
await fetch('foxgirl', { session: 'id', id: 'user123', count: 2 });
|
|
15
|
+
await fetch('catgirl', { tags: 'animal-ears' });
|
|
16
16
|
})();
|
|
@@ -4,8 +4,8 @@ const { NekosiaAPI } = require('../index.js');
|
|
|
4
4
|
const response = await NekosiaAPI.fetchCategoryImages('foxgirl', {
|
|
5
5
|
session: 'ip',
|
|
6
6
|
count: 1,
|
|
7
|
-
additionalTags: ['cute', 'sakura', '
|
|
8
|
-
blacklistedTags: ['beret'],
|
|
7
|
+
additionalTags: ['cute', 'sakura', 'blue-hair', 'blue-eyes'],
|
|
8
|
+
blacklistedTags: ['beret', 'hat'],
|
|
9
9
|
});
|
|
10
10
|
|
|
11
11
|
console.log(response);
|
package/examples/fetchImages.js
CHANGED
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
const { NekosiaAPI } = require('../index.js');
|
|
2
2
|
|
|
3
3
|
(async () => {
|
|
4
|
-
const response = await NekosiaAPI.fetchImages({
|
|
4
|
+
const response = await NekosiaAPI.fetchImages({
|
|
5
|
+
session: 'ip',
|
|
6
|
+
count: 1,
|
|
7
|
+
tags: ['cute', 'sakura', 'blue-hair', 'blue-eyes'],
|
|
8
|
+
blacklist: ['beret', 'hat'],
|
|
9
|
+
});
|
|
10
|
+
|
|
5
11
|
console.log(response);
|
|
6
12
|
})();
|
package/index.js
CHANGED
|
@@ -27,18 +27,19 @@ class NekosiaAPI {
|
|
|
27
27
|
|
|
28
28
|
async fetchCategoryImages(category, options = {}) {
|
|
29
29
|
if (!category) {
|
|
30
|
-
throw new Error('
|
|
30
|
+
throw new Error('Image category is required. For example: fetchCategoryImages(\'catgirl\')');
|
|
31
31
|
}
|
|
32
32
|
|
|
33
33
|
if (options.session && !['id', 'ip'].includes(options.session)) {
|
|
34
|
-
throw new Error('The `session` setting can contain only the following values `id` and `ip`, both as strings
|
|
34
|
+
throw new Error('The `session` setting can contain only the following values `id` and `ip`, both as strings');
|
|
35
35
|
}
|
|
36
36
|
|
|
37
37
|
if (!options.session && options.id) {
|
|
38
38
|
throw new Error('`id` is not required if the session is `null` or `undefined`');
|
|
39
39
|
}
|
|
40
40
|
|
|
41
|
-
|
|
41
|
+
const query = this.buildQueryParams(options);
|
|
42
|
+
return this.makeHttpRequest(`${API_URL}/images/${category}${query ? `?${query}` : ''}`);
|
|
42
43
|
}
|
|
43
44
|
|
|
44
45
|
async fetchImages(options = {}) {
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nekosia.js",
|
|
3
|
-
"version": "0.2.
|
|
4
|
-
"description": "A simple wrapper for the Nekosia API that offers seamless access to random anime images. Add a touch of anime magic and feline charm to your projects, meow
|
|
3
|
+
"version": "0.2.1",
|
|
4
|
+
"description": "A simple wrapper for the Nekosia API that offers seamless access to random anime images. Add a touch of anime magic and feline charm to your projects, meow~! Find out why Nekosia is the purrfect choice!",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"anime api",
|
|
7
7
|
"anime art",
|
|
@@ -57,8 +57,8 @@
|
|
|
57
57
|
"up": "ncu -u && npm install && npm update && npm audit fix"
|
|
58
58
|
},
|
|
59
59
|
"devDependencies": {
|
|
60
|
-
"@eslint/js": "^9.
|
|
61
|
-
"globals": "^
|
|
60
|
+
"@eslint/js": "^9.25.0",
|
|
61
|
+
"globals": "^16.0.0",
|
|
62
62
|
"jest": "^29.7.0"
|
|
63
63
|
}
|
|
64
64
|
}
|
package/services/https.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
const https = require('https');
|
|
2
|
-
const { name, version,
|
|
2
|
+
const { name, version, devDependencies } = require('../package.json');
|
|
3
3
|
|
|
4
4
|
const headers = {
|
|
5
|
-
'User-Agent':
|
|
5
|
+
'User-Agent': `${name}/${version} (+https://github.com/Nekosia-API/nekosia.js)${process.env.JEST_WORKER_ID ? ` jest/${devDependencies.jest.replace(/^[^0-9]*/, '')}` : ''}`,
|
|
6
6
|
'Accept': 'application/json',
|
|
7
7
|
'Content-Type': 'application/json',
|
|
8
8
|
'Cache-Control': 'no-cache',
|
|
@@ -13,7 +13,7 @@ const headers = {
|
|
|
13
13
|
const timeout = 25000;
|
|
14
14
|
|
|
15
15
|
const get = async url => {
|
|
16
|
-
if (!url || typeof url !== 'string') throw new Error('Missing URL, expected a string
|
|
16
|
+
if (!url || typeof url !== 'string') throw new Error('Missing URL, expected a string');
|
|
17
17
|
|
|
18
18
|
return new Promise((resolve, reject) => {
|
|
19
19
|
const req = https.get(url, { headers, timeout }, res => {
|
|
@@ -41,7 +41,7 @@ const get = async url => {
|
|
|
41
41
|
|
|
42
42
|
req.on('timeout', () => {
|
|
43
43
|
req.destroy();
|
|
44
|
-
reject(new Error(`Request timed out after ${timeout} ms
|
|
44
|
+
reject(new Error(`Request timed out after ${timeout} ms`));
|
|
45
45
|
});
|
|
46
46
|
});
|
|
47
47
|
};
|
package/test/api.test.js
CHANGED
|
@@ -1,109 +1,134 @@
|
|
|
1
1
|
const { NekosiaAPI } = require('../index.js');
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
const expectValidImageObject = res => {
|
|
4
|
+
expect(res.success).toBe(true);
|
|
5
|
+
expect(res.status).toBe(200);
|
|
6
|
+
expect(res).toHaveProperty('image');
|
|
7
|
+
expect(res.image.original.url).toEqual(expect.any(String));
|
|
8
|
+
expect(res.tags.length).toBeGreaterThan(0);
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
describe('nekosia.js tests', () => {
|
|
4
12
|
|
|
5
13
|
describe('fetchCategoryImages', () => {
|
|
6
|
-
|
|
14
|
+
|
|
15
|
+
it('should fetch one image when count is 1', async () => {
|
|
7
16
|
const res = await NekosiaAPI.fetchCategoryImages('catgirl', { count: 1 });
|
|
17
|
+
expectValidImageObject(res);
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
it('should fetch multiple images when count is between 2 and 24', async () => {
|
|
21
|
+
const res = await NekosiaAPI.fetchCategoryImages('catgirl', { count: 3 });
|
|
8
22
|
|
|
9
|
-
expect(res).toBeInstanceOf(Object);
|
|
10
23
|
expect(res.success).toBe(true);
|
|
11
24
|
expect(res.status).toBe(200);
|
|
25
|
+
expect(Array.isArray(res.images)).toBe(true);
|
|
26
|
+
expect(res.images.length).toBe(3);
|
|
12
27
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
expect(res.
|
|
23
|
-
|
|
24
|
-
expect(res.
|
|
25
|
-
expect(res.
|
|
26
|
-
expect(res.metadata.original).toHaveProperty('height');
|
|
27
|
-
expect(res.metadata.original).toHaveProperty('size');
|
|
28
|
-
expect(res.metadata.original).toHaveProperty('extension');
|
|
29
|
-
|
|
30
|
-
expect(res.metadata).toHaveProperty('compressed');
|
|
31
|
-
expect(res.metadata.compressed).toHaveProperty('width');
|
|
32
|
-
expect(res.metadata.compressed).toHaveProperty('height');
|
|
33
|
-
expect(res.metadata.compressed).toHaveProperty('size');
|
|
34
|
-
expect(res.metadata.compressed).toHaveProperty('extension');
|
|
35
|
-
|
|
36
|
-
expect(res).toHaveProperty('tags');
|
|
37
|
-
expect(res.tags).toBeInstanceOf(Array);
|
|
38
|
-
expect(res.tags.length).toBeGreaterThan(0);
|
|
39
|
-
|
|
40
|
-
expect(res).toHaveProperty('rating');
|
|
41
|
-
expect(res).toHaveProperty('source');
|
|
42
|
-
expect(res.source).toHaveProperty('url');
|
|
28
|
+
for (const img of res.images) {
|
|
29
|
+
expect(img).toHaveProperty('image');
|
|
30
|
+
expect(img.image.original.url).toEqual(expect.any(String));
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
it('should fetch maximum allowed number of images (24)', async () => {
|
|
35
|
+
const res = await NekosiaAPI.fetchCategoryImages('catgirl', { count: 24 });
|
|
36
|
+
|
|
37
|
+
expect(res.success).toBe(true);
|
|
38
|
+
expect(res.status).toBe(200);
|
|
39
|
+
expect(Array.isArray(res.images)).toBe(true);
|
|
40
|
+
expect(res.images.length).toBe(24);
|
|
43
41
|
});
|
|
44
42
|
|
|
45
|
-
it('should return
|
|
46
|
-
const res = await NekosiaAPI.fetchCategoryImages('
|
|
43
|
+
it('should return error if count exceeds the maximum (25)', async () => {
|
|
44
|
+
const res = await NekosiaAPI.fetchCategoryImages('catgirl', { count: 25 });
|
|
47
45
|
|
|
48
46
|
expect(res.success).toBe(false);
|
|
49
47
|
expect(res.status).toBe(400);
|
|
48
|
+
expect(res.message).toMatch(/Count must be between 1 and 24/i);
|
|
50
49
|
});
|
|
51
50
|
|
|
52
|
-
it('should return
|
|
53
|
-
const res = await NekosiaAPI.fetchCategoryImages('catgirl', { count:
|
|
54
|
-
|
|
55
|
-
expect(res).
|
|
56
|
-
expect(res.success).toBe(true);
|
|
57
|
-
expect(res.status).toBe(200);
|
|
58
|
-
expect(res).toHaveProperty('images');
|
|
59
|
-
expect(res.images).toBeInstanceOf(Array);
|
|
60
|
-
expect(res.images.length).toBe(3);
|
|
51
|
+
it('should return error for invalid count value', async () => {
|
|
52
|
+
const res = await NekosiaAPI.fetchCategoryImages('catgirl', { count: 'invalid' });
|
|
53
|
+
expect(res.success).toBe(false);
|
|
54
|
+
expect(res.status).toBe(400);
|
|
61
55
|
});
|
|
62
|
-
});
|
|
63
56
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
57
|
+
it('should return error for negative count', async () => {
|
|
58
|
+
const res = await NekosiaAPI.fetchCategoryImages('catgirl', { count: -5 });
|
|
59
|
+
expect(res.success).toBe(false);
|
|
60
|
+
expect(res.status).toBe(400);
|
|
61
|
+
});
|
|
67
62
|
|
|
63
|
+
it('should return error for count = 0', async () => {
|
|
64
|
+
const res = await NekosiaAPI.fetchCategoryImages('catgirl', { count: 0 });
|
|
68
65
|
expect(res.success).toBe(false);
|
|
69
66
|
expect(res.status).toBe(400);
|
|
70
67
|
});
|
|
71
68
|
|
|
72
|
-
it('should
|
|
73
|
-
await
|
|
69
|
+
it('should handle random category', async () => {
|
|
70
|
+
const res = await NekosiaAPI.fetchCategoryImages('random');
|
|
71
|
+
|
|
72
|
+
expectValidImageObject(res);
|
|
74
73
|
});
|
|
75
74
|
|
|
76
|
-
it('should return
|
|
77
|
-
const res = await NekosiaAPI.fetchCategoryImages('
|
|
75
|
+
it('should return error for invalid category', async () => {
|
|
76
|
+
const res = await NekosiaAPI.fetchCategoryImages('invalid-category');
|
|
78
77
|
expect(res.success).toBe(false);
|
|
79
78
|
expect(res.status).toBe(400);
|
|
80
|
-
expect(res.message).toBe('Invalid count parameter. Expected a number between 1 and 48 (>48).');
|
|
81
79
|
});
|
|
82
80
|
});
|
|
83
81
|
|
|
84
|
-
describe('
|
|
85
|
-
it('should
|
|
86
|
-
const res = await NekosiaAPI.
|
|
82
|
+
describe('fetchImages', () => {
|
|
83
|
+
it('should return error when no image matches tags', async () => {
|
|
84
|
+
const res = await NekosiaAPI.fetchImages({
|
|
85
|
+
count: 1,
|
|
86
|
+
tags: ['invalid-tag1', 'invalid-tag2'],
|
|
87
|
+
});
|
|
87
88
|
|
|
88
|
-
|
|
89
|
-
|
|
89
|
+
expect(res.success).toBe(false);
|
|
90
|
+
expect(res.status).toBe(400);
|
|
91
|
+
});
|
|
90
92
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
expect(res2).toHaveProperty('image');
|
|
96
|
-
} else {
|
|
97
|
-
throw new Error('No images available to fetch by ID');
|
|
98
|
-
}
|
|
93
|
+
it('should throw if tags array is empty', async () => {
|
|
94
|
+
await expect(() => NekosiaAPI.fetchImages({ tags: [] }))
|
|
95
|
+
.rejects
|
|
96
|
+
.toThrow('`tags` must be a non-empty array');
|
|
99
97
|
});
|
|
100
98
|
|
|
101
|
-
it('should return
|
|
102
|
-
const res = await NekosiaAPI.
|
|
99
|
+
it('should return a valid image for known tag', async () => {
|
|
100
|
+
const res = await NekosiaAPI.fetchImages({
|
|
101
|
+
count: 1,
|
|
102
|
+
tags: ['catgirl'],
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
expectValidImageObject(res);
|
|
106
|
+
});
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
describe('fetchById', () => {
|
|
110
|
+
it('should fetch image by ID', async () => {
|
|
111
|
+
const preview = await NekosiaAPI.fetchCategoryImages('catgirl', { count: 1 });
|
|
112
|
+
if (!preview.success || !preview.id) throw new Error('No valid image to fetch by ID');
|
|
113
|
+
|
|
114
|
+
const fetched = await NekosiaAPI.fetchById(preview.id);
|
|
115
|
+
expect(fetched.success).toBe(true);
|
|
116
|
+
expect(fetched.status).toBe(200);
|
|
117
|
+
expect(fetched.id).toBe(preview.id);
|
|
118
|
+
expect(fetched).toHaveProperty('image');
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
it('should return error for malformed ID', async () => {
|
|
122
|
+
const res = await NekosiaAPI.fetchById('12345');
|
|
103
123
|
expect(res.success).toBe(false);
|
|
104
124
|
expect(res.status).toBe(400);
|
|
105
|
-
expect(res.message).
|
|
125
|
+
expect(res.message).toMatch(/The image with the provided identifier was not found/);
|
|
106
126
|
});
|
|
107
|
-
});
|
|
108
127
|
|
|
128
|
+
it('should return error for valid format but non-existent ID', async () => {
|
|
129
|
+
const res = await NekosiaAPI.fetchById('keyboardcat');
|
|
130
|
+
expect(res.success).toBe(false);
|
|
131
|
+
expect(400).toBe(res.status);
|
|
132
|
+
});
|
|
133
|
+
});
|
|
109
134
|
});
|
package/test/integration.test.js
CHANGED
|
@@ -14,6 +14,11 @@ describe('NekosiaAPI', () => {
|
|
|
14
14
|
const result = NekosiaAPI.buildQueryParams(options);
|
|
15
15
|
expect(result).toBe('count=3&additionalTags=tag1,tag2,tag3,tag4');
|
|
16
16
|
});
|
|
17
|
+
|
|
18
|
+
it('should return empty string for empty options', () => {
|
|
19
|
+
const result = NekosiaAPI.buildQueryParams({});
|
|
20
|
+
expect(result).toBe('');
|
|
21
|
+
});
|
|
17
22
|
});
|
|
18
23
|
|
|
19
24
|
describe('makeHttpRequest', () => {
|
|
@@ -54,13 +59,42 @@ describe('NekosiaAPI', () => {
|
|
|
54
59
|
expect(res).toEqual(mockResponse);
|
|
55
60
|
expect(https.get).toHaveBeenCalledWith(expectedEndpoint);
|
|
56
61
|
});
|
|
62
|
+
|
|
63
|
+
it('should build correct endpoint with no query params if options are empty', async () => {
|
|
64
|
+
const mockResponse = { data: { results: [] } };
|
|
65
|
+
https.get.mockResolvedValue(mockResponse);
|
|
66
|
+
|
|
67
|
+
const expectedEndpoint = 'https://api.nekosia.cat/api/v1/images/catgirl';
|
|
68
|
+
const res = await NekosiaAPI.fetchCategoryImages('catgirl');
|
|
69
|
+
|
|
70
|
+
expect(res).toEqual(mockResponse);
|
|
71
|
+
expect(https.get).toHaveBeenCalledWith(expectedEndpoint);
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
it('should include count=1 if explicitly set', async () => {
|
|
75
|
+
const mockResponse = { data: { results: [] } };
|
|
76
|
+
https.get.mockResolvedValue(mockResponse);
|
|
77
|
+
|
|
78
|
+
const expectedEndpoint = 'https://api.nekosia.cat/api/v1/images/catgirl?count=1';
|
|
79
|
+
const res = await NekosiaAPI.fetchCategoryImages('catgirl', { count: 1 });
|
|
80
|
+
|
|
81
|
+
expect(res).toEqual(mockResponse);
|
|
82
|
+
expect(https.get).toHaveBeenCalledWith(expectedEndpoint);
|
|
83
|
+
});
|
|
84
|
+
|
|
57
85
|
});
|
|
58
86
|
|
|
59
87
|
describe('fetchImages', () => {
|
|
60
|
-
it('should throw an error if
|
|
88
|
+
it('should throw an error if tags is missing', async () => {
|
|
61
89
|
await expect(NekosiaAPI.fetchImages({})).rejects.toThrow('`tags` must be a non-empty array');
|
|
62
90
|
});
|
|
63
91
|
|
|
92
|
+
it('should throw an error if tags is not an array', async () => {
|
|
93
|
+
await expect(NekosiaAPI.fetchImages({ tags: 'not-an-array' }))
|
|
94
|
+
.rejects
|
|
95
|
+
.toThrow('`tags` must be a non-empty array');
|
|
96
|
+
});
|
|
97
|
+
|
|
64
98
|
it('should correctly call fetchImages with additionalTags', async () => {
|
|
65
99
|
const mockResponse = { data: { results: [] } };
|
|
66
100
|
https.get.mockResolvedValue(mockResponse);
|
|
@@ -74,8 +108,10 @@ describe('NekosiaAPI', () => {
|
|
|
74
108
|
});
|
|
75
109
|
|
|
76
110
|
describe('fetchById', () => {
|
|
77
|
-
it('should throw an error if id is
|
|
78
|
-
|
|
111
|
+
it('should throw an error if id is missing or empty', async () => {
|
|
112
|
+
for (const id of [undefined, '']) {
|
|
113
|
+
await expect(NekosiaAPI.fetchById(id)).rejects.toThrow('`id` parameter is required');
|
|
114
|
+
}
|
|
79
115
|
});
|
|
80
116
|
|
|
81
117
|
it('should correctly fetch image by ID', async () => {
|
package/types/index.d.ts
CHANGED
|
@@ -28,7 +28,7 @@ declare module 'nekosia.js' {
|
|
|
28
28
|
* The number of images to fetch. WARNING! The higher the number, the more data the server will need to process, leading to longer response times.
|
|
29
29
|
*
|
|
30
30
|
* - Minimum - 1
|
|
31
|
-
* - Maximum -
|
|
31
|
+
* - Maximum - 24
|
|
32
32
|
* @type Number
|
|
33
33
|
* @default 1
|
|
34
34
|
*/
|
|
@@ -38,7 +38,7 @@ declare module 'nekosia.js' {
|
|
|
38
38
|
* Additional tags to include in the image search.
|
|
39
39
|
* This can be a single string representing one tag or an array of strings for multiple tags.
|
|
40
40
|
* @type Array
|
|
41
|
-
* @example ["cute", "sakura", "
|
|
41
|
+
* @example ["cute", "sakura", "blue-eyes"]
|
|
42
42
|
* @default []
|
|
43
43
|
*/
|
|
44
44
|
additionalTags?: AllTagsList | AllTagsList[];
|
|
@@ -66,7 +66,7 @@ declare module 'nekosia.js' {
|
|
|
66
66
|
* @example safe
|
|
67
67
|
* @default safe
|
|
68
68
|
*/
|
|
69
|
-
rating?: 'safe' | '
|
|
69
|
+
rating?: 'safe' | 'suggestive';
|
|
70
70
|
}
|
|
71
71
|
|
|
72
72
|
/**
|
|
@@ -401,7 +401,7 @@ declare module 'nekosia.js' {
|
|
|
401
401
|
* @type Object
|
|
402
402
|
* @returns A Promise resolving to an `ImageResponse`.
|
|
403
403
|
*/
|
|
404
|
-
static fetchCategoryImages(category: AllTagsList, options?: FetchImagesCategoryOptions): Promise<ImageResponse>;
|
|
404
|
+
static fetchCategoryImages(category: AllTagsList | 'random', options?: FetchImagesCategoryOptions): Promise<ImageResponse>;
|
|
405
405
|
|
|
406
406
|
/**
|
|
407
407
|
* Fetches images based solely on the tags provided by the user. The main category does not affect the image selection as it is not provided here.
|
package/types/tags.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
-
export const TAGS = ['absolute-territory','after-the-rain','afternoon-tea','ahoge','ajitani-hifumi','akazukin','aksktrpg','akura','alice-in-wonderland','alice-margatroid','alice-tendou','alllisso','alluring-face','alona','alone','amamine','amamineko-cafe','amashiro-natsuki','ame-nochi-yuki','ameto-yuki','angel','angry-face','animal-ears','apex','apple','apple-caramel','apple-pie','apron-dress','aqua','aquarium','areola-slip','aria-tsukushi','arknights','arknights-battle-illustration-contest','armed-girls','armpits','ashen-hair','assault-rifle','autumn','autumn-leaves','axillary-costume','azki','azkiart','azur-lane','babydoll','back-alley','background','balloon','balloons','bandages','bandaid','bangtail','bare-feet','bare-soles','barefoot','basketball','basketball-uniform','bath-time','bath-towel','beach','beach-ball','bear-ears','beargirl','beast-girl','beautiful','beautiful-reimu','bed','bed-hair','bedroom','belly','belly-glimpse','bellybutton','bench','beret','bewitching-thighs','bikini','bikini-top','birthday','black-and-white','black-bikini','black-dress','black-hair','black-hair-with-red-eyes','black-knee-high-socks','black-ribbon','black-sailor-uniform','black-shoes','black-skirt','black-stockings','black-thigh-high-socks','black-thigh-highs','black-tights','blazer','blonde','bloomers','blue-archive','blue-eues','blue-eyes','blue-hair','blue-ribbon','blue-shoes','blue-skirt','blue-sky','blushing','bocchi-chan','bondage','botamochi','bottomless','boy-cut','bra','braid','breast-hold','breasts','bride','brown-hair','bubble-tea','bunny-ears','bunny-girl','butterfly','by-the-window','cable-knitting','cake','cameltoe','camisole','camisole-dress','canal','candy','candy-apple','car','cardigan','cardigan-uniform','casual-wear','cat','cat-and-girl','cat-ears','cat-ears-hat','cat-ears-headphones','cat-ears-hoodie','cat-ears-maid','cat-mouth','cat-paws','cat-pose','cat-tail','catboy','catgirl','cats','celia-claire','celica','cheeks','cheerleader','chericot-rozel','cherry','cherry-blossom','cherry-petals','chess','chest-outline','chibi','chihuahua','chin-resting','chinese-lolita','chinese-style','chino','chino-kafuu','chitosezaka-suzu','chiyu','chocolate','chocolate-mint','choker','christmas','chuuni','classroom','cloak','closed-eyes','clouds','cocoa-hoto','coffee','collar','comic-treasure','confused','cookie','corset','cosmos','costume-change','cross-halter-bikini','crossed-legs','crying','cuite','cutaway-shoulder','cute','cute-cat','cuteness-is-justice','dakimakura-cover','dango','detexted','dog-and-girl','dog-ears','dog-girl','doll','donut','doujin','drawers','drawmei','dress','dress-shirt','dvdart','elementary-school-student','elevator','enticing-brassiere','epic-seven','exposed-back','eye-mask','eyepatch','fairy-eye','fairy-tale','fallenshadow','fantasy','fantasy-girl','feather-ears','feet','felicia-lulufleur','festival-of-white','firefly','fishnets','flare-skirt','flared-bikini','flat-chest','floral-playing-cards','flower','flowers-and-girls','forest','fox','fox-ears','fox-mask','fox-shrine-maiden','foxgirl','frills','fubuki-shiragami','fubuki-shiragami-fanart','fuwamoco','fuwawa-abyssgard','fuyoyo','fuzzy','fwmcpix','game','game-pad','gamer','gamer-girl','ganbare-ganbare','garter','garterbelt','gawr-gura','genshin-impact','gensokyo-in-spring','getting-dressed','gijinka','girl','girls','girls-frontline','glasses','gloves','gothic-lolita','greek-foot','green-eyes','green-hair','green-ribbon','guildcq','guitar','gun','gym-uniform','hairdressing','hairpin','hairstyle-change','hajime-todoroki','hakui-koyori','half-pants','half-pigtails','half-up-hairstyle','halloween','halo','hamico','hammock','han-costume','hanami','hands-forming-a-heart','harness','haruhara-shun','hayate-hisakawa','hazakura-chikori','headband','headboard-angle','headdress','headphone','headphones','headset','heart','heart-eyes','heartbreak','hearts','hedgehog','heels','herta','heterochromia','hibiki','hibiscus','high-angle','high-school-girl','high-waisted-skirt','hiiro','hikaru','himura-moritaka','hizuki-miu','hizuki-rurufu','holding-hands-with-fingers-interlocked','holding-ice-in-mouth','hololive','hololive-en','hololive-english','hololiveen','holox','hong','honkaistarrail','hood','hoodie','hoshi','hoshino','hoshitsuki-neiro','hoshizora-no-memoria','hot-spring','houzuki-michiru','hu-tao','hutao','hydrangea','ice-cream','ichigo','ichigori-ena','idol','illumination','in-the-train','incredibly-cute','indie-virtual-youtuber','indie-vtuber','indoor-shoes','infamous-left-foot-defense','inflatable-pool','inner-color','inugami-korone','itigori-ena','itou-yuna','izayoi-nonomi','jagged-sclera','japanese-clothes','japanese-maid','japanese-style','japanese-style-maid','japanese-umbrella','jersey','jk','jumper-skirt','jumpy','just-woke-up','kabashima-hana','kamiko-kana','kamioka-chiroru','kamisato-ayaka','kamiyama-shiki','kanade-otonose','kancolle','kantai-collection','kanzaki-ririka','karin','karyl','katana','katcolle','kazari-rua','kazueru','kazusa-kyoyama','kigurumi','kimono','kimono-dress','kindergarten-pupil','kingdom','kirakira-monstars','kiryuu-kikyou','kitchen','klee','knee-high-socks','kneeling','knockout-knockers','kohaku-nene','koharu','koiko-irori','koito-amuno','kokoro-amamiya','korie-riko','koyori-hakui','koyori-sketch','kuda-izuna','kuro-namako','kuromi-serika','kuroneko','kyaru','kyouyama-kazusa','lancat','lanmewko','lap-pillow','laplus-darkness','large-breasts','lattice-tower','left-foot-shield','legato','leggings','legs','lemon','leo','lily-of-the-valley','lime','lingerie','little-devil','lolipop-complete','lolita','lolita-fashion','lollipop','long-black-hair','long-blond-hair','long-gloves','long-hair','long-pink-hair','long-red-hair','long-white-gloves','long-white-hair','loungewear','lying-down','lying-on-one-side','macaron','machikaze-fuuna','mad','magical-girl','maid','maid-bikini','maid-uniform','makeup','mari-iochi','marie','marine','marine-day','marine-look','maruro','mascot','matsumiya-kiseri','mayoi-shigure','mea-kagura','medium-hair','mf-bunko-j','middle-school-student','midori-matsukaze','midriff','mihoshi-mei','miike-chan','mika','mika-misono','mikeneko','miko','miku-maekawa','minami-kotone','minato-aqua','mini-hakama','miniskirt','miniskirt-miko','mint','mirror','miu-channel','miu-hizuki','mizukiart','mococo','mococo-abyssgard','mole-under-the-eye','moon','murasaki-shion','muryo','myoya','nachoneko','nagi-hisakawa','nahida','nail-polish','nanashi-mumei','nap','natori-sana','necktie','necomi','needs-to-be-appreciated-more','negligee','nekoha-shizuku','nekomata-okayu','nene-kusanagi','new-year','newsboy-cap','night','night-sky','nijisanji','nikke','nine-tailed','nintendo-switch','nintendoswitch','no-game-no-life','noire','nolan','nonaka-yuu','nurse','off-shoulder','off-shoulder-dress','okomeillust','okusora-ayane','old-fashioned-school-swimsuit','older-girl','omochi-box','omochi-monaka','one-eye-covered','one-piece','one-piece-swimsuit','ookami-mio','open-shirt','orange-hair','orange-ribbon','otokonoko','overalls','overly-long-sleeves','pajamas','panchira','panda-ears','panties','pants','parasol','park','patting','paw-pads','peace-sign','pekora-usada-fanart','personification-of-drinks','photo-editing','pigtails','pillow','pinching-garments','pink','pink-eyes','pink-hair','pink-ribbon','pink-shoes','pink-skirt','pink-sweater','pink-twintails','plaid-pattern','plaid-skirt','plastic-bottle','platform','playing-cards','plump-thighs','plushie','pocky','pointy-ears','polar-bear','ponytail','pool','pool-at-night','porch','present','princess-connect','project-sekai','prone-position','psycho','pu-ht','purple-ears','purple-eyes','purple-hair','purple-ribbon','purple-skirt','queen-of-hearts','rabbit-girl','ragna-doll','railroad-crossing','railway','rain','rainy-season','ramune','randoseru','rawr','re-oekaki','red-and-blue','red-eyes','red-hair','red-pigtails','red-ribbon','red-ribbons','red-skirt','reflected-glare','regloss','reimu-hakurei','reisa-uzawa','remilia-scarlet','rena-yorumi','reverse-sitting','rhodes','ribbed-fabric','ribbon','ribbonos','ribbons','ringo-chan','roar','rocket-launcher','roxanne','rribbon','rubbib','rucaco','rukako','ruki-roki','rumi','runa-shinomiya','rurudo','rurudo-lion','rushia-uruha','sad','saekiya-sabou','saiba-midori','saiba-momoi','sailor','sailor-dress','sailor-one-piece','sailor-swimsuit','sailor-uniform','sakamata-chloe','sakura','sakura-miko','sakuraba-moeka','sakurada-hane','sakuradahane','sakurai-hana','sand','santa','santa-cosplay','sassy-loli','scared','scarf','scenery','school-swimsuit','school-uniform','school-uniform-cardigan','school-uniform-hoodie','schoolgirl','scornful-eyes','sea','see-through','selfie','setokane','shano-hiyori','shanoa-asmr','shigure','shiori','shirai-tanuki','shirakami-fubuki','shirakawa-yumea','shirasu-azusa','shiroko','shiroko-terror','shiromichan','shooting-star','short-boots','short-haircut','short-pants','short-white-hair','shouu-kun','showgirl','shy','side-string-bikini','side-tie-panty','silver-hair','silver-long-hair','singer','sisters','sitting','sitting-on-feet','sitting-with-hands-around-knees','skirt','skirt-lift','skirtm','sleep','sleep-wear','sleeping-face','sleepy','sleepy-face','sleeveless','sleeveless-dress','sleeveless-parka','small-breasts','small-fangs','smile','snack-nili','sneakers','snow','snow-leopard','snowman','snowy-landscape','socks','sofa','sole','somna','sorasaki-hina','spiral-eyes','splashes','spring','squirrel','stairs','standing-picture','starlight-stage','starry-sky','starry-sky-dress','steamed-bun-with-meat-filling','stockings','straight-fringe','strap-shoes','straw-hat','strawberries','strawberry','streaked-hair','string-ribbon','striped-bikini','striped-thigh-high-socks','sukumizu','summer','summer-dress','summer-kimono','summer-pockets','sunaookami-shiroko','sunflowers','sunglasses','sunohara-kokona','sunset','supine','suspender-skirt','suzuho-hotaru','sweat','sweater','sweets','swim-ring','swimsuit','swimsuit-parka','swimwear','swing','sword','t-shirt','tail','tail-from-under-skirt','tail-holding','tail-with-ribbon','taiwan','takanashi','takanashi-hoshino','tattoo','tea','tea-time','tears','teary-eyed','teary-eyes','telephone','tenshinoikenie','test','the-person-behind','the-soles-of-feet-in-socks','theriantrope','thick-eyebrows','thigh-high-socks','thigh-highs','thighhighs','thighs','tie-side-bikini','tiered-dress','tiger','tights','tired','tobu-railway','toes','tokoshibyra','tongue-out','touhou','touhou-project','towel','transparency','trick-or-treat','tropical-fish','tsugiri-noa','twins','twintails','uise-iu','umbrella','underwater','uniform','upwards-gaze','uruha-rushia-fanart','usada-pekora','usagigo','valentine','vampire','vdonburi','vrchat','vtuber','w-sitting','wa-lolita','waitress','wallpaper','water','water-surface','watermelon','weapon','wearing-only-a-shirt','wedding-dress','wet','wet-see-through','white-bikini','white-cat','white-day','white-dress','white-hair','white-hairpin','white-hait','white-high-socks','white-knee-high-socks','white-ribbon','white-sailor-uniform','white-school-swimsuit','white-skirt','white-socks','white-stockings','white-swimsuit','white-thigh-high-socks','white-tiger','white-tights','white-twintails','wings','wink','winter','witch','wolf-ears','wolf-girl','yandere','yaoyao','yawn','yellow-eyes','yellow-hair','yellow-ribbon','yoko','young-boy','young-girl','yuika-shiina','yukata','yukihana-lamy','yukinoshita-peo','yutori-natsu','yuuki-sakuna'] as const;
|
|
1
|
+
export const TAGS =
|
|
2
|
+
['absolute-territory','after-the-rain','afternoon-tea','akazukin','alice-in-wonderland','alice-mana','alllisso','alluring-face','alona','alone','amamine','amamineko-cafe','amashiro-natsuki','angel','angry-face','animal-ears','apex','apple','apple-caramel','apple-pie','apron-dress','aqua','aquarium','aria-tsukushi','arknights','arknights-battle-illustration-contest','armed-girls','armpits','ashen-hair','assault-rifle','autumn','autumn-leaves','axillary-costume','azki','azkiart','azur-lane','babydoll','back-alley','background','balloon','balloons','bandages','bandaid','bare-feet','barefoot','basketball','basketball-uniform','beach','beast-girl','beautiful','beautiful-reimu','bed','bed-hair','bedroom','belly-glimpse','bellybutton','bench','beret','bewitching-thighs','birthday','black-and-white','black-dress','black-hair','black-hair-with-red-eyes','black-knee-high-socks','black-ribbon','black-sailor-uniform','black-shoes','black-skirt','black-stockings','black-thigh-high-socks','black-thigh-highs','black-tights','blazer','blonde','bloomers','blue-archive','blue-eyes','blue-hair','blue-ribbon','blue-shoes','blue-skirt','blue-sky','blushing','bocchi-chan','botamochi','bottomless','boy-cut','braid','breasts','brown-hair','bubble-tea','bunny-ears','bunny-girl','butterfly','by-the-window','cable-knitting','cafe','cake','camisole','camisole-dress','canal','candy-apple','car','cardigan','cardigan-uniform','casual-wear','cat','cat-and-girl','cat-ears','cat-ears-hat','cat-ears-headband','cat-ears-headphones','cat-ears-hoodie','cat-ears-maid','cat-mouth','cat-paws','cat-pose','cat-tail','catboy','catgirl','cats','cheeks','cherry','cherry-blossom','cherry-petals','chess','chibi','chihuahua','chin-resting','chinese-lolita','chinese-style','chino','chino-kafuu','chitosezaka-suzu','chocolate','chocolate-mint','choker','christmas','chuuni','classroom','cloak','closed-eyes','clouds','cocoa-hoto','coffee','coffee-shop','collar','comic-treasure','confused','cookie','corset','cosmos','crossed-legs','crying','cutaway-shoulder','cute','cute-cat','cuteness-is-justice','cyte','detexted','dog','dog-and-girl','dog-ears','dog-girl','doll','donut','doujin','drawers','drawmei','dress','dress-shirt','dvdart','elaina','elementary-school-student','elevator','epic-seven','eye-mask','eyepatch','fairy-eye','fairy-tale','fantasy','fantasy-girl','feather-ears','feet','felicia-lulufleur','festival-of-white','firefly','fireworks','fishnets','flare-skirt','flat-chest','floral-playing-cards','flower','flowers','flowers-and-girls','food','footwear','forest','fox','fox-ears','fox-mask','fox-shrine-maiden','foxgirl','frills','fubuki-shiragami','fubuki-shiragami-fanart','fuwamoco','fuyoyo','fuzzy','game','game-pad','gamer','gamer-girl','garter','garterbelt','gawr-gura','genshin-impact','gensokyo-in-spring','getting-dressed','ghost','gijinka','girl','girls','glasses','gloves','gothic-lolita','green-eyes','green-hair','green-ribbon','guildcq','guitar','gun','gym-uniform','hair-tie-in-mouth','hairdressing','hairpin','hairstyle-change','hajime-todoroki','hakui-koyori','half-pants','half-pigtails','half-up-hairstyle','halloween','halo','hamico','han-costume','hanami','hands-forming-a-heart','harness','hayate-hisakawa','hazakura-chikori','headband','headboard-angle','headdress','headphone','headphones','headset','heart','heart-eyes','heartbreak','hearts','hedgehog','heels','herta','heterochromia','hibiki','hibiscus','high-angle','high-school-girl','high-waisted-skirt','hiiro','hikaru','hizamaru','holding-hands-with-fingers-interlocked','holding-ice-in-mouth','hololive','hololive-en','hololive-english','hololiveen','holox','hong','honkaistarrail','hood','hoodie','hoshi','hoshino','hoshizora-no-memoria','hot-spring','hu-tao','hutao','hydrangea','ice-cream','ichigo','ichigori-ena','idol','illumination','in-the-train','incredibly-cute','indie-vtuber','indoor-shoes','inner-color','inugami-korone','itigori-ena','jagged-sclera','japanese-clothes','japanese-maid','japanese-style','japanese-style-maid','japanese-umbrella','jk','jumper-skirt','jumpy','just-woke-up','kabashima-hana','kamiko-kana','kamioka-chiroru','kamisato-ayaka','kamiyama-shiki','kanade-otonose','kancolle','kanon-mashiro','kantai-collection','karin','katana','katcolle','kazari-rua','kazueru','kazusa-kyoyama','kimono','kimono-dress','kindergarten-pupil','kingdom','kirakira-monstars','kiryuu-kikyou','kitchen','klee','knee-high-socks','knitted-vest','koharu','koiko-irori','koito-amuno','korie-riko','koyori-hakui','koyori-sketch','kuda-izuna','kuro-namako','kuroneko','kyaru','kyouyama-kazusa','lancat','lanmewko','laplus-darkness','large-breasts','lattice-tower','left-foot-shield','legato','leggings','legs','lemon','leo','lily-of-the-valley','lime','lingerie','little-devil','lolipop-complete','lolita','lolita-fashion','lollipop','long-black-hair','long-blond-hair','long-hair','long-pink-hair','long-red-hair','long-white-gloves','long-white-hair','loungewear','lying-down','lying-on-one-side','macaron','mad','magical-girl','maid','maid-uniform','makeup','mari-iochi','marie','marine-look','maruro','mascot','mayoi-shigure','medium-hair','middle-school-student','midori-matsukaze','mihoshi-mei','miike-chan','mika','mika-misono','mikeneko','miko','minato-aqua','mini-hakama','miniskirt','miniskirt-miko','mint','mirror','mizukiart','mococo','mococo-abyssgard','moon','murasaki-shion','muryo','myoya','nachoneko','nagi-hisakawa','nahida','nail-polish','nana-kagura','nanashi-mumei','nap','natori-sana','necktie','negligee','nekoha-shizuku','nekomata-okayu','new-year','newsboy-cap','night','night-sky','nijisanji','nikke','nine-tailed','nintendo-switch','nintendoswitch','noire','nolan','nonaka-yuu','nurse','off-shoulder','off-shoulder-dress','okomeillust','omochi-box','omochi-monaka','one-eye-covered','one-piece','ookami-mio','orange-hair','otokonoko','overalls','overly-long-sleeves','painting','pajamas','panda-ears','parasol','park','patting','peace-sign','pekora-usada-fanart','personification-of-drinks','photo-editing','pigtails','pillow','pinching-garments','pink','pink-eyes','pink-hair','pink-ribbon','pink-shoes','pink-skirt','pink-twintails','plaid-pattern','plaid-skirt','platform','playing-cards','plump-thighs','plushie','pocky','pointy-ears','ponytail','porch','present','princess-connect','project-sekai','prone-position','pu-ht','purple-ears','purple-eyes','purple-hair','purple-ribbon','purple-skirt','queen-of-hearts','railroad-crossing','railway','rain','rainy-season','ramune','randoseru','rawr','red-and-blue','red-eyes','red-hair','red-pigtails','red-ribbon','red-skirt','reflected-glare','regloss','reimu-hakurei','reisa-uzawa','remilia-scarlet','reverse-sitting','rhodes','ribbed-fabric','ribbon','ringo-chan','roar','rocket-launcher','rucaco','rukako','ruki-roki','rumi','runa-shinomiya','rurudo','rurudo-lion','rushia-uruha','sad','saiba-midori','saiba-momoi','sailor-dress','sailor-one-piece','sailor-uniform','sakamata-chloe','sakura','sakura-miko','sakuraba-moeka','sakurada-hane','sakuradahane','sakurai-hana','santa','sassy-loli','scared','scarf','scenery','school-sweater','school-uniform','school-uniform-cardigan','school-uniform-hoodie','schoolgirl','scornful-eyes','sea','see-through','selfie','setokane','shano-hiyori','shanoa-asmr','shiba-inu','shigure','shiori','shirakawa-yumea','shirasu-azusa','shiroko','shiroko-terror','shiromichan','shooting-star','short-boots','short-haircut','short-pants','short-white-hair','shouu-kun','showgirl','shy','silver-hair','silver-long-hair','singer','sisters','sitting','skirt','skirt-lift','skirtm','sleep','sleeping-face','sleepwear','sleepy','sleepy-face','sleeveless','sleeveless-dress','sleeveless-parka','small-fangs','smartphone','smile','smug-face','sneakers','snow','snowman','snowy-landscape','socks','sofa','sole','somna','sorasaki-hina','sousei','spiral-eyes','splashes','spring','squirrel','standing-picture','starlight-stage','starry-sky','starry-sky-dress','steamed-bun-with-meat-filling','stockings','straight-fringe','strap-shoes','straw-hat','strawberries','strawberry','streaked-hair','striped-thigh-high-socks','summer','summer-dress','summer-kimono','summer-pockets','sunaookami-shiroko','sunflowers','sunohara-kokona','sunset','supine','suspender-skirt','suzuho-hotaru','sweat','sweater','sweets','swimwear','swing','sword','tail','tail-from-under-skirt','tail-holding','tail-with-ribbon','taiwan','takanashi','takanashi-hoshino','tea','tea-time','tears','teary-eyed','teddy-bear','telephone','the-person-behind','the-soles-of-feet-in-socks','thick-eyebrows','thigh-high-socks','thigh-highs','thighhighs','thighs','tiered-dress','tiger','tights','tired','tobu-railway','toes','tongue-out','touhou','touhou-project','tropical-fish','twins','twintails','uise-iu','umbrella','underwater','uniform','upwards-gaze','usada-pekora','usagigo','valentine','vampire','vdonburi','vrchat','vtuber','w-sitting','wa-lolita','waitress','wallpaper','wallpapers','water','water-surface','watermelon','weapon','wedding-dress','wet','what-is-this-cuteness','white-cat','white-day','white-dress','white-hair','white-hait','white-high-socks','white-knee-high-socks','white-ribbon','white-sailor-uniform','white-skirt','white-socks','white-stockings','white-thigh-high-socks','white-tiger','white-tights','white-twintails','wings','wink','winter','witch','wolf','wolf-ears','wolf-girl','yandere','yaoyao','yawn','yellow-eyes','yellow-hair','yellow-ribbon','yoko','young-boy','young-girl','yuika-shiina','yuimisu','yukata','yukihana-lamy','yukinoshita-peo','yutori-natsu','yuuki-sakuna'] as const;
|
|
2
3
|
|
|
3
|
-
// https://api.nekosia.cat/api/v1/tags
|
|
4
|
+
// GET https://api.nekosia.cat/api/v1/tags
|