Compare commits

..

37 Commits
3.1.0 ... main

Author SHA1 Message Date
Vjacheslav Trushkin a3d158f99c chore: make dockerfile work 2025-11-27 20:31:47 +02:00
Vjacheslav Trushkin 407792e2bc chore: publish new minor version 2025-11-27 19:14:13 +02:00
Vjacheslav Trushkin 8e35844326 chore: update all dependencies, update routes for latest fastify 2025-11-27 17:31:14 +02:00
Vjacheslav Trushkin f79638ef5f chore: update dependencies, clean up renovate config 2025-11-18 09:07:18 +02:00
Vjacheslav Trushkin 23b5dc510e
Merge pull request #61 from iconify/revert-51-renovate/fastify-formbody-8.x
Revert "fix(deps): update dependency @fastify/formbody to v8"
2025-11-18 08:30:40 +02:00
Vjacheslav Trushkin 238e12a016
Revert "fix(deps): update dependency @fastify/formbody to v8" 2025-11-18 08:30:29 +02:00
Vjacheslav Trushkin 26828c1152
Merge pull request #55 from iconify/renovate/node-22.x
chore(deps): update node.js to v22
2025-10-16 09:11:08 +03:00
renovate[bot] d24e229645
chore(deps): update node.js to v22 2025-10-14 05:30:30 +00:00
Vjacheslav Trushkin 62fa26b541
Merge pull request #51 from iconify/renovate/fastify-formbody-8.x
fix(deps): update dependency @fastify/formbody to v8
2025-10-14 08:28:09 +03:00
renovate[bot] 65af386d3c
fix(deps): update dependency @fastify/formbody to v8 2025-10-14 05:26:58 +00:00
Vjacheslav Trushkin ae0e4c929d
Merge pull request #42 from iconify/renovate/typescript-5.x
chore(deps): update dependency typescript to ^5.9.3
2025-10-14 08:25:25 +03:00
renovate[bot] 116d8e20df
chore(deps): update dependency typescript to ^5.9.3 2025-10-14 05:25:18 +00:00
Vjacheslav Trushkin a7e3d99d9e
Merge pull request #41 from iconify/renovate/node-20.x
chore(deps): update dependency @types/node to ^20.19.21
2025-10-14 08:24:36 +03:00
Vjacheslav Trushkin 2521142eca
Merge pull request #40 from iconify/renovate/fastify-4.x
fix(deps): update dependency fastify to ^4.29.1
2025-10-14 08:24:24 +03:00
Vjacheslav Trushkin 84590145c9
Merge pull request #39 from iconify/renovate/iconify-tools-4.x
fix(deps): update dependency @iconify/tools to ^4.1.4
2025-10-14 08:24:04 +03:00
renovate[bot] 88b88251aa
chore(deps): update dependency @types/node to ^20.19.21 2025-10-14 05:23:20 +00:00
Vjacheslav Trushkin 262783f704
Merge pull request #45 from iconify/renovate/npm-11.x
chore(deps): update npm to v11.6.2
2025-10-14 08:23:03 +03:00
Vjacheslav Trushkin 48b0da6d55
Merge pull request #50 from iconify/renovate/major-jest-monorepo
chore(deps): update dependency @types/jest to v30
2025-10-14 08:22:52 +03:00
Vjacheslav Trushkin 119538fbff
Merge pull request #47 from iconify/renovate/actions-checkout-5.x
chore(deps): update actions/checkout action to v5
2025-10-14 08:22:18 +03:00
renovate[bot] 3141131ab7
chore(deps): update dependency @types/jest to v30 2025-10-14 05:22:12 +00:00
renovate[bot] ba72402310
chore(deps): update actions/checkout action to v5 2025-10-14 05:21:57 +00:00
Vjacheslav Trushkin 6f33b7c4c5
Merge pull request #49 from iconify/renovate/actions-setup-node-6.x
chore(deps): update actions/setup-node action to v6
2025-10-14 08:20:38 +03:00
renovate[bot] 44884118f3
chore(deps): update actions/setup-node action to v6 2025-10-14 03:49:55 +00:00
renovate[bot] 9ec6b365a0
chore(deps): update npm to v11.6.2 2025-10-12 08:03:54 +00:00
renovate[bot] 5e1dbe8d4f
fix(deps): update dependency fastify to ^4.29.1 2025-10-08 19:57:57 +00:00
renovate[bot] 9b7b1a4279
fix(deps): update dependency @iconify/tools to ^4.1.4 2025-10-08 19:57:49 +00:00
Vjacheslav Trushkin 871028175b
chore: update renovate.json 2025-10-06 12:45:59 +03:00
Vjacheslav Trushkin a752e1ee7f
Merge pull request #35 from iconify/renovate/configure
chore: Configure Renovate
2025-10-06 12:45:06 +03:00
renovate[bot] 39e5bb4817
Add renovate.json 2025-10-06 08:02:52 +00:00
Vjacheslav Trushkin 2afff788df chore: update version number 2025-02-12 00:24:55 +02:00
Vjacheslav Trushkin 8300891cba chore: update dependencies 2025-02-12 00:20:29 +02:00
Vjacheslav Trushkin f62b8ba8e6 chore: clean up params in svg query 2025-02-12 00:16:48 +02:00
Vjacheslav Trushkin 65b0eca32e chore: update dependencies 2024-10-16 20:23:53 +03:00
Vjacheslav Trushkin a02dd19d51 chore: fix error codes 2024-10-16 20:20:08 +03:00
Vjacheslav Trushkin e44822a40d chore: allow updating specific importer 2024-05-14 16:33:31 +03:00
Vjacheslav Trushkin c5260541b8 chore: move github data to .github repo 2024-05-14 15:55:46 +03:00
Vjacheslav Trushkin 1d55e2dafd chore: publish as latest tag 2024-04-26 16:16:10 +03:00
14 changed files with 2543 additions and 3597 deletions

1
.github/FUNDING.yml vendored
View File

@ -1 +0,0 @@
github: cyberalien

View File

@ -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'

View File

@ -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

0
license.txt Executable file → Normal file
View File

5999
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -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"
}
}

27
renovate.json Normal file
View File

@ -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"
}
]
}

View File

@ -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;

View File

@ -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';
}

View File

@ -0,0 +1,6 @@
/**
* Basic cleanup for parameters
*/
export function cleanupQueryValue(value: string | undefined) {
return value ? value.replace(/['"<>&]/g, '') : undefined;
}

View File

@ -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);
}

View File

@ -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

View File

@ -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;
}

View File

@ -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);
}