Skip to content

Commit

Permalink
add auth refresh to trpc in figma
Browse files Browse the repository at this point in the history
  • Loading branch information
tomasfrancisco committed Aug 22, 2024
1 parent bc5fa8a commit ca5309b
Show file tree
Hide file tree
Showing 17 changed files with 173 additions and 308 deletions.
1 change: 0 additions & 1 deletion apps/dashboard/src/types/kv-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ export interface KVCredentialsRead {
export interface KVCredentials {
accessToken: string;
refreshToken: string;

expiresAt: number;
}

Expand Down
6 changes: 6 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,5 +21,11 @@
"packageManager": "[email protected]",
"engines": {
"node": "^20"
},
"pnpm": {
"overrides": {
"@trpc/client": "11.0.0-rc.482",
"@trpc/server": "11.0.0-rc.482"
}
}
}
4 changes: 2 additions & 2 deletions packages/api/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,16 +26,16 @@
"author": "",
"license": "ISC",
"dependencies": {
"style-dictionary": "catalog:",
"@ds-project/services": "workspace:*",
"@ds-project/auth": "workspace:*",
"@ds-project/database": "workspace:*",
"@ds-project/services": "workspace:*",
"@tanstack/react-query": "^5.51.24",
"@trpc/client": "catalog:",
"@trpc/react-query": "catalog:",
"@trpc/server": "catalog:",
"next": "catalog:",
"react": "catalog:",
"style-dictionary": "catalog:",
"superjson": "^2.2.1",
"zod": "catalog:"
},
Expand Down
2 changes: 1 addition & 1 deletion packages/api/src/query-client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ export const createQueryClient = () =>
queries: {
// With SSR, we usually want to set some default staleTime
// above 0 to avoid refetching immediately on the client
staleTime: 30 * 1000,
staleTime: 30 * 1000, // 30 seconds
},
dehydrate: {
serializeData: SuperJSON.serialize,
Expand Down
64 changes: 36 additions & 28 deletions packages/api/src/react.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
'use client';

import type { QueryClient } from '@tanstack/react-query';
import { useState } from 'react';
import { QueryClientProvider } from '@tanstack/react-query';
import type { TRPCLink } from '@trpc/client';
import { loggerLink, unstable_httpBatchStreamLink } from '@trpc/client';
import { createTRPCReact } from '@trpc/react-query';
import SuperJSON from 'superjson';

import { createQueryClient } from './query-client';
import type { AppRouter } from './app-router';
import { useMemo } from 'react';

let clientQueryClientSingleton: QueryClient | undefined = undefined;
const getQueryClient = () => {
Expand All @@ -23,33 +24,40 @@ const getQueryClient = () => {

export const api = createTRPCReact<AppRouter>();

export function TRPCReactProvider(props: { children: React.ReactNode }) {
export function TRPCReactProvider(props: {
children: React.ReactNode;
source: string;
accessToken?: string;
trpcLinks?: TRPCLink<AppRouter>[];
}) {
const queryClient = getQueryClient();

const [trpcClient] = useState(() =>
api.createClient({
links: [
loggerLink({
enabled: (op) =>
// eslint-disable-next-line turbo/no-undeclared-env-vars
process.env.NODE_ENV === 'development' ||
(op.direction === 'down' && op.result instanceof Error),
}),
unstable_httpBatchStreamLink({
transformer: SuperJSON,
url: getBaseUrl() + '/api/trpc',
headers() {
const headerObject: Record<string, string> = {};
const headers = new Headers();
headers.set('x-trpc-source', 'nextjs-react');
headers.forEach((header, value) => {
headerObject[header] = value;
});
return headerObject;
},
}),
],
})
const trpcClient = useMemo(
() =>
api.createClient({
links: [
...(props.trpcLinks ?? []),
loggerLink({
enabled: (op) =>
// eslint-disable-next-line turbo/no-undeclared-env-vars
process.env.NODE_ENV === 'development' ||
(op.direction === 'down' && op.result instanceof Error),
}),
unstable_httpBatchStreamLink({
transformer: SuperJSON,
url: getBaseUrl() + '/api/v1',
headers() {
return {
'x-trpc-source': props.source,
...(props.accessToken
? { Authorization: `Bearer ${props.accessToken}` }
: {}),
};
},
}),
],
}),
[props.accessToken, props.source, props.trpcLinks]
);

return (
Expand All @@ -62,10 +70,10 @@ export function TRPCReactProvider(props: { children: React.ReactNode }) {
}

const getBaseUrl = () => {
if (typeof window !== 'undefined') return window.location.origin;
// if (typeof window !== 'undefined') return window.location.origin;
// eslint-disable-next-line turbo/no-undeclared-env-vars
if (process.env.VERCEL_URL) return `https://${process.env.VERCEL_URL}`;

// eslint-disable-next-line turbo/no-undeclared-env-vars
return `http://localhost:${process.env.PORT ?? 3000}`;
return `https://localhost:${process.env.PORT ?? 3000}`;
};
13 changes: 9 additions & 4 deletions packages/figma-plugin/eslint.config.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,19 @@
import baseConfig from '@ds-project/eslint/base';
import reactConfig from '@ds-project/eslint/react';
// import figmaPlugin from '@figma/eslint-plugin-figma-plugins';

/** @type {import('typescript-eslint').Config} */
export default [
{
ignores: ['dist/**'],
extends: ['plugin:@figma/figma-plugins/recommended'],
globals: {
figma: 'readable',
__html__: 'readable',
languageOptions: {
globals: {
figma: 'readable',
__html__: 'readable',
},
},
rules: {
// ...figmaPlugin.configs.recommended.rules,
},
},
...baseConfig,
Expand Down
5 changes: 3 additions & 2 deletions packages/figma-plugin/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,10 @@
"type-check": "tsc --noEmit --emitDeclarationOnly false"
},
"dependencies": {
"@ds-project/types": "workspace:*",
"@apollo/client": "^3.7.11",
"@ds-project/api": "workspace:*",
"@ds-project/components": "workspace:*",
"@ds-project/types": "workspace:*",
"@octokit/core": "^6.1.2",
"@octokit/request": "^9.1.3",
"@octokit/types": "^13.5.0",
Expand All @@ -35,7 +35,8 @@
"sass": "^1.60.0",
"style-dictionary": "catalog:",
"superjson": "^2.2.1",
"tailwindcss": "catalog:"
"tailwindcss": "catalog:",
"trpc-token-refresh-link": "^0.5.0"
},
"devDependencies": {
"@ds-project/eslint": "workspace:*",
Expand Down
2 changes: 0 additions & 2 deletions packages/figma-plugin/src/plugin/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,6 @@ AsyncMessage.plugin.handle(AsyncMessageTypes.GetCredentials, async () => {
throw new Error('No DS Credentials found');
}

console.log(credentialsString);

return { credentials };
});

Expand Down
1 change: 1 addition & 0 deletions packages/figma-plugin/src/types/credentials.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
export interface Credentials {
accessToken: string;
refreshToken: string;
expireAt: number;
}
4 changes: 2 additions & 2 deletions packages/figma-plugin/src/ui/app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ import { AsyncMessageTypes } from '../message.types';
import { AsyncMessage } from '../message';
import { LinkDesignSystem } from './modules/link-design-system';
import { useAuth } from './modules/providers/auth-provider';
import { api } from '@ds-project/api/react';
import { useConfig } from './modules/providers/config-provider';
import { api } from '@ds-project/api/react';

function App() {
const { login, logout, state } = useAuth();
Expand All @@ -22,7 +22,7 @@ function App() {
})
.then(({ designTokens }) => {
if (fileName) {
void updateDesignTokens({ designTokens, name: fileName });
// void updateDesignTokens({ designTokens, name: fileName });
}
})
.catch((error) => {
Expand Down
65 changes: 0 additions & 65 deletions packages/figma-plugin/src/ui/lib/api.tsx

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ import {
import { useCallback, useEffect, useState } from 'react';
import { AsyncMessage } from '../../../message';
import { AsyncMessageTypes } from '../../../message.types';
import { api } from '@ds-project/api/react';
import { useConfig } from '../providers/config-provider';
import { api } from '@ds-project/api/react';

export function LinkDesignSystem() {
const { fileName } = useConfig();
Expand Down
41 changes: 41 additions & 0 deletions packages/figma-plugin/src/ui/modules/providers/api-provider.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { useMemo } from 'react';
import { TRPCReactProvider } from '@ds-project/api/react';
import { useAuth } from './auth-provider';
import { tokenRefreshLink } from 'trpc-token-refresh-link';
import type { AppRouter } from '../../../../../api/src/app-router';

export function ApiProvider({ children }: { children: React.ReactNode }) {
const { credentials, refreshAccessToken, logout } = useAuth();

const authTrpcLink = useMemo(
() =>
tokenRefreshLink<AppRouter>({
tokenRefreshNeeded: () => {
if (!credentials) {
return false;
}

return credentials.expireAt - Date.now() < 0;
},
fetchAccessToken: async () => {
console.log('✨ Refreshing token...');
try {
void refreshAccessToken();
} catch (error) {
await logout();
}
},
}),
[credentials, logout, refreshAccessToken]
);

return (
<TRPCReactProvider
accessToken={credentials?.accessToken}
source="figma"
trpcLinks={[authTrpcLink]}
>
{children}
</TRPCReactProvider>
);
}
Loading

0 comments on commit ca5309b

Please sign in to comment.