Frame.io, Surfline, Resend, and APNs
Integrations
Surflink integrates with several external services for video management, surf conditions, email delivery, and push notifications.
Frame.io (Video Assets)
File: src/lib/frameio.js
Surflink integrates with Adobe Frame.io V4 to allow coaches to browse and import video assets from their Frame.io accounts directly into the platform.
OAuth Flow
Frame.io uses Adobe IMS (Identity Management System) for OAuth:
- Coach clicks "Connect Frame.io" in the upload page
- Redirected to Adobe IMS authorization URL with scopes for Frame.io access
- User authorizes the application
- Callback exchanges the authorization code for access + refresh tokens
- Tokens are stored in HTTP-only cookies (
frameio_token,frameio_refresh_token) - Token refresh is handled automatically when the access token expires
API Methods
| Method | Description |
|---|---|
getMe() | Get current user profile |
getWorkspaces(accountId) | List workspaces for an account |
getProjects(workspaceId) | List projects in a workspace |
getFolderChildren(folderId) | List files and folders |
getFile(fileId) | Get file metadata |
downloadAssetBuffer(url) | Download file content as buffer |
Import Flow
- Coach browses their Frame.io account through the
FrameIOBrowsercomponent - Selects video files for import (max 10 per batch)
/api/frameio/importdownloads each asset and creates session + clip records- Each clip is sent to Modal for AI analysis
- Processing follows the standard video pipeline
Surfline (Surf Conditions)
File: src/lib/surfline.js
Surflink wraps the Surfline KBYG (Know Before You Go) API to provide real-time surf condition data.
Caching
All Surfline API responses are cached in-memory with:
- 10-minute TTL per cache entry
- 200-entry LRU eviction to prevent memory bloat
- Cache keys are based on the full request URL
Available Data
| Data Type | Description |
|---|---|
| Wave Forecast | Height (min/max), period, direction, optimal score |
| Wind | Speed, direction, gusts, optimal score |
| Surf Rating | 0-5 star rating with human-readable conditions |
| Tides | High/low tide times and heights |
| Map View | Bounding-box based spot discovery |
API Methods
| Method | Description |
|---|---|
getWaveForecast(spotId, days) | Wave data for a spot |
getWindForecast(spotId, days) | Wind data for a spot |
getRating(spotId, days) | Surf quality rating |
getTides(spotId, days) | Tide schedule |
getConditions(spotId) | Current conditions summary |
getSpotForecast(spotId, days) | Composite: wave + wind + rating + tides in parallel |
getMapview(bounds) | Spots within a bounding box |
Integration Points
- Dashboard widget -- Current conditions at the coach's home break
- Surf forecast widget -- Multi-day outlook
- Lesson scheduling -- Forecast data for the scheduled date and location
- Journal entries -- Conditions at the time of the session
The default configuration focuses on Barbados surf spots with a pre-configured bounding box and spot database.
Resend (Email)
Package: resend
Used for transactional email delivery:
- Student invitations -- Email with invite link when a coach adds a new student
- Critical notifications -- Lesson reminders, achievement awards, and other important updates
Emails are sent through the /api/notifications/send and /api/invite endpoints.
Apple Push Notifications (APNs)
Package: jose (for JWT signing)
Push notifications are sent to registered iOS and watchOS devices:
Token Registration
Devices register their push tokens via the push_tokens table. Each token records the user ID, device token, platform (apns/fcm/web), and device name.
Sending Flow
/api/notifications/sendreceives a notification request- Creates a notification record in the database
- Queries
push_tokensfor the target user's registered devices - Signs a JWT using the APNs private key (via
jose) - Sends the push payload to Apple's APNs HTTP/2 endpoint
- Handles token expiration and invalid token cleanup
Configuration
Requires these environment variables:
APNS_KEY_ID-- Key ID from Apple Developer portalAPNS_TEAM_ID-- Apple Developer Team IDAPNS_PRIVATE_KEY-- The .p8 private key contentAPNS_BUNDLE_ID-- App bundle identifierAPNS_ENVIRONMENT--developmentorproduction