diff --git a/.env.example b/.env.example
index 869c0124..bbdc5e48 100644
--- a/.env.example
+++ b/.env.example
@@ -104,3 +104,9 @@ POSTIZ_OAUTH_CLIENT_SECRET=""
# DUB_TOKEN="" # Your self-hosted Dub API token
# DUB_API_ENDPOINT="https://api.dub.co" # Your self-hosted Dub API endpoint
# DUB_SHORT_LINK_DOMAIN="dub.sh" # Your self-hosted Dub domain
+
+# SHORT_IO_SECRET_KEY="" # Your Short.io API secret key
+
+# KUTT_API_KEY="" # Your Kutt.it API key
+# KUTT_API_ENDPOINT="https://kutt.it/api/v2" # Your self-hosted Kutt API endpoint
+# KUTT_SHORT_LINK_DOMAIN="kutt.it" # Your self-hosted Kutt domain
\ No newline at end of file
diff --git a/README.md b/README.md
index 8ce65f8c..6afe8ff9 100644
--- a/README.md
+++ b/README.md
@@ -14,8 +14,8 @@
-
-
+
+
diff --git a/apps/frontend/src/components/launches/providers/pinterest/pinterest.provider.tsx b/apps/frontend/src/components/launches/providers/pinterest/pinterest.provider.tsx
index 6e7c468e..ee97a378 100644
--- a/apps/frontend/src/components/launches/providers/pinterest/pinterest.provider.tsx
+++ b/apps/frontend/src/components/launches/providers/pinterest/pinterest.provider.tsx
@@ -10,6 +10,7 @@ const PinterestSettings: FC = () => {
return (
+
({
+ headers: {
+ 'X-API-Key': process.env.KUTT_API_KEY,
+ 'Content-Type': 'application/json',
+ },
+});
+
+export class Kutt implements ShortLinking {
+ shortLinkDomain = KUTT_SHORT_LINK_DOMAIN;
+
+ async linksStatistics(links: string[]) {
+ return Promise.all(
+ links.map(async (link) => {
+ const linkId = link.split('/').pop();
+
+ try {
+ const response = await fetch(
+ `${KUTT_API_ENDPOINT}/links/${linkId}/stats`,
+ getOptions()
+ );
+
+ if (!response.ok) {
+ throw new Error(`HTTP error! status: ${response.status}`);
+ }
+
+ const data = await response.json();
+
+ return {
+ short: link,
+ original: data.address || '',
+ clicks: data.lastDay?.stats?.reduce((total: number, stat: any) => total + stat, 0)?.toString() || '0',
+ };
+ } catch (error) {
+ return {
+ short: link,
+ original: '',
+ clicks: '0',
+ };
+ }
+ })
+ );
+ }
+
+ async convertLinkToShortLink(id: string, link: string) {
+ try {
+ const response = await fetch(`${KUTT_API_ENDPOINT}/links`, {
+ ...getOptions(),
+ method: 'POST',
+ body: JSON.stringify({
+ target: link,
+ domain: this.shortLinkDomain,
+ reuse: false,
+ }),
+ });
+
+ if (!response.ok) {
+ throw new Error(`HTTP error! status: ${response.status}`);
+ }
+
+ const data = await response.json();
+ return data.link;
+ } catch (error) {
+ throw new Error(`Failed to create short link: ${error}`);
+ }
+ }
+
+ async convertShortLinkToLink(shortLink: string) {
+ const linkId = shortLink.split('/').pop();
+
+ try {
+ const response = await fetch(
+ `${KUTT_API_ENDPOINT}/links/${linkId}/stats`,
+ getOptions()
+ );
+
+ if (!response.ok) {
+ throw new Error(`HTTP error! status: ${response.status}`);
+ }
+
+ const data = await response.json();
+ return data.address || '';
+ } catch (error) {
+ throw new Error(`Failed to get original link: ${error}`);
+ }
+ }
+
+ async getAllLinksStatistics(
+ id: string,
+ page = 1
+ ): Promise<{ short: string; original: string; clicks: string }[]> {
+ try {
+ const response = await fetch(
+ `${KUTT_API_ENDPOINT}/links?limit=100&skip=${(page - 1) * 100}`,
+ getOptions()
+ );
+
+ if (!response.ok) {
+ throw new Error(`HTTP error! status: ${response.status}`);
+ }
+
+ const data = await response.json();
+
+ const mapLinks = data.data?.map((link: any) => ({
+ short: link.link,
+ original: link.address,
+ clicks: link.visit_count?.toString() || '0',
+ })) || [];
+
+ if (mapLinks.length < 100) {
+ return mapLinks;
+ }
+
+ return [...mapLinks, ...(await this.getAllLinksStatistics(id, page + 1))];
+ } catch (error) {
+ return [];
+ }
+ }
+}
\ No newline at end of file
diff --git a/libraries/nestjs-libraries/src/short-linking/short.link.service.ts b/libraries/nestjs-libraries/src/short-linking/short.link.service.ts
index c8ed16db..bb73aa9e 100644
--- a/libraries/nestjs-libraries/src/short-linking/short.link.service.ts
+++ b/libraries/nestjs-libraries/src/short-linking/short.link.service.ts
@@ -3,6 +3,7 @@ import { Empty } from '@gitroom/nestjs-libraries/short-linking/providers/empty';
import { ShortLinking } from '@gitroom/nestjs-libraries/short-linking/short-linking.interface';
import { Injectable } from '@nestjs/common';
import { ShortIo } from './providers/short.io';
+import { Kutt } from './providers/kutt';
const getProvider = (): ShortLinking => {
if (process.env.DUB_TOKEN) {
@@ -13,6 +14,10 @@ const getProvider = (): ShortLinking => {
return new ShortIo();
}
+ if (process.env.KUTT_API_KEY) {
+ return new Kutt();
+ }
+
return new Empty();
};