veryfront 0.0.49 → 0.0.51
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/components.js +260 -56
- package/dist/ai/components.js.map +4 -4
- package/dist/ai/index.d.ts +1 -0
- package/dist/ai/index.js +12 -4
- package/dist/ai/index.js.map +2 -2
- package/dist/ai/primitives.js +55 -10
- package/dist/ai/primitives.js.map +3 -3
- package/dist/ai/react.js +140 -1
- package/dist/ai/react.js.map +3 -3
- package/dist/ai/workflow-react.js +458 -0
- package/dist/ai/workflow-react.js.map +7 -0
- package/dist/ai/workflow.js +5422 -0
- package/dist/ai/workflow.js.map +7 -0
- package/dist/cli.js +957 -215
- package/dist/components.js +12 -4
- package/dist/components.js.map +2 -2
- package/dist/config.js +12 -4
- package/dist/config.js.map +2 -2
- package/dist/data.js +12 -4
- package/dist/data.js.map +2 -2
- package/dist/index.js +12 -4
- package/dist/index.js.map +2 -2
- package/dist/integrations/_base/files/SETUP.md +667 -98
- 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 +26 -0
- package/dist/integrations/_base/files/app/components/ServiceConnections.tsx +2 -1
- package/dist/integrations/_base/files/app/setup/page.tsx +869 -55
- package/dist/integrations/_base/files/lib/token-store-examples.ts +435 -0
- package/dist/integrations/_base/files/lib/token-store.ts +273 -23
- package/dist/integrations/airtable/connector.json +99 -0
- package/dist/integrations/airtable/files/ai/tools/create-record.ts +25 -0
- package/dist/integrations/airtable/files/ai/tools/get-base.ts +34 -0
- package/dist/integrations/airtable/files/ai/tools/get-record.ts +23 -0
- package/dist/integrations/airtable/files/ai/tools/list-bases.ts +19 -0
- package/dist/integrations/airtable/files/ai/tools/list-records.ts +47 -0
- package/dist/integrations/airtable/files/app/api/auth/airtable/callback/route.ts +11 -0
- package/dist/integrations/airtable/files/app/api/auth/airtable/route.ts +9 -0
- package/dist/integrations/airtable/files/lib/airtable-client.ts +244 -0
- package/dist/integrations/anthropic/README.md +181 -0
- package/dist/integrations/anthropic/connector.json +88 -0
- package/dist/integrations/anthropic/files/_env.example +4 -0
- package/dist/integrations/anthropic/files/ai/tools/get-organization.ts +36 -0
- package/dist/integrations/anthropic/files/ai/tools/get-usage.ts +100 -0
- package/dist/integrations/anthropic/files/ai/tools/list-api-keys.ts +64 -0
- package/dist/integrations/anthropic/files/ai/tools/list-members.ts +65 -0
- package/dist/integrations/anthropic/files/ai/tools/list-workspaces.ts +35 -0
- package/dist/integrations/anthropic/files/lib/anthropic-admin-client.ts +264 -0
- package/dist/integrations/asana/connector.json +85 -0
- package/dist/integrations/asana/files/_env.example +4 -0
- package/dist/integrations/asana/files/ai/tools/create-task.ts +34 -0
- package/dist/integrations/asana/files/ai/tools/get-task.ts +26 -0
- package/dist/integrations/asana/files/ai/tools/list-projects.ts +26 -0
- package/dist/integrations/asana/files/ai/tools/list-tasks.ts +50 -0
- package/dist/integrations/asana/files/ai/tools/update-task.ts +36 -0
- package/dist/integrations/asana/files/app/api/auth/asana/callback/route.ts +11 -0
- package/dist/integrations/asana/files/app/api/auth/asana/route.ts +7 -0
- package/dist/integrations/asana/files/lib/asana-client.ts +162 -0
- package/dist/integrations/aws/connector.json +72 -0
- package/dist/integrations/aws/files/_env.example +10 -0
- package/dist/integrations/aws/files/ai/tools/get-s3-object.ts +62 -0
- package/dist/integrations/aws/files/ai/tools/list-ec2-instances.ts +56 -0
- package/dist/integrations/aws/files/ai/tools/list-lambda-functions.ts +57 -0
- package/dist/integrations/aws/files/ai/tools/list-s3-buckets.ts +44 -0
- package/dist/integrations/aws/files/ai/tools/list-s3-objects.ts +58 -0
- package/dist/integrations/aws/files/lib/aws-client.ts +255 -0
- package/dist/integrations/bitbucket/connector.json +85 -0
- package/dist/integrations/bitbucket/files/_env.example +9 -0
- package/dist/integrations/bitbucket/files/ai/tools/create-pull-request.ts +83 -0
- package/dist/integrations/bitbucket/files/ai/tools/list-issues.ts +112 -0
- package/dist/integrations/bitbucket/files/ai/tools/list-pull-requests.ts +91 -0
- package/dist/integrations/bitbucket/files/ai/tools/list-repositories.ts +78 -0
- package/dist/integrations/bitbucket/files/app/api/auth/bitbucket/callback/route.ts +11 -0
- package/dist/integrations/bitbucket/files/app/api/auth/bitbucket/route.ts +9 -0
- package/dist/integrations/bitbucket/files/lib/bitbucket-client.ts +316 -0
- package/dist/integrations/box/connector.json +85 -0
- package/dist/integrations/box/files/_env.example +4 -0
- package/dist/integrations/box/files/ai/tools/create-folder.ts +28 -0
- package/dist/integrations/box/files/ai/tools/get-file.ts +29 -0
- package/dist/integrations/box/files/ai/tools/list-files.ts +33 -0
- package/dist/integrations/box/files/ai/tools/search-files.ts +35 -0
- package/dist/integrations/box/files/ai/tools/upload-file.ts +32 -0
- package/dist/integrations/box/files/app/api/auth/box/callback/route.ts +11 -0
- package/dist/integrations/box/files/app/api/auth/box/route.ts +7 -0
- package/dist/integrations/box/files/lib/box-client.ts +280 -0
- package/dist/integrations/calendar/files/app/api/auth/calendar/callback/route.ts +7 -110
- package/dist/integrations/calendar/files/app/api/auth/calendar/route.ts +5 -25
- package/dist/integrations/clickup/connector.json +85 -0
- package/dist/integrations/clickup/files/_env.example +4 -0
- package/dist/integrations/clickup/files/ai/tools/create-task.ts +64 -0
- package/dist/integrations/clickup/files/ai/tools/get-task.ts +59 -0
- package/dist/integrations/clickup/files/ai/tools/list-lists.ts +109 -0
- package/dist/integrations/clickup/files/ai/tools/list-tasks.ts +95 -0
- package/dist/integrations/clickup/files/ai/tools/update-task.ts +85 -0
- package/dist/integrations/clickup/files/app/api/auth/clickup/callback/route.ts +11 -0
- package/dist/integrations/clickup/files/app/api/auth/clickup/route.ts +7 -0
- package/dist/integrations/clickup/files/lib/clickup-client.ts +439 -0
- package/dist/integrations/confluence/README.md +246 -0
- package/dist/integrations/confluence/connector.json +104 -0
- package/dist/integrations/confluence/files/_env.example +4 -0
- package/dist/integrations/confluence/files/ai/tools/create-page.ts +43 -0
- package/dist/integrations/confluence/files/ai/tools/get-page.ts +30 -0
- package/dist/integrations/confluence/files/ai/tools/list-spaces.ts +31 -0
- package/dist/integrations/confluence/files/ai/tools/search-content.ts +38 -0
- package/dist/integrations/confluence/files/ai/tools/update-page.ts +45 -0
- package/dist/integrations/confluence/files/app/api/auth/confluence/callback/route.ts +11 -0
- package/dist/integrations/confluence/files/app/api/auth/confluence/route.ts +9 -0
- package/dist/integrations/confluence/files/lib/confluence-client.ts +281 -0
- package/dist/integrations/discord/connector.json +100 -0
- package/dist/integrations/discord/files/_env.example +12 -0
- package/dist/integrations/discord/files/ai/tools/get-messages.ts +55 -0
- package/dist/integrations/discord/files/ai/tools/get-user.ts +32 -0
- package/dist/integrations/discord/files/ai/tools/list-channels.ts +32 -0
- package/dist/integrations/discord/files/ai/tools/list-guilds.ts +24 -0
- package/dist/integrations/discord/files/ai/tools/send-message.ts +33 -0
- package/dist/integrations/discord/files/app/api/auth/discord/callback/route.ts +11 -0
- package/dist/integrations/discord/files/app/api/auth/discord/route.ts +9 -0
- package/dist/integrations/discord/files/lib/discord-client.ts +273 -0
- package/dist/integrations/docs-google/connector.json +101 -0
- package/dist/integrations/docs-google/files/_env.example +8 -0
- package/dist/integrations/docs-google/files/ai/tools/create-document.ts +46 -0
- package/dist/integrations/docs-google/files/ai/tools/get-document.ts +46 -0
- package/dist/integrations/docs-google/files/ai/tools/list-documents.ts +42 -0
- package/dist/integrations/docs-google/files/ai/tools/search-documents.ts +38 -0
- package/dist/integrations/docs-google/files/ai/tools/update-document.ts +131 -0
- package/dist/integrations/docs-google/files/app/api/auth/docs-google/callback/route.ts +11 -0
- package/dist/integrations/docs-google/files/app/api/auth/docs-google/route.ts +9 -0
- package/dist/integrations/docs-google/files/lib/docs-client.ts +582 -0
- package/dist/integrations/drive/connector.json +134 -0
- package/dist/integrations/drive/files/_env.example +9 -0
- package/dist/integrations/drive/files/ai/tools/create-folder.ts +47 -0
- package/dist/integrations/drive/files/ai/tools/get-file.ts +55 -0
- package/dist/integrations/drive/files/ai/tools/list-files.ts +78 -0
- package/dist/integrations/drive/files/ai/tools/search-files.ts +79 -0
- package/dist/integrations/drive/files/ai/tools/upload-file.ts +59 -0
- package/dist/integrations/drive/files/app/api/auth/drive/callback/route.ts +11 -0
- package/dist/integrations/drive/files/app/api/auth/drive/route.ts +9 -0
- package/dist/integrations/drive/files/lib/drive-client.ts +359 -0
- package/dist/integrations/dropbox/connector.json +107 -0
- package/dist/integrations/dropbox/files/_env.example +24 -0
- package/dist/integrations/dropbox/files/ai/tools/get-account.ts +58 -0
- package/dist/integrations/dropbox/files/ai/tools/get-file.ts +61 -0
- package/dist/integrations/dropbox/files/ai/tools/list-files.ts +56 -0
- package/dist/integrations/dropbox/files/ai/tools/search-files.ts +70 -0
- package/dist/integrations/dropbox/files/ai/tools/upload-file.ts +48 -0
- package/dist/integrations/dropbox/files/app/api/auth/dropbox/callback/route.ts +11 -0
- package/dist/integrations/dropbox/files/app/api/auth/dropbox/route.ts +9 -0
- package/dist/integrations/dropbox/files/lib/dropbox-client.ts +397 -0
- package/dist/integrations/figma/INTEGRATION_SUMMARY.md +436 -0
- package/dist/integrations/figma/README.md +287 -0
- package/dist/integrations/figma/connector.json +100 -0
- package/dist/integrations/figma/files/_env.example +5 -0
- package/dist/integrations/figma/files/ai/tools/get-comments.ts +72 -0
- package/dist/integrations/figma/files/ai/tools/get-file.ts +54 -0
- package/dist/integrations/figma/files/ai/tools/list-files.ts +39 -0
- package/dist/integrations/figma/files/ai/tools/list-projects.ts +69 -0
- package/dist/integrations/figma/files/ai/tools/post-comment.ts +54 -0
- package/dist/integrations/figma/files/app/api/auth/figma/callback/route.ts +11 -0
- package/dist/integrations/figma/files/app/api/auth/figma/route.ts +9 -0
- package/dist/integrations/figma/files/lib/figma-client.ts +355 -0
- package/dist/integrations/figma/files/lib/types.ts +503 -0
- package/dist/integrations/freshdesk/connector.json +85 -0
- package/dist/integrations/freshdesk/files/_env.example +4 -0
- package/dist/integrations/freshdesk/files/ai/tools/create-ticket.ts +60 -0
- package/dist/integrations/freshdesk/files/ai/tools/get-ticket.ts +46 -0
- package/dist/integrations/freshdesk/files/ai/tools/list-contacts.ts +37 -0
- package/dist/integrations/freshdesk/files/ai/tools/list-tickets.ts +59 -0
- package/dist/integrations/freshdesk/files/ai/tools/update-ticket.ts +61 -0
- package/dist/integrations/freshdesk/files/app/api/auth/freshdesk/callback/route.ts +11 -0
- package/dist/integrations/freshdesk/files/app/api/auth/freshdesk/route.ts +7 -0
- package/dist/integrations/freshdesk/files/lib/freshdesk-client.ts +178 -0
- package/dist/integrations/github/files/app/api/auth/github/callback/route.ts +6 -127
- package/dist/integrations/github/files/app/api/auth/github/route.ts +4 -24
- package/dist/integrations/gitlab/connector.json +100 -0
- package/dist/integrations/gitlab/files/_env.example +7 -0
- package/dist/integrations/gitlab/files/ai/tools/create-issue.ts +49 -0
- package/dist/integrations/gitlab/files/ai/tools/get-issue.ts +56 -0
- package/dist/integrations/gitlab/files/ai/tools/list-merge-requests.ts +75 -0
- package/dist/integrations/gitlab/files/ai/tools/list-projects.ts +51 -0
- package/dist/integrations/gitlab/files/ai/tools/search-issues.ts +67 -0
- package/dist/integrations/gitlab/files/app/api/auth/gitlab/callback/route.ts +11 -0
- package/dist/integrations/gitlab/files/app/api/auth/gitlab/route.ts +9 -0
- package/dist/integrations/gitlab/files/lib/gitlab-client.ts +366 -0
- package/dist/integrations/gmail/files/app/api/auth/gmail/callback/route.ts +7 -108
- package/dist/integrations/gmail/files/app/api/auth/gmail/route.ts +5 -23
- package/dist/integrations/gmail/files/lib/gmail-client.ts +16 -55
- package/dist/integrations/hubspot/connector.json +98 -0
- package/dist/integrations/hubspot/files/_env.example +5 -0
- package/dist/integrations/hubspot/files/ai/tools/create-contact.ts +41 -0
- package/dist/integrations/hubspot/files/ai/tools/create-deal.ts +41 -0
- package/dist/integrations/hubspot/files/ai/tools/get-contact.ts +39 -0
- package/dist/integrations/hubspot/files/ai/tools/list-contacts.ts +43 -0
- package/dist/integrations/hubspot/files/ai/tools/list-deals.ts +41 -0
- package/dist/integrations/hubspot/files/app/api/auth/hubspot/callback/route.ts +11 -0
- package/dist/integrations/hubspot/files/app/api/auth/hubspot/route.ts +9 -0
- package/dist/integrations/hubspot/files/lib/hubspot-client.ts +393 -0
- package/dist/integrations/intercom/connector.json +85 -0
- package/dist/integrations/intercom/files/_env.example +4 -0
- package/dist/integrations/intercom/files/ai/tools/get-contact.ts +35 -0
- package/dist/integrations/intercom/files/ai/tools/get-conversation.ts +55 -0
- package/dist/integrations/intercom/files/ai/tools/list-contacts.ts +35 -0
- package/dist/integrations/intercom/files/ai/tools/list-conversations.ts +49 -0
- package/dist/integrations/intercom/files/ai/tools/send-message.ts +34 -0
- package/dist/integrations/intercom/files/app/api/auth/intercom/callback/route.ts +11 -0
- package/dist/integrations/intercom/files/app/api/auth/intercom/route.ts +7 -0
- package/dist/integrations/intercom/files/lib/intercom-client.ts +308 -0
- package/dist/integrations/jira/connector.json +109 -0
- package/dist/integrations/jira/files/ai/tools/create-issue.ts +47 -0
- package/dist/integrations/jira/files/ai/tools/get-issue.ts +57 -0
- package/dist/integrations/jira/files/ai/tools/list-projects.ts +30 -0
- package/dist/integrations/jira/files/ai/tools/search-issues.ts +49 -0
- package/dist/integrations/jira/files/ai/tools/update-issue.ts +81 -0
- package/dist/integrations/jira/files/app/api/auth/jira/callback/route.ts +11 -0
- package/dist/integrations/jira/files/app/api/auth/jira/route.ts +9 -0
- package/dist/integrations/jira/files/lib/jira-client.ts +338 -0
- package/dist/integrations/linear/connector.json +100 -0
- package/dist/integrations/linear/files/_env.example +6 -0
- package/dist/integrations/linear/files/ai/tools/create-issue.ts +71 -0
- package/dist/integrations/linear/files/ai/tools/get-issue.ts +55 -0
- package/dist/integrations/linear/files/ai/tools/list-projects.ts +43 -0
- package/dist/integrations/linear/files/ai/tools/search-issues.ts +54 -0
- package/dist/integrations/linear/files/ai/tools/update-issue.ts +71 -0
- package/dist/integrations/linear/files/app/api/auth/linear/callback/route.ts +11 -0
- package/dist/integrations/linear/files/app/api/auth/linear/route.ts +9 -0
- package/dist/integrations/linear/files/lib/linear-client.ts +464 -0
- package/dist/integrations/mailchimp/connector.json +85 -0
- package/dist/integrations/mailchimp/files/_env.example +4 -0
- package/dist/integrations/mailchimp/files/ai/tools/get-campaign.ts +45 -0
- package/dist/integrations/mailchimp/files/ai/tools/get-list.ts +51 -0
- package/dist/integrations/mailchimp/files/ai/tools/list-campaigns.ts +46 -0
- package/dist/integrations/mailchimp/files/ai/tools/list-lists.ts +46 -0
- package/dist/integrations/mailchimp/files/ai/tools/list-members.ts +58 -0
- package/dist/integrations/mailchimp/files/app/api/auth/mailchimp/callback/route.ts +11 -0
- package/dist/integrations/mailchimp/files/app/api/auth/mailchimp/route.ts +7 -0
- package/dist/integrations/mailchimp/files/lib/mailchimp-client.ts +267 -0
- package/dist/integrations/mixpanel/connector.json +96 -0
- package/dist/integrations/mixpanel/files/_env.example +11 -0
- package/dist/integrations/mixpanel/files/ai/tools/get-funnel.ts +46 -0
- package/dist/integrations/mixpanel/files/ai/tools/get-retention.ts +64 -0
- package/dist/integrations/mixpanel/files/ai/tools/list-cohorts.ts +46 -0
- package/dist/integrations/mixpanel/files/ai/tools/query-events.ts +43 -0
- package/dist/integrations/mixpanel/files/ai/tools/track-event.ts +41 -0
- package/dist/integrations/mixpanel/files/lib/mixpanel-client.ts +319 -0
- package/dist/integrations/monday/connector.json +85 -0
- package/dist/integrations/monday/files/_env.example +4 -0
- package/dist/integrations/monday/files/ai/tools/create-item.ts +36 -0
- package/dist/integrations/monday/files/ai/tools/get-item.ts +31 -0
- package/dist/integrations/monday/files/ai/tools/list-boards.ts +29 -0
- package/dist/integrations/monday/files/ai/tools/list-items.ts +36 -0
- package/dist/integrations/monday/files/ai/tools/update-item.ts +36 -0
- package/dist/integrations/monday/files/app/api/auth/monday/callback/route.ts +11 -0
- package/dist/integrations/monday/files/app/api/auth/monday/route.ts +7 -0
- package/dist/integrations/monday/files/lib/monday-client.ts +329 -0
- package/dist/integrations/neon/connector.json +89 -0
- package/dist/integrations/neon/files/_env.example +6 -0
- package/dist/integrations/neon/files/ai/tools/describe-table.ts +38 -0
- package/dist/integrations/neon/files/ai/tools/list-branches.ts +35 -0
- package/dist/integrations/neon/files/ai/tools/list-projects.ts +31 -0
- package/dist/integrations/neon/files/ai/tools/list-tables.ts +49 -0
- package/dist/integrations/neon/files/ai/tools/query-database.ts +33 -0
- package/dist/integrations/neon/files/app/api/auth/neon/route.ts +51 -0
- package/dist/integrations/neon/files/lib/neon-client.ts +294 -0
- package/dist/integrations/notion/connector.json +87 -0
- package/dist/integrations/notion/files/_env.example +6 -0
- package/dist/integrations/notion/files/ai/tools/create-page.ts +32 -0
- package/dist/integrations/notion/files/ai/tools/query-database.ts +44 -0
- package/dist/integrations/notion/files/ai/tools/read-page.ts +34 -0
- package/dist/integrations/notion/files/ai/tools/search-notion.ts +51 -0
- package/dist/integrations/notion/files/app/api/auth/notion/callback/route.ts +11 -0
- package/dist/integrations/notion/files/app/api/auth/notion/route.ts +9 -0
- package/dist/integrations/notion/files/lib/notion-client.ts +218 -0
- package/dist/integrations/onedrive/connector.json +100 -0
- package/dist/integrations/onedrive/files/_env.example +23 -0
- package/dist/integrations/onedrive/files/ai/tools/download-file.ts +38 -0
- package/dist/integrations/onedrive/files/ai/tools/list-files.ts +63 -0
- package/dist/integrations/onedrive/files/ai/tools/search-files.ts +59 -0
- package/dist/integrations/onedrive/files/ai/tools/upload-file.ts +43 -0
- package/dist/integrations/onedrive/files/app/api/auth/onedrive/callback/route.ts +11 -0
- package/dist/integrations/onedrive/files/app/api/auth/onedrive/route.ts +9 -0
- package/dist/integrations/onedrive/files/lib/onedrive-client.ts +314 -0
- package/dist/integrations/outlook/README.md +308 -0
- package/dist/integrations/outlook/connector.json +98 -0
- package/dist/integrations/outlook/files/_env.example +8 -0
- package/dist/integrations/outlook/files/ai/tools/get-email.ts +47 -0
- package/dist/integrations/outlook/files/ai/tools/list-emails.ts +46 -0
- package/dist/integrations/outlook/files/ai/tools/list-folders.ts +22 -0
- package/dist/integrations/outlook/files/ai/tools/search-emails.ts +41 -0
- package/dist/integrations/outlook/files/ai/tools/send-email.ts +41 -0
- package/dist/integrations/outlook/files/app/api/auth/outlook/callback/route.ts +11 -0
- package/dist/integrations/outlook/files/app/api/auth/outlook/route.ts +9 -0
- package/dist/integrations/outlook/files/lib/outlook-client.ts +204 -0
- package/dist/integrations/pipedrive/connector.json +85 -0
- package/dist/integrations/pipedrive/files/_env.example +4 -0
- package/dist/integrations/pipedrive/files/ai/tools/create-deal.ts +44 -0
- package/dist/integrations/pipedrive/files/ai/tools/get-deal.ts +34 -0
- package/dist/integrations/pipedrive/files/ai/tools/list-deals.ts +40 -0
- package/dist/integrations/pipedrive/files/ai/tools/list-persons.ts +33 -0
- package/dist/integrations/pipedrive/files/ai/tools/update-deal.ts +46 -0
- package/dist/integrations/pipedrive/files/app/api/auth/pipedrive/callback/route.ts +11 -0
- package/dist/integrations/pipedrive/files/app/api/auth/pipedrive/route.ts +7 -0
- package/dist/integrations/pipedrive/files/lib/pipedrive-client.ts +259 -0
- package/dist/integrations/posthog/connector.json +84 -0
- package/dist/integrations/posthog/files/_env.example +6 -0
- package/dist/integrations/posthog/files/ai/tools/capture-event.ts +37 -0
- package/dist/integrations/posthog/files/ai/tools/get-trends.ts +44 -0
- package/dist/integrations/posthog/files/ai/tools/list-feature-flags.ts +38 -0
- package/dist/integrations/posthog/files/ai/tools/list-persons.ts +32 -0
- package/dist/integrations/posthog/files/lib/posthog-client.ts +286 -0
- package/dist/integrations/quickbooks/connector.json +85 -0
- package/dist/integrations/quickbooks/files/_env.example +4 -0
- package/dist/integrations/quickbooks/files/ai/tools/create-invoice.ts +48 -0
- package/dist/integrations/quickbooks/files/ai/tools/get-customer.ts +36 -0
- package/dist/integrations/quickbooks/files/ai/tools/get-invoice.ts +46 -0
- package/dist/integrations/quickbooks/files/ai/tools/list-customers.ts +37 -0
- package/dist/integrations/quickbooks/files/ai/tools/list-invoices.ts +40 -0
- package/dist/integrations/quickbooks/files/app/api/auth/quickbooks/callback/route.ts +11 -0
- package/dist/integrations/quickbooks/files/app/api/auth/quickbooks/route.ts +7 -0
- package/dist/integrations/quickbooks/files/lib/quickbooks-client.ts +252 -0
- package/dist/integrations/salesforce/connector.json +104 -0
- package/dist/integrations/salesforce/files/ai/tools/create-lead.ts +101 -0
- package/dist/integrations/salesforce/files/ai/tools/get-account.ts +53 -0
- package/dist/integrations/salesforce/files/ai/tools/list-accounts.ts +50 -0
- package/dist/integrations/salesforce/files/ai/tools/list-contacts.ts +54 -0
- package/dist/integrations/salesforce/files/ai/tools/list-opportunities.ts +55 -0
- package/dist/integrations/salesforce/files/app/api/auth/salesforce/callback/route.ts +11 -0
- package/dist/integrations/salesforce/files/app/api/auth/salesforce/route.ts +9 -0
- package/dist/integrations/salesforce/files/lib/salesforce-client.ts +539 -0
- package/dist/integrations/sentry/connector.json +84 -0
- package/dist/integrations/sentry/files/_env.example +6 -0
- package/dist/integrations/sentry/files/ai/tools/get-issue.ts +66 -0
- package/dist/integrations/sentry/files/ai/tools/list-issues.ts +57 -0
- package/dist/integrations/sentry/files/ai/tools/list-projects.ts +32 -0
- package/dist/integrations/sentry/files/ai/tools/resolve-issue.ts +28 -0
- package/dist/integrations/sentry/files/lib/sentry-client.ts +268 -0
- package/dist/integrations/servicenow/connector.json +66 -0
- package/dist/integrations/servicenow/files/_env.example +5 -0
- package/dist/integrations/servicenow/files/ai/tools/create-incident.ts +58 -0
- package/dist/integrations/servicenow/files/ai/tools/get-incident.ts +59 -0
- package/dist/integrations/servicenow/files/ai/tools/list-incidents.ts +72 -0
- package/dist/integrations/servicenow/files/ai/tools/search-knowledge.ts +48 -0
- package/dist/integrations/servicenow/files/ai/tools/update-incident.ts +60 -0
- package/dist/integrations/servicenow/files/app/api/auth/servicenow/callback/route.ts +89 -0
- package/dist/integrations/servicenow/files/app/api/auth/servicenow/route.ts +42 -0
- package/dist/integrations/servicenow/files/lib/servicenow-client.ts +239 -0
- package/dist/integrations/sharepoint/connector.json +99 -0
- package/dist/integrations/sharepoint/files/ai/tools/get-file.ts +93 -0
- package/dist/integrations/sharepoint/files/ai/tools/get-site.ts +51 -0
- package/dist/integrations/sharepoint/files/ai/tools/list-files.ts +63 -0
- package/dist/integrations/sharepoint/files/ai/tools/list-sites.ts +28 -0
- package/dist/integrations/sharepoint/files/ai/tools/upload-file.ts +72 -0
- package/dist/integrations/sharepoint/files/app/api/auth/sharepoint/callback/route.ts +11 -0
- package/dist/integrations/sharepoint/files/app/api/auth/sharepoint/route.ts +9 -0
- package/dist/integrations/sharepoint/files/lib/sharepoint-client.ts +420 -0
- package/dist/integrations/sheets/README.md +331 -0
- package/dist/integrations/sheets/connector.json +99 -0
- package/dist/integrations/sheets/files/_env.example +8 -0
- package/dist/integrations/sheets/files/ai/tools/create-spreadsheet.ts +85 -0
- package/dist/integrations/sheets/files/ai/tools/get-spreadsheet.ts +39 -0
- package/dist/integrations/sheets/files/ai/tools/list-spreadsheets.ts +41 -0
- package/dist/integrations/sheets/files/ai/tools/read-range.ts +35 -0
- package/dist/integrations/sheets/files/ai/tools/write-range.ts +51 -0
- package/dist/integrations/sheets/files/app/api/auth/sheets/callback/route.ts +11 -0
- package/dist/integrations/sheets/files/app/api/auth/sheets/route.ts +9 -0
- package/dist/integrations/sheets/files/lib/sheets-client.ts +425 -0
- package/dist/integrations/shopify/connector.json +99 -0
- package/dist/integrations/shopify/files/_env.example +5 -0
- package/dist/integrations/shopify/files/ai/tools/get-order.ts +49 -0
- package/dist/integrations/shopify/files/ai/tools/get-product.ts +39 -0
- package/dist/integrations/shopify/files/ai/tools/list-customers.ts +40 -0
- package/dist/integrations/shopify/files/ai/tools/list-orders.ts +52 -0
- package/dist/integrations/shopify/files/ai/tools/list-products.ts +39 -0
- package/dist/integrations/shopify/files/app/api/auth/shopify/callback/route.ts +11 -0
- package/dist/integrations/shopify/files/app/api/auth/shopify/route.ts +7 -0
- package/dist/integrations/shopify/files/lib/shopify-client.ts +198 -0
- package/dist/integrations/slack/files/app/api/auth/slack/callback/route.ts +6 -127
- package/dist/integrations/slack/files/app/api/auth/slack/route.ts +4 -24
- package/dist/integrations/snowflake/connector.json +151 -0
- package/dist/integrations/snowflake/files/_env.example +16 -0
- package/dist/integrations/snowflake/files/ai/tools/describe-table.ts +57 -0
- package/dist/integrations/snowflake/files/ai/tools/list-databases.ts +34 -0
- package/dist/integrations/snowflake/files/ai/tools/list-schemas.ts +40 -0
- package/dist/integrations/snowflake/files/ai/tools/list-tables.ts +49 -0
- package/dist/integrations/snowflake/files/ai/tools/run-query.ts +119 -0
- package/dist/integrations/snowflake/files/lib/snowflake-client.ts +389 -0
- package/dist/integrations/stripe/connector.json +97 -0
- package/dist/integrations/stripe/files/_env.example +6 -0
- package/dist/integrations/stripe/files/ai/tools/get-balance.ts +28 -0
- package/dist/integrations/stripe/files/ai/tools/get-customer.ts +26 -0
- package/dist/integrations/stripe/files/ai/tools/list-customers.ts +42 -0
- package/dist/integrations/stripe/files/ai/tools/list-payments.ts +45 -0
- package/dist/integrations/stripe/files/ai/tools/list-subscriptions.ts +67 -0
- package/dist/integrations/stripe/files/app/api/auth/stripe/route.ts +71 -0
- package/dist/integrations/stripe/files/lib/stripe-client.ts +376 -0
- package/dist/integrations/supabase/connector.json +101 -0
- package/dist/integrations/supabase/files/_env.example +6 -0
- package/dist/integrations/supabase/files/ai/tools/delete-row.ts +77 -0
- package/dist/integrations/supabase/files/ai/tools/insert-row.ts +35 -0
- package/dist/integrations/supabase/files/ai/tools/list-tables.ts +60 -0
- package/dist/integrations/supabase/files/ai/tools/query-table.ts +48 -0
- package/dist/integrations/supabase/files/ai/tools/update-row.ts +64 -0
- package/dist/integrations/supabase/files/app/api/auth/supabase/route.ts +91 -0
- package/dist/integrations/supabase/files/lib/supabase-client.ts +296 -0
- package/dist/integrations/teams/README.md +256 -0
- package/dist/integrations/teams/connector.json +99 -0
- package/dist/integrations/teams/files/ai/tools/get-messages.ts +55 -0
- package/dist/integrations/teams/files/ai/tools/list-channels.ts +28 -0
- package/dist/integrations/teams/files/ai/tools/list-chats.ts +41 -0
- package/dist/integrations/teams/files/ai/tools/list-teams.ts +27 -0
- package/dist/integrations/teams/files/ai/tools/send-message.ts +61 -0
- package/dist/integrations/teams/files/app/api/auth/teams/callback/route.ts +11 -0
- package/dist/integrations/teams/files/app/api/auth/teams/route.ts +9 -0
- package/dist/integrations/teams/files/lib/teams-client.ts +345 -0
- package/dist/integrations/trello/connector.json +85 -0
- package/dist/integrations/trello/files/_env.example +4 -0
- package/dist/integrations/trello/files/ai/tools/create-card.ts +54 -0
- package/dist/integrations/trello/files/ai/tools/get-card.ts +33 -0
- package/dist/integrations/trello/files/ai/tools/list-boards.ts +29 -0
- package/dist/integrations/trello/files/ai/tools/list-cards.ts +52 -0
- package/dist/integrations/trello/files/ai/tools/update-card.ts +65 -0
- package/dist/integrations/trello/files/app/api/auth/trello/callback/route.ts +11 -0
- package/dist/integrations/trello/files/app/api/auth/trello/route.ts +7 -0
- package/dist/integrations/trello/files/lib/trello-client.ts +202 -0
- package/dist/integrations/twilio/connector.json +146 -0
- package/dist/integrations/twilio/files/_env.example +14 -0
- package/dist/integrations/twilio/files/ai/tools/get-message.ts +58 -0
- package/dist/integrations/twilio/files/ai/tools/list-calls.ts +129 -0
- package/dist/integrations/twilio/files/ai/tools/list-messages.ts +97 -0
- package/dist/integrations/twilio/files/ai/tools/send-sms.ts +75 -0
- package/dist/integrations/twilio/files/ai/tools/send-whatsapp.ts +81 -0
- package/dist/integrations/twilio/files/lib/twilio-client.ts +375 -0
- package/dist/integrations/twitter/connector.json +87 -0
- package/dist/integrations/twitter/files/_env.example +6 -0
- package/dist/integrations/twitter/files/ai/tools/get-timeline.ts +59 -0
- package/dist/integrations/twitter/files/ai/tools/post-tweet.ts +49 -0
- package/dist/integrations/twitter/files/ai/tools/search-tweets.ts +71 -0
- package/dist/integrations/twitter/files/app/api/auth/twitter/callback/route.ts +11 -0
- package/dist/integrations/twitter/files/app/api/auth/twitter/route.ts +9 -0
- package/dist/integrations/twitter/files/lib/twitter-client.ts +236 -0
- package/dist/integrations/webex/connector.json +85 -0
- package/dist/integrations/webex/files/_env.example +4 -0
- package/dist/integrations/webex/files/ai/tools/create-meeting.ts +69 -0
- package/dist/integrations/webex/files/ai/tools/get-meeting.ts +31 -0
- package/dist/integrations/webex/files/ai/tools/list-meetings.ts +44 -0
- package/dist/integrations/webex/files/ai/tools/list-rooms.ts +35 -0
- package/dist/integrations/webex/files/ai/tools/send-message.ts +51 -0
- package/dist/integrations/webex/files/app/api/auth/webex/callback/route.ts +11 -0
- package/dist/integrations/webex/files/app/api/auth/webex/route.ts +7 -0
- package/dist/integrations/webex/files/lib/webex-client.ts +279 -0
- package/dist/integrations/xero/connector.json +85 -0
- package/dist/integrations/xero/files/_env.example +4 -0
- package/dist/integrations/xero/files/ai/tools/create-invoice.ts +65 -0
- package/dist/integrations/xero/files/ai/tools/get-contact.ts +40 -0
- package/dist/integrations/xero/files/ai/tools/get-invoice.ts +44 -0
- package/dist/integrations/xero/files/ai/tools/list-contacts.ts +54 -0
- package/dist/integrations/xero/files/ai/tools/list-invoices.ts +54 -0
- package/dist/integrations/xero/files/app/api/auth/xero/callback/route.ts +11 -0
- package/dist/integrations/xero/files/app/api/auth/xero/route.ts +7 -0
- package/dist/integrations/xero/files/lib/xero-client.ts +292 -0
- package/dist/integrations/zendesk/connector.json +61 -0
- package/dist/integrations/zendesk/files/_env.example +5 -0
- package/dist/integrations/zendesk/files/ai/tools/create-ticket.ts +82 -0
- package/dist/integrations/zendesk/files/ai/tools/get-ticket.ts +53 -0
- package/dist/integrations/zendesk/files/ai/tools/list-tickets.ts +60 -0
- package/dist/integrations/zendesk/files/ai/tools/search-tickets.ts +56 -0
- package/dist/integrations/zendesk/files/app/api/auth/zendesk/callback/route.ts +91 -0
- package/dist/integrations/zendesk/files/app/api/auth/zendesk/route.ts +41 -0
- package/dist/integrations/zendesk/files/lib/zendesk-client.ts +265 -0
- package/dist/integrations/zoom/connector.json +85 -0
- package/dist/integrations/zoom/files/_env.example +4 -0
- package/dist/integrations/zoom/files/ai/tools/create-meeting.ts +106 -0
- package/dist/integrations/zoom/files/ai/tools/delete-meeting.ts +32 -0
- package/dist/integrations/zoom/files/ai/tools/get-meeting.ts +44 -0
- package/dist/integrations/zoom/files/ai/tools/list-meetings.ts +47 -0
- package/dist/integrations/zoom/files/ai/tools/update-meeting.ts +111 -0
- package/dist/integrations/zoom/files/app/api/auth/zoom/callback/route.ts +11 -0
- package/dist/integrations/zoom/files/app/api/auth/zoom/route.ts +7 -0
- package/dist/integrations/zoom/files/lib/zoom-client.ts +228 -0
- package/dist/oauth/handlers.js +554 -0
- package/dist/oauth/handlers.js.map +7 -0
- package/dist/oauth/index.js +1157 -0
- package/dist/oauth/index.js.map +7 -0
- package/dist/oauth/providers.js +927 -0
- package/dist/oauth/providers.js.map +7 -0
- package/dist/oauth/token-store.js +82 -0
- package/dist/oauth/token-store.js.map +7 -0
- package/package.json +25 -1
- package/dist/integrations/calendar/files/lib/token-store.ts +0 -113
- package/dist/integrations/github/files/lib/token-store.ts +0 -113
- package/dist/integrations/gmail/files/lib/oauth.ts +0 -145
- package/dist/integrations/gmail/files/lib/token-store.ts +0 -113
- package/dist/integrations/slack/files/lib/oauth.ts +0 -145
- package/dist/integrations/slack/files/lib/token-store.ts +0 -113
- /package/dist/integrations/{calendar → docs-google}/files/lib/oauth.ts +0 -0
- /package/dist/integrations/{github → drive}/files/lib/oauth.ts +0 -0
|
@@ -0,0 +1,554 @@
|
|
|
1
|
+
// src/platform/compat/runtime.ts
|
|
2
|
+
var isDeno = typeof Deno !== "undefined";
|
|
3
|
+
var isNode = typeof globalThis.process !== "undefined" && globalThis.process?.versions?.node !== void 0;
|
|
4
|
+
var isBun = typeof globalThis.Bun !== "undefined";
|
|
5
|
+
var isCloudflare = typeof globalThis !== "undefined" && "caches" in globalThis && "WebSocketPair" in globalThis;
|
|
6
|
+
|
|
7
|
+
// src/platform/compat/process.ts
|
|
8
|
+
var nodeProcess = globalThis.process;
|
|
9
|
+
var hasNodeProcess = !!nodeProcess?.versions?.node;
|
|
10
|
+
function getEnv(key) {
|
|
11
|
+
if (isDeno) {
|
|
12
|
+
return process.env(key);
|
|
13
|
+
}
|
|
14
|
+
if (hasNodeProcess) {
|
|
15
|
+
return nodeProcess.env[key];
|
|
16
|
+
}
|
|
17
|
+
return void 0;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// src/core/oauth/providers/base.ts
|
|
21
|
+
function generateRandomString(length) {
|
|
22
|
+
const array = new Uint8Array(length);
|
|
23
|
+
crypto.getRandomValues(array);
|
|
24
|
+
return Array.from(array, (byte) => byte.toString(16).padStart(2, "0")).join("").slice(0, length);
|
|
25
|
+
}
|
|
26
|
+
function generateCodeVerifier() {
|
|
27
|
+
return generateRandomString(64);
|
|
28
|
+
}
|
|
29
|
+
async function generateCodeChallenge(verifier) {
|
|
30
|
+
const encoder = new TextEncoder();
|
|
31
|
+
const data = encoder.encode(verifier);
|
|
32
|
+
const hash = await crypto.subtle.digest("SHA-256", data);
|
|
33
|
+
return btoa(String.fromCharCode(...new Uint8Array(hash))).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
|
|
34
|
+
}
|
|
35
|
+
var OAuthProvider = class {
|
|
36
|
+
constructor(config) {
|
|
37
|
+
this.config = config;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Get client ID from environment
|
|
41
|
+
*/
|
|
42
|
+
getClientId() {
|
|
43
|
+
return getEnv(this.config.clientIdEnvVar) || null;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Get client secret from environment
|
|
47
|
+
*/
|
|
48
|
+
getClientSecret() {
|
|
49
|
+
return getEnv(this.config.clientSecretEnvVar) || null;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Check if provider is configured
|
|
53
|
+
*/
|
|
54
|
+
isConfigured() {
|
|
55
|
+
return !!(this.getClientId() && this.getClientSecret());
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Create authorization URL
|
|
59
|
+
*/
|
|
60
|
+
async createAuthorizationUrl(options = {}) {
|
|
61
|
+
const clientId = this.getClientId();
|
|
62
|
+
if (!clientId) {
|
|
63
|
+
throw new Error(`${this.config.clientIdEnvVar} not configured`);
|
|
64
|
+
}
|
|
65
|
+
const state = options.state || generateRandomString(32);
|
|
66
|
+
const scopes = options.scopes || options.defaultScopes || [];
|
|
67
|
+
const redirectUri = options.redirectUri || "";
|
|
68
|
+
const usePkce = options.usePkce !== false;
|
|
69
|
+
let codeVerifier;
|
|
70
|
+
let codeChallenge;
|
|
71
|
+
if (usePkce) {
|
|
72
|
+
codeVerifier = generateCodeVerifier();
|
|
73
|
+
codeChallenge = await generateCodeChallenge(codeVerifier);
|
|
74
|
+
}
|
|
75
|
+
const params = new URLSearchParams({
|
|
76
|
+
client_id: clientId,
|
|
77
|
+
redirect_uri: redirectUri,
|
|
78
|
+
response_type: "code",
|
|
79
|
+
state,
|
|
80
|
+
...scopes.length > 0 && { scope: scopes.join(" ") },
|
|
81
|
+
...codeChallenge && {
|
|
82
|
+
code_challenge: codeChallenge,
|
|
83
|
+
code_challenge_method: "S256"
|
|
84
|
+
},
|
|
85
|
+
...this.config.additionalAuthParams,
|
|
86
|
+
...options.additionalParams
|
|
87
|
+
});
|
|
88
|
+
const oauthState = {
|
|
89
|
+
state,
|
|
90
|
+
codeVerifier,
|
|
91
|
+
redirectUri,
|
|
92
|
+
scopes,
|
|
93
|
+
createdAt: Date.now()
|
|
94
|
+
};
|
|
95
|
+
return {
|
|
96
|
+
url: `${this.config.authorizationUrl}?${params.toString()}`,
|
|
97
|
+
state: oauthState
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Exchange authorization code for tokens
|
|
102
|
+
*/
|
|
103
|
+
async exchangeCode(options) {
|
|
104
|
+
const clientId = this.getClientId();
|
|
105
|
+
const clientSecret = this.getClientSecret();
|
|
106
|
+
if (!clientId || !clientSecret) {
|
|
107
|
+
return {
|
|
108
|
+
success: false,
|
|
109
|
+
error: "OAuth not configured",
|
|
110
|
+
errorDescription: `Missing ${this.config.clientIdEnvVar} or ${this.config.clientSecretEnvVar}`
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
const body = new URLSearchParams({
|
|
114
|
+
grant_type: "authorization_code",
|
|
115
|
+
code: options.code,
|
|
116
|
+
redirect_uri: options.redirectUri,
|
|
117
|
+
...options.codeVerifier && { code_verifier: options.codeVerifier },
|
|
118
|
+
...!this.config.useBasicAuth && {
|
|
119
|
+
client_id: clientId,
|
|
120
|
+
client_secret: clientSecret
|
|
121
|
+
},
|
|
122
|
+
...this.config.additionalTokenParams
|
|
123
|
+
});
|
|
124
|
+
const headers = {
|
|
125
|
+
"Content-Type": "application/x-www-form-urlencoded",
|
|
126
|
+
Accept: "application/json"
|
|
127
|
+
};
|
|
128
|
+
if (this.config.useBasicAuth) {
|
|
129
|
+
const credentials = btoa(`${clientId}:${clientSecret}`);
|
|
130
|
+
headers.Authorization = `Basic ${credentials}`;
|
|
131
|
+
}
|
|
132
|
+
try {
|
|
133
|
+
const response = await fetch(this.config.tokenUrl, {
|
|
134
|
+
method: "POST",
|
|
135
|
+
headers,
|
|
136
|
+
body: body.toString()
|
|
137
|
+
});
|
|
138
|
+
const data = await response.json();
|
|
139
|
+
if (!response.ok) {
|
|
140
|
+
return {
|
|
141
|
+
success: false,
|
|
142
|
+
error: data.error || "token_exchange_failed",
|
|
143
|
+
errorDescription: data.error_description || `Status ${response.status}`
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
const mapping = this.config.tokenResponseMapping || {};
|
|
147
|
+
const tokens = {
|
|
148
|
+
accessToken: data[mapping.accessToken || "access_token"],
|
|
149
|
+
refreshToken: data[mapping.refreshToken || "refresh_token"],
|
|
150
|
+
tokenType: data[mapping.tokenType || "token_type"],
|
|
151
|
+
scope: data[mapping.scope || "scope"],
|
|
152
|
+
idToken: data.id_token
|
|
153
|
+
};
|
|
154
|
+
const expiresIn = data[mapping.expiresIn || "expires_in"];
|
|
155
|
+
if (expiresIn) {
|
|
156
|
+
tokens.expiresAt = Date.now() + expiresIn * 1e3;
|
|
157
|
+
}
|
|
158
|
+
return { success: true, tokens };
|
|
159
|
+
} catch (error) {
|
|
160
|
+
return {
|
|
161
|
+
success: false,
|
|
162
|
+
error: "network_error",
|
|
163
|
+
errorDescription: error instanceof Error ? error.message : "Unknown error"
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* Refresh access token
|
|
169
|
+
*/
|
|
170
|
+
async refreshTokens(refreshToken) {
|
|
171
|
+
const clientId = this.getClientId();
|
|
172
|
+
const clientSecret = this.getClientSecret();
|
|
173
|
+
if (!clientId || !clientSecret) {
|
|
174
|
+
return {
|
|
175
|
+
success: false,
|
|
176
|
+
error: "OAuth not configured"
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
const body = new URLSearchParams({
|
|
180
|
+
grant_type: "refresh_token",
|
|
181
|
+
refresh_token: refreshToken,
|
|
182
|
+
...!this.config.useBasicAuth && {
|
|
183
|
+
client_id: clientId,
|
|
184
|
+
client_secret: clientSecret
|
|
185
|
+
}
|
|
186
|
+
});
|
|
187
|
+
const headers = {
|
|
188
|
+
"Content-Type": "application/x-www-form-urlencoded",
|
|
189
|
+
Accept: "application/json"
|
|
190
|
+
};
|
|
191
|
+
if (this.config.useBasicAuth) {
|
|
192
|
+
const credentials = btoa(`${clientId}:${clientSecret}`);
|
|
193
|
+
headers.Authorization = `Basic ${credentials}`;
|
|
194
|
+
}
|
|
195
|
+
try {
|
|
196
|
+
const response = await fetch(this.config.tokenUrl, {
|
|
197
|
+
method: "POST",
|
|
198
|
+
headers,
|
|
199
|
+
body: body.toString()
|
|
200
|
+
});
|
|
201
|
+
const data = await response.json();
|
|
202
|
+
if (!response.ok) {
|
|
203
|
+
return {
|
|
204
|
+
success: false,
|
|
205
|
+
error: data.error || "refresh_failed",
|
|
206
|
+
errorDescription: data.error_description
|
|
207
|
+
};
|
|
208
|
+
}
|
|
209
|
+
const mapping = this.config.tokenResponseMapping || {};
|
|
210
|
+
const tokens = {
|
|
211
|
+
accessToken: data[mapping.accessToken || "access_token"],
|
|
212
|
+
refreshToken: data[mapping.refreshToken || "refresh_token"] || refreshToken,
|
|
213
|
+
tokenType: data[mapping.tokenType || "token_type"],
|
|
214
|
+
scope: data[mapping.scope || "scope"]
|
|
215
|
+
};
|
|
216
|
+
const expiresIn = data[mapping.expiresIn || "expires_in"];
|
|
217
|
+
if (expiresIn) {
|
|
218
|
+
tokens.expiresAt = Date.now() + expiresIn * 1e3;
|
|
219
|
+
}
|
|
220
|
+
return { success: true, tokens };
|
|
221
|
+
} catch (error) {
|
|
222
|
+
return {
|
|
223
|
+
success: false,
|
|
224
|
+
error: "network_error",
|
|
225
|
+
errorDescription: error instanceof Error ? error.message : "Unknown error"
|
|
226
|
+
};
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
/**
|
|
230
|
+
* Revoke tokens
|
|
231
|
+
*/
|
|
232
|
+
async revokeToken(token) {
|
|
233
|
+
if (!this.config.revocationUrl) {
|
|
234
|
+
return false;
|
|
235
|
+
}
|
|
236
|
+
try {
|
|
237
|
+
const response = await fetch(this.config.revocationUrl, {
|
|
238
|
+
method: "POST",
|
|
239
|
+
headers: {
|
|
240
|
+
"Content-Type": "application/x-www-form-urlencoded"
|
|
241
|
+
},
|
|
242
|
+
body: new URLSearchParams({ token }).toString()
|
|
243
|
+
});
|
|
244
|
+
return response.ok;
|
|
245
|
+
} catch {
|
|
246
|
+
return false;
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
};
|
|
250
|
+
var OAuthService = class extends OAuthProvider {
|
|
251
|
+
constructor(config, tokenStore) {
|
|
252
|
+
super(config);
|
|
253
|
+
this.serviceConfig = config;
|
|
254
|
+
this.tokenStore = tokenStore;
|
|
255
|
+
}
|
|
256
|
+
/**
|
|
257
|
+
* Get service ID
|
|
258
|
+
*/
|
|
259
|
+
get serviceId() {
|
|
260
|
+
return this.serviceConfig.serviceId;
|
|
261
|
+
}
|
|
262
|
+
/**
|
|
263
|
+
* Get API base URL
|
|
264
|
+
*/
|
|
265
|
+
get apiBaseUrl() {
|
|
266
|
+
return this.serviceConfig.apiBaseUrl;
|
|
267
|
+
}
|
|
268
|
+
/**
|
|
269
|
+
* Create authorization URL with service defaults
|
|
270
|
+
*/
|
|
271
|
+
createAuthorizationUrl(options = {}) {
|
|
272
|
+
return super.createAuthorizationUrl({
|
|
273
|
+
...options,
|
|
274
|
+
defaultScopes: this.serviceConfig.defaultScopes
|
|
275
|
+
});
|
|
276
|
+
}
|
|
277
|
+
/**
|
|
278
|
+
* Get valid access token (refreshing if needed)
|
|
279
|
+
*/
|
|
280
|
+
async getAccessToken() {
|
|
281
|
+
if (!this.tokenStore) {
|
|
282
|
+
return null;
|
|
283
|
+
}
|
|
284
|
+
const tokens = await this.tokenStore.getTokens(this.serviceId);
|
|
285
|
+
if (!tokens) {
|
|
286
|
+
return null;
|
|
287
|
+
}
|
|
288
|
+
if (tokens.expiresAt && Date.now() > tokens.expiresAt - 3e5) {
|
|
289
|
+
if (tokens.refreshToken) {
|
|
290
|
+
const result = await this.refreshTokens(tokens.refreshToken);
|
|
291
|
+
if (result.success && result.tokens) {
|
|
292
|
+
await this.tokenStore.setTokens(this.serviceId, result.tokens);
|
|
293
|
+
return result.tokens.accessToken;
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
return null;
|
|
297
|
+
}
|
|
298
|
+
return tokens.accessToken;
|
|
299
|
+
}
|
|
300
|
+
/**
|
|
301
|
+
* Make authenticated API request
|
|
302
|
+
*/
|
|
303
|
+
async fetch(endpoint, options = {}) {
|
|
304
|
+
const token = await this.getAccessToken();
|
|
305
|
+
if (!token) {
|
|
306
|
+
throw new Error(`Not authenticated with ${this.serviceConfig.displayName}`);
|
|
307
|
+
}
|
|
308
|
+
const url = endpoint.startsWith("http") ? endpoint : `${this.apiBaseUrl}${endpoint}`;
|
|
309
|
+
const response = await fetch(url, {
|
|
310
|
+
...options,
|
|
311
|
+
headers: {
|
|
312
|
+
Authorization: `Bearer ${token}`,
|
|
313
|
+
"Content-Type": "application/json",
|
|
314
|
+
...options.headers
|
|
315
|
+
}
|
|
316
|
+
});
|
|
317
|
+
if (!response.ok) {
|
|
318
|
+
const error = await response.text();
|
|
319
|
+
throw new Error(`${this.serviceConfig.displayName} API error: ${response.status} ${error}`);
|
|
320
|
+
}
|
|
321
|
+
return response.json();
|
|
322
|
+
}
|
|
323
|
+
};
|
|
324
|
+
|
|
325
|
+
// src/core/oauth/token-store/memory.ts
|
|
326
|
+
var MemoryTokenStore = class {
|
|
327
|
+
constructor() {
|
|
328
|
+
this.tokens = /* @__PURE__ */ new Map();
|
|
329
|
+
this.states = /* @__PURE__ */ new Map();
|
|
330
|
+
/** State expiration time in ms (10 minutes) */
|
|
331
|
+
this.stateExpirationMs = 10 * 60 * 1e3;
|
|
332
|
+
}
|
|
333
|
+
getTokens(serviceId) {
|
|
334
|
+
return Promise.resolve(this.tokens.get(serviceId) || null);
|
|
335
|
+
}
|
|
336
|
+
setTokens(serviceId, tokens) {
|
|
337
|
+
this.tokens.set(serviceId, tokens);
|
|
338
|
+
return Promise.resolve();
|
|
339
|
+
}
|
|
340
|
+
clearTokens(serviceId) {
|
|
341
|
+
this.tokens.delete(serviceId);
|
|
342
|
+
return Promise.resolve();
|
|
343
|
+
}
|
|
344
|
+
getState(state) {
|
|
345
|
+
const oauthState = this.states.get(state);
|
|
346
|
+
if (!oauthState) {
|
|
347
|
+
return Promise.resolve(null);
|
|
348
|
+
}
|
|
349
|
+
if (Date.now() - oauthState.createdAt > this.stateExpirationMs) {
|
|
350
|
+
this.states.delete(state);
|
|
351
|
+
return Promise.resolve(null);
|
|
352
|
+
}
|
|
353
|
+
return Promise.resolve(oauthState);
|
|
354
|
+
}
|
|
355
|
+
setState(oauthState) {
|
|
356
|
+
this.states.set(oauthState.state, oauthState);
|
|
357
|
+
this.cleanupExpiredStates();
|
|
358
|
+
return Promise.resolve();
|
|
359
|
+
}
|
|
360
|
+
clearState(state) {
|
|
361
|
+
this.states.delete(state);
|
|
362
|
+
return Promise.resolve();
|
|
363
|
+
}
|
|
364
|
+
/**
|
|
365
|
+
* Clean up expired states
|
|
366
|
+
*/
|
|
367
|
+
cleanupExpiredStates() {
|
|
368
|
+
const now = Date.now();
|
|
369
|
+
for (const [state, oauthState] of this.states) {
|
|
370
|
+
if (now - oauthState.createdAt > this.stateExpirationMs) {
|
|
371
|
+
this.states.delete(state);
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
/**
|
|
376
|
+
* Get all stored service IDs
|
|
377
|
+
*/
|
|
378
|
+
getConnectedServices() {
|
|
379
|
+
return Array.from(this.tokens.keys());
|
|
380
|
+
}
|
|
381
|
+
/**
|
|
382
|
+
* Check if a service is connected
|
|
383
|
+
*/
|
|
384
|
+
isConnected(serviceId) {
|
|
385
|
+
const tokens = this.tokens.get(serviceId);
|
|
386
|
+
if (!tokens)
|
|
387
|
+
return false;
|
|
388
|
+
if (tokens.expiresAt && Date.now() > tokens.expiresAt) {
|
|
389
|
+
return !!tokens.refreshToken;
|
|
390
|
+
}
|
|
391
|
+
return true;
|
|
392
|
+
}
|
|
393
|
+
/**
|
|
394
|
+
* Clear all tokens
|
|
395
|
+
*/
|
|
396
|
+
clearAll() {
|
|
397
|
+
this.tokens.clear();
|
|
398
|
+
this.states.clear();
|
|
399
|
+
}
|
|
400
|
+
};
|
|
401
|
+
var memoryTokenStore = new MemoryTokenStore();
|
|
402
|
+
|
|
403
|
+
// src/core/oauth/handlers/callback-handler.ts
|
|
404
|
+
function createOAuthCallbackHandler(config, options = {}) {
|
|
405
|
+
const {
|
|
406
|
+
tokenStore = memoryTokenStore,
|
|
407
|
+
baseUrl,
|
|
408
|
+
successRedirect = "/",
|
|
409
|
+
errorRedirect = "/",
|
|
410
|
+
onSuccess,
|
|
411
|
+
onError
|
|
412
|
+
} = options;
|
|
413
|
+
return async (request) => {
|
|
414
|
+
const url = new URL(request.url);
|
|
415
|
+
const code = url.searchParams.get("code");
|
|
416
|
+
const state = url.searchParams.get("state");
|
|
417
|
+
const error = url.searchParams.get("error");
|
|
418
|
+
const errorDescription = url.searchParams.get("error_description");
|
|
419
|
+
const appUrl = baseUrl || getEnv("APP_URL") || getEnv("NEXT_PUBLIC_APP_URL") || "http://localhost:3000";
|
|
420
|
+
if (error) {
|
|
421
|
+
console.error(`OAuth error for ${config.serviceId}:`, error, errorDescription);
|
|
422
|
+
if (onError) {
|
|
423
|
+
await onError(config.serviceId, error);
|
|
424
|
+
}
|
|
425
|
+
const errorUrl = new URL(errorRedirect, appUrl);
|
|
426
|
+
errorUrl.searchParams.set("error", error);
|
|
427
|
+
if (errorDescription) {
|
|
428
|
+
errorUrl.searchParams.set("error_description", errorDescription);
|
|
429
|
+
}
|
|
430
|
+
return Response.redirect(errorUrl.toString());
|
|
431
|
+
}
|
|
432
|
+
if (!code) {
|
|
433
|
+
if (onError) {
|
|
434
|
+
await onError(config.serviceId, "no_code");
|
|
435
|
+
}
|
|
436
|
+
const errorUrl = new URL(errorRedirect, appUrl);
|
|
437
|
+
errorUrl.searchParams.set("error", "no_code");
|
|
438
|
+
return Response.redirect(errorUrl.toString());
|
|
439
|
+
}
|
|
440
|
+
let oauthState = null;
|
|
441
|
+
if (state) {
|
|
442
|
+
oauthState = await tokenStore.getState(state);
|
|
443
|
+
if (!oauthState) {
|
|
444
|
+
console.warn(`Invalid or expired state for ${config.serviceId}`);
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
const service = new OAuthService(config, tokenStore);
|
|
448
|
+
const redirectUri = `${appUrl}/api/auth/${config.serviceId}/callback`;
|
|
449
|
+
try {
|
|
450
|
+
const result = await service.exchangeCode({
|
|
451
|
+
code,
|
|
452
|
+
redirectUri,
|
|
453
|
+
codeVerifier: oauthState?.codeVerifier
|
|
454
|
+
});
|
|
455
|
+
if (!result.success || !result.tokens) {
|
|
456
|
+
console.error(`Token exchange failed for ${config.serviceId}:`, result.error);
|
|
457
|
+
if (onError) {
|
|
458
|
+
await onError(config.serviceId, result.error || "exchange_failed");
|
|
459
|
+
}
|
|
460
|
+
const errorUrl = new URL(errorRedirect, appUrl);
|
|
461
|
+
errorUrl.searchParams.set("error", result.error || "token_exchange_failed");
|
|
462
|
+
return Response.redirect(errorUrl.toString());
|
|
463
|
+
}
|
|
464
|
+
await tokenStore.setTokens(config.serviceId, result.tokens);
|
|
465
|
+
if (state) {
|
|
466
|
+
await tokenStore.clearState(state);
|
|
467
|
+
}
|
|
468
|
+
if (onSuccess) {
|
|
469
|
+
await onSuccess(config.serviceId, result.tokens);
|
|
470
|
+
}
|
|
471
|
+
const successUrl = new URL(successRedirect, appUrl);
|
|
472
|
+
successUrl.searchParams.set("connected", config.serviceId);
|
|
473
|
+
return Response.redirect(successUrl.toString());
|
|
474
|
+
} catch (err) {
|
|
475
|
+
console.error(`OAuth callback error for ${config.serviceId}:`, err);
|
|
476
|
+
if (onError) {
|
|
477
|
+
await onError(config.serviceId, "callback_error");
|
|
478
|
+
}
|
|
479
|
+
const errorUrl = new URL(errorRedirect, appUrl);
|
|
480
|
+
errorUrl.searchParams.set("error", "callback_error");
|
|
481
|
+
return Response.redirect(errorUrl.toString());
|
|
482
|
+
}
|
|
483
|
+
};
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
// src/core/oauth/handlers/init-handler.ts
|
|
487
|
+
function createOAuthInitHandler(config, options = {}) {
|
|
488
|
+
const { tokenStore = memoryTokenStore, baseUrl, authOptions = {} } = options;
|
|
489
|
+
return async () => {
|
|
490
|
+
const service = new OAuthService(config, tokenStore);
|
|
491
|
+
if (!service.isConfigured()) {
|
|
492
|
+
return Response.json(
|
|
493
|
+
{
|
|
494
|
+
error: `${config.displayName} OAuth not configured`,
|
|
495
|
+
details: `Missing ${config.clientIdEnvVar} or ${config.clientSecretEnvVar}`
|
|
496
|
+
},
|
|
497
|
+
{ status: 500 }
|
|
498
|
+
);
|
|
499
|
+
}
|
|
500
|
+
const appUrl = baseUrl || getEnv("APP_URL") || getEnv("NEXT_PUBLIC_APP_URL") || "http://localhost:3000";
|
|
501
|
+
const redirectUri = `${appUrl}/api/auth/${config.serviceId}/callback`;
|
|
502
|
+
try {
|
|
503
|
+
const { url, state } = await service.createAuthorizationUrl({
|
|
504
|
+
...authOptions,
|
|
505
|
+
redirectUri
|
|
506
|
+
});
|
|
507
|
+
await tokenStore.setState(state);
|
|
508
|
+
return Response.redirect(url);
|
|
509
|
+
} catch (error) {
|
|
510
|
+
console.error(`OAuth init error for ${config.serviceId}:`, error);
|
|
511
|
+
return Response.json(
|
|
512
|
+
{
|
|
513
|
+
error: "Failed to initiate OAuth flow",
|
|
514
|
+
details: error instanceof Error ? error.message : "Unknown error"
|
|
515
|
+
},
|
|
516
|
+
{ status: 500 }
|
|
517
|
+
);
|
|
518
|
+
}
|
|
519
|
+
};
|
|
520
|
+
}
|
|
521
|
+
function createOAuthStatusHandler(config, options = {}) {
|
|
522
|
+
const { tokenStore = memoryTokenStore } = options;
|
|
523
|
+
return async () => {
|
|
524
|
+
const tokens = await tokenStore.getTokens(config.serviceId);
|
|
525
|
+
const isConnected = !!tokens?.accessToken;
|
|
526
|
+
const isExpired = tokens?.expiresAt ? Date.now() > tokens.expiresAt : false;
|
|
527
|
+
const hasRefreshToken = !!tokens?.refreshToken;
|
|
528
|
+
return Response.json({
|
|
529
|
+
service: config.serviceId,
|
|
530
|
+
displayName: config.displayName,
|
|
531
|
+
connected: isConnected && (!isExpired || hasRefreshToken),
|
|
532
|
+
configured: !!(getEnv(config.clientIdEnvVar) && getEnv(config.clientSecretEnvVar)),
|
|
533
|
+
expiresAt: tokens?.expiresAt,
|
|
534
|
+
hasRefreshToken
|
|
535
|
+
});
|
|
536
|
+
};
|
|
537
|
+
}
|
|
538
|
+
function createOAuthDisconnectHandler(config, options = {}) {
|
|
539
|
+
const { tokenStore = memoryTokenStore } = options;
|
|
540
|
+
return async () => {
|
|
541
|
+
await tokenStore.clearTokens(config.serviceId);
|
|
542
|
+
return Response.json({
|
|
543
|
+
success: true,
|
|
544
|
+
message: `Disconnected from ${config.displayName}`
|
|
545
|
+
});
|
|
546
|
+
};
|
|
547
|
+
}
|
|
548
|
+
export {
|
|
549
|
+
createOAuthCallbackHandler,
|
|
550
|
+
createOAuthDisconnectHandler,
|
|
551
|
+
createOAuthInitHandler,
|
|
552
|
+
createOAuthStatusHandler
|
|
553
|
+
};
|
|
554
|
+
//# sourceMappingURL=handlers.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../src/platform/compat/runtime.ts", "../../../src/platform/compat/process.ts", "../../../src/core/oauth/providers/base.ts", "../../../src/core/oauth/token-store/memory.ts", "../../../src/core/oauth/handlers/callback-handler.ts", "../../../src/core/oauth/handlers/init-handler.ts"],
|
|
4
|
+
"sourcesContent": ["export const isDeno = typeof Deno !== \"undefined\";\nexport const isNode =\n typeof (globalThis as { process?: { versions?: { node?: string } } }).process !== \"undefined\" &&\n (globalThis as { process?: { versions?: { node?: string } } }).process?.versions?.node !==\n undefined;\nexport const isBun = typeof (globalThis as { Bun?: unknown }).Bun !== \"undefined\";\nexport const isCloudflare = typeof globalThis !== \"undefined\" && \"caches\" in globalThis &&\n \"WebSocketPair\" in globalThis;\n\n/**\n * Detect if running in Node.js (vs Deno)\n * Use this function instead of the constant when runtime detection needs to happen\n * at call time (e.g., when bundled with esbuild's __esm lazy initialization pattern)\n */\nexport function isNodeRuntime(): boolean {\n // deno-lint-ignore no-explicit-any\n const _global = globalThis as any;\n return typeof Deno === \"undefined\" && typeof _global.process !== \"undefined\" &&\n !!_global.process?.versions?.node;\n}\n", "import { isDeno as IS_DENO } from \"./runtime.ts\";\n\nconst nodeProcess = (globalThis as { process?: typeof import(\"node:process\") }).process;\nconst hasNodeProcess = !!nodeProcess?.versions?.node;\n\nexport function getArgs(): string[] {\n if (IS_DENO) {\n return Deno.args;\n }\n if (hasNodeProcess) {\n return nodeProcess!.argv.slice(2);\n }\n return [];\n}\n\nexport function exit(code?: number): never {\n if (IS_DENO) {\n Deno.exit(code);\n }\n if (hasNodeProcess) {\n nodeProcess!.exit(code);\n }\n throw new Error(\"exit() is not supported in this runtime\");\n}\n\nexport function cwd(): string {\n if (IS_DENO) {\n return Deno.cwd();\n }\n if (hasNodeProcess) {\n return nodeProcess!.cwd();\n }\n throw new Error(\"cwd() is not supported in this runtime\");\n}\n\nexport function chdir(directory: string): void {\n if (IS_DENO) {\n Deno.chdir(directory);\n } else {\n if (hasNodeProcess) {\n nodeProcess!.chdir(directory);\n return;\n }\n throw new Error(\"chdir() is not supported in this runtime\");\n }\n}\n\nexport function env(): Record<string, string> {\n if (IS_DENO) {\n return Deno.env.toObject();\n }\n if (hasNodeProcess) {\n return nodeProcess!.env as Record<string, string>;\n }\n return {};\n}\n\nexport function getEnv(key: string): string | undefined {\n if (IS_DENO) {\n return Deno.env.get(key);\n }\n if (hasNodeProcess) {\n return nodeProcess!.env[key];\n }\n return undefined;\n}\n\n/**\n * Get an environment variable or throw if not set\n * @throws Error if the environment variable is not set\n */\nexport function requireEnv(key: string): string {\n const value = getEnv(key);\n if (value === undefined) {\n throw new Error(`Required environment variable \"${key}\" is not set`);\n }\n return value;\n}\n\nexport function setEnv(key: string, value: string): void {\n if (IS_DENO) {\n Deno.env.set(key, value);\n } else {\n if (hasNodeProcess) {\n nodeProcess!.env[key] = value;\n return;\n }\n throw new Error(\"setEnv() is not supported in this runtime\");\n }\n}\n\nexport function deleteEnv(key: string): void {\n if (IS_DENO) {\n Deno.env.delete(key);\n } else {\n if (hasNodeProcess) {\n delete nodeProcess!.env[key];\n return;\n }\n throw new Error(\"deleteEnv() is not supported in this runtime\");\n }\n}\n\nexport function pid(): number {\n if (IS_DENO) {\n return Deno.pid;\n }\n if (hasNodeProcess) {\n return nodeProcess!.pid;\n }\n return 0;\n}\n\nexport function ppid(): number {\n if (IS_DENO && \"ppid\" in Deno) {\n return Deno.ppid || 0;\n }\n if (hasNodeProcess) {\n return nodeProcess!.ppid || 0;\n }\n return 0;\n}\n\nexport function memoryUsage(): {\n rss: number;\n heapTotal: number;\n heapUsed: number;\n external: number;\n} {\n if (IS_DENO) {\n const usage = Deno.memoryUsage();\n return {\n rss: usage.rss,\n heapTotal: usage.heapTotal,\n heapUsed: usage.heapUsed,\n external: usage.external,\n };\n }\n\n if (!hasNodeProcess) {\n throw new Error(\"memoryUsage() is not supported in this runtime\");\n }\n\n const usage = nodeProcess!.memoryUsage();\n return {\n rss: usage.rss,\n heapTotal: usage.heapTotal,\n heapUsed: usage.heapUsed,\n external: usage.external || 0,\n };\n}\n\n/**\n * Check if stdin is a TTY (terminal)\n */\nexport function isInteractive(): boolean {\n if (IS_DENO) {\n return Deno.stdin.isTerminal();\n }\n if (hasNodeProcess) {\n return nodeProcess!.stdin.isTTY ?? false;\n }\n return false;\n}\n\n/**\n * Get network interfaces\n */\nexport async function getNetworkInterfaces(): Promise<\n Array<{ name: string; address: string; family: \"IPv4\" | \"IPv6\" }>\n> {\n if (IS_DENO) {\n const interfaces = Deno.networkInterfaces();\n return interfaces.map((iface) => ({\n name: iface.name,\n address: iface.address,\n family: iface.family as \"IPv4\" | \"IPv6\",\n }));\n }\n\n if (!hasNodeProcess) {\n throw new Error(\"networkInterfaces() is not supported in this runtime\");\n }\n\n const os = await import(\"node:os\");\n const interfaces = os.networkInterfaces();\n const result: Array<{ name: string; address: string; family: \"IPv4\" | \"IPv6\" }> = [];\n\n for (const [name, addrs] of Object.entries(interfaces)) {\n if (!addrs) continue;\n for (const addr of addrs) {\n result.push({\n name,\n address: addr.address,\n family: addr.family as \"IPv4\" | \"IPv6\",\n });\n }\n }\n\n return result;\n}\n\n/**\n * Get runtime version string\n */\nexport function getRuntimeVersion(): string {\n if (IS_DENO) {\n return `Deno ${Deno.version.deno}`;\n }\n if (\"Bun\" in globalThis) {\n return `Bun ${(globalThis as unknown as { Bun: { version: string } }).Bun.version}`;\n }\n if (hasNodeProcess) {\n return `Node.js ${nodeProcess!.version}`;\n }\n return \"unknown\";\n}\n\n/**\n * Register a signal handler (SIGINT, SIGTERM) for graceful shutdown\n */\nexport function onSignal(signal: \"SIGINT\" | \"SIGTERM\", handler: () => void): void {\n if (IS_DENO) {\n Deno.addSignalListener(signal, handler);\n } else if (hasNodeProcess) {\n nodeProcess!.on(signal, handler);\n }\n}\n\n/**\n * Unreference a timer to prevent it from keeping the process alive\n */\nexport function unrefTimer(timerId: ReturnType<typeof setInterval>): void {\n if (IS_DENO) {\n Deno.unrefTimer(timerId as number);\n } else if (timerId && typeof timerId === \"object\" && \"unref\" in timerId) {\n (timerId as { unref: () => void }).unref();\n }\n}\n\n/**\n * Get the executable path of the current runtime\n */\nexport function execPath(): string {\n if (IS_DENO) {\n return Deno.execPath();\n }\n if (hasNodeProcess) {\n return nodeProcess!.execPath;\n }\n return \"\";\n}\n\n/**\n * Get process uptime in seconds\n * Returns OS uptime on Deno, process uptime on Node.js\n */\nexport function uptime(): number {\n if (IS_DENO) {\n // Deno.osUptime() returns system uptime in seconds\n return Deno.osUptime?.() ?? 0;\n }\n if (hasNodeProcess) {\n // process.uptime() returns process uptime in seconds\n return nodeProcess!.uptime?.() ?? 0;\n }\n return 0;\n}\n\n/**\n * Get stdout stream for writing\n * Returns null if not available (e.g., in browser/workers)\n */\nexport function getStdout(): { write: (data: string) => void } | null {\n if (IS_DENO) {\n const encoder = new TextEncoder();\n return {\n write: (data: string) => {\n Deno.stdout.writeSync(encoder.encode(data));\n },\n };\n }\n if (hasNodeProcess && nodeProcess!.stdout) {\n return {\n write: (data: string) => {\n nodeProcess!.stdout.write(data);\n },\n };\n }\n return null;\n}\n\n// Cached Node.js modules for synchronous prompt\nlet cachedNodeFs: typeof import(\"node:fs\") | null = null;\n\n/**\n * Synchronous prompt function that works across Deno and Node.js\n * Displays a message and reads user input from stdin\n */\nexport function promptSync(message?: string): string | null {\n if (IS_DENO) {\n // Deno has a built-in prompt() function\n return prompt(message);\n }\n\n if (hasNodeProcess) {\n // Print the message\n if (message) {\n nodeProcess!.stdout.write(message + \" \");\n }\n\n // Lazy load fs module\n if (!cachedNodeFs) {\n // Dynamic import converted to sync require for bundling\n // @ts-ignore - dynamic require for Node.js\n cachedNodeFs = globalThis.require?.(\"node:fs\") || null;\n if (!cachedNodeFs) {\n // Try alternative approach\n try {\n // @ts-ignore: __require is injected by bundlers for Node.js require\n cachedNodeFs = __require(\"node:fs\");\n } catch {\n return null;\n }\n }\n }\n\n if (!cachedNodeFs) {\n return null;\n }\n\n // Read synchronously using fs\n // This works by reading from file descriptor 0 (stdin)\n // Use Uint8Array for cross-platform compatibility\n const bufferSize = 1024;\n const uint8Array = new Uint8Array(bufferSize);\n let input = \"\";\n\n try {\n // Read from stdin (fd 0) synchronously\n const bytesRead = cachedNodeFs.readSync(0, uint8Array, 0, bufferSize, null);\n if (bytesRead > 0) {\n const decoder = new TextDecoder(\"utf-8\");\n input = decoder.decode(uint8Array.subarray(0, bytesRead)).trim();\n }\n } catch {\n // If stdin is not available or EOF, return null\n return null;\n }\n\n return input || null;\n }\n\n return null;\n}\n", "/**\n * Base OAuth Provider\n *\n * Generic OAuth 2.0 implementation that can be extended for specific providers.\n */\n\nimport type {\n AuthorizationUrlOptions,\n OAuthProviderConfig,\n OAuthServiceConfig,\n OAuthState,\n OAuthTokens,\n TokenExchangeOptions,\n TokenExchangeResult,\n TokenStore,\n} from \"../types.ts\";\nimport { getEnv } from \"../../../platform/compat/process.ts\";\n\n/**\n * Generate cryptographically secure random string\n */\nfunction generateRandomString(length: number): string {\n const array = new Uint8Array(length);\n crypto.getRandomValues(array);\n return Array.from(array, (byte) => byte.toString(16).padStart(2, \"0\")).join(\"\").slice(0, length);\n}\n\n/**\n * Generate PKCE code verifier\n */\nfunction generateCodeVerifier(): string {\n return generateRandomString(64);\n}\n\n/**\n * Generate PKCE code challenge from verifier\n */\nasync function generateCodeChallenge(verifier: string): Promise<string> {\n const encoder = new TextEncoder();\n const data = encoder.encode(verifier);\n const hash = await crypto.subtle.digest(\"SHA-256\", data);\n return btoa(String.fromCharCode(...new Uint8Array(hash)))\n .replace(/\\+/g, \"-\")\n .replace(/\\//g, \"_\")\n .replace(/=+$/, \"\");\n}\n\n/**\n * Base OAuth provider class\n */\nexport class OAuthProvider {\n protected config: OAuthProviderConfig;\n\n constructor(config: OAuthProviderConfig) {\n this.config = config;\n }\n\n /**\n * Get client ID from environment\n */\n getClientId(): string | null {\n return getEnv(this.config.clientIdEnvVar) || null;\n }\n\n /**\n * Get client secret from environment\n */\n getClientSecret(): string | null {\n return getEnv(this.config.clientSecretEnvVar) || null;\n }\n\n /**\n * Check if provider is configured\n */\n isConfigured(): boolean {\n return !!(this.getClientId() && this.getClientSecret());\n }\n\n /**\n * Create authorization URL\n */\n async createAuthorizationUrl(\n options: AuthorizationUrlOptions & { defaultScopes?: string[] } = {},\n ): Promise<{ url: string; state: OAuthState }> {\n const clientId = this.getClientId();\n if (!clientId) {\n throw new Error(`${this.config.clientIdEnvVar} not configured`);\n }\n\n const state = options.state || generateRandomString(32);\n const scopes = options.scopes || options.defaultScopes || [];\n const redirectUri = options.redirectUri || \"\";\n const usePkce = options.usePkce !== false;\n\n let codeVerifier: string | undefined;\n let codeChallenge: string | undefined;\n\n if (usePkce) {\n codeVerifier = generateCodeVerifier();\n codeChallenge = await generateCodeChallenge(codeVerifier);\n }\n\n const params = new URLSearchParams({\n client_id: clientId,\n redirect_uri: redirectUri,\n response_type: \"code\",\n state,\n ...(scopes.length > 0 && { scope: scopes.join(\" \") }),\n ...(codeChallenge && {\n code_challenge: codeChallenge,\n code_challenge_method: \"S256\",\n }),\n ...this.config.additionalAuthParams,\n ...options.additionalParams,\n });\n\n const oauthState: OAuthState = {\n state,\n codeVerifier,\n redirectUri,\n scopes,\n createdAt: Date.now(),\n };\n\n return {\n url: `${this.config.authorizationUrl}?${params.toString()}`,\n state: oauthState,\n };\n }\n\n /**\n * Exchange authorization code for tokens\n */\n async exchangeCode(options: TokenExchangeOptions): Promise<TokenExchangeResult> {\n const clientId = this.getClientId();\n const clientSecret = this.getClientSecret();\n\n if (!clientId || !clientSecret) {\n return {\n success: false,\n error: \"OAuth not configured\",\n errorDescription:\n `Missing ${this.config.clientIdEnvVar} or ${this.config.clientSecretEnvVar}`,\n };\n }\n\n const body = new URLSearchParams({\n grant_type: \"authorization_code\",\n code: options.code,\n redirect_uri: options.redirectUri,\n ...(options.codeVerifier && { code_verifier: options.codeVerifier }),\n ...(!this.config.useBasicAuth && {\n client_id: clientId,\n client_secret: clientSecret,\n }),\n ...this.config.additionalTokenParams,\n });\n\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/x-www-form-urlencoded\",\n Accept: \"application/json\",\n };\n\n if (this.config.useBasicAuth) {\n const credentials = btoa(`${clientId}:${clientSecret}`);\n headers.Authorization = `Basic ${credentials}`;\n }\n\n try {\n const response = await fetch(this.config.tokenUrl, {\n method: \"POST\",\n headers,\n body: body.toString(),\n });\n\n const data = await response.json();\n\n if (!response.ok) {\n return {\n success: false,\n error: data.error || \"token_exchange_failed\",\n errorDescription: data.error_description || `Status ${response.status}`,\n };\n }\n\n const mapping = this.config.tokenResponseMapping || {};\n const tokens: OAuthTokens = {\n accessToken: data[mapping.accessToken || \"access_token\"],\n refreshToken: data[mapping.refreshToken || \"refresh_token\"],\n tokenType: data[mapping.tokenType || \"token_type\"],\n scope: data[mapping.scope || \"scope\"],\n idToken: data.id_token,\n };\n\n const expiresIn = data[mapping.expiresIn || \"expires_in\"];\n if (expiresIn) {\n tokens.expiresAt = Date.now() + expiresIn * 1000;\n }\n\n return { success: true, tokens };\n } catch (error) {\n return {\n success: false,\n error: \"network_error\",\n errorDescription: error instanceof Error ? error.message : \"Unknown error\",\n };\n }\n }\n\n /**\n * Refresh access token\n */\n async refreshTokens(refreshToken: string): Promise<TokenExchangeResult> {\n const clientId = this.getClientId();\n const clientSecret = this.getClientSecret();\n\n if (!clientId || !clientSecret) {\n return {\n success: false,\n error: \"OAuth not configured\",\n };\n }\n\n const body = new URLSearchParams({\n grant_type: \"refresh_token\",\n refresh_token: refreshToken,\n ...(!this.config.useBasicAuth && {\n client_id: clientId,\n client_secret: clientSecret,\n }),\n });\n\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/x-www-form-urlencoded\",\n Accept: \"application/json\",\n };\n\n if (this.config.useBasicAuth) {\n const credentials = btoa(`${clientId}:${clientSecret}`);\n headers.Authorization = `Basic ${credentials}`;\n }\n\n try {\n const response = await fetch(this.config.tokenUrl, {\n method: \"POST\",\n headers,\n body: body.toString(),\n });\n\n const data = await response.json();\n\n if (!response.ok) {\n return {\n success: false,\n error: data.error || \"refresh_failed\",\n errorDescription: data.error_description,\n };\n }\n\n const mapping = this.config.tokenResponseMapping || {};\n const tokens: OAuthTokens = {\n accessToken: data[mapping.accessToken || \"access_token\"],\n refreshToken: data[mapping.refreshToken || \"refresh_token\"] || refreshToken,\n tokenType: data[mapping.tokenType || \"token_type\"],\n scope: data[mapping.scope || \"scope\"],\n };\n\n const expiresIn = data[mapping.expiresIn || \"expires_in\"];\n if (expiresIn) {\n tokens.expiresAt = Date.now() + expiresIn * 1000;\n }\n\n return { success: true, tokens };\n } catch (error) {\n return {\n success: false,\n error: \"network_error\",\n errorDescription: error instanceof Error ? error.message : \"Unknown error\",\n };\n }\n }\n\n /**\n * Revoke tokens\n */\n async revokeToken(token: string): Promise<boolean> {\n if (!this.config.revocationUrl) {\n return false;\n }\n\n try {\n const response = await fetch(this.config.revocationUrl, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/x-www-form-urlencoded\",\n },\n body: new URLSearchParams({ token }).toString(),\n });\n\n return response.ok;\n } catch {\n return false;\n }\n }\n}\n\n/**\n * Service-specific OAuth handler\n */\nexport class OAuthService extends OAuthProvider {\n protected serviceConfig: OAuthServiceConfig;\n protected tokenStore?: TokenStore;\n\n constructor(config: OAuthServiceConfig, tokenStore?: TokenStore) {\n super(config);\n this.serviceConfig = config;\n this.tokenStore = tokenStore;\n }\n\n /**\n * Get service ID\n */\n get serviceId(): string {\n return this.serviceConfig.serviceId;\n }\n\n /**\n * Get API base URL\n */\n get apiBaseUrl(): string {\n return this.serviceConfig.apiBaseUrl;\n }\n\n /**\n * Create authorization URL with service defaults\n */\n override createAuthorizationUrl(\n options: AuthorizationUrlOptions = {},\n ): Promise<{ url: string; state: OAuthState }> {\n return super.createAuthorizationUrl({\n ...options,\n defaultScopes: this.serviceConfig.defaultScopes,\n });\n }\n\n /**\n * Get valid access token (refreshing if needed)\n */\n async getAccessToken(): Promise<string | null> {\n if (!this.tokenStore) {\n return null;\n }\n\n const tokens = await this.tokenStore.getTokens(this.serviceId);\n if (!tokens) {\n return null;\n }\n\n // Check if token is expired (with 5 min buffer)\n if (tokens.expiresAt && Date.now() > tokens.expiresAt - 300000) {\n if (tokens.refreshToken) {\n const result = await this.refreshTokens(tokens.refreshToken);\n if (result.success && result.tokens) {\n await this.tokenStore.setTokens(this.serviceId, result.tokens);\n return result.tokens.accessToken;\n }\n }\n return null;\n }\n\n return tokens.accessToken;\n }\n\n /**\n * Make authenticated API request\n */\n async fetch<T>(\n endpoint: string,\n options: RequestInit = {},\n ): Promise<T> {\n const token = await this.getAccessToken();\n if (!token) {\n throw new Error(`Not authenticated with ${this.serviceConfig.displayName}`);\n }\n\n const url = endpoint.startsWith(\"http\") ? endpoint : `${this.apiBaseUrl}${endpoint}`;\n\n const response = await fetch(url, {\n ...options,\n headers: {\n Authorization: `Bearer ${token}`,\n \"Content-Type\": \"application/json\",\n ...options.headers,\n },\n });\n\n if (!response.ok) {\n const error = await response.text();\n throw new Error(`${this.serviceConfig.displayName} API error: ${response.status} ${error}`);\n }\n\n return response.json();\n }\n}\n", "/**\n * In-Memory Token Store\n *\n * Simple in-memory storage for OAuth tokens and state.\n * Suitable for development and single-instance deployments.\n */\n\nimport type { OAuthState, OAuthTokens, TokenStore } from \"../types.ts\";\n\n/**\n * In-memory token store implementation\n */\nexport class MemoryTokenStore implements TokenStore {\n private tokens: Map<string, OAuthTokens> = new Map();\n private states: Map<string, OAuthState> = new Map();\n\n /** State expiration time in ms (10 minutes) */\n private stateExpirationMs = 10 * 60 * 1000;\n\n getTokens(serviceId: string): Promise<OAuthTokens | null> {\n return Promise.resolve(this.tokens.get(serviceId) || null);\n }\n\n setTokens(serviceId: string, tokens: OAuthTokens): Promise<void> {\n this.tokens.set(serviceId, tokens);\n return Promise.resolve();\n }\n\n clearTokens(serviceId: string): Promise<void> {\n this.tokens.delete(serviceId);\n return Promise.resolve();\n }\n\n getState(state: string): Promise<OAuthState | null> {\n const oauthState = this.states.get(state);\n if (!oauthState) {\n return Promise.resolve(null);\n }\n\n // Check if state has expired\n if (Date.now() - oauthState.createdAt > this.stateExpirationMs) {\n this.states.delete(state);\n return Promise.resolve(null);\n }\n\n return Promise.resolve(oauthState);\n }\n\n setState(oauthState: OAuthState): Promise<void> {\n this.states.set(oauthState.state, oauthState);\n this.cleanupExpiredStates();\n return Promise.resolve();\n }\n\n clearState(state: string): Promise<void> {\n this.states.delete(state);\n return Promise.resolve();\n }\n\n /**\n * Clean up expired states\n */\n private cleanupExpiredStates(): void {\n const now = Date.now();\n for (const [state, oauthState] of this.states) {\n if (now - oauthState.createdAt > this.stateExpirationMs) {\n this.states.delete(state);\n }\n }\n }\n\n /**\n * Get all stored service IDs\n */\n getConnectedServices(): string[] {\n return Array.from(this.tokens.keys());\n }\n\n /**\n * Check if a service is connected\n */\n isConnected(serviceId: string): boolean {\n const tokens = this.tokens.get(serviceId);\n if (!tokens) return false;\n\n // Check if token is expired\n if (tokens.expiresAt && Date.now() > tokens.expiresAt) {\n // Token expired, but might be refreshable\n return !!tokens.refreshToken;\n }\n\n return true;\n }\n\n /**\n * Clear all tokens\n */\n clearAll(): void {\n this.tokens.clear();\n this.states.clear();\n }\n}\n\n/**\n * Default in-memory token store instance\n */\nexport const memoryTokenStore = new MemoryTokenStore();\n", "/**\n * OAuth Callback Handler\n *\n * Reusable handler for OAuth callback routes.\n */\n\nimport { OAuthService } from \"../providers/base.ts\";\nimport type { OAuthServiceConfig, TokenStore } from \"../types.ts\";\nimport { memoryTokenStore } from \"../token-store/memory.ts\";\nimport { getEnv } from \"../../../platform/compat/process.ts\";\n\nexport interface OAuthCallbackHandlerOptions {\n /** Token store to use (defaults to memory store) */\n tokenStore?: TokenStore;\n\n /** Base URL for redirects (defaults to APP_URL or localhost) */\n baseUrl?: string;\n\n /** Success redirect path */\n successRedirect?: string;\n\n /** Error redirect path */\n errorRedirect?: string;\n\n /** Custom success callback */\n onSuccess?: (serviceId: string, tokens: unknown) => void | Promise<void>;\n\n /** Custom error callback */\n onError?: (serviceId: string, error: string) => void | Promise<void>;\n}\n\n/**\n * Create an OAuth callback route handler\n *\n * @example\n * ```typescript\n * // app/api/auth/gmail/callback/route.ts\n * import { createOAuthCallbackHandler } from \"veryfront/oauth\";\n * import { gmailConfig } from \"veryfront/oauth/providers\";\n *\n * export const GET = createOAuthCallbackHandler(gmailConfig);\n * ```\n */\nexport function createOAuthCallbackHandler(\n config: OAuthServiceConfig,\n options: OAuthCallbackHandlerOptions = {},\n): (request: Request) => Promise<Response> {\n const {\n tokenStore = memoryTokenStore,\n baseUrl,\n successRedirect = \"/\",\n errorRedirect = \"/\",\n onSuccess,\n onError,\n } = options;\n\n return async (request: Request): Promise<Response> => {\n const url = new URL(request.url);\n const code = url.searchParams.get(\"code\");\n const state = url.searchParams.get(\"state\");\n const error = url.searchParams.get(\"error\");\n const errorDescription = url.searchParams.get(\"error_description\");\n\n const appUrl = baseUrl ||\n getEnv(\"APP_URL\") ||\n getEnv(\"NEXT_PUBLIC_APP_URL\") ||\n \"http://localhost:3000\";\n\n // Handle OAuth errors\n if (error) {\n console.error(`OAuth error for ${config.serviceId}:`, error, errorDescription);\n if (onError) {\n await onError(config.serviceId, error);\n }\n const errorUrl = new URL(errorRedirect, appUrl);\n errorUrl.searchParams.set(\"error\", error);\n if (errorDescription) {\n errorUrl.searchParams.set(\"error_description\", errorDescription);\n }\n return Response.redirect(errorUrl.toString());\n }\n\n // Validate code\n if (!code) {\n if (onError) {\n await onError(config.serviceId, \"no_code\");\n }\n const errorUrl = new URL(errorRedirect, appUrl);\n errorUrl.searchParams.set(\"error\", \"no_code\");\n return Response.redirect(errorUrl.toString());\n }\n\n // Validate and retrieve state\n let oauthState = null;\n if (state) {\n oauthState = await tokenStore.getState(state);\n if (!oauthState) {\n console.warn(`Invalid or expired state for ${config.serviceId}`);\n // Continue anyway - some providers don't properly return state\n }\n }\n\n const service = new OAuthService(config, tokenStore);\n const redirectUri = `${appUrl}/api/auth/${config.serviceId}/callback`;\n\n try {\n const result = await service.exchangeCode({\n code,\n redirectUri,\n codeVerifier: oauthState?.codeVerifier,\n });\n\n if (!result.success || !result.tokens) {\n console.error(`Token exchange failed for ${config.serviceId}:`, result.error);\n if (onError) {\n await onError(config.serviceId, result.error || \"exchange_failed\");\n }\n const errorUrl = new URL(errorRedirect, appUrl);\n errorUrl.searchParams.set(\"error\", result.error || \"token_exchange_failed\");\n return Response.redirect(errorUrl.toString());\n }\n\n // Store tokens\n await tokenStore.setTokens(config.serviceId, result.tokens);\n\n // Clear state\n if (state) {\n await tokenStore.clearState(state);\n }\n\n // Call success callback\n if (onSuccess) {\n await onSuccess(config.serviceId, result.tokens);\n }\n\n // Redirect to success URL\n const successUrl = new URL(successRedirect, appUrl);\n successUrl.searchParams.set(\"connected\", config.serviceId);\n return Response.redirect(successUrl.toString());\n } catch (err) {\n console.error(`OAuth callback error for ${config.serviceId}:`, err);\n if (onError) {\n await onError(config.serviceId, \"callback_error\");\n }\n const errorUrl = new URL(errorRedirect, appUrl);\n errorUrl.searchParams.set(\"error\", \"callback_error\");\n return Response.redirect(errorUrl.toString());\n }\n };\n}\n", "/**\n * OAuth Init Handler\n *\n * Reusable handler for initiating OAuth flows.\n */\n\nimport { OAuthService } from \"../providers/base.ts\";\nimport type { AuthorizationUrlOptions, OAuthServiceConfig, TokenStore } from \"../types.ts\";\nimport { memoryTokenStore } from \"../token-store/memory.ts\";\nimport { getEnv } from \"../../../platform/compat/process.ts\";\n\nexport interface OAuthInitHandlerOptions {\n /** Token store to use (defaults to memory store) */\n tokenStore?: TokenStore;\n\n /** Base URL for callbacks (defaults to APP_URL or localhost) */\n baseUrl?: string;\n\n /** Additional authorization options */\n authOptions?: AuthorizationUrlOptions;\n}\n\n/**\n * Create an OAuth init route handler\n *\n * @example\n * ```typescript\n * // app/api/auth/gmail/route.ts\n * import { createOAuthInitHandler } from \"veryfront/oauth\";\n * import { gmailConfig } from \"veryfront/oauth/providers\";\n *\n * export const GET = createOAuthInitHandler(gmailConfig);\n * ```\n */\nexport function createOAuthInitHandler(\n config: OAuthServiceConfig,\n options: OAuthInitHandlerOptions = {},\n): () => Promise<Response> {\n const { tokenStore = memoryTokenStore, baseUrl, authOptions = {} } = options;\n\n return async (): Promise<Response> => {\n const service = new OAuthService(config, tokenStore);\n\n if (!service.isConfigured()) {\n return Response.json(\n {\n error: `${config.displayName} OAuth not configured`,\n details: `Missing ${config.clientIdEnvVar} or ${config.clientSecretEnvVar}`,\n },\n { status: 500 },\n );\n }\n\n const appUrl = baseUrl ||\n getEnv(\"APP_URL\") ||\n getEnv(\"NEXT_PUBLIC_APP_URL\") ||\n \"http://localhost:3000\";\n\n const redirectUri = `${appUrl}/api/auth/${config.serviceId}/callback`;\n\n try {\n const { url, state } = await service.createAuthorizationUrl({\n ...authOptions,\n redirectUri,\n });\n\n // Store state for CSRF protection\n await tokenStore.setState(state);\n\n return Response.redirect(url);\n } catch (error) {\n console.error(`OAuth init error for ${config.serviceId}:`, error);\n return Response.json(\n {\n error: \"Failed to initiate OAuth flow\",\n details: error instanceof Error ? error.message : \"Unknown error\",\n },\n { status: 500 },\n );\n }\n };\n}\n\n/**\n * Create an OAuth status check handler\n *\n * @example\n * ```typescript\n * // app/api/auth/gmail/status/route.ts\n * import { createOAuthStatusHandler } from \"veryfront/oauth\";\n * import { gmailConfig } from \"veryfront/oauth/providers\";\n *\n * export const GET = createOAuthStatusHandler(gmailConfig);\n * ```\n */\nexport function createOAuthStatusHandler(\n config: OAuthServiceConfig,\n options: { tokenStore?: TokenStore } = {},\n): () => Promise<Response> {\n const { tokenStore = memoryTokenStore } = options;\n\n return async (): Promise<Response> => {\n const tokens = await tokenStore.getTokens(config.serviceId);\n\n const isConnected = !!tokens?.accessToken;\n const isExpired = tokens?.expiresAt ? Date.now() > tokens.expiresAt : false;\n const hasRefreshToken = !!tokens?.refreshToken;\n\n return Response.json({\n service: config.serviceId,\n displayName: config.displayName,\n connected: isConnected && (!isExpired || hasRefreshToken),\n configured: !!(getEnv(config.clientIdEnvVar) && getEnv(config.clientSecretEnvVar)),\n expiresAt: tokens?.expiresAt,\n hasRefreshToken,\n });\n };\n}\n\n/**\n * Create an OAuth disconnect handler\n *\n * @example\n * ```typescript\n * // app/api/auth/gmail/route.ts\n * import { createOAuthDisconnectHandler } from \"veryfront/oauth\";\n * import { gmailConfig } from \"veryfront/oauth/providers\";\n *\n * export const DELETE = createOAuthDisconnectHandler(gmailConfig);\n * ```\n */\nexport function createOAuthDisconnectHandler(\n config: OAuthServiceConfig,\n options: { tokenStore?: TokenStore } = {},\n): () => Promise<Response> {\n const { tokenStore = memoryTokenStore } = options;\n\n return async (): Promise<Response> => {\n await tokenStore.clearTokens(config.serviceId);\n\n return Response.json({\n success: true,\n message: `Disconnected from ${config.displayName}`,\n });\n };\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|