mirror of https://github.com/iconify/api.git
Compare commits
37 Commits
| Author | SHA1 | Date |
|---|---|---|
|
|
a3d158f99c | |
|
|
407792e2bc | |
|
|
8e35844326 | |
|
|
f79638ef5f | |
|
|
23b5dc510e | |
|
|
238e12a016 | |
|
|
26828c1152 | |
|
|
d24e229645 | |
|
|
62fa26b541 | |
|
|
65af386d3c | |
|
|
ae0e4c929d | |
|
|
116d8e20df | |
|
|
a7e3d99d9e | |
|
|
2521142eca | |
|
|
84590145c9 | |
|
|
88b88251aa | |
|
|
262783f704 | |
|
|
48b0da6d55 | |
|
|
119538fbff | |
|
|
3141131ab7 | |
|
|
ba72402310 | |
|
|
6f33b7c4c5 | |
|
|
44884118f3 | |
|
|
9ec6b365a0 | |
|
|
5e1dbe8d4f | |
|
|
9b7b1a4279 | |
|
|
871028175b | |
|
|
a752e1ee7f | |
|
|
39e5bb4817 | |
|
|
2afff788df | |
|
|
8300891cba | |
|
|
f62b8ba8e6 | |
|
|
65b0eca32e | |
|
|
a02dd19d51 | |
|
|
e44822a40d | |
|
|
c5260541b8 | |
|
|
1d55e2dafd |
|
|
@ -1 +0,0 @@
|
|||
github: cyberalien
|
||||
|
|
@ -15,8 +15,8 @@ jobs:
|
|||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-node@v4
|
||||
- uses: actions/checkout@v5
|
||||
- uses: actions/setup-node@v6
|
||||
with:
|
||||
node-version: 'latest'
|
||||
|
||||
|
|
|
|||
10
Dockerfile
10
Dockerfile
|
|
@ -1,11 +1,11 @@
|
|||
ARG ARCH=amd64
|
||||
ARG NODE_VERSION=18
|
||||
ARG NODE_VERSION=22
|
||||
ARG OS=bullseye-slim
|
||||
ARG ICONIFY_API_VERSION=3.0.0
|
||||
ARG ICONIFY_API_VERSION=3.2.0
|
||||
ARG SRC_PATH=./
|
||||
|
||||
#### Stage BASE ########################################################################################################
|
||||
FROM ${ARCH}/node:${NODE_VERSION}-${OS} AS base
|
||||
FROM --platform=${ARCH} node:${NODE_VERSION}-${OS} AS base
|
||||
|
||||
# This gives node.js apps access to the OS CAs
|
||||
ENV NODE_EXTRA_CA_CERTS=/etc/ssl/certs/ca-certificates.crt
|
||||
|
|
@ -53,8 +53,8 @@ COPY ${SRC_PATH}icons/ /data/iconify-api/icons/
|
|||
# Build API
|
||||
RUN npm run build
|
||||
|
||||
#### Stage RELEASE #####################################################################################################
|
||||
FROM iconify-api-install AS RELEASE
|
||||
#### Stage release #####################################################################################################
|
||||
FROM iconify-api-install AS release
|
||||
ARG BUILD_DATE
|
||||
ARG BUILD_VERSION
|
||||
ARG BUILD_REF
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
28
package.json
28
package.json
|
|
@ -3,11 +3,7 @@
|
|||
"description": "Iconify API",
|
||||
"author": "Vjacheslav Trushkin",
|
||||
"license": "MIT",
|
||||
"version": "3.1.0",
|
||||
"publishConfig": {
|
||||
"access": "public",
|
||||
"tag": "next"
|
||||
},
|
||||
"version": "3.2.0",
|
||||
"type": "module",
|
||||
"bugs": "https://github.com/iconify/api/issues",
|
||||
"homepage": "https://github.com/iconify/api",
|
||||
|
|
@ -15,9 +11,9 @@
|
|||
"type": "git",
|
||||
"url": "https://github.com/iconify/api.git"
|
||||
},
|
||||
"packageManager": "npm@10.6.0",
|
||||
"packageManager": "npm@11.6.4",
|
||||
"engines": {
|
||||
"node": ">=16.15.0"
|
||||
"node": ">=22.20.0"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "tsc -b",
|
||||
|
|
@ -30,17 +26,17 @@
|
|||
"docker:publish": "docker push iconify/api"
|
||||
},
|
||||
"dependencies": {
|
||||
"@fastify/formbody": "^7.4.0",
|
||||
"@iconify/tools": "^4.0.4",
|
||||
"@fastify/formbody": "^8.0.2",
|
||||
"@iconify/tools": "^5.0.0",
|
||||
"@iconify/types": "^2.0.0",
|
||||
"@iconify/utils": "^2.1.23",
|
||||
"dotenv": "^16.4.5",
|
||||
"fastify": "^4.26.2"
|
||||
"@iconify/utils": "^3.1.0",
|
||||
"dotenv": "^17.2.3",
|
||||
"fastify": "^5.6.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/jest": "^29.5.12",
|
||||
"@types/node": "^20.12.7",
|
||||
"typescript": "^5.4.5",
|
||||
"vitest": "^1.5.2"
|
||||
"@types/jest": "^30.0.0",
|
||||
"@types/node": "^24.10.1",
|
||||
"typescript": "^5.9.3",
|
||||
"vitest": "^4.0.14"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,27 @@
|
|||
{
|
||||
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
|
||||
"extends": ["config:recommended"],
|
||||
"rangeStrategy": "bump",
|
||||
"packageRules": [
|
||||
{
|
||||
"matchDepTypes": ["peerDependencies"],
|
||||
"enabled": false
|
||||
},
|
||||
{
|
||||
"matchPackageNames": ["fastify"],
|
||||
"allowedVersions": "<4.0.0"
|
||||
},
|
||||
{
|
||||
"matchPackageNames": ["@fastify/formbody"],
|
||||
"allowedVersions": "<8.0.0"
|
||||
},
|
||||
{
|
||||
"matchPackageNames": ["@iconify/utils"],
|
||||
"allowedVersions": "<3.0.0"
|
||||
},
|
||||
{
|
||||
"matchPackageNames": ["@iconify/tools"],
|
||||
"allowedVersions": "<5.0.0"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -125,7 +125,7 @@ export function updateIconSets(): number {
|
|||
/**
|
||||
* Trigger update
|
||||
*/
|
||||
export function triggerIconSetsUpdate(done?: (success?: boolean) => void) {
|
||||
export function triggerIconSetsUpdate(index?: number | null, done?: (success?: boolean) => void) {
|
||||
if (!importers) {
|
||||
done?.();
|
||||
return;
|
||||
|
|
@ -141,6 +141,9 @@ export function triggerIconSetsUpdate(done?: (success?: boolean) => void) {
|
|||
// Check for updates
|
||||
let updated = false;
|
||||
for (let i = 0; i < importers?.length; i++) {
|
||||
if (typeof index === 'number' && i !== index) {
|
||||
continue;
|
||||
}
|
||||
updated = (await importers[i].checkForUpdate()) || updated;
|
||||
}
|
||||
return updated;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,10 @@
|
|||
export function errorText(code: number) {
|
||||
switch (code) {
|
||||
case 404:
|
||||
return 'Not found';
|
||||
|
||||
case 400:
|
||||
return 'Bad request';
|
||||
}
|
||||
return 'Internal server error';
|
||||
}
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
/**
|
||||
* Basic cleanup for parameters
|
||||
*/
|
||||
export function cleanupQueryValue(value: string | undefined) {
|
||||
return value ? value.replace(/['"<>&]/g, '') : undefined;
|
||||
}
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
import type { FastifyReply, FastifyRequest } from 'fastify';
|
||||
import { checkJSONPQuery, sendJSONResponse } from './json.js';
|
||||
import { errorText } from './errors.js';
|
||||
|
||||
type CallbackResult = object | number;
|
||||
|
||||
|
|
@ -17,14 +18,14 @@ export function handleJSONResponse(
|
|||
const wrap = checkJSONPQuery(q);
|
||||
if (!wrap) {
|
||||
// Invalid JSONP callback
|
||||
res.send(400);
|
||||
res.code(400).send(errorText(400));
|
||||
return;
|
||||
}
|
||||
|
||||
// Function to send response
|
||||
const respond = (result: CallbackResult) => {
|
||||
if (typeof result === 'number') {
|
||||
res.send(result);
|
||||
res.code(result).send(errorText(result));
|
||||
} else {
|
||||
sendJSONResponse(result, q, wrap, res);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ import { generateUpdateResponse } from './responses/update.js';
|
|||
import { initVersionResponse, versionResponse } from './responses/version.js';
|
||||
import { generateIconsStyleResponse } from './responses/css.js';
|
||||
import { handleJSONResponse } from './helpers/send.js';
|
||||
import { errorText } from './helpers/errors.js';
|
||||
|
||||
/**
|
||||
* Start HTTP server
|
||||
|
|
@ -22,7 +23,9 @@ import { handleJSONResponse } from './helpers/send.js';
|
|||
export async function startHTTPServer() {
|
||||
// Create HTP server
|
||||
const server = fastify({
|
||||
caseSensitive: true,
|
||||
routerOptions: {
|
||||
caseSensitive: true,
|
||||
},
|
||||
});
|
||||
|
||||
// Support `application/x-www-form-urlencoded`
|
||||
|
|
@ -82,7 +85,7 @@ export async function startHTTPServer() {
|
|||
generateSVGResponse(name.prefix, name.name, req.query, res);
|
||||
});
|
||||
} else {
|
||||
res.send(404);
|
||||
res.code(404).send(errorText(404));
|
||||
}
|
||||
});
|
||||
|
||||
|
|
@ -178,7 +181,7 @@ export async function startHTTPServer() {
|
|||
|
||||
// Options
|
||||
server.options('/*', (req, res) => {
|
||||
res.send(200);
|
||||
res.code(204).header('Content-Length', '0').send();
|
||||
});
|
||||
|
||||
// Robots
|
||||
|
|
@ -198,21 +201,21 @@ export async function startHTTPServer() {
|
|||
|
||||
// Redirect
|
||||
server.get('/', (req, res) => {
|
||||
res.redirect(301, appConfig.redirectIndex);
|
||||
res.redirect(appConfig.redirectIndex, 301);
|
||||
});
|
||||
|
||||
// Error handling
|
||||
server.setDefaultRoute((req, res) => {
|
||||
server.setNotFoundHandler((req, res) => {
|
||||
res.statusCode = 404;
|
||||
console.log('404:', req.url);
|
||||
|
||||
// Need to set custom headers because hooks don't work here
|
||||
for (let i = 0; i < headers.length; i++) {
|
||||
const header = headers[i];
|
||||
res.setHeader(header.key, header.value);
|
||||
res.header(header.key, header.value);
|
||||
}
|
||||
|
||||
res.end();
|
||||
res.send();
|
||||
});
|
||||
|
||||
// Start it
|
||||
|
|
|
|||
|
|
@ -5,6 +5,8 @@ import type { IconCSSIconSetOptions } from '@iconify/utils/lib/css/types';
|
|||
import { getStoredIconsData } from '../../data/icon-set/utils/get-icons.js';
|
||||
import { iconSets } from '../../data/icon-sets.js';
|
||||
import { paramToBoolean } from '../../misc/bool.js';
|
||||
import { errorText } from '../helpers/errors.js';
|
||||
import { cleanupQueryValue } from '../helpers/query.js';
|
||||
|
||||
/**
|
||||
* Check selector for weird stuff
|
||||
|
|
@ -26,7 +28,7 @@ export function generateIconsStyleResponse(prefix: string, query: FastifyRequest
|
|||
|
||||
if (!names || !names.length) {
|
||||
// Missing or invalid icons parameter
|
||||
res.send(404);
|
||||
res.code(404).send(errorText(404));
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -34,7 +36,7 @@ export function generateIconsStyleResponse(prefix: string, query: FastifyRequest
|
|||
const iconSet = iconSets[prefix];
|
||||
if (!iconSet) {
|
||||
// No such icon set
|
||||
res.send(404);
|
||||
res.code(404).send(errorText(404));
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -56,7 +58,7 @@ export function generateIconsStyleResponse(prefix: string, query: FastifyRequest
|
|||
|
||||
// 'color': string
|
||||
// Sets color for monotone images
|
||||
const color = qOptions.color;
|
||||
const color = cleanupQueryValue(qOptions.color);
|
||||
if (typeof color === 'string' && stringToColor(color)) {
|
||||
options.color = color;
|
||||
}
|
||||
|
|
@ -97,7 +99,7 @@ export function generateIconsStyleResponse(prefix: string, query: FastifyRequest
|
|||
// 'commonSelector': string
|
||||
// Common selector for all requested icons
|
||||
// Alias: 'common'
|
||||
const commonSelector = qOptions.commonSelector || q.common;
|
||||
const commonSelector = cleanupQueryValue(qOptions.commonSelector || q.common);
|
||||
if (checkSelector(commonSelector)) {
|
||||
options.commonSelector = commonSelector;
|
||||
}
|
||||
|
|
@ -105,7 +107,7 @@ export function generateIconsStyleResponse(prefix: string, query: FastifyRequest
|
|||
// 'iconSelector': string
|
||||
// Icon selector
|
||||
// Alias: 'selector'
|
||||
const iconSelector = qOptions.iconSelector || q.selector;
|
||||
const iconSelector = cleanupQueryValue(qOptions.iconSelector || q.selector);
|
||||
if (checkSelector(iconSelector)) {
|
||||
options.iconSelector = iconSelector;
|
||||
}
|
||||
|
|
@ -113,7 +115,7 @@ export function generateIconsStyleResponse(prefix: string, query: FastifyRequest
|
|||
// 'overrideSelector': string
|
||||
// Selector for rules in icon that override common rules
|
||||
// Alias: 'override'
|
||||
const overrideSelector = qOptions.overrideSelector || q.override;
|
||||
const overrideSelector = cleanupQueryValue(qOptions.overrideSelector || q.override);
|
||||
if (checkSelector(overrideSelector)) {
|
||||
options.overrideSelector = overrideSelector;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,6 +7,8 @@ import { defaultIconCustomisations, IconifyIconCustomisations } from '@iconify/u
|
|||
import type { FastifyReply, FastifyRequest } from 'fastify';
|
||||
import { getStoredIconData } from '../../data/icon-set/utils/get-icon.js';
|
||||
import { iconSets } from '../../data/icon-sets.js';
|
||||
import { errorText } from '../helpers/errors.js';
|
||||
import { cleanupQueryValue } from '../helpers/query.js';
|
||||
|
||||
/**
|
||||
* Generate SVG
|
||||
|
|
@ -16,7 +18,7 @@ export function generateSVGResponse(prefix: string, name: string, query: Fastify
|
|||
const iconSetItem = iconSets[prefix]?.item;
|
||||
if (!iconSetItem) {
|
||||
// No such icon set
|
||||
res.send(404);
|
||||
res.code(404).send(errorText(404));
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -24,7 +26,7 @@ export function generateSVGResponse(prefix: string, name: string, query: Fastify
|
|||
const icons = iconSetItem.icons;
|
||||
if (!(icons.visible[name] || icons.hidden[name]) && !iconSetItem.icons.chars?.[name]) {
|
||||
// No such icon
|
||||
res.send(404);
|
||||
res.code(404).send(errorText(404));
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -32,7 +34,7 @@ export function generateSVGResponse(prefix: string, name: string, query: Fastify
|
|||
getStoredIconData(iconSetItem, name, (data) => {
|
||||
if (!data) {
|
||||
// Invalid icon
|
||||
res.send(404);
|
||||
res.code(404).send(errorText(404));
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -42,8 +44,8 @@ export function generateSVGResponse(prefix: string, name: string, query: Fastify
|
|||
const customisations: IconifyIconCustomisations = {};
|
||||
|
||||
// Dimensions
|
||||
customisations.width = q.width || defaultIconCustomisations.width;
|
||||
customisations.height = q.height || defaultIconCustomisations.height;
|
||||
customisations.width = cleanupQueryValue(q.width) || defaultIconCustomisations.width;
|
||||
customisations.height = cleanupQueryValue(q.height) || defaultIconCustomisations.height;
|
||||
|
||||
// Rotation
|
||||
customisations.rotate = q.rotate ? rotateFromString(q.rotate, 0) : 0;
|
||||
|
|
@ -74,7 +76,7 @@ export function generateSVGResponse(prefix: string, name: string, query: Fastify
|
|||
let html = iconToHTML(body, svg.attributes);
|
||||
|
||||
// Change color
|
||||
const color = q.color;
|
||||
const color = cleanupQueryValue(q.color);
|
||||
if (color && html.indexOf('currentColor') !== -1 && color.indexOf('"') === -1) {
|
||||
html = html.split('currentColor').join(color);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue