Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor to dub TypeScript SDK #13449

Merged
merged 11 commits into from
Jul 19, 2024
Merged
10 changes: 10 additions & 0 deletions extensions/dub-link-shortener/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# Dub Link Shortener Changelog


## [Workspace API Keys] - 2024-07-19

- Simplify Dub Raycast Extension by using [`dub` TypeScript SDK](https://dub.co/solutions/typescript)
- ⚠️This is a breaking change if you are using _User API Keys_. Please switch to using [Workspace API keys](https://dub.co/blog/workspace-api-keys) to continue using the extension.

## [Minor metadata updates] - 2024-07-16

- Updated the title, description, logo, and auth instructions
Expand All @@ -17,16 +23,20 @@
- Used React hooks from @raycast/utils and upgraded dependencies

## [Enhancement: Remove long URL in the list view for clarity] - 2024-02-07

- Take in urlKey that sets a custom short URL
- Support arguments inline to the shorten link command

## [Enhancement: Remove long URL in the list view for clarity] - 2023-12-21

- Showing both the shortened & long URL was cluttering the list view, so removing the long URL for now

## [Enhancement: Show the shortened and long URL in the list view] - 2023-12-14

- Be consistent with the web app and show both the short and long URL for each item in the list view

## [Enhancement: Better feedback and UX] - 2023-12-06

- More specific language around copying to clipboard
- Showing the shortened link as pop up text after successfully shortening

Expand Down
127 changes: 27 additions & 100 deletions extensions/dub-link-shortener/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 5 additions & 4 deletions extensions/dub-link-shortener/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -46,15 +46,16 @@
"dependencies": {
"@raycast/api": "^1.61.2",
"@raycast/utils": "^1.16.0",
"axios": "^1.6.2"
"dub": "^0.33.1",
"undici": "^6.19.2"
},
"preferences": [
{
"name": "apiKey",
"name": "workspaceApiKey",
"type": "password",
"required": true,
"title": "API Key",
"description": "Dub API key."
"title": "Workspace API Key",
"description": "Workspace API key on Dub. Learn more: https://d.to/tokens"
}
],
"devDependencies": {
Expand Down
75 changes: 28 additions & 47 deletions extensions/dub-link-shortener/src/api/index.ts
Original file line number Diff line number Diff line change
@@ -1,66 +1,47 @@
import axios, { AxiosRequestConfig } from "axios";
import { BASE_API_URL } from "@utils/constants";
import { apiKey, commandName, extensionName } from "@utils/env";
import { DeleteLinkResponseBody, LinkSchema, TagSchema, WorkspaceId, WorkspaceSchema } from "@/types";
import { captureException } from "@raycast/api";
import { Dub } from "dub";
import { workspaceApiKey } from "@utils/env";

const hasHttps = (url: string) => url.startsWith("https://");
const headers = {
Authorization: "Bearer " + apiKey,
"Content-Type": "application/json",
"user-agent": `raycast/${extensionName}/${commandName}`,
};

/**
* todo: Replace with SDK https://d.to/sdk once it is stable
* see: https://github.com/dubinc/dub-node/blob/765e170c45a361de3ae62e0d19571ceca4a3f0f4/README.md#maturity
*/
export const callApi = async <T>(config: AxiosRequestConfig) => {
return await axios({ ...config, headers })
.then(({ data }) => data as T)
.catch(({ response }) => {
const err = new Error(response?.data?.error?.message ?? "Unknown error");
captureException(err);
throw err;
});
};

export const getAllWorkspaces = async () => {
return await callApi<WorkspaceSchema[]>({ method: "GET", url: `${BASE_API_URL}/workspaces` });
};
const dub = new Dub({
token: workspaceApiKey,
});

export const createShortLink = async ({
originalUrl,
key,
workspaceId,
domain,
tagIds,
comments,
}: { originalUrl: string; key?: string; domain?: string; tagIds?: string[]; comments?: string } & WorkspaceId) => {
const url = hasHttps(originalUrl) ? originalUrl : `https://${originalUrl}`;
return await callApi<LinkSchema>({
method: "POST",
url: workspaceId ? `${BASE_API_URL}/links?workspaceId=${workspaceId}` : `${BASE_API_URL}/links`,
data: { domain, url, key, tagIds, comments },
}: {
originalUrl: string;
key?: string;
domain?: string;
tagIds?: string[];
comments?: string;
}) => {
return dub.links.create({
url: originalUrl,
steven-tey marked this conversation as resolved.
Show resolved Hide resolved
key,
domain,
tagIds,
comments,
});
};

export const getAllShortLinks = async ({ workspaceId }: WorkspaceId = {}) => {
const url = workspaceId ? `${BASE_API_URL}/links?workspaceId=${workspaceId}` : `${BASE_API_URL}/links`;
return await callApi<LinkSchema[]>({ method: "GET", url });
export const getAllShortLinks = async () => {
return dub.links.list();
};

export const deleteShortLink = async ({ linkId, workspaceId }: { linkId: string } & WorkspaceId) => {
const url = workspaceId
? `${BASE_API_URL}/links/${linkId}?workspaceId=${workspaceId}`
: `${BASE_API_URL}/links/${linkId}`;
return await callApi<DeleteLinkResponseBody>({ method: "DELETE", url });
export const deleteShortLink = async (linkId: string) => {
return dub.links.delete(linkId);
};

/**
* todo: Add commands and api(s) to create/manage tags in the workspace.
*/
export const getAllTags = async ({ workspaceId }: WorkspaceId = {}) => {
const url = workspaceId ? `${BASE_API_URL}/tags?workspaceId=${workspaceId}` : `${BASE_API_URL}/tags`;
return await callApi<TagSchema[]>({ method: "GET", url });
export const getAllTags = async () => {
return dub.tags.list();
};

export const getAllDomains = async () => {
return dub.domains.list();
};
16 changes: 16 additions & 0 deletions extensions/dub-link-shortener/src/hooks/use-domains.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { useCachedPromise } from "@raycast/utils";
import { getAllDomains } from "@/api";

export const useDomains = () => {
const {
data: domains,
isLoading,
error,
mutate,
} = useCachedPromise(getAllDomains, [], {
initialData: [],
failureToastOptions: { title: "❗ Failed to fetch domains" },
});

return { domains, mutate, isLoading: (!domains && !error) || isLoading, error };
};
10 changes: 2 additions & 8 deletions extensions/dub-link-shortener/src/hooks/use-short-links.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,14 @@
import { useCachedPromise } from "@raycast/utils";
import { getAllShortLinks } from "@/api";
import { WorkspaceId } from "@/types";

export const useShortLinks = ({
workspaceId,
isLoadingWorkspaces,
workspacesError,
}: WorkspaceId & { isLoadingWorkspaces: boolean; workspacesError?: Error }) => {
export const useShortLinks = () => {
const {
data: shortLinks,
isLoading,
error,
mutate,
} = useCachedPromise(getAllShortLinks, [{ workspaceId }], {
} = useCachedPromise(getAllShortLinks, [], {
initialData: [],
execute: !isLoadingWorkspaces && !workspacesError,
failureToastOptions: { title: "❗ Failed to fetch short links" },
});

Expand Down
Loading