Skip to content

Commit 67db40f

Browse files
Cleaning up code
1 parent b156115 commit 67db40f

File tree

5 files changed

+213
-258
lines changed

5 files changed

+213
-258
lines changed

docs-v2/components/GlobalConnectProvider.jsx

Lines changed: 32 additions & 103 deletions
Original file line numberDiff line numberDiff line change
@@ -1,105 +1,60 @@
11
"use client";
22

3-
import {
4-
createContext, useContext, useState, useEffect,
5-
} from "react";
3+
import { createContext, useContext, useState, useEffect } from "react";
64
import { createFrontendClient } from "@pipedream/sdk/browser";
7-
import {
8-
getServerCodeSnippet, getClientCodeSnippet,
9-
} from "./ConnectCodeSnippets";
5+
import { getServerCodeSnippet, getClientCodeSnippet } from "./ConnectCodeSnippets";
6+
import { generateConnectToken, fetchAccountDetails } from "./api";
107

11-
// Generate a UUID v4 for use as external_user_id
8+
/**
9+
* Generate a UUID v4 for use as external_user_id
10+
*/
1211
function generateUUID() {
1312
return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, function(c) {
1413
const r = Math.random() * 16 | 0;
15-
const v = c === "x"
16-
? r
17-
: (r & 0x3 | 0x8);
14+
const v = c === "x" ? r : (r & 0x3 | 0x8);
1815
return v.toString(16);
1916
});
2017
}
2118

2219
// Create the context
2320
const GlobalConnectContext = createContext(null);
2421

25-
// Provider component
22+
/**
23+
* Provider component for Connect demo state management
24+
*/
2625
export function GlobalConnectProvider({ children }) {
27-
// User and account state
28-
const [
29-
appSlug,
30-
setAppSlug,
31-
] = useState("slack");
32-
const [
33-
externalUserId,
34-
setExternalUserId,
35-
] = useState("");
36-
const [
37-
connectedAccount,
38-
setConnectedAccount,
39-
] = useState(null);
26+
// User and app state
27+
const [appSlug, setAppSlug] = useState("slack");
28+
const [externalUserId, setExternalUserId] = useState("");
29+
const [connectedAccount, setConnectedAccount] = useState(null);
4030

4131
// Token state
42-
const [
43-
tokenData,
44-
setTokenData,
45-
] = useState(null);
46-
32+
const [tokenData, setTokenData] = useState(null);
33+
4734
// UI state
48-
const [
49-
tokenLoading,
50-
setTokenLoading,
51-
] = useState(false);
52-
const [
53-
error,
54-
setError,
55-
] = useState(null);
35+
const [tokenLoading, setTokenLoading] = useState(false);
36+
const [error, setError] = useState(null);
5637

5738
// Generate a new UUID when the component mounts
5839
useEffect(() => {
5940
setExternalUserId(generateUUID());
6041
}, []);
6142

62-
// Get server code snippet wrapper function
43+
// Get code snippet wrapper functions
6344
const getServerSnippet = () => getServerCodeSnippet(externalUserId);
64-
65-
// Get client code snippet wrapper function
6645
const getClientSnippet = () => getClientCodeSnippet(appSlug, tokenData);
6746

6847
/**
69-
* Generate a request token based on the browser environment
70-
* This creates a token that matches what the API will generate
48+
* Generate a token for the Connect demo
7149
*/
72-
function generateRequestToken() {
73-
const baseString = `${navigator.userAgent}:${window.location.host}:connect-demo`;
74-
return btoa(baseString);
75-
}
76-
77-
// Generate token async function
7850
async function generateToken() {
7951
setTokenLoading(true);
8052
setError(null);
8153
// Clear any previously connected account when generating a new token
8254
setConnectedAccount(null);
8355

8456
try {
85-
const requestToken = generateRequestToken();
86-
const response = await fetch("/docs/api-demo-connect/token", {
87-
method: "POST",
88-
headers: {
89-
"Content-Type": "application/json",
90-
"X-Request-Token": requestToken,
91-
},
92-
body: JSON.stringify({
93-
external_user_id: externalUserId,
94-
}),
95-
});
96-
97-
if (!response.ok) {
98-
const errorData = await response.json();
99-
throw new Error(errorData.error || "Failed to get token");
100-
}
101-
102-
const data = await response.json();
57+
const data = await generateConnectToken(externalUserId);
10358
setTokenData(data);
10459
} catch (err) {
10560
setError(err.message || "An error occurred");
@@ -108,37 +63,9 @@ export function GlobalConnectProvider({ children }) {
10863
}
10964
}
11065

111-
// Fetch account details from API
112-
async function fetchAccountDetails(accountId) {
113-
try {
114-
// Fetch the account details from our API endpoint
115-
const requestToken = generateRequestToken();
116-
const response = await fetch(`/docs/api-demo-connect/accounts/${accountId}`, {
117-
method: "GET",
118-
headers: {
119-
"Content-Type": "application/json",
120-
"X-Request-Token": requestToken,
121-
},
122-
});
123-
124-
if (!response.ok) {
125-
console.warn("Failed to fetch account details", await response.text());
126-
return {
127-
id: accountId,
128-
}; // Fall back to just the ID
129-
}
130-
131-
const data = await response.json();
132-
return data; // Return the full account details
133-
} catch (err) {
134-
console.warn("Error fetching account details:", err);
135-
return {
136-
id: accountId,
137-
}; // Fall back to just the ID
138-
}
139-
}
140-
141-
// Connect account function
66+
/**
67+
* Connect an account using the Pipedream Connect SDK
68+
*/
14269
function connectAccount() {
14370
if (!tokenData?.token) {
14471
setError("Please generate a token first");
@@ -153,7 +80,7 @@ export function GlobalConnectProvider({ children }) {
15380
app: appSlug,
15481
token: tokenData.token,
15582
onSuccess: async (account) => {
156-
// Initialize with just the ID
83+
// Initialize with just the ID and loading state
15784
setConnectedAccount({
15885
id: account.id,
15986
loading: true,
@@ -172,7 +99,7 @@ export function GlobalConnectProvider({ children }) {
17299
setTokenData(null);
173100
},
174101
onError: (err) => {
175-
setError(err.message || "Failed to connect account, please refresh the page and try again.");
102+
setError(err.message || "Failed to connect account");
176103
},
177104
onClose: () => {
178105
// Dialog closed by user - no action needed
@@ -183,8 +110,8 @@ export function GlobalConnectProvider({ children }) {
183110
}
184111
}
185112

186-
// Create value object
187-
const value = {
113+
// Create context value object
114+
const contextValue = {
188115
// State
189116
appSlug,
190117
externalUserId,
@@ -204,13 +131,15 @@ export function GlobalConnectProvider({ children }) {
204131
};
205132

206133
return (
207-
<GlobalConnectContext.Provider value={value}>
134+
<GlobalConnectContext.Provider value={contextValue}>
208135
{children}
209136
</GlobalConnectContext.Provider>
210137
);
211138
}
212139

213-
// Custom hook for using the context
140+
/**
141+
* Custom hook for accessing the Connect demo context
142+
*/
214143
export function useGlobalConnect() {
215144
const context = useContext(GlobalConnectContext);
216145
if (!context) {

docs-v2/components/api.js

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
/**
2+
* API client functions for demo components
3+
*/
4+
5+
/**
6+
* Generate a request token based on the browser environment
7+
* Creates a token that matches what the API will generate
8+
*/
9+
export function generateRequestToken() {
10+
if (typeof window === "undefined") return "";
11+
12+
const baseString = `${navigator.userAgent}:${window.location.host}:connect-demo`;
13+
return btoa(baseString);
14+
}
15+
16+
/**
17+
* Generate a token for the Connect demo
18+
* @param {string} externalUserId - The user ID to associate with the token
19+
* @returns {Promise<Object>} - The token data
20+
*/
21+
export async function generateConnectToken(externalUserId) {
22+
const requestToken = generateRequestToken();
23+
const response = await fetch("/docs/api-demo-connect/token", {
24+
method: "POST",
25+
headers: {
26+
"Content-Type": "application/json",
27+
"X-Request-Token": requestToken,
28+
},
29+
body: JSON.stringify({
30+
external_user_id: externalUserId,
31+
}),
32+
});
33+
34+
if (!response.ok) {
35+
const errorData = await response.json();
36+
throw new Error(errorData.error || "Failed to get token");
37+
}
38+
39+
return await response.json();
40+
}
41+
42+
/**
43+
* Fetch account details from the API
44+
* @param {string} accountId - The account ID to fetch
45+
* @returns {Promise<Object>} - The account details
46+
*/
47+
export async function fetchAccountDetails(accountId) {
48+
const requestToken = generateRequestToken();
49+
const response = await fetch(`/docs/api-demo-connect/accounts/${accountId}`, {
50+
method: "GET",
51+
headers: {
52+
"Content-Type": "application/json",
53+
"X-Request-Token": requestToken,
54+
},
55+
});
56+
57+
if (!response.ok) {
58+
return {
59+
id: accountId,
60+
}; // Fall back to just the ID
61+
}
62+
63+
return await response.json();
64+
}

docs-v2/pages/api/demo-connect/accounts/[id].js

Lines changed: 6 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -3,83 +3,12 @@
33
* Retrieves information about connected accounts for the interactive demo
44
*/
55
import { createBackendClient } from "@pipedream/sdk/server";
6-
7-
// Allowed origins for CORS security
8-
const ALLOWED_ORIGINS = [
9-
"https://pipedream.com",
10-
"https://www.pipedream.com",
11-
"http://localhost:3000", // For local development
12-
];
6+
import { createApiHandler } from "../utils";
137

148
/**
15-
* Generate a browser-specific token based on request properties
16-
* Used to verify requests are coming from our frontend
9+
* Handler for account details retrieval
1710
*/
18-
function generateRequestToken(req) {
19-
const baseString = `${req.headers["user-agent"]}:${req.headers["host"]}:connect-demo`;
20-
return Buffer.from(baseString).toString("base64");
21-
}
22-
23-
/**
24-
* Security middleware to validate requests
25-
* Ensures requests only come from our documentation site
26-
*/
27-
function validateRequest(req, res) {
28-
const origin = req.headers.origin;
29-
const referer = req.headers.referer;
30-
const requestToken = req.headers["x-request-token"];
31-
32-
// Origin validation
33-
if (origin && !ALLOWED_ORIGINS.includes(origin)) {
34-
return res.status(403).json({
35-
error: "Access denied",
36-
});
37-
}
38-
39-
// Referer validation
40-
if (referer && !ALLOWED_ORIGINS.some((allowed) => referer.startsWith(allowed)) &&
41-
!referer.includes("/docs/connect/")) {
42-
return res.status(403).json({
43-
error: "Access denied",
44-
});
45-
}
46-
47-
// Request token validation to prevent API automation
48-
const expectedToken = generateRequestToken(req);
49-
if (!requestToken || requestToken !== expectedToken) {
50-
return res.status(403).json({
51-
error: "Access denied",
52-
});
53-
}
54-
55-
// Method validation
56-
if (req.method !== "GET") {
57-
return res.status(405).json({
58-
error: "Method not allowed",
59-
});
60-
}
61-
62-
// All security checks passed
63-
return null;
64-
}
65-
66-
export default async function handler(req, res) {
67-
// Set CORS headers
68-
res.setHeader("Access-Control-Allow-Origin", ALLOWED_ORIGINS.includes(req.headers.origin)
69-
? req.headers.origin
70-
: "");
71-
res.setHeader("Access-Control-Allow-Methods", "GET, OPTIONS");
72-
res.setHeader("Access-Control-Allow-Headers", "Content-Type, X-Request-Token");
73-
74-
// Handle preflight requests
75-
if (req.method === "OPTIONS") {
76-
return res.status(200).end();
77-
}
78-
79-
// Validate the request
80-
const validationError = validateRequest(req, res);
81-
if (validationError) return validationError;
82-
11+
async function accountHandler(req, res) {
8312
const { id } = req.query;
8413

8514
if (!id) {
@@ -105,10 +34,11 @@ export default async function handler(req, res) {
10534
// Return the account details
10635
return res.status(200).json(accountDetails);
10736
} catch (err) {
108-
console.error("Error fetching account details:", err);
10937
return res.status(500).json({
11038
error: "Failed to fetch account details",
111-
message: err.message,
11239
});
11340
}
11441
}
42+
43+
// Export the handler with validation and CORS
44+
export default createApiHandler(accountHandler, "GET");

0 commit comments

Comments
 (0)