Documentation Index
Fetch the complete documentation index at: https://mintlify.com/theopenlane/openlane-ui/llms.txt
Use this file to discover all available pages before exploring further.
Overview
The @repo/dally package provides authentication utilities, environment configuration, and API helpers for Openlane applications. It centralizes configuration management and provides type-safe functions for user authentication and AI features.
Installation
Package Exports
| Export | Path | Description |
|---|
auth | @repo/dally/auth | Environment config and API URLs |
user | @repo/dally/user | User authentication functions |
chat | @repo/dally/chat | Chat configuration |
ai | @repo/dally/ai | AI/LLM configuration |
Authentication Configuration
API URLs and Configuration
import {
openlaneAPIUrl,
openlaneGQLUrl,
websocketGQLUrl,
sessionCookieName,
sessionCookieDomain,
cookieDomain,
csrfCookieName,
csrfHeader,
siteUrl
} from '@repo/dally/auth'
// API base URL
const apiUrl = openlaneAPIUrl // process.env.NEXT_PUBLIC_OPENLANE_URL
// GraphQL endpoint
const gqlUrl = openlaneGQLUrl // ${NEXT_PUBLIC_OPENLANE_URL}/query
// WebSocket GraphQL URL
const wsUrl = websocketGQLUrl // wss://api.example.com/query
// Session configuration
const sessionName = sessionCookieName
const sessionDomain = sessionCookieDomain
// CSRF protection
const csrfCookie = csrfCookieName // 'ol.csrf-token'
const csrfHeaderName = csrfHeader // 'X-CSRF-Token'
Environment Detection
import {
isDevelopment,
isVercelDev
} from '@repo/dally/auth'
if (isDevelopment) {
console.log('Running in development mode')
}
if (isVercelDev) {
console.log('Running on Vercel preview/dev environment')
}
Security Configuration
import {
recaptchaSiteKey,
allowedLoginDomains
} from '@repo/dally/auth'
// reCAPTCHA integration
function LoginForm() {
return (
<ReCAPTCHA
sitekey={recaptchaSiteKey}
onChange={handleCaptchaChange}
/>
)
}
// Domain restrictions
const isAllowedDomain = allowedLoginDomains.includes(emailDomain)
Feature Flags
import {
includeQuestionnaireCreation,
enableDevrevChat,
cname
} from '@repo/dally/auth'
// Conditional feature rendering
{includeQuestionnaireCreation && (
<Button>Create Questionnaire</Button>
)}
// Chat integration
{enableDevrevChat && (
<ChatWidget appId={chatAppId} />
)}
// Custom domain
const customDomain = cname
Third-party Integration
import {
chatAppId,
surveyLicenseKey,
pirschAnalyticsKey,
stripeSecretKey
} from '@repo/dally/auth'
// Chat application
const chatId = chatAppId // NEXT_PUBLIC_CHAT_APP_ID
// Survey.js license
const surveyKey = surveyLicenseKey // NEXT_PUBLIC_SURVEYJS_KEY
// Analytics
const analyticsKey = pirschAnalyticsKey // NEXT_PUBLIC_PIRSCH_KEY
// Payment processing (server-side only)
const stripeKey = stripeSecretKey
User Authentication
User Registration
import { registerUser, type RegisterUser } from '@repo/dally/user'
async function handleRegister(data: RegisterUser) {
const result = await registerUser({
username: data.username,
password: data.password,
confirmedPassword: data.confirmedPassword,
})
if (result.message) {
console.error('Registration failed:', result.message)
} else {
console.log('Registration successful:', result)
}
}
// Example component
function SignupForm() {
const [formData, setFormData] = useState<RegisterUser>({
username: '',
password: '',
confirmedPassword: ''
})
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault()
await handleRegister(formData)
}
return (
<form onSubmit={handleSubmit}>
<input
type="email"
value={formData.username}
onChange={(e) => setFormData({ ...formData, username: e.target.value })}
placeholder="Email"
/>
<input
type="password"
value={formData.password}
onChange={(e) => setFormData({ ...formData, password: e.target.value })}
placeholder="Password"
/>
<input
type="password"
value={formData.confirmedPassword}
onChange={(e) => setFormData({ ...formData, confirmedPassword: e.target.value })}
placeholder="Confirm Password"
/>
<button type="submit">Sign Up</button>
</form>
)
}
User Verification
import { verifyUser } from '@repo/dally/user'
async function handleEmailVerification(token: string) {
const result = await verifyUser(token)
if (result.message) {
console.error('Verification failed:', result.message)
} else {
console.log('Email verified successfully:', result)
}
}
// Example usage in a verification page
function VerifyEmailPage() {
const searchParams = useSearchParams()
const token = searchParams.get('token')
useEffect(() => {
if (token) {
handleEmailVerification(token)
}
}, [token])
return <div>Verifying your email...</div>
}
User Login Types
import { type LoginUser } from '@repo/dally/user'
const credentials: LoginUser = {
username: 'user@example.com',
password: 'secure-password'
}
// Use with your authentication flow
function LoginForm() {
const [loginData, setLoginData] = useState<LoginUser>({
username: '',
password: ''
})
// Handle login with your auth provider
}
Chat Configuration
import {
bedrockModelArn,
enableChat
} from '@repo/dally/chat'
// Check if chat is enabled
if (enableChat === 'true') {
// Initialize chat features
}
// AWS Bedrock model configuration
const modelArn = bedrockModelArn
AI Configuration
AI Feature Detection
import { aiEnabled } from '@repo/dally/ai'
function PolicyEditor() {
return (
<div>
<textarea />
{aiEnabled && (
<Button>Generate with AI</Button>
)}
</div>
)
}
Google Vertex AI Configuration
import {
googleAPIKey,
googleProjectID,
googleAIRegion,
aiLogBucket,
ragCorpusID,
geminiModelName
} from '@repo/dally/ai'
// Vertex AI client configuration
const vertexConfig = {
apiKey: googleAPIKey,
projectId: googleProjectID,
region: googleAIRegion,
logBucket: aiLogBucket,
ragCorpus: ragCorpusID
}
// Model selection
const modelName = geminiModelName // Default: 'gemini-2.5-flash'
AI Generation Parameters
import {
aiSystemInstruction,
controlSystemInstruction,
policyPrompt,
temperature,
maxOutputTokens
} from '@repo/dally/ai'
// System instructions
const systemPrompt = aiSystemInstruction
// "You are a helpful assistant that provides concise and accurate answers..."
const controlPrompt = controlSystemInstruction
// "When referencing controls, always use their ref codes..."
// Generate policy prompt
const prompt = policyPrompt('Data Privacy Policy')
// "Generate a formal policy document for 'Data Privacy Policy'..."
// Model parameters
const modelConfig = {
temperature: temperature, // Default: 0.1
maxOutputTokens: maxOutputTokens // Default: 5000
}
AI Integration Example
import {
aiEnabled,
policyPrompt,
temperature,
maxOutputTokens
} from '@repo/dally/ai'
function PolicyGenerator() {
const [policyName, setPolicyName] = useState('')
const [generatedContent, setGeneratedContent] = useState('')
const generatePolicy = async () => {
if (!aiEnabled) {
console.error('AI features are not enabled')
return
}
const prompt = policyPrompt(policyName)
// Call your AI generation endpoint
const response = await fetch('/api/generate-policy', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
prompt,
temperature,
maxOutputTokens
})
})
const data = await response.json()
setGeneratedContent(data.content)
}
return (
<div>
<input
value={policyName}
onChange={(e) => setPolicyName(e.target.value)}
placeholder="Policy name"
/>
{aiEnabled && (
<Button onClick={generatePolicy}>Generate with AI</Button>
)}
<div>{generatedContent}</div>
</div>
)
}
Common Patterns
WebSocket Connection
import { websocketGQLUrl } from '@repo/dally/auth'
import { createClient } from 'graphql-ws'
const wsClient = createClient({
url: websocketGQLUrl,
connectionParams: {
// Authentication headers
}
})
API Client Configuration
import { openlaneGQLUrl, csrfHeader, csrfCookieName } from '@repo/dally/auth'
import { GraphQLClient } from 'graphql-request'
const client = new GraphQLClient(openlaneGQLUrl, {
headers: {
[csrfHeader]: getCSRFToken(),
},
credentials: 'include',
})
function getCSRFToken() {
return document.cookie
.split('; ')
.find(row => row.startsWith(`${csrfCookieName}=`))
?.split('=')[1]
}
Protected Route Check
import { sessionCookieName } from '@repo/dally/auth'
import { cookies } from 'next/headers'
export async function middleware(request: Request) {
const cookieStore = cookies()
const session = cookieStore.get(sessionCookieName)
if (!session) {
return Response.redirect(new URL('/login', request.url))
}
}
Environment Variables
The package expects these environment variables:
Authentication
NEXT_PUBLIC_OPENLANE_URL - Openlane API base URL
SESSION_COOKIE_NAME - Session cookie name
SESSION_COOKIE_DOMAIN - Session cookie domain
COOKIE_DOMAIN - General cookie domain
NEXT_PUBLIC_CSRF_COOKIE_NAME - CSRF token cookie
NEXT_PUBLIC_CSRF_HEADER - CSRF header name
Features
NEXT_PUBLIC_INCLUDE_QUESTIONNAIRE_CREATION - Enable questionnaire features
NEXT_PUBLIC_ENABLE_CHATBOT - Enable chat features
NEXT_PUBLIC_ENABLE_DEVREV_CHAT - Enable DevRev chat
NEXT_PUBLIC_AI_SUGGESTIONS_ENABLED - Enable AI features
Third-party
NEXT_PUBLIC_RECAPTCHA_SITE_KEY - reCAPTCHA site key
NEXT_PUBLIC_CHAT_APP_ID - Chat application ID
NEXT_PUBLIC_SURVEYJS_KEY - Survey.js license key
NEXT_PUBLIC_PIRSCH_KEY - Pirsch analytics key
STRIPE_SECRET_KEY - Stripe secret key (server-side)
AI Configuration
GOOGLE_SERVICE_ACCOUNT_KEY_B64 - Google service account key
GOOGLE_AI_PROJECT_ID - Google AI project ID
GOOGLE_AI_REGION - Google AI region
GOOGLE_AI_MODEL_NAME - Gemini model name
BEDROCK_MODEL_ARN - AWS Bedrock model ARN
Best Practices
- Centralize configuration - Import from
@repo/dally instead of accessing process.env directly
- Type safety - Use exported types like
LoginUser and RegisterUser
- Error handling - Always check for
.message property in API responses
- Feature flags - Check configuration before rendering features
- Server vs Client - Be aware of which values are public vs server-only
Security Considerations
- CSRF tokens are included in API requests
- Session cookies use secure domains
- reCAPTCHA prevents automated abuse
- Environment variables separate public and private config
- Email domain restrictions can be enforced