veryfront 0.0.50 → 0.0.52
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/ai/index.js +1 -1
- package/dist/ai/index.js.map +1 -1
- package/dist/ai/workflow.js +1 -1
- package/dist/ai/workflow.js.map +1 -1
- package/dist/cli.js +123 -23
- package/dist/components.js +2 -1
- package/dist/components.js.map +2 -2
- package/dist/config.js +1 -1
- package/dist/config.js.map +1 -1
- package/dist/data.js +1 -1
- package/dist/data.js.map +1 -1
- package/dist/index.js +8 -1
- package/dist/index.js.map +2 -2
- package/dist/integrations/_base/files/app/api/integrations/status/route.ts +3 -3
- package/dist/integrations/_base/files/app/api/integrations/token-storage/route.ts +18 -6
- package/dist/integrations/_base/files/app/page.tsx +128 -0
- package/dist/integrations/_base/files/app/setup/page.tsx +11 -1
- package/dist/integrations/gmail/files/lib/gmail-client.ts +2 -8
- package/dist/templates/ai/app/page.tsx +6 -1
- package/package.json +1 -1
- package/dist/integrations/airtable/files/lib/token-store.ts +0 -5
- package/dist/integrations/asana/files/lib/token-store.ts +0 -11
- package/dist/integrations/bitbucket/files/lib/token-store.ts +0 -5
- package/dist/integrations/box/files/lib/token-store.ts +0 -11
- package/dist/integrations/calendar/files/lib/token-store.ts +0 -5
- package/dist/integrations/clickup/files/lib/token-store.ts +0 -11
- package/dist/integrations/confluence/files/lib/token-store.ts +0 -5
- package/dist/integrations/discord/files/lib/token-store.ts +0 -5
- package/dist/integrations/docs-google/files/lib/token-store.ts +0 -5
- package/dist/integrations/drive/files/lib/token-store.ts +0 -113
- package/dist/integrations/dropbox/files/lib/token-store.ts +0 -5
- package/dist/integrations/figma/files/lib/token-store.ts +0 -5
- package/dist/integrations/freshdesk/files/lib/token-store.ts +0 -11
- package/dist/integrations/github/files/lib/token-store.ts +0 -5
- package/dist/integrations/gitlab/files/lib/token-store.ts +0 -5
- package/dist/integrations/gmail/files/lib/token-store.ts +0 -8
- package/dist/integrations/hubspot/files/lib/token-store.ts +0 -5
- package/dist/integrations/intercom/files/lib/token-store.ts +0 -11
- package/dist/integrations/jira/files/lib/token-store.ts +0 -5
- package/dist/integrations/linear/files/lib/token-store.ts +0 -5
- package/dist/integrations/mailchimp/files/lib/token-store.ts +0 -11
- package/dist/integrations/mixpanel/files/lib/token-store.ts +0 -43
- package/dist/integrations/monday/files/lib/token-store.ts +0 -11
- package/dist/integrations/neon/files/lib/token-store.ts +0 -29
- package/dist/integrations/notion/files/lib/token-store.ts +0 -5
- package/dist/integrations/onedrive/files/lib/token-store.ts +0 -5
- package/dist/integrations/outlook/files/lib/token-store.ts +0 -5
- package/dist/integrations/pipedrive/files/lib/token-store.ts +0 -11
- package/dist/integrations/posthog/files/lib/token-store.ts +0 -21
- package/dist/integrations/quickbooks/files/lib/token-store.ts +0 -11
- package/dist/integrations/salesforce/files/lib/token-store.ts +0 -5
- package/dist/integrations/sentry/files/lib/token-store.ts +0 -29
- package/dist/integrations/servicenow/files/lib/token-store.ts +0 -42
- package/dist/integrations/sharepoint/files/lib/token-store.ts +0 -5
- package/dist/integrations/sheets/files/lib/token-store.ts +0 -5
- package/dist/integrations/shopify/files/lib/token-store.ts +0 -11
- package/dist/integrations/slack/files/lib/token-store.ts +0 -5
- package/dist/integrations/snowflake/files/lib/token-store.ts +0 -77
- package/dist/integrations/stripe/files/lib/token-store.ts +0 -21
- package/dist/integrations/supabase/files/lib/token-store.ts +0 -47
- package/dist/integrations/teams/files/lib/token-store.ts +0 -5
- package/dist/integrations/trello/files/lib/token-store.ts +0 -11
- package/dist/integrations/twilio/files/lib/token-store.ts +0 -60
- package/dist/integrations/twitter/files/lib/token-store.ts +0 -5
- package/dist/integrations/webex/files/lib/token-store.ts +0 -11
- package/dist/integrations/xero/files/lib/token-store.ts +0 -11
- package/dist/integrations/zendesk/files/lib/token-store.ts +0 -47
- package/dist/integrations/zoom/files/lib/token-store.ts +0 -11
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* Used by the setup guide to show which services are connected.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
import { tokenStore } from "../../../../lib/token-store
|
|
8
|
+
import { tokenStore } from "../../../../lib/token-store";
|
|
9
9
|
|
|
10
10
|
// Define available integrations - will be populated based on project config
|
|
11
11
|
const INTEGRATIONS = [
|
|
@@ -23,12 +23,12 @@ export async function GET(_req: Request) {
|
|
|
23
23
|
|
|
24
24
|
const statuses = await Promise.all(
|
|
25
25
|
INTEGRATIONS.map(async (integration) => {
|
|
26
|
-
const
|
|
26
|
+
const connected = await tokenStore.isConnected(userId, integration.id);
|
|
27
27
|
return {
|
|
28
28
|
id: integration.id,
|
|
29
29
|
name: integration.name,
|
|
30
30
|
icon: integration.icon,
|
|
31
|
-
connected
|
|
31
|
+
connected,
|
|
32
32
|
connectUrl: `/api/auth/${integration.id}`,
|
|
33
33
|
};
|
|
34
34
|
}),
|
|
@@ -2,13 +2,25 @@
|
|
|
2
2
|
* Token Storage Status API
|
|
3
3
|
*
|
|
4
4
|
* Returns the current token storage mode and encryption status.
|
|
5
|
+
* This endpoint is self-contained to work with any version of token-store.
|
|
5
6
|
*/
|
|
6
7
|
|
|
7
|
-
import { getStorageMode, isEncryptionEnabled } from "../../../../lib/token-store";
|
|
8
|
-
|
|
9
8
|
export async function GET() {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
9
|
+
// Detect storage mode from environment variables
|
|
10
|
+
const env = process.env;
|
|
11
|
+
let mode: "memory" | "database" | "kv" | "redis" = "memory";
|
|
12
|
+
|
|
13
|
+
if (env.DATABASE_URL) {
|
|
14
|
+
mode = "database";
|
|
15
|
+
} else if (env.KV_REST_API_URL) {
|
|
16
|
+
mode = "kv";
|
|
17
|
+
} else if (env.REDIS_URL) {
|
|
18
|
+
mode = "redis";
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// Check if encryption is enabled
|
|
22
|
+
const encryptionKey = env.TOKEN_ENCRYPTION_KEY;
|
|
23
|
+
const encrypted = typeof encryptionKey === "string" && encryptionKey.length === 64;
|
|
24
|
+
|
|
25
|
+
return Response.json({ mode, encrypted });
|
|
14
26
|
}
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
import { Chat } from 'veryfront/ai/components'
|
|
4
|
+
import { useChat } from 'veryfront/ai/react'
|
|
5
|
+
import { ServiceConnections } from './components/ServiceConnections'
|
|
6
|
+
|
|
7
|
+
// Define services for this project - automatically populated by scaffolding
|
|
8
|
+
// Each integration adds its service here when installed
|
|
9
|
+
const SERVICES = [
|
|
10
|
+
// Services will be dynamically populated based on installed integrations
|
|
11
|
+
// For now, we fetch from the status API instead
|
|
12
|
+
]
|
|
13
|
+
|
|
14
|
+
export default function ChatPage() {
|
|
15
|
+
const chat = useChat({ api: '/api/chat' })
|
|
16
|
+
|
|
17
|
+
return (
|
|
18
|
+
<div className="flex flex-col h-screen bg-white dark:bg-neutral-900">
|
|
19
|
+
{/* Header - sticky at top, full width */}
|
|
20
|
+
<header className="sticky top-0 z-10 flex-shrink-0 border-b border-neutral-200 dark:border-neutral-800 bg-white dark:bg-neutral-900">
|
|
21
|
+
<div className="px-4 py-3 flex items-center justify-between">
|
|
22
|
+
<h1 className="font-medium text-neutral-900 dark:text-white">AI Assistant</h1>
|
|
23
|
+
<div className="flex items-center gap-4">
|
|
24
|
+
<IntegrationStatus />
|
|
25
|
+
<a
|
|
26
|
+
href="/setup"
|
|
27
|
+
className="text-sm text-neutral-500 hover:text-neutral-700 dark:text-neutral-400 dark:hover:text-neutral-200"
|
|
28
|
+
>
|
|
29
|
+
Setup
|
|
30
|
+
</a>
|
|
31
|
+
</div>
|
|
32
|
+
</div>
|
|
33
|
+
</header>
|
|
34
|
+
|
|
35
|
+
{/* Chat - fills remaining space with scrollable content */}
|
|
36
|
+
<Chat {...chat} className="flex-1 min-h-0" placeholder="Message" />
|
|
37
|
+
</div>
|
|
38
|
+
)
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// Component to show integration status from the API
|
|
42
|
+
function IntegrationStatus() {
|
|
43
|
+
// Note: ServiceConnections fetches from /api/auth/status
|
|
44
|
+
// We'll use the integrations/status API which has the full list
|
|
45
|
+
return <ServiceStatusFromAPI />
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
import { useEffect, useState } from 'react'
|
|
49
|
+
|
|
50
|
+
interface Integration {
|
|
51
|
+
id: string
|
|
52
|
+
name: string
|
|
53
|
+
connected: boolean
|
|
54
|
+
connectUrl: string
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function ServiceStatusFromAPI() {
|
|
58
|
+
const [integrations, setIntegrations] = useState<Integration[]>([])
|
|
59
|
+
const [loading, setLoading] = useState(true)
|
|
60
|
+
|
|
61
|
+
useEffect(() => {
|
|
62
|
+
async function fetchStatus() {
|
|
63
|
+
try {
|
|
64
|
+
const res = await fetch('/api/integrations/status')
|
|
65
|
+
if (res.ok) {
|
|
66
|
+
const data = await res.json()
|
|
67
|
+
setIntegrations(data.integrations || [])
|
|
68
|
+
}
|
|
69
|
+
} catch (error) {
|
|
70
|
+
console.error('Failed to fetch integration status:', error)
|
|
71
|
+
} finally {
|
|
72
|
+
setLoading(false)
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
fetchStatus()
|
|
76
|
+
}, [])
|
|
77
|
+
|
|
78
|
+
if (loading) {
|
|
79
|
+
return (
|
|
80
|
+
<div className="flex items-center gap-2">
|
|
81
|
+
<div className="animate-pulse h-6 w-24 bg-neutral-200 dark:bg-neutral-700 rounded-full" />
|
|
82
|
+
</div>
|
|
83
|
+
)
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
if (integrations.length === 0) {
|
|
87
|
+
return null
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
const connected = integrations.filter(i => i.connected)
|
|
91
|
+
const disconnected = integrations.filter(i => !i.connected)
|
|
92
|
+
|
|
93
|
+
return (
|
|
94
|
+
<div className="flex items-center gap-2">
|
|
95
|
+
{/* Show connected services as green badges */}
|
|
96
|
+
{connected.map(service => (
|
|
97
|
+
<span
|
|
98
|
+
key={service.id}
|
|
99
|
+
className="inline-flex items-center gap-1.5 px-2.5 py-1 rounded-full text-xs font-medium bg-green-100 text-green-800 dark:bg-green-900/30 dark:text-green-400"
|
|
100
|
+
title={`${service.name} connected`}
|
|
101
|
+
>
|
|
102
|
+
<span className="w-1.5 h-1.5 rounded-full bg-green-500" />
|
|
103
|
+
{service.name}
|
|
104
|
+
</span>
|
|
105
|
+
))}
|
|
106
|
+
|
|
107
|
+
{/* Show disconnected services as clickable grey badges */}
|
|
108
|
+
{disconnected.map(service => (
|
|
109
|
+
<a
|
|
110
|
+
key={service.id}
|
|
111
|
+
href={service.connectUrl}
|
|
112
|
+
className="inline-flex items-center gap-1.5 px-2.5 py-1 rounded-full text-xs font-medium bg-neutral-100 text-neutral-600 hover:bg-neutral-200 dark:bg-neutral-800 dark:text-neutral-400 dark:hover:bg-neutral-700 transition-colors"
|
|
113
|
+
title={`Connect ${service.name}`}
|
|
114
|
+
>
|
|
115
|
+
<span className="w-1.5 h-1.5 rounded-full bg-neutral-400" />
|
|
116
|
+
{service.name}
|
|
117
|
+
</a>
|
|
118
|
+
))}
|
|
119
|
+
|
|
120
|
+
{/* Show count if not all connected */}
|
|
121
|
+
{disconnected.length > 0 && (
|
|
122
|
+
<span className="text-xs text-neutral-500 dark:text-neutral-400">
|
|
123
|
+
{connected.length}/{integrations.length}
|
|
124
|
+
</span>
|
|
125
|
+
)}
|
|
126
|
+
</div>
|
|
127
|
+
)
|
|
128
|
+
}
|
|
@@ -719,10 +719,16 @@ export default function SetupPage() {
|
|
|
719
719
|
async function fetchStatus() {
|
|
720
720
|
try {
|
|
721
721
|
const res = await fetch("/api/integrations/status");
|
|
722
|
+
if (!res.ok) {
|
|
723
|
+
console.error("Failed to fetch integration status:", res.status);
|
|
724
|
+
setIntegrations([]);
|
|
725
|
+
return;
|
|
726
|
+
}
|
|
722
727
|
const data = await res.json();
|
|
723
|
-
setIntegrations(data.integrations);
|
|
728
|
+
setIntegrations(data.integrations || []);
|
|
724
729
|
} catch (error) {
|
|
725
730
|
console.error("Failed to fetch integration status:", error);
|
|
731
|
+
setIntegrations([]);
|
|
726
732
|
} finally {
|
|
727
733
|
setLoading(false);
|
|
728
734
|
}
|
|
@@ -731,6 +737,10 @@ export default function SetupPage() {
|
|
|
731
737
|
async function fetchTokenStorage() {
|
|
732
738
|
try {
|
|
733
739
|
const res = await fetch("/api/integrations/token-storage");
|
|
740
|
+
if (!res.ok) {
|
|
741
|
+
setTokenStorage({ mode: "memory", encrypted: false });
|
|
742
|
+
return;
|
|
743
|
+
}
|
|
734
744
|
const data = await res.json();
|
|
735
745
|
setTokenStorage(data);
|
|
736
746
|
} catch {
|
|
@@ -46,18 +46,12 @@ const gmailService = new OAuthService(gmailConfig, memoryTokenStore);
|
|
|
46
46
|
* Create a Gmail client for API operations
|
|
47
47
|
*/
|
|
48
48
|
export function createGmailClient() {
|
|
49
|
+
// OAuthService.fetch() already handles auth, error checking, and JSON parsing
|
|
49
50
|
async function apiRequest<T>(
|
|
50
51
|
endpoint: string,
|
|
51
52
|
options: RequestInit = {},
|
|
52
53
|
): Promise<T> {
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
if (!response.ok) {
|
|
56
|
-
const error = await response.text();
|
|
57
|
-
throw new Error(`Gmail API error: ${response.status} - ${error}`);
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
return response.json();
|
|
54
|
+
return gmailService.fetch<T>(endpoint, options);
|
|
61
55
|
}
|
|
62
56
|
|
|
63
57
|
return {
|
|
@@ -12,7 +12,12 @@ export default function ChatPage() {
|
|
|
12
12
|
<header className="sticky top-0 z-10 flex-shrink-0 border-b border-neutral-200 dark:border-neutral-800 bg-white dark:bg-neutral-900">
|
|
13
13
|
<div className="px-4 py-3 flex items-center justify-between">
|
|
14
14
|
<h1 className="font-medium text-neutral-900 dark:text-white">AI Assistant</h1>
|
|
15
|
-
|
|
15
|
+
<a
|
|
16
|
+
href="/setup"
|
|
17
|
+
className="text-sm text-neutral-500 hover:text-neutral-700 dark:text-neutral-400 dark:hover:text-neutral-200"
|
|
18
|
+
>
|
|
19
|
+
Setup
|
|
20
|
+
</a>
|
|
16
21
|
</div>
|
|
17
22
|
</header>
|
|
18
23
|
|
package/package.json
CHANGED
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Asana Token Store
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
export { memoryTokenStore as tokenStore, type OAuthTokens, type TokenStore } from "veryfront/oauth";
|
|
6
|
-
|
|
7
|
-
export async function getAccessToken(): Promise<string | null> {
|
|
8
|
-
const { tokenStore } = await import("./token-store.ts");
|
|
9
|
-
const tokens = await tokenStore.get("asana");
|
|
10
|
-
return tokens?.accessToken ?? null;
|
|
11
|
-
}
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Box Token Store
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
export { memoryTokenStore as tokenStore, type OAuthTokens, type TokenStore } from "veryfront/oauth";
|
|
6
|
-
|
|
7
|
-
export async function getAccessToken(): Promise<string | null> {
|
|
8
|
-
const { tokenStore } = await import("./token-store.ts");
|
|
9
|
-
const tokens = await tokenStore.get("box");
|
|
10
|
-
return tokens?.accessToken ?? null;
|
|
11
|
-
}
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* ClickUp Token Store
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
export { memoryTokenStore as tokenStore, type OAuthTokens, type TokenStore } from "veryfront/oauth";
|
|
6
|
-
|
|
7
|
-
export async function getAccessToken(): Promise<string | null> {
|
|
8
|
-
const { tokenStore } = await import("./token-store.ts");
|
|
9
|
-
const tokens = await tokenStore.get("clickup");
|
|
10
|
-
return tokens?.accessToken ?? null;
|
|
11
|
-
}
|
|
@@ -1,113 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* OAuth Token Store
|
|
3
|
-
*
|
|
4
|
-
* Simple in-memory token store for development.
|
|
5
|
-
* Replace with a database or KV store for production.
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
export interface OAuthToken {
|
|
9
|
-
accessToken: string;
|
|
10
|
-
refreshToken?: string;
|
|
11
|
-
expiresAt?: number;
|
|
12
|
-
tokenType?: string;
|
|
13
|
-
scope?: string;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
export interface TokenStore {
|
|
17
|
-
getToken(userId: string, service: string): Promise<OAuthToken | null>;
|
|
18
|
-
setToken(userId: string, service: string, token: OAuthToken): Promise<void>;
|
|
19
|
-
revokeToken(userId: string, service: string): Promise<void>;
|
|
20
|
-
isConnected(userId: string, service: string): Promise<boolean>;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
// In-memory storage for development
|
|
24
|
-
// Use globalThis to share across esbuild bundles (each API route is bundled separately)
|
|
25
|
-
const TOKENS_KEY = "__veryfront_oauth_tokens__";
|
|
26
|
-
// deno-lint-ignore no-explicit-any
|
|
27
|
-
const globalStore = globalThis as any;
|
|
28
|
-
const tokens: Map<string, OAuthToken> = globalStore[TOKENS_KEY] ||= new Map<string, OAuthToken>();
|
|
29
|
-
|
|
30
|
-
function getKey(userId: string, service: string): string {
|
|
31
|
-
return `${userId}:${service}`;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
/**
|
|
35
|
-
* Simple in-memory token store
|
|
36
|
-
*
|
|
37
|
-
* NOTE: This is for development only. In production, use:
|
|
38
|
-
* - Database (Postgres, SQLite, etc.)
|
|
39
|
-
* - KV store (Cloudflare Workers KV, Vercel KV, etc.)
|
|
40
|
-
* - Encrypted file storage
|
|
41
|
-
*/
|
|
42
|
-
export const tokenStore: TokenStore = {
|
|
43
|
-
getToken(userId: string, service: string): Promise<OAuthToken | null> {
|
|
44
|
-
const key = getKey(userId, service);
|
|
45
|
-
return Promise.resolve(tokens.get(key) || null);
|
|
46
|
-
},
|
|
47
|
-
|
|
48
|
-
setToken(
|
|
49
|
-
userId: string,
|
|
50
|
-
service: string,
|
|
51
|
-
token: OAuthToken,
|
|
52
|
-
): Promise<void> {
|
|
53
|
-
const key = getKey(userId, service);
|
|
54
|
-
tokens.set(key, token);
|
|
55
|
-
return Promise.resolve();
|
|
56
|
-
},
|
|
57
|
-
|
|
58
|
-
revokeToken(userId: string, service: string): Promise<void> {
|
|
59
|
-
const key = getKey(userId, service);
|
|
60
|
-
tokens.delete(key);
|
|
61
|
-
return Promise.resolve();
|
|
62
|
-
},
|
|
63
|
-
|
|
64
|
-
async isConnected(userId: string, service: string): Promise<boolean> {
|
|
65
|
-
const token = await this.getToken(userId, service);
|
|
66
|
-
if (!token) return false;
|
|
67
|
-
// Check if token is not expired (if no expiry, token doesn't expire)
|
|
68
|
-
return !token.expiresAt || token.expiresAt > Date.now();
|
|
69
|
-
},
|
|
70
|
-
};
|
|
71
|
-
|
|
72
|
-
/**
|
|
73
|
-
* Factory function to create a custom token store
|
|
74
|
-
*/
|
|
75
|
-
export function createTokenStore(options: {
|
|
76
|
-
get: (key: string) => Promise<string | null>;
|
|
77
|
-
set: (key: string, value: string) => Promise<void>;
|
|
78
|
-
delete: (key: string) => Promise<void>;
|
|
79
|
-
}): TokenStore {
|
|
80
|
-
return {
|
|
81
|
-
async getToken(userId: string, service: string): Promise<OAuthToken | null> {
|
|
82
|
-
const key = getKey(userId, service);
|
|
83
|
-
const data = await options.get(key);
|
|
84
|
-
if (!data) return null;
|
|
85
|
-
try {
|
|
86
|
-
return JSON.parse(data) as OAuthToken;
|
|
87
|
-
} catch {
|
|
88
|
-
return null;
|
|
89
|
-
}
|
|
90
|
-
},
|
|
91
|
-
|
|
92
|
-
async setToken(
|
|
93
|
-
userId: string,
|
|
94
|
-
service: string,
|
|
95
|
-
token: OAuthToken,
|
|
96
|
-
): Promise<void> {
|
|
97
|
-
const key = getKey(userId, service);
|
|
98
|
-
await options.set(key, JSON.stringify(token));
|
|
99
|
-
},
|
|
100
|
-
|
|
101
|
-
async revokeToken(userId: string, service: string): Promise<void> {
|
|
102
|
-
const key = getKey(userId, service);
|
|
103
|
-
await options.delete(key);
|
|
104
|
-
},
|
|
105
|
-
|
|
106
|
-
async isConnected(userId: string, service: string): Promise<boolean> {
|
|
107
|
-
const token = await this.getToken(userId, service);
|
|
108
|
-
if (!token) return false;
|
|
109
|
-
// Check if token is not expired (if no expiry, token doesn't expire)
|
|
110
|
-
return !token.expiresAt || token.expiresAt > Date.now();
|
|
111
|
-
},
|
|
112
|
-
};
|
|
113
|
-
}
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Freshdesk Token Store
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
export { memoryTokenStore as tokenStore, type OAuthTokens, type TokenStore } from "veryfront/oauth";
|
|
6
|
-
|
|
7
|
-
export async function getAccessToken(): Promise<string | null> {
|
|
8
|
-
const { tokenStore } = await import("./token-store.ts");
|
|
9
|
-
const tokens = await tokenStore.get("freshdesk");
|
|
10
|
-
return tokens?.accessToken ?? null;
|
|
11
|
-
}
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Gmail Token Store
|
|
3
|
-
*
|
|
4
|
-
* Re-exports the shared memory token store from veryfront/oauth.
|
|
5
|
-
* Replace with a custom implementation for production (database, KV, etc.)
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
export { memoryTokenStore as tokenStore, type OAuthTokens, type TokenStore } from "veryfront/oauth";
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Intercom Token Store
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
export { memoryTokenStore as tokenStore, type OAuthTokens, type TokenStore } from "veryfront/oauth";
|
|
6
|
-
|
|
7
|
-
export async function getAccessToken(): Promise<string | null> {
|
|
8
|
-
const { tokenStore } = await import("./token-store.ts");
|
|
9
|
-
const tokens = await tokenStore.get("intercom");
|
|
10
|
-
return tokens?.accessToken ?? null;
|
|
11
|
-
}
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Mailchimp Token Store
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
export { memoryTokenStore as tokenStore, type OAuthTokens, type TokenStore } from "veryfront/oauth";
|
|
6
|
-
|
|
7
|
-
export async function getAccessToken(): Promise<string | null> {
|
|
8
|
-
const { tokenStore } = await import("./token-store.ts");
|
|
9
|
-
const tokens = await tokenStore.get("mailchimp");
|
|
10
|
-
return tokens?.accessToken ?? null;
|
|
11
|
-
}
|
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
// In-memory token store for development
|
|
2
|
-
// For production, replace with a secure database-backed implementation
|
|
3
|
-
|
|
4
|
-
let projectToken: string | null = null;
|
|
5
|
-
let apiSecret: string | null = null;
|
|
6
|
-
let projectId: string | null = null;
|
|
7
|
-
|
|
8
|
-
export function setProjectToken(token: string): void {
|
|
9
|
-
projectToken = token;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
export function getProjectToken(): string | null {
|
|
13
|
-
// Try environment variable first, then in-memory store
|
|
14
|
-
return process.env.MIXPANEL_PROJECT_TOKEN || projectToken;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
export function setApiSecret(secret: string): void {
|
|
18
|
-
apiSecret = secret;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
export function getApiSecret(): string | null {
|
|
22
|
-
// Try environment variable first, then in-memory store
|
|
23
|
-
return process.env.MIXPANEL_API_SECRET || apiSecret;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
export function setProjectId(id: string): void {
|
|
27
|
-
projectId = id;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
export function getProjectId(): string | null {
|
|
31
|
-
// Try environment variable first, then in-memory store
|
|
32
|
-
return process.env.MIXPANEL_PROJECT_ID || projectId;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
export function clearTokens(): void {
|
|
36
|
-
projectToken = null;
|
|
37
|
-
apiSecret = null;
|
|
38
|
-
projectId = null;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
export function isAuthenticated(): boolean {
|
|
42
|
-
return getProjectToken() !== null && getApiSecret() !== null && getProjectId() !== null;
|
|
43
|
-
}
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Monday.com Token Store
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
export { memoryTokenStore as tokenStore, type OAuthTokens, type TokenStore } from "veryfront/oauth";
|
|
6
|
-
|
|
7
|
-
export async function getAccessToken(): Promise<string | null> {
|
|
8
|
-
const { tokenStore } = await import("./token-store.ts");
|
|
9
|
-
const tokens = await tokenStore.get("monday");
|
|
10
|
-
return tokens?.accessToken ?? null;
|
|
11
|
-
}
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
// In-memory token store for development
|
|
2
|
-
// For production, replace with a database-backed implementation
|
|
3
|
-
|
|
4
|
-
interface TokenData {
|
|
5
|
-
apiKey: string;
|
|
6
|
-
databaseUrl?: string;
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
let tokenStore: TokenData | null = null;
|
|
10
|
-
|
|
11
|
-
export function setApiKey(apiKey: string, databaseUrl?: string): void {
|
|
12
|
-
tokenStore = { apiKey, databaseUrl };
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
export function getApiKey(): string | null {
|
|
16
|
-
return tokenStore?.apiKey || null;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
export function getDatabaseUrl(): string | null {
|
|
20
|
-
return tokenStore?.databaseUrl || process.env.DATABASE_URL || null;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
export function clearTokens(): void {
|
|
24
|
-
tokenStore = null;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
export function isAuthenticated(): boolean {
|
|
28
|
-
return tokenStore !== null && tokenStore.apiKey !== null;
|
|
29
|
-
}
|