@oxy.so/core 7.25.0 → 7.26.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/index.js +5 -4
- package/dist/cjs/utils/profileLinks.js +34 -0
- package/dist/esm/index.js +1 -1
- package/dist/esm/utils/profileLinks.js +33 -0
- package/dist/types/index.d.ts +2 -2
- package/dist/types/utils/profileLinks.d.ts +13 -0
- package/package.json +1 -1
- package/src/index.ts +2 -2
- package/src/utils/profileLinks.ts +44 -0
package/dist/cjs/index.js
CHANGED
|
@@ -21,10 +21,10 @@
|
|
|
21
21
|
* If a symbol does not appear here, it is NOT part of the public API.
|
|
22
22
|
*/
|
|
23
23
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
24
|
-
exports.
|
|
25
|
-
exports.
|
|
26
|
-
exports.
|
|
27
|
-
exports.packageInfo = exports.consumeOAuthReturnPath = exports.persistOAuthReturnPath = exports.clearOAuthHandshake = exports.readOAuthHandshake = exports.persistOAuthHandshake = exports.canonicalizeOAuthRedirectUri = exports.normalizeOAuthRedirectUri = exports.OXY_OAUTH_RETURN_PATH_STORAGE_KEY = exports.OXY_OAUTH_REDIRECT_URI_STORAGE_KEY = exports.OXY_OAUTH_CODE_VERIFIER_STORAGE_KEY = exports.OXY_OAUTH_STATE_STORAGE_KEY = exports.OXY_AUTHORIZE_URL = exports.DEFAULT_OAUTH_SCOPE = exports.generatePkcePair = exports.generateOAuthState = exports.computeCodeChallenge = exports.buildOAuthAuthorizeUrl = exports.CENTRAL_IDP_APEX = exports.AUTH_WEB_ORIGIN = exports.getAccountColor = exports.formatPublicKeyHandle = exports.getAccountFallbackHandle = exports.getAccountDisplayName = exports.createQuickAccount = exports.buildAccountsArray = exports.updateAvatarVisibility = exports.isDev = exports.consoleSink = exports.resetLoggerConfig = exports.getLoggerConfig = exports.configureLogger = exports.createLogger = exports.logger = exports.normalizeMultilineText = exports.normalizeInlineText = void 0;
|
|
24
|
+
exports.TopicSource = exports.TopicType = exports.SECURITY_EVENT_SEVERITY_MAP = exports.sessionsArraysEqual = exports.normalizeAndSortSessions = exports.mergeSessions = exports.authenticatedApiCall = exports.withAuthErrorHandling = exports.isAuthenticationError = exports.ensureValidToken = exports.AuthenticationFailedError = exports.SessionSyncRequiredError = exports.supportProviderOf = exports.normalizeProfileLinks = exports.getNormalizedUserHandle = exports.getCanonicalUserHandle = exports.normalizeUserIdentityOrNull = exports.normalizeUserIdentity = exports.getNormalizedUserId = exports.commonsDeliveryPlatform = exports.pushTargetsFromDelivery = exports.selectCommonsDelivery = exports.parseCommonsApprovalExpiresAt = exports.getCommonsApprovalBlockingReason = exports.OxyAppDataIdentifierError = exports.AccountNotOnDeviceError = exports.REPUTATION_CACHE_PREFIX = exports.StoreInstallerError = exports.setStoreInstaller = exports.getStoreInstaller = exports.kindAcceptsAccountCategories = exports.isSelectableAccountCategoryId = exports.SELECTABLE_ACCOUNT_CATEGORY_IDS = exports.MAX_ACCOUNT_CATEGORIES = exports.ACCOUNT_CATEGORY_IDS = exports.buildUserDid = exports.DirectUploadInterruptedError = exports.MAX_UPLOAD_BYTES = exports.assetUrlCacheTTL = exports.ASSET_MULTIPART_UPLOAD_MAX_BYTES = exports.sameHolderIdentity = exports.retryAfterSecondsOf = exports.ServiceAssetMetadataError = exports.AssetUrlResolutionError = exports.OxyAuthenticationTimeoutError = exports.OxyAuthenticationError = exports.OxyApiError = exports.OXY_CLOUD_URL = exports.OXY_API_URL = exports.OxyServices = void 0;
|
|
25
|
+
exports.withRetry = exports.delay = exports.shouldAllowRequest = exports.recordSuccess = exports.recordFailure = exports.calculateBackoffInterval = exports.createCircuitBreakerState = exports.DEFAULT_CIRCUIT_BREAKER_CONFIG = exports.isRetryableError = exports.isNetworkError = exports.isServerError = exports.isRateLimitError = exports.isNotFoundError = exports.isForbiddenError = exports.isUnauthorizedError = exports.isAlreadyRegisteredError = exports.getErrorMessage = exports.getErrorStatus = exports.HttpStatus = exports.getSystemColorScheme = exports.systemPrefersDarkMode = exports.getOppositeTheme = exports.normalizeColorScheme = exports.normalizeTheme = exports.getContrastTextColor = exports.isLightColor = exports.withOpacity = exports.rgbToHex = exports.hexToRgb = exports.lightenColor = exports.darkenColor = exports.isWebBrowser = exports.isAndroid = exports.isIOS = exports.isNative = exports.isWeb = exports.setPlatformOS = exports.getPlatformOS = exports.coerceToSupportedLocale = exports.getPrimaryLanguage = exports.getUserLanguages = exports.isRTLLocale = exports.getNativeLanguageName = exports.getLanguageName = exports.getLanguageMetadata = exports.isSupportedLocale = exports.normalizeLocale = exports.getBaseLanguage = exports.FALLBACK_LOCALE = exports.SUPPORTED_LANGUAGES = void 0;
|
|
26
|
+
exports.isValidObjectId = exports.sanitizeHTML = exports.sanitizeString = exports.isValidFileType = exports.isValidFileSize = exports.isValidDate = exports.isValidURL = exports.isValidUUID = exports.isValidObject = exports.isValidArray = exports.isRequiredBoolean = exports.isRequiredNumber = exports.isRequiredString = exports.DISPLAY_NAME_UNFLANKED_SEPARATOR_SOURCE = exports.DISPLAY_NAME_ORPHANED_MARK_SOURCE = exports.DISPLAY_NAME_DISALLOWED_SOURCE = exports.DISPLAY_NAME_ALLOWED_SCRIPTS = exports.accountNameInvalidKey = exports.accountNameInvalidMessage = exports.accountNameMaxLength = exports.isValidAccountName = exports.isValidDisplayName = exports.isValidPassword = exports.isValidEmail = exports.ACCOUNT_TITLE_INVALID_MESSAGE = exports.DISPLAY_NAME_INVALID_MESSAGE = exports.MAX_DISPLAY_NAME_LENGTH = exports.PASSWORD_REGEX = exports.EMAIL_REGEX = exports.retryAsync = exports.validateRequiredFields = exports.parseHttpErrorBody = exports.isHttpRequestError = exports.handleHttpError = exports.createApiError = exports.ErrorCodes = exports.safeJsonParse = exports.buildPaginationParams = exports.buildUrl = exports.buildSearchParams = exports.buildQueryParams = exports.trustTierLabel = exports.reputationCategoryLabel = exports.accountRoleLabel = exports.accountCategoryLabel = exports.getLocalesVersion = exports.subscribeLocales = exports.isLocaleLoaded = exports.loadLocale = exports.translate = void 0;
|
|
27
|
+
exports.packageInfo = exports.consumeOAuthReturnPath = exports.persistOAuthReturnPath = exports.clearOAuthHandshake = exports.readOAuthHandshake = exports.persistOAuthHandshake = exports.canonicalizeOAuthRedirectUri = exports.normalizeOAuthRedirectUri = exports.OXY_OAUTH_RETURN_PATH_STORAGE_KEY = exports.OXY_OAUTH_REDIRECT_URI_STORAGE_KEY = exports.OXY_OAUTH_CODE_VERIFIER_STORAGE_KEY = exports.OXY_OAUTH_STATE_STORAGE_KEY = exports.OXY_AUTHORIZE_URL = exports.DEFAULT_OAUTH_SCOPE = exports.generatePkcePair = exports.generateOAuthState = exports.computeCodeChallenge = exports.buildOAuthAuthorizeUrl = exports.CENTRAL_IDP_APEX = exports.AUTH_WEB_ORIGIN = exports.getAccountColor = exports.formatPublicKeyHandle = exports.getAccountFallbackHandle = exports.getAccountDisplayName = exports.createQuickAccount = exports.buildAccountsArray = exports.updateAvatarVisibility = exports.isDev = exports.consoleSink = exports.resetLoggerConfig = exports.getLoggerConfig = exports.configureLogger = exports.createLogger = exports.logger = exports.normalizeMultilineText = exports.normalizeInlineText = exports.validateAndSanitizeUserInput = void 0;
|
|
28
28
|
// The crypto shim MUST stay the first import. The root itself ships no crypto
|
|
29
29
|
// library (`__tests__/rootEntryGraph.test.ts`), but `@oxy.so/protocol`'s root
|
|
30
30
|
// entry (reached by the OAuth/PKCE and device helpers) does, and Metro does not
|
|
@@ -97,6 +97,7 @@ Object.defineProperty(exports, "getCanonicalUserHandle", { enumerable: true, get
|
|
|
97
97
|
Object.defineProperty(exports, "getNormalizedUserHandle", { enumerable: true, get: function () { return userHandle_1.getNormalizedUserHandle; } });
|
|
98
98
|
var profileLinks_1 = require("./utils/profileLinks");
|
|
99
99
|
Object.defineProperty(exports, "normalizeProfileLinks", { enumerable: true, get: function () { return profileLinks_1.normalizeProfileLinks; } });
|
|
100
|
+
Object.defineProperty(exports, "supportProviderOf", { enumerable: true, get: function () { return profileLinks_1.supportProviderOf; } });
|
|
100
101
|
// ---------------------------------------------------------------------------
|
|
101
102
|
// Auth helpers (token refresh, error normalisation, retry policies)
|
|
102
103
|
// ---------------------------------------------------------------------------
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.normalizeProfileLinks = normalizeProfileLinks;
|
|
4
|
+
exports.supportProviderOf = supportProviderOf;
|
|
4
5
|
function cleanUrl(value) {
|
|
5
6
|
if (typeof value !== 'string')
|
|
6
7
|
return null;
|
|
@@ -37,12 +38,14 @@ function normalizeProfileLinks(linksMetadata, links) {
|
|
|
37
38
|
const title = typeof entry?.title === 'string' ? entry.title : undefined;
|
|
38
39
|
const description = typeof entry?.description === 'string' ? entry.description : undefined;
|
|
39
40
|
const image = typeof entry?.image === 'string' ? entry.image : undefined;
|
|
41
|
+
const faviconUrl = typeof entry?.faviconUrl === 'string' ? entry.faviconUrl : undefined;
|
|
40
42
|
result.push({
|
|
41
43
|
id,
|
|
42
44
|
url,
|
|
43
45
|
...(title !== undefined ? { title } : {}),
|
|
44
46
|
...(description !== undefined ? { description } : {}),
|
|
45
47
|
...(image !== undefined ? { image } : {}),
|
|
48
|
+
...(faviconUrl !== undefined ? { faviconUrl } : {}),
|
|
46
49
|
});
|
|
47
50
|
});
|
|
48
51
|
return result;
|
|
@@ -59,3 +62,34 @@ function normalizeProfileLinks(linksMetadata, links) {
|
|
|
59
62
|
}
|
|
60
63
|
return [];
|
|
61
64
|
}
|
|
65
|
+
const SUPPORT_PROVIDERS = [
|
|
66
|
+
{ provider: { id: 'patreon', name: 'Patreon' }, hosts: ['patreon.com'] },
|
|
67
|
+
{ provider: { id: 'kofi', name: 'Ko-fi' }, hosts: ['ko-fi.com'] },
|
|
68
|
+
{ provider: { id: 'buymeacoffee', name: 'Buy Me a Coffee' }, hosts: ['buymeacoffee.com'] },
|
|
69
|
+
{ provider: { id: 'github-sponsors', name: 'GitHub Sponsors' }, hosts: ['github.com'] },
|
|
70
|
+
{ provider: { id: 'liberapay', name: 'Liberapay' }, hosts: ['liberapay.com'] },
|
|
71
|
+
];
|
|
72
|
+
/**
|
|
73
|
+
* The support platform a link points at, or `null`. GitHub Sponsors is the one
|
|
74
|
+
* host shared with ordinary GitHub pages, so only its `/sponsors/` path counts.
|
|
75
|
+
*/
|
|
76
|
+
function supportProviderOf(url) {
|
|
77
|
+
let parsed;
|
|
78
|
+
try {
|
|
79
|
+
parsed = new URL(url);
|
|
80
|
+
}
|
|
81
|
+
catch {
|
|
82
|
+
return null;
|
|
83
|
+
}
|
|
84
|
+
const host = parsed.hostname.toLowerCase().replace(/^www\./, '');
|
|
85
|
+
for (const { provider, hosts } of SUPPORT_PROVIDERS) {
|
|
86
|
+
if (!hosts.some((known) => host === known || host.endsWith(`.${known}`)))
|
|
87
|
+
continue;
|
|
88
|
+
if (provider.id === 'github-sponsors' &&
|
|
89
|
+
!parsed.pathname.toLowerCase().startsWith('/sponsors/')) {
|
|
90
|
+
continue;
|
|
91
|
+
}
|
|
92
|
+
return provider;
|
|
93
|
+
}
|
|
94
|
+
return null;
|
|
95
|
+
}
|
package/dist/esm/index.js
CHANGED
|
@@ -53,7 +53,7 @@ export { selectCommonsDelivery, pushTargetsFromDelivery, commonsDeliveryPlatform
|
|
|
53
53
|
// ---------------------------------------------------------------------------
|
|
54
54
|
export { getNormalizedUserId, normalizeUserIdentity, normalizeUserIdentityOrNull, } from './utils/userIdentity.js';
|
|
55
55
|
export { getCanonicalUserHandle, getNormalizedUserHandle, } from './utils/userHandle.js';
|
|
56
|
-
export { normalizeProfileLinks } from './utils/profileLinks.js';
|
|
56
|
+
export { normalizeProfileLinks, supportProviderOf } from './utils/profileLinks.js';
|
|
57
57
|
// ---------------------------------------------------------------------------
|
|
58
58
|
// Auth helpers (token refresh, error normalisation, retry policies)
|
|
59
59
|
// ---------------------------------------------------------------------------
|
|
@@ -34,12 +34,14 @@ export function normalizeProfileLinks(linksMetadata, links) {
|
|
|
34
34
|
const title = typeof entry?.title === 'string' ? entry.title : undefined;
|
|
35
35
|
const description = typeof entry?.description === 'string' ? entry.description : undefined;
|
|
36
36
|
const image = typeof entry?.image === 'string' ? entry.image : undefined;
|
|
37
|
+
const faviconUrl = typeof entry?.faviconUrl === 'string' ? entry.faviconUrl : undefined;
|
|
37
38
|
result.push({
|
|
38
39
|
id,
|
|
39
40
|
url,
|
|
40
41
|
...(title !== undefined ? { title } : {}),
|
|
41
42
|
...(description !== undefined ? { description } : {}),
|
|
42
43
|
...(image !== undefined ? { image } : {}),
|
|
44
|
+
...(faviconUrl !== undefined ? { faviconUrl } : {}),
|
|
43
45
|
});
|
|
44
46
|
});
|
|
45
47
|
return result;
|
|
@@ -56,3 +58,34 @@ export function normalizeProfileLinks(linksMetadata, links) {
|
|
|
56
58
|
}
|
|
57
59
|
return [];
|
|
58
60
|
}
|
|
61
|
+
const SUPPORT_PROVIDERS = [
|
|
62
|
+
{ provider: { id: 'patreon', name: 'Patreon' }, hosts: ['patreon.com'] },
|
|
63
|
+
{ provider: { id: 'kofi', name: 'Ko-fi' }, hosts: ['ko-fi.com'] },
|
|
64
|
+
{ provider: { id: 'buymeacoffee', name: 'Buy Me a Coffee' }, hosts: ['buymeacoffee.com'] },
|
|
65
|
+
{ provider: { id: 'github-sponsors', name: 'GitHub Sponsors' }, hosts: ['github.com'] },
|
|
66
|
+
{ provider: { id: 'liberapay', name: 'Liberapay' }, hosts: ['liberapay.com'] },
|
|
67
|
+
];
|
|
68
|
+
/**
|
|
69
|
+
* The support platform a link points at, or `null`. GitHub Sponsors is the one
|
|
70
|
+
* host shared with ordinary GitHub pages, so only its `/sponsors/` path counts.
|
|
71
|
+
*/
|
|
72
|
+
export function supportProviderOf(url) {
|
|
73
|
+
let parsed;
|
|
74
|
+
try {
|
|
75
|
+
parsed = new URL(url);
|
|
76
|
+
}
|
|
77
|
+
catch {
|
|
78
|
+
return null;
|
|
79
|
+
}
|
|
80
|
+
const host = parsed.hostname.toLowerCase().replace(/^www\./, '');
|
|
81
|
+
for (const { provider, hosts } of SUPPORT_PROVIDERS) {
|
|
82
|
+
if (!hosts.some((known) => host === known || host.endsWith(`.${known}`)))
|
|
83
|
+
continue;
|
|
84
|
+
if (provider.id === 'github-sponsors' &&
|
|
85
|
+
!parsed.pathname.toLowerCase().startsWith('/sponsors/')) {
|
|
86
|
+
continue;
|
|
87
|
+
}
|
|
88
|
+
return provider;
|
|
89
|
+
}
|
|
90
|
+
return null;
|
|
91
|
+
}
|
package/dist/types/index.d.ts
CHANGED
|
@@ -70,8 +70,8 @@ export type { CommonsDeliveryFacts, CommonsDeliveryPlatform, CommonsDeliveryRout
|
|
|
70
70
|
export { getNormalizedUserId, normalizeUserIdentity, normalizeUserIdentityOrNull, } from './utils/userIdentity';
|
|
71
71
|
export { getCanonicalUserHandle, getNormalizedUserHandle, } from './utils/userHandle';
|
|
72
72
|
export type { CanonicalUserHandleInput, UserHandleInput } from './utils/userHandle';
|
|
73
|
-
export { normalizeProfileLinks } from './utils/profileLinks';
|
|
74
|
-
export type { ProfileLink, ProfileLinkMetadata } from './utils/profileLinks';
|
|
73
|
+
export { normalizeProfileLinks, supportProviderOf } from './utils/profileLinks';
|
|
74
|
+
export type { ProfileLink, ProfileLinkMetadata, SupportProvider } from './utils/profileLinks';
|
|
75
75
|
export { SessionSyncRequiredError, AuthenticationFailedError, ensureValidToken, isAuthenticationError, withAuthErrorHandling, authenticatedApiCall, } from './utils/authHelpers';
|
|
76
76
|
export type { HandleApiErrorOptions } from './utils/authHelpers';
|
|
77
77
|
export { mergeSessions, normalizeAndSortSessions, sessionsArraysEqual, } from './utils/sessionUtils';
|
|
@@ -13,6 +13,8 @@ export interface ProfileLink {
|
|
|
13
13
|
url: string;
|
|
14
14
|
description?: string;
|
|
15
15
|
image?: string;
|
|
16
|
+
/** Clarity's favicon for the link's host, when Clarity has one. */
|
|
17
|
+
faviconUrl?: string;
|
|
16
18
|
}
|
|
17
19
|
/** Source shape of a single `User.linksMetadata` entry. */
|
|
18
20
|
export interface ProfileLinkMetadata {
|
|
@@ -21,6 +23,7 @@ export interface ProfileLinkMetadata {
|
|
|
21
23
|
description?: string;
|
|
22
24
|
image?: string;
|
|
23
25
|
id?: string;
|
|
26
|
+
faviconUrl?: string;
|
|
24
27
|
}
|
|
25
28
|
/**
|
|
26
29
|
* Normalizes a user's profile links into a clean display shape.
|
|
@@ -42,3 +45,13 @@ export interface ProfileLinkMetadata {
|
|
|
42
45
|
* as `https://`; prefixing is a display concern left to the caller.
|
|
43
46
|
*/
|
|
44
47
|
export declare function normalizeProfileLinks(linksMetadata?: ProfileLinkMetadata[], links?: string[]): ProfileLink[];
|
|
48
|
+
/** A platform a profile can point supporters to, recognised by the link's host. */
|
|
49
|
+
export interface SupportProvider {
|
|
50
|
+
id: 'patreon' | 'kofi' | 'buymeacoffee' | 'github-sponsors' | 'liberapay';
|
|
51
|
+
name: string;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* The support platform a link points at, or `null`. GitHub Sponsors is the one
|
|
55
|
+
* host shared with ordinary GitHub pages, so only its `/sponsors/` path counts.
|
|
56
|
+
*/
|
|
57
|
+
export declare function supportProviderOf(url: string): SupportProvider | null;
|
package/package.json
CHANGED
package/src/index.ts
CHANGED
|
@@ -319,8 +319,8 @@ export {
|
|
|
319
319
|
getNormalizedUserHandle,
|
|
320
320
|
} from './utils/userHandle';
|
|
321
321
|
export type { CanonicalUserHandleInput, UserHandleInput } from './utils/userHandle';
|
|
322
|
-
export { normalizeProfileLinks } from './utils/profileLinks';
|
|
323
|
-
export type { ProfileLink, ProfileLinkMetadata } from './utils/profileLinks';
|
|
322
|
+
export { normalizeProfileLinks, supportProviderOf } from './utils/profileLinks';
|
|
323
|
+
export type { ProfileLink, ProfileLinkMetadata, SupportProvider } from './utils/profileLinks';
|
|
324
324
|
|
|
325
325
|
// ---------------------------------------------------------------------------
|
|
326
326
|
// Auth helpers (token refresh, error normalisation, retry policies)
|
|
@@ -13,6 +13,8 @@ export interface ProfileLink {
|
|
|
13
13
|
url: string;
|
|
14
14
|
description?: string;
|
|
15
15
|
image?: string;
|
|
16
|
+
/** Clarity's favicon for the link's host, when Clarity has one. */
|
|
17
|
+
faviconUrl?: string;
|
|
16
18
|
}
|
|
17
19
|
|
|
18
20
|
/** Source shape of a single `User.linksMetadata` entry. */
|
|
@@ -22,6 +24,7 @@ export interface ProfileLinkMetadata {
|
|
|
22
24
|
description?: string;
|
|
23
25
|
image?: string;
|
|
24
26
|
id?: string;
|
|
27
|
+
faviconUrl?: string;
|
|
25
28
|
}
|
|
26
29
|
|
|
27
30
|
function cleanUrl(value: unknown): string | null {
|
|
@@ -63,12 +66,14 @@ export function normalizeProfileLinks(
|
|
|
63
66
|
const title = typeof entry?.title === 'string' ? entry.title : undefined;
|
|
64
67
|
const description = typeof entry?.description === 'string' ? entry.description : undefined;
|
|
65
68
|
const image = typeof entry?.image === 'string' ? entry.image : undefined;
|
|
69
|
+
const faviconUrl = typeof entry?.faviconUrl === 'string' ? entry.faviconUrl : undefined;
|
|
66
70
|
result.push({
|
|
67
71
|
id,
|
|
68
72
|
url,
|
|
69
73
|
...(title !== undefined ? { title } : {}),
|
|
70
74
|
...(description !== undefined ? { description } : {}),
|
|
71
75
|
...(image !== undefined ? { image } : {}),
|
|
76
|
+
...(faviconUrl !== undefined ? { faviconUrl } : {}),
|
|
72
77
|
});
|
|
73
78
|
});
|
|
74
79
|
return result;
|
|
@@ -86,3 +91,42 @@ export function normalizeProfileLinks(
|
|
|
86
91
|
|
|
87
92
|
return [];
|
|
88
93
|
}
|
|
94
|
+
|
|
95
|
+
/** A platform a profile can point supporters to, recognised by the link's host. */
|
|
96
|
+
export interface SupportProvider {
|
|
97
|
+
id: 'patreon' | 'kofi' | 'buymeacoffee' | 'github-sponsors' | 'liberapay';
|
|
98
|
+
name: string;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
const SUPPORT_PROVIDERS: readonly { provider: SupportProvider; hosts: readonly string[] }[] = [
|
|
102
|
+
{ provider: { id: 'patreon', name: 'Patreon' }, hosts: ['patreon.com'] },
|
|
103
|
+
{ provider: { id: 'kofi', name: 'Ko-fi' }, hosts: ['ko-fi.com'] },
|
|
104
|
+
{ provider: { id: 'buymeacoffee', name: 'Buy Me a Coffee' }, hosts: ['buymeacoffee.com'] },
|
|
105
|
+
{ provider: { id: 'github-sponsors', name: 'GitHub Sponsors' }, hosts: ['github.com'] },
|
|
106
|
+
{ provider: { id: 'liberapay', name: 'Liberapay' }, hosts: ['liberapay.com'] },
|
|
107
|
+
];
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* The support platform a link points at, or `null`. GitHub Sponsors is the one
|
|
111
|
+
* host shared with ordinary GitHub pages, so only its `/sponsors/` path counts.
|
|
112
|
+
*/
|
|
113
|
+
export function supportProviderOf(url: string): SupportProvider | null {
|
|
114
|
+
let parsed: URL;
|
|
115
|
+
try {
|
|
116
|
+
parsed = new URL(url);
|
|
117
|
+
} catch {
|
|
118
|
+
return null;
|
|
119
|
+
}
|
|
120
|
+
const host = parsed.hostname.toLowerCase().replace(/^www\./, '');
|
|
121
|
+
for (const { provider, hosts } of SUPPORT_PROVIDERS) {
|
|
122
|
+
if (!hosts.some((known) => host === known || host.endsWith(`.${known}`))) continue;
|
|
123
|
+
if (
|
|
124
|
+
provider.id === 'github-sponsors' &&
|
|
125
|
+
!parsed.pathname.toLowerCase().startsWith('/sponsors/')
|
|
126
|
+
) {
|
|
127
|
+
continue;
|
|
128
|
+
}
|
|
129
|
+
return provider;
|
|
130
|
+
}
|
|
131
|
+
return null;
|
|
132
|
+
}
|