Back to packages list

Vals using badgen

Description from the NPM package:
Fast svg badge generator.

Val license badge generator

Generates readme badge from SPDX-License-Identifier comment.

![](https://vladimyr-licensebadge.web.val.run/v/vladimyr/licenseBadge)

Usage

https://vladimyr-licensebadge.web.val.run/v/<author>/<val>

Example

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
// SPDX-License-Identifier: 0BSD
import { fetchVal } from "https://esm.town/v/vladimyr/fetchVal";
import { formatLicenseInfo, parseLicenseInfo } from "https://esm.town/v/vladimyr/parseLicense";
import { serveReadme } from "https://esm.town/v/vladimyr/serveReadme";
import { toHonoHandler } from "https://esm.town/v/vladimyr/toHonoHandler";
import type { BadgenOptions } from "npm:badgen";
import { badgen as createBadge } from "npm:badgen";
import { Hono } from "npm:hono";
const router = new Hono();
router.get("/", toHonoHandler(serveReadme(import.meta.url)));
router.get("/v/:author/:name", async (c) => {
const { author, name } = c.req.param();
let badgeOptions: BadgenOptions = { label: "license", status: undefined };
try {
const { code } = await fetchVal(author, name);
try {
const info = parseLicenseInfo(code);
badgeOptions.status = formatLicenseInfo(info);
} catch {
badgeOptions.color = "gray";
badgeOptions.status = "invalid";
}
} catch (err) {
badgeOptions.color = "red";
badgeOptions.status = err?.code ?? "error";
}
return c.newResponse(
createBadge(badgeOptions),
{ headers: { "content-type": "image/svg+xml" } },
);
});
export default router.fetch;

Val license badge generator

Generates readme badge from SPDX-License-Identifier comment.

![](https://vladimyr-licensebadge.web.val.run/v/vladimyr/licenseBadge)

Usage

https://vladimyr-licensebadge.web.val.run/v/<author>/<val>

Example

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
// SPDX-License-Identifier: 0BSD
import { fetchVal } from "https://esm.town/v/vladimyr/fetchVal";
import { formatLicenseInfo, parseLicenseInfo } from "https://esm.town/v/vladimyr/parseLicense";
import { serveReadme } from "https://esm.town/v/vladimyr/serveReadme";
import { toHonoHandler } from "https://esm.town/v/vladimyr/toHonoHandler";
import { badgen as createBadge, type BadgenOptions } from "npm:badgen";
import { Hono } from "npm:hono";
const router = new Hono();
router.get("/", toHonoHandler(serveReadme(import.meta.url)));
router.get("/v/:author/:name", async (c) => {
const { author, name } = c.req.param();
let badgeOptions: BadgenOptions = { label: "license", status: undefined };
try {
const { code } = await fetchVal(author, name);
try {
const info = parseLicenseInfo(code);
badgeOptions.status = formatLicenseInfo(info);
} catch {
badgeOptions.color = "gray";
badgeOptions.status = "invalid";
}
} catch (err) {
badgeOptions.color = "red";
badgeOptions.status = err?.code ?? "error";
}
return c.newResponse(
createBadge(badgeOptions),
{ headers: { "content-type": "image/svg+xml" } },
);
});
export default router.fetch;

ASP badge generator

This is small SVG badge generator made for Ariadne.id Signature Profiles. Route format is:

https://vladimyr-aspbadge.web.val.run/<aspe_uri>

with optional format and debug query params. Use ?format=json to get back JSON response. JSON format can be used as an input for Shields.io's dynamic endpoint badge.

Badge with legacy ASPE URI:

[![](https://vladimyr-aspbadge.web.val.run/aspe:keyoxide.org:TOICV3SYXNJP7E4P5AOK5DHW44)](https://keyoxide.org/aspe:keyoxide.org:TOICV3SYXNJP7E4P5AOK5DHW44)

🔬️ inspect ASP JWT token

Badge with new ASPE URI (not functional yet ⚠️):

[![](https://vladimyr-aspbadge.web.val.run/aspe:fe7b75c54b95ac019dd48fbefe8d654af383cbfe)](https://keyoxide.org/aspe:fe7b75c54b95ac019dd48fbefe8d654af383cbfe)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
// SPDX-License-Identifier: 0BSD
import {
AspeURI,
calculateFingerprint,
fetchASP,
formatFingerprint,
getKeyId,
HTTPError,
LegacyAspeURI,
parseAspeURI,
parseLegacyAspeURI,
} from "https://esm.town/v/vladimyr/libasp";
import { serveReadme } from "https://esm.town/v/vladimyr/serveReadme";
import { badgen as createBadge, BadgenOptions } from "npm:badgen";
import svg2dataURL from "npm:mini-svg-data-uri";
type BadgeConfig = BadgenOptions & { _debug?: object };
// @see: https://design.keyoxide.org/
const BADGE_ICON =
"<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"feather feather-key\"><path d=\"M21 2l-2 2m-7.61 7.61a5.5 5.5 0 1 1-7.778
.replace("stroke=\"currentColor\"", "stroke=\"#ffffff\"");
const BADGE_LABEL = "ASP";
const BADGE_COLOR = "6855c3";
export default async function(req: Request): Promise<Response> {
const reqURL = new URL(req.url);
if (reqURL.pathname === "/") {
return serveReadme(import.meta.url)();
}
const { format, debug } = Object.fromEntries(reqURL.searchParams.entries());
const isDebugEnabled = debug && debug !== "false";
const aspeUri = reqURL.pathname.slice(1);
if (!aspeUri) return new Response(null, { status: 404 });
const badgeConfig = await getBadgeConfig(aspeUri, isDebugEnabled);
if (format === "json") {
const data = {
schemaVersion: 1,
label: badgeConfig.label,
message: badgeConfig.status,
color: badgeConfig.color,
logoSvg: BADGE_ICON,
_debug: undefined,
};
if (isDebugEnabled) data._debug = badgeConfig._debug;
return Response.json(data);
}
badgeConfig.icon = svg2dataURL(BADGE_ICON);
return new Response(createBadge(badgeConfig), {
headers: {
"content-type": "image/svg+xml",
},
});
}
async function getBadgeConfig(aspeUri: string, debug = false): Promise<BadgeConfig> {
const config: BadgeConfig = {
label: BADGE_LABEL,
status: "",
color: BADGE_COLOR,
};
try {
const data = await processAspeUri(aspeUri);
config.status = data.keyId;
if (debug) config._debug = data;
return config;
} catch (err) {
if (err instanceof HTTPError) {
config.status = String(err.response.status);
config.color = "red";
return config;
}
config.status = "invalid";
config.color = "gray";
return config;
}
}
async function processAspeUri(aspeUri: string) {
let aspeURI: AspeURI | LegacyAspeURI = parseAspeURI(aspeUri);
if (!aspeURI) {
aspeURI = parseLegacyAspeURI(aspeUri);
}
if (!aspeURI) {
throw new Error("error: invalid ASPE URI");
}
let fingerprint;
if ("keyId" in aspeURI) {
const asp = await fetchASP(aspeURI.keyId, aspeURI.hostname);
fingerprint = calculateFingerprint(asp);
} else {
fingerprint = aspeURI.fingerprint;
}
const hostname = aspeURI.hostname || "keyoxide.org";
return {
fingerprint,
formattedFingerprint: formatFingerprint(fingerprint),
keyId: getKeyId(fingerprint),
aspeUri: `aspe:${fingerprint}`,
aspeUriWithAuthority: `aspe://${hostname}/${fingerprint}`,
  • Console DevTools
  • devtools.fm
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
import { Hono } from "https://deno.land/x/hono@v3.11.1/mod.ts";
import { getItunesId, isApplePodcast } from "https://esm.town/v/vladimyr/applePodcast?v=5";
import { getLastPubDate } from "https://esm.town/v/vladimyr/podcast?v=21";
import { getFeedUrl } from "https://esm.town/v/vladimyr/podnews?v=16";
import { getSpotifyId, isSpotifyPodcast } from "https://esm.town/v/vladimyr/spotifyPodcast?v=1";
import { badgen as createBadge, BadgenOptions } from "npm:badgen@3.2.3";
import friendlyTime from "npm:friendly-time@1.1.1";
import ky, { HTTPError } from "npm:ky@1.1.3";
import { withQuery } from "npm:ufo@1.3.2";
const BADGE_LABEL = "last episode";
const app = new Hono();
app.get("/", async (c) => {
const { q: feedUrl, ...query } = c.req.query();
if (!feedUrl) return c.body("");
if (isApplePodcast(feedUrl)) {
return c.redirect(withQuery(`/i/${getItunesId(feedUrl)}`, query));
}
if (isSpotifyPodcast(feedUrl)) {
return c.redirect(withQuery(`/s/${getSpotifyId(feedUrl)}`, query));
}
const badgeOptions = await getBadgeOptions(feedUrl);
if (query.format === "json") {
return c.json({
schemaVersion: 1,
label: badgeOptions.label,
message: badgeOptions.status,
color: badgeOptions.color,
});
}
c.header("Content-Type", "image/svg+xml");
return c.body(createBadge(badgeOptions));
});
app.get("/:service{(?:i(?:tunes)?|s(?:potify)?)}/:podcastId", async (c) => {
const podcastId = c.req.param("podcastId");
const { format, debug } = c.req.query();
const feedUrl = await getFeedUrl({ podcastId });
const badgeOptions = await getBadgeOptions(feedUrl);
if (format === "json") {
const badgeInfo = {
schemaVersion: 1,
label: badgeOptions.label,
message: badgeOptions.status,
color: badgeOptions.color,
};
if (debug) {
Object.assign(badgeInfo, {
_debug: { feedUrl },
});
}
return c.json(badgeInfo);
}
c.header("Content-Type", "image/svg+xml");
return c.body(createBadge(badgeOptions));
});
export default app.fetch;
async function getBadgeOptions(rssUrl: string | URL): Promise<BadgenOptions> {
const label = BADGE_LABEL;
try {
rssUrl = new URL(rssUrl);
} catch (err) {
if (err instanceof TypeError) {
return { label, status: "400", color: "red" };
}
}
let xml;
try {
xml = await ky.get(rssUrl).text();
} catch (err) {
if (err instanceof HTTPError) {
const status = String(err.response.status);
return { label, status, color: "red" };
}
}
let pubDate;
try {
pubDate = await getLastPubDate(xml);
} catch (err) {
if (err instanceof TypeError) {
return { label, status: "invalid", color: "grey" };
}
}
if (!pubDate) {
return { label, status: "unknown", color: "grey" };
}
return { label, status: friendlyTime(pubDate), color: "blue" };
}
1
Next