'use strict';
const node_buffer = require('node:buffer');
const ofetch = require('ofetch');
const imageDataURI = require('image-data-uri');
const sharp = require('sharp');
const consola = require('consola');
const unconfig = require('unconfig');
const process = require('node:process');
const dotenv = require('dotenv');
const nodeHtmlParser = require('node-html-parser');
const node_crypto = require('node:crypto');
function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e.default : e; }
const imageDataURI__default = /*#__PURE__*/_interopDefaultCompat(imageDataURI);
const sharp__default = /*#__PURE__*/_interopDefaultCompat(sharp);
const process__default = /*#__PURE__*/_interopDefaultCompat(process);
const dotenv__default = /*#__PURE__*/_interopDefaultCompat(dotenv);
var __defProp = Object.defineProperty;
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
var __publicField = (obj, key, value) => {
__defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
return value;
};
let index = 0;
function genSvgImage(x, y, size, url) {
++index;
return `
`;
}
function generateBadge(x, y, sponsor, preset) {
const size = preset.avatar.size;
const { login } = sponsor;
let name = (sponsor.name || sponsor.login).trim();
const url = sponsor.linkUrl;
if (preset.name && preset.name.maxLength && name.length > preset.name.maxLength) {
if (name.includes(" "))
name = name.split(" ")[0];
else
name = `${name.slice(0, preset.name.maxLength - 3)}...`;
}
const avatarUrl = (size < 50 ? sponsor.avatarUrlLowRes : size < 90 ? sponsor.avatarUrlMediumRes : sponsor.avatarUrlHighRes) || sponsor.avatarUrl;
return `
${preset.name ? `${encodeHtmlEntities(name)}
` : ""}${genSvgImage(x, y, size, avatarUrl)}
`.trim();
}
class SvgComposer {
constructor(config) {
this.config = config;
__publicField(this, "height", 0);
__publicField(this, "body", "");
}
addSpan(height = 0) {
this.height += height;
return this;
}
addTitle(text, classes = "sponsorkit-tier-title") {
return this.addText(text, classes);
}
addText(text, classes = "text") {
this.body += `${text}`;
this.height += 20;
return this;
}
addRaw(svg) {
this.body += svg;
return this;
}
addSponsorLine(sponsors, preset) {
const offsetX = (this.config.width - sponsors.length * preset.boxWidth) / 2 + (preset.boxWidth - preset.avatar.size) / 2;
this.body += sponsors.map((s, i) => {
const x = offsetX + preset.boxWidth * i;
const y = this.height;
return generateBadge(x, y, s.sponsor, preset);
}).join("\n");
this.height += preset.boxHeight;
}
addSponsorGrid(sponsors, preset) {
const perLine = Math.floor((this.config.width - (preset.container?.sidePadding || 0) * 2) / preset.boxWidth);
Array.from({ length: Math.ceil(sponsors.length / perLine) }).fill(0).forEach((_, i) => {
this.addSponsorLine(sponsors.slice(i * perLine, (i + 1) * perLine), preset);
});
return this;
}
generateSvg() {
return `
`;
}
}
function encodeHtmlEntities(str) {
return String(str).replace(/&/g, "&").replace(//g, ">").replace(/"/g, """);
}
async function resolveAvatars(ships, fallbackAvatar, t = consola.consola) {
return Promise.all(ships.map(async (ship) => {
const data = await ofetch.$fetch(ship.sponsor.avatarUrl, { responseType: "arrayBuffer" }).catch((e) => {
t.error(`Failed to fetch avatar for ${ship.sponsor.login || ship.sponsor.name} [${ship.sponsor.avatarUrl}]`);
t.error(e);
if (typeof fallbackAvatar === "string")
return ofetch.$fetch(fallbackAvatar, { responseType: "arrayBuffer" });
if (fallbackAvatar)
return fallbackAvatar;
throw e;
});
const radius = ship.sponsor.type === "User" ? 0.5 : 0.15;
ship.sponsor.avatarUrlHighRes = await imageDataURI__default.encode(await round(data, radius, 120), "PNG");
ship.sponsor.avatarUrlMediumRes = await imageDataURI__default.encode(await round(data, radius, 80), "PNG");
ship.sponsor.avatarUrlLowRes = await imageDataURI__default.encode(await round(data, radius, 50), "PNG");
}));
}
function toBuffer(ab) {
const buf = node_buffer.Buffer.alloc(ab.byteLength);
const view = new Uint8Array(ab);
for (let i = 0; i < buf.length; ++i)
buf[i] = view[i];
return buf;
}
async function round(image, radius = 0.5, size = 100) {
const rect = node_buffer.Buffer.from(
``
);
return await sharp__default(typeof image === "string" ? image : toBuffer(image)).resize(size, size, { fit: sharp__default.fit.cover }).composite([{
blend: "dest-in",
input: rect,
density: 72
}]).png({ quality: 80, compressionLevel: 8 }).toBuffer();
}
function svgToPng(svg) {
return sharp__default(node_buffer.Buffer.from(svg), { density: 150 }).png({ quality: 90 }).toBuffer();
}
function base64ToArrayBuffer(base64) {
const binaryString = atob(base64);
const len = binaryString.length;
const bytes = new Uint8Array(len);
for (let i = 0; i < len; i++)
bytes[i] = binaryString.charCodeAt(i);
return bytes.buffer;
}
function arrayBufferToBase64(buffer) {
let binary = "";
const bytes = new Uint8Array(buffer);
const len = bytes.byteLength;
for (let i = 0; i < len; i++)
binary += String.fromCharCode(bytes[i]);
return btoa(binary);
}
function pngToDataUri(png) {
return `data:image/png;base64,${png.toString("base64")}`;
}
function getDeprecatedEnv(name, replacement) {
const value = process__default.env[name];
if (value)
console.warn(`[sponsorkit] env.${name} is deprecated, use env.${replacement} instead`);
return value;
}
function loadEnv() {
dotenv__default.config();
const config = {
github: {
login: process__default.env.SPONSORKIT_GITHUB_LOGIN || process__default.env.GITHUB_LOGIN || getDeprecatedEnv("SPONSORKIT_LOGIN", "SPONSORKIT_GITHUB_LOGIN"),
token: process__default.env.SPONSORKIT_GITHUB_TOKEN || process__default.env.GITHUB_TOKEN || getDeprecatedEnv("SPONSORKIT_TOKEN", "SPONSORKIT_GITHUB_TOKEN"),
type: process__default.env.SPONSORKIT_GITHUB_TYPE || process__default.env.GITHUB_TYPE
},
patreon: {
token: process__default.env.SPONSORKIT_PATREON_TOKEN || process__default.env.PATREON_TOKEN
},
opencollective: {
key: process__default.env.SPONSORKIT_OPENCOLLECTIVE_KEY || process__default.env.OPENCOLLECTIVE_KEY,
id: process__default.env.SPONSORKIT_OPENCOLLECTIVE_ID || process__default.env.OPENCOLLECTIVE_ID,
slug: process__default.env.SPONSORKIT_OPENCOLLECTIVE_SLUG || process__default.env.OPENCOLLECTIVE_SLUG,
githubHandle: process__default.env.SPONSORKIT_OPENCOLLECTIVE_GH_HANDLE || process__default.env.OPENCOLLECTIVE_GH_HANDLE,
type: process__default.env.SPONSORKIT_OPENCOLLECTIVE_TYPE || process__default.env.OPENCOLLECTIVE_TYPE
},
afdian: {
userId: process__default.env.SPONSORKIT_AFDIAN_USER_ID || process__default.env.AFDIAN_USER_ID,
token: process__default.env.SPONSORKIT_AFDIAN_TOKEN || process__default.env.AFDIAN_TOKEN,
exechangeRate: Number.parseFloat(process__default.env.SPONSORKIT_AFDIAN_EXECHANGERATE || process__default.env.AFDIAN_EXECHANGERATE) || void 0
},
outputDir: process__default.env.SPONSORKIT_DIR
};
return JSON.parse(JSON.stringify(config));
}
const fallback = `
`;
const FALLBACK_AVATAR = svgToPng(fallback);
const none = {
avatar: {
size: 0
},
boxWidth: 0,
boxHeight: 0,
container: {
sidePadding: 0
}
};
const base = {
avatar: {
size: 40
},
boxWidth: 48,
boxHeight: 48,
container: {
sidePadding: 30
}
};
const xs = {
avatar: {
size: 25
},
boxWidth: 30,
boxHeight: 30,
container: {
sidePadding: 30
}
};
const small = {
avatar: {
size: 35
},
boxWidth: 38,
boxHeight: 38,
container: {
sidePadding: 30
}
};
const medium = {
avatar: {
size: 50
},
boxWidth: 80,
boxHeight: 90,
container: {
sidePadding: 20
},
name: {
maxLength: 10
}
};
const large = {
avatar: {
size: 70
},
boxWidth: 95,
boxHeight: 115,
container: {
sidePadding: 20
},
name: {
maxLength: 16
}
};
const xl = {
avatar: {
size: 90
},
boxWidth: 120,
boxHeight: 130,
container: {
sidePadding: 20
},
name: {
maxLength: 20
}
};
const presets = {
none,
xs,
small,
base,
medium,
large,
xl
};
const defaultTiers = [
{
title: "Past Sponsors",
monthlyDollars: -1,
preset: presets.xs
},
{
title: "Backers",
preset: presets.base
},
{
title: "Sponsors",
monthlyDollars: 10,
preset: presets.medium
},
{
title: "Silver Sponsors",
monthlyDollars: 50,
preset: presets.large
},
{
title: "Gold Sponsors",
monthlyDollars: 100,
preset: presets.xl
}
];
const defaultInlineCSS = `
text {
font-weight: 300;
font-size: 14px;
fill: #777777;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
}
.sponsorkit-link {
cursor: pointer;
}
.sponsorkit-tier-title {
font-weight: 500;
font-size: 20px;
}
`;
const defaultConfig = {
width: 800,
outputDir: "./sponsorkit",
cacheFile: ".cache.json",
formats: ["json", "svg", "png"],
tiers: defaultTiers,
name: "sponsors",
includePrivate: false,
svgInlineCSS: defaultInlineCSS
};
function defineConfig(config) {
return config;
}
async function loadConfig(inlineConfig = {}) {
const env = loadEnv();
const { config = {} } = await unconfig.loadConfig({
sources: [
{
files: "sponsor.config"
},
{
files: "sponsorkit.config"
}
],
merge: true
});
const hasNegativeTier = !!config.tiers?.find((tier) => tier && tier.monthlyDollars <= 0);
const resolved = {
fallbackAvatar: FALLBACK_AVATAR,
includePastSponsors: hasNegativeTier,
...defaultConfig,
...env,
...config,
...inlineConfig,
github: {
...env.github,
...config.github,
...inlineConfig.github
},
patreon: {
...env.patreon,
...config.patreon,
...inlineConfig.patreon
},
opencollective: {
...env.opencollective,
...config.opencollective,
...inlineConfig.opencollective
},
afdian: {
...env.afdian,
...config.afdian,
...inlineConfig.afdian
}
};
return resolved;
}
function partitionTiers(sponsors, tiers) {
const tierMappings = tiers.map((tier) => ({
monthlyDollars: tier.monthlyDollars ?? 0,
tier,
sponsors: []
}));
tierMappings.sort((a, b) => b.monthlyDollars - a.monthlyDollars);
const finalSponsors = tierMappings.filter((i) => i.monthlyDollars === 0);
if (finalSponsors.length !== 1)
throw new Error(`There should be exactly one tier with no \`monthlyDollars\`, but got ${finalSponsors.length}`);
sponsors.sort((a, b) => Date.parse(a.createdAt) - Date.parse(b.createdAt)).forEach((sponsor) => {
const tier = tierMappings.find((t) => sponsor.monthlyDollars >= t.monthlyDollars) ?? tierMappings[0];
tier.sponsors.push(sponsor);
});
return tierMappings;
}
function pickSponsorsInfo(html) {
const root = nodeHtmlParser.parse(html);
const baseDate = /* @__PURE__ */ new Date("2000-1-1");
const sponsors = root.querySelectorAll("div").map((el) => {
const isPublic = el.querySelector("img");
const name = isPublic ? isPublic?.getAttribute("alt")?.replace("@", "") : "Private Sponsor";
const avatarUrl = isPublic ? isPublic?.getAttribute("src") : FALLBACK_AVATAR;
const login = isPublic ? el.querySelector("a")?.getAttribute("href")?.replace("/", "") : void 0;
const type = el.querySelector("a")?.getAttribute("data-hovercard-type")?.replace(/^\S/, (s) => s.toUpperCase());
return {
sponsor: {
__typename: void 0,
linkUrl: `https://github.com/${name}`,
login,
name,
avatarUrl,
type
},
isOneTime: void 0,
monthlyDollars: -1,
privacyLevel: isPublic ? "PUBLIC" : "PRIVATE",
tierName: void 0,
createdAt: baseDate.toUTCString()
};
});
return sponsors;
}
async function getPastSponsors(username) {
const allSponsors = [];
let newSponsors = [];
let cursor = 1;
do {
const content = await ofetch.$fetch(`https://github.com/sponsors/${username}/sponsors_partial?filter=inactive&page=${cursor++}`, { method: "GET" });
newSponsors = pickSponsorsInfo(content);
allSponsors.push(...newSponsors);
} while (newSponsors.length);
return allSponsors;
}
const API$1 = "https://api.github.com/graphql";
const graphql$1 = String.raw;
const GitHubProvider = {
name: "github",
fetchSponsors(config) {
return fetchGitHubSponsors(
config.github?.token || config.token,
config.github?.login || config.login,
config.github?.type || "user",
config
);
}
};
async function fetchGitHubSponsors(token, login, type, config) {
if (!token)
throw new Error("GitHub token is required");
if (!login)
throw new Error("GitHub login is required");
if (!["user", "organization"].includes(type))
throw new Error("GitHub type must be either `user` or `organization`");
const sponsors = [];
let cursor;
do {
const query = makeQuery$1(login, type, cursor);
const data = await ofetch.$fetch(API$1, {
method: "POST",
body: { query },
headers: {
"Authorization": `bearer ${token}`,
"Content-Type": "application/json"
}
});
if (!data)
throw new Error(`Get no response on requesting ${API$1}`);
else if (data.errors?.[0]?.type === "INSUFFICIENT_SCOPES")
throw new Error("Token is missing the `read:user` and/or `read:org` scopes");
else if (data.errors?.length)
throw new Error(`GitHub API error:
${JSON.stringify(data.errors, null, 2)}`);
sponsors.push(
...data.data[type].sponsorshipsAsMaintainer.nodes || []
);
if (data.data[type].sponsorshipsAsMaintainer.pageInfo.hasNextPage)
cursor = data.data[type].sponsorshipsAsMaintainer.pageInfo.endCursor;
else
cursor = void 0;
} while (cursor);
const processed = sponsors.map((raw) => ({
sponsor: {
...raw.sponsorEntity,
linkUrl: `https://github.com/${raw.sponsorEntity.login}`,
__typename: void 0,
type: raw.sponsorEntity.__typename
},
isOneTime: raw.tier.isOneTime,
monthlyDollars: raw.tier.monthlyPriceInDollars,
privacyLevel: raw.privacyLevel,
tierName: raw.tier.name,
createdAt: raw.createdAt
}));
if (config.includePastSponsors) {
try {
processed.push(...await getPastSponsors(login));
} catch (e) {
console.error("Failed to fetch past sponsors:", e);
}
}
return processed;
}
function makeQuery$1(login, type, cursor) {
return graphql$1`{
${type}(login: "${login}") {
sponsorshipsAsMaintainer(first: 100${cursor ? ` after: "${cursor}"` : ""}) {
totalCount
pageInfo {
endCursor
hasNextPage
}
nodes {
createdAt
privacyLevel
tier {
name
isOneTime
monthlyPriceInCents
monthlyPriceInDollars
}
sponsorEntity {
__typename
...on Organization {
login
name
avatarUrl
websiteUrl
}
...on User {
login
name
avatarUrl
websiteUrl
}
}
}
}
}
}`;
}
const PatreonProvider = {
name: "patreon",
fetchSponsors(config) {
return fetchPatreonSponsors(config.patreon?.token || config.token);
}
};
async function fetchPatreonSponsors(token) {
if (!token)
throw new Error("Patreon token is required");
const userData = await ofetch.$fetch(
"https://www.patreon.com/api/oauth2/api/current_user/campaigns?include=null",
{
method: "GET",
headers: {
"Authorization": `bearer ${token}`,
"Content-Type": "application/json"
},
responseType: "json"
}
);
const userCampaignId = userData.data[0].id;
const sponsors = [];
let sponsorshipApi = `https://www.patreon.com/api/oauth2/v2/campaigns/${userCampaignId}/members?include=user&fields%5Bmember%5D=currently_entitled_amount_cents,patron_status,pledge_relationship_start,lifetime_support_cents&fields%5Buser%5D=image_url,url,first_name,full_name&page%5Bcount%5D=100`;
do {
const sponsorshipData = await ofetch.$fetch(sponsorshipApi, {
method: "GET",
headers: {
"Authorization": `bearer ${token}`,
"Content-Type": "application/json"
},
responseType: "json"
});
sponsors.push(
...sponsorshipData.data.filter((membership) => {
return membership.attributes.patron_status !== "declined_patron" && membership.attributes.patron_status !== null;
}).map((membership) => ({
membership,
patron: sponsorshipData.included.find(
(v) => v.id === membership.relationships.user.data.id
)
}))
);
sponsorshipApi = sponsorshipData.links?.next;
} while (sponsorshipApi);
const processed = sponsors.map(
(raw) => ({
sponsor: {
avatarUrl: raw.patron.attributes.image_url,
login: raw.patron.attributes.first_name,
name: raw.patron.attributes.full_name,
type: "User",
// Patreon only support user
linkUrl: raw.patron.attributes.url
},
isOneTime: false,
// One-time pledges not supported
monthlyDollars: raw.membership.attributes.patron_status === "former_patron" ? -1 : Math.floor(raw.membership.attributes.currently_entitled_amount_cents / 100),
privacyLevel: "PUBLIC",
// Patreon is all public
tierName: "Patreon",
createdAt: raw.membership.attributes.pledge_relationship_start
})
);
return processed;
}
const OpenCollectiveProvider = {
name: "opencollective",
fetchSponsors(config) {
return fetchOpenCollectiveSponsors(
config.opencollective?.key,
config.opencollective?.id,
config.opencollective?.slug,
config.opencollective?.githubHandle,
config.opencollective?.type
);
}
};
const API = "https://api.opencollective.com/graphql/v2/";
const graphql = String.raw;
async function fetchOpenCollectiveSponsors(key, id, slug, githubHandle, type) {
if (!key)
throw new Error("OpenCollective api key is required");
if (!slug && !id && !githubHandle)
throw new Error("OpenCollective collective id or slug or GitHub handle is required");
let collective = true;
if (type && type !== "collective")
collective = false;
const sponsors = [];
let offset;
offset = 0;
do {
const query = makeQuery(id, slug, githubHandle, offset, collective);
const data = await ofetch.$fetch(API, {
method: "POST",
body: { query },
headers: {
"Api-Key": `${key}`,
"Content-Type": "application/json"
}
});
const nodes = collective ? data.data.collective?.members.nodes : data.data.account?.transactions.nodes;
sponsors.push(...nodes || []);
if (nodes.length !== 0)
offset += nodes.length;
else
offset = void 0;
} while (offset);
const count = [];
const processed = [];
for (const i in sponsors.sort((a, b) => new Date(b.createdAt).getDate() - new Date(a.createdAt).getDate())) {
const v = sponsors[i];
const slug2 = collective ? v.account.slug : v.oppositeAccount.slug;
if (!collective) {
if (slug2 in count) {
delete processed[count[slug2].index];
count[slug2].valueInCents += v.amount.valueInCents;
count[slug2].index = i;
} else {
count[slug2] = {
index: i,
valueInCents: v.amount.valueInCents
};
}
}
processed.push({
sponsor: {
name: collective ? v.account.name : v.oppositeAccount.name,
type: (collective ? v.account.type : v.oppositeAccount.name) === "INDIVIDUAL" ? "User" : "Organization",
login: slug2,
avatarUrl: collective ? v.account.imageUrl : v.oppositeAccount.imageUrl,
websiteUrl: collective ? v.account.website : v.oppositeAccount.website,
linkUrl: `https://opencollective.com/${slug2}`
},
isOneTime: !v.tier || v.tier.type === "DONATION",
monthlyDollars: (collective ? v.tier ? v.tier.amount.valueInCents : v.totalDonations.valueInCents : count[slug2].valueInCents) / 100,
privacyLevel: (collective ? v.account.isIncognito : v.oppositeAccount.isIncognito) ? "PRIVATE" : "PUBLIC",
tierName: collective ? !v.tier ? "" : v.tier.name : void 0,
createdAt: v.createdAt
});
}
return processed.filter((i) => i !== null);
}
function makeQuery(id, slug, githubHandle, offset, collective = true) {
return graphql`{
${collective ? "collective" : "account"}(${id ? `id: "${id}", ` : ""}${slug ? `slug: "${slug}", ` : ""}${githubHandle ? `githubHandle: "${githubHandle}", ` : ""}throwIfMissing: true) {
${collective ? "members" : "transactions"}(limit: 100${offset ? ` offset: ${offset}` : ""}${collective ? " role: [BACKER]" : ""}) {
offset
limit
totalCount
nodes {
id
createdAt
${collective ? `
role
tier {
name
type
amount {
valueInCents
}
}` : ""}
${collective ? "totalDonations" : "amount"} {
valueInCents
}
${collective ? "account" : "oppositeAccount"} {
name
slug
type
website
isIncognito
imageUrl(height: 460, format: png)
}
}
}
}
}`;
}
const AfdianProvider = {
name: "afdian",
fetchSponsors(config) {
return fetchAfdianSponsors(config.afdian);
}
};
async function fetchAfdianSponsors(options = {}) {
const {
userId,
token,
exechangeRate = 6.5
} = options;
if (!userId || !token)
throw new Error("Afdian id and token are required");
const sponsors = [];
const sponsorshipApi = "https://afdian.net/api/open/query-sponsor";
let page = 1;
let pages = 1;
do {
const params = JSON.stringify({ page });
const ts = Math.round(+ new Date() / 1e3);
const sign = md5(token, params, ts, userId);
const sponsorshipData = await ofetch.$fetch(sponsorshipApi, {
method: "POST",
headers: {
"Content-Type": "application/json"
},
responseType: "json",
body: {
user_id: userId,
params,
ts,
sign
}
});
page += 1;
if (sponsorshipData?.ec !== 200)
break;
pages = sponsorshipData.data.total_page;
sponsors.push(...sponsorshipData.data.list);
} while (page <= pages);
const processed = sponsors.map((raw) => {
const current = raw.current_plan;
const expireTime = current?.expire_time;
const isExpired = expireTime ? expireTime < Date.now() / 1e3 : true;
return {
sponsor: {
type: "User",
login: raw.user.user_id,
name: raw.user.name,
avatarUrl: raw.user.avatar,
linkUrl: `https://afdian.net/u/${raw.user.user_id}`
},
// all_sum_amount is based on cny
monthlyDollars: isExpired ? -1 : Number.parseFloat(raw.all_sum_amount) / exechangeRate,
privacyLevel: "PUBLIC",
tierName: "Afdian",
createdAt: new Date(raw.first_pay_time * 1e3).toISOString(),
expireAt: expireTime ? new Date(expireTime * 1e3).toISOString() : void 0,
// empty string means no plan, consider as one time sponsor
isOneTime: Boolean(raw.current_plan?.name),
provider: "afdian",
raw
};
});
return processed;
}
function md5(token, params, ts, userId) {
return node_crypto.createHash("md5").update(`${token}params${params}ts${ts}user_id${userId}`).digest("hex");
}
const ProvidersMap = {
github: GitHubProvider,
patreon: PatreonProvider,
opencollective: OpenCollectiveProvider,
afdian: AfdianProvider
};
function guessProviders(config) {
const items = [];
if (config.github && config.github.login)
items.push("github");
if (config.patreon && config.patreon.token)
items.push("patreon");
if (config.opencollective && (config.opencollective.id || config.opencollective.slug || config.opencollective.githubHandle))
items.push("opencollective");
if (config.afdian && config.afdian.userId && config.afdian.token)
items.push("afdian");
if (!items.length)
items.push("github");
return items;
}
function resolveProviders(names) {
return Array.from(new Set(names)).map((i) => {
if (typeof i === "string") {
const provider = ProvidersMap[i];
if (!provider)
throw new Error(`Unknown provider: ${i}`);
return provider;
}
return i;
});
}
async function fetchSponsors(config) {
const providers = resolveProviders(guessProviders(config));
const sponsorships = await Promise.all(
providers.map((provider) => provider.fetchSponsors(config))
);
return sponsorships.flat(1);
}
exports.GitHubProvider = GitHubProvider;
exports.ProvidersMap = ProvidersMap;
exports.SvgComposer = SvgComposer;
exports.arrayBufferToBase64 = arrayBufferToBase64;
exports.base64ToArrayBuffer = base64ToArrayBuffer;
exports.defaultConfig = defaultConfig;
exports.defaultInlineCSS = defaultInlineCSS;
exports.defaultTiers = defaultTiers;
exports.defineConfig = defineConfig;
exports.fetchGitHubSponsors = fetchGitHubSponsors;
exports.fetchSponsors = fetchSponsors;
exports.genSvgImage = genSvgImage;
exports.generateBadge = generateBadge;
exports.guessProviders = guessProviders;
exports.loadConfig = loadConfig;
exports.makeQuery = makeQuery$1;
exports.partitionTiers = partitionTiers;
exports.pngToDataUri = pngToDataUri;
exports.presets = presets;
exports.resolveAvatars = resolveAvatars;
exports.resolveProviders = resolveProviders;
exports.round = round;
exports.svgToPng = svgToPng;