cdn-iconify
v0.0.1
Local Iconify collection adapter for the CDN capability
Run
wippy run wippy/cdn-iconifyWippy CDN Iconify adapter
The public release of wippy/cdn-iconify is version 0.0.4. It requires wippy/cdn >=0.0.3 and wippy/facade >=0.6.45. Facade 0.6.45 selects Host 1.0.64 (npm 0.0.64) by default.
The adapter serves locally stored Iconify collections under /cdn/iconify. It supports icon JSON requests, collection listing and detail, search, and last-modified data. It does not implement every Iconify API endpoint.
Default collections
The module includes three collections from @iconify/json 2.2.460, which is the version the Wippy Web Host locks. Each collection ships with its license notice, and the CDN core checks each file against its pinned size and SHA-256 before it activates the collection.
| Prefix | Collection | License | Icons and aliases |
|---|---|---|---|
| tabler | Tabler Icons 3.41.1 | MIT | 6,140 icons, 184 aliases |
| mdi | Material Design Icons, by Pictogrammers | Apache-2.0 | 7,638 icons, 6,363 aliases |
| svg-spinners | SVG Spinners, by Utkarsh Verma | MIT | 46 icons |
@iconify/json records no source version for mdi and svg-spinners. Their license notices come from the upstream repository commit closest to each collection's lastModified time, and the module records that commit in the source metadata. The Web Host mirror under public/iconify/ pins the same bytes.
A committed collection stays available without network access. When an installed module starts, the CDN core activates each default that has no selection yet. A collection that is already selected keeps its selected revision.
Icon source modes
The adapter has two modes for icon requests (GET /cdn/iconify/<prefix>.json?icons=...). Offline mode is the default.
In offline mode, the adapter answers only from collections stored on this server, and it makes no outbound network request. A request for a collection that is not stored returns 404 {"error":"Icon set not found"}. A name that a stored collection lacks is listed in not_found. Browsers that use this server as their Iconify provider never contact an outside icon service through it.
In hybrid mode, the adapter first answers from local collections. For names that are not stored here, the server requests them from the configured upstream Iconify API, and it returns them in the same response. The server fetches the icons itself because the Web Host's Iconify client (@iconify/vue 5.0.0) treats a 404 as final and never asks a second provider. The upstream request is GET <upstream_url>/<prefix>.json?icons=<names>.
Hybrid mode has these effects on privacy and the network:
- The server, not the browser, sends the collection prefix and the missing icon names to the upstream. It sends no cookies, tokens or user data, and the upstream sees the server's address.
- Local collections always win. An upstream icon is added only for a name that the stored collection does not have.
- The adapter trusts the upstream as much as a browser that loads it directly. It accepts only the requested names and their alias parents, checks every value, and drops a body that contains scripts, event handlers, external references or character entities.
- The runtime blocks private and loopback addresses for outbound requests, so the upstream must use a public address. A self-hosted Iconify API on a private network does not work in this release.
- Only icon data requests use the upstream. Collection listing and detail, search and last-modified stay local in both modes.
Hybrid mode keeps fetched icons and aliases in a memory cache, which is lost on restart. When the cache is full, new icons are not cached, and the adapter fetches them again on the next request. When the upstream fails or times out, the adapter answers from local data and the cache, and it pauses upstream requests for 30 seconds. A collection that is neither stored nor in the cache then returns 502. The upstream API reports an unknown collection, and the adapter returns 404 for it as in offline mode.
Local misses are recorded for management review in both modes, including names that hybrid mode filled from the upstream.
Options
| Requirement | Environment variable | Default | Meaning |
|---|---|---|---|
| mode | WIPPY_CDN_ICONIFY_MODE | offline | offline or hybrid. |
| upstream_url | WIPPY_CDN_ICONIFY_UPSTREAM_URL | https://api.iconify.design | Origin of the upstream Iconify API: http or https, a host, an optional port and no path. |
| upstream_timeout_seconds | WIPPY_CDN_ICONIFY_UPSTREAM_TIMEOUT_SECONDS | 5 | Timeout for one upstream request, 1 to 30 seconds. |
| cache_ttl_seconds | WIPPY_CDN_ICONIFY_CACHE_TTL_SECONDS | 86400 | How long a fetched icon stays cached, 0 to 2592000 seconds. 0 turns the cache off. |
| cache_max_entries | none | 4096 | Maximum number of icons and aliases in the cache. Give it as a number. |
An operating-system environment variable overrides the requirement value. An unknown mode or an invalid upstream URL selects offline mode, and the adapter logs a warning, so a wrong value never starts outbound traffic. An invalid timeout or cache lifetime uses its default.
Switching modes
To turn on hybrid mode, set mode in the application's dependency on this module:
- name: cdn-iconify
kind: ns.dependency
component: wippy/cdn-iconify
version: '0.0.4'
parameters:
- name: server
value: app:gateway
- name: mode
value: hybrid
You can also set it for one run with -o wippy.cdn.iconify:mode:default=hybrid, or set WIPPY_CDN_ICONIFY_MODE=hybrid in the process environment. To return to offline mode, remove the setting or set it to offline, and restart the application. Restarting also clears the hybrid-mode cache.
Manual collections
Place one complete Iconify JSON file at:
<cdn-data-root>/iconify/library/<prefix>.json
Write to .json.part first, close the file, then rename it to .json. The collection must have a nonempty icons object, and its prefix must match the filename. The module scans the library and copies the complete bytes into private staging before validation and activation. Do not edit a published file in place. A failed or incomplete copy leaves the last committed revision in service.
The reader accepts up to 32 MiB per collection and validates at most 100,000 icons and aliases combined. Alias chains may be at most 32 levels deep.
The module stores the icon, alias and hidden name lists of a collection as newline-separated strings in the stored manifest. The CDN core joins every value of a manifest in one Lua call when it saves the manifest, and that call fails at about 30,000 values, so name lists of the size of mdi could not be stored as lists. Manifests that version 0.0.3 stored with name lists stay readable.
Local API
The host binds the router to its existing gateway. Example requests use the application's origin:
GET https://your-wippy-origin.example/cdn/iconify/tabler.json?icons=home,user
GET https://your-wippy-origin.example/cdn/iconify/collections
GET https://your-wippy-origin.example/cdn/iconify/collection?prefix=tabler
GET https://your-wippy-origin.example/cdn/iconify/search?query=home
GET https://your-wippy-origin.example/cdn/iconify/last-modified?prefixes=tabler
Icon requests require the icons query. They return the requested local icons and aliases, and in hybrid mode the upstream icons for names that are not stored here. Unknown names are reported in not_found and may be recorded for management review. A miss never adds a collection to the CDN store. Mutable Iconify responses use no-store caching so a document reload can read a changed selection.
Explicit acquisition and import
An authorized management client may request an exact @iconify-json/ version through POST /cdn/iconify//acquire. Send a JSON body with version. For an existing selection, include base_revision and expected_selection_token from the reviewed catalog snapshot. Poll the returned operation_id at GET /cdn/operations/<operation_id>.
SVG source import is a separate explicit action through POST /cdn/iconify//import. The host supplies the authenticated management router and the scope marker wippy.cdn:management_access. The public adapter does not expose provider update routes.
The SVG validator accepts a restricted element set: svg, g, defs, path, rect, circle, ellipse, line, polyline, polygon, linearGradient, radialGradient, stop, clipPath, mask, use, animate, animateTransform, filter, feGaussianBlur, feColorMatrix, and feBlend. It validates supported attributes and local references as well. Stored collections and SVG imports use the same rules.
Animation is limited to declarative animate and animateTransform elements inside a shape or group. An animation may change only geometry, paint, opacity and stroke attributes of its parent, and each animated value must be valid for that attribute, so an animation cannot add a reference or a URL. Animation timing accepts clock values and the begin or end of another animation in the same icon. Filters must be defined inside defs, and elements refer to them with a local url(#id). Scripts, images, set, event timing, and other filter primitives are not accepted. Use an icon whose source fits the supported SVG subset.
Applying the local provider is a host decision. After a provider or collection change, reload affected host and child documents so their in-memory icon stores read the selected local revision. See the Wippy CDN core README for shared storage and management setup.
Facade can discover this adapter's module-owned local_source function when a saved source choice is This server. It passes the validated public base URL and the static iconify default to the function. The function returns a composed overrides.iconify JSON string and declares iconify as a replacement. It changes only the default provider's resources and path, including any deployment path prefix. Other static Iconify settings and named providers remain in place. An explicit application iconify string, including an empty string, bypasses this local provider. The function does not fetch assets, write source preferences, or add CSS. Internet remains the default until an authorized user saves a source choice.
Inspector panel
The lazy wippy-cdn-iconify-admin component provides local collection details, local previews, bounded missing-name records for the selected collection, revision actions, protected SVG import, and an explicit exact-version review before acquisition. SVG files are sent to the existing management import endpoint for server validation. The panel does not render uploaded SVG source. The standard wippy-cdn-admin shell needs no API-base or public-base attributes and uses the AppConfig proxy for requests. The source endpoint defaults to /api/v1/cdn-config/sources; source-settings-api is an optional relative compatibility attribute.
Build the panel with make.bat build-wc-admin. The build writes static/wc/admin/index.js; Wippy serves it at /cdn/admin/iconify/index.js. The component is announced but loads only when the host calls loadByTagName.
The pinned display-name catalog is derived from Iconify's collections snapshot dated 2026-10-15. Source: https://raw.githubusercontent.com/iconify/icon-sets/master/collections.json. Snapshot SHA-256: f59b581affd4010a50d8b914e9cec1d563ce0ad0ea27bcc7ab9ea6c6a3666e32. The source catalog's per-collection license fields are retained. This catalog is local metadata; the panel does not refresh it when opened.
Tests
The cdn_iconify suite covers the embedded defaults, the SVG subset, offline and hybrid icon responses with a fake upstream and cache, and the compact collection facts. Its entries have the test type, so the published package leaves them out. They need the wippy/test module but not the CDN core, so they run in an application that loads this module's sources together with wippy/test. Run make.bat check for native lint.