TypeScript API Client
Glean's TypeScript API client provides full type safety for integrating Glean's search and AI capabilities into web applications and Node.js services.
@gleanwork/api-client
Official TypeScript/JavaScript client for Glean's Client API
Installation
- npm
- yarn
- pnpm
npm install @gleanwork/api-client
yarn add @gleanwork/api-client
pnpm add @gleanwork/api-client
Quick Start
import { Glean } from "@gleanwork/api-client";
const client = new Glean({
apiToken: process.env.GLEAN_API_TOKEN,
instance: process.env.GLEAN_INSTANCE,
});
const result = await client.client.chat.create({
messages: [{
fragments: [{ text: "What are our company values?" }]
}]
});
Core Features
Chat API
// Simple chat
const response = await client.client.chat.create({
messages: [{ fragments: [{ text: "Explain our Q4 strategy" }] }]
});
// Streaming responses
const stream = client.client.chat.stream({
messages: [{ fragments: [{ text: "What are our priorities?" }] }]
});
for await (const chunk of stream) {
console.log(chunk.text);
}
Search API
const results = await client.client.search.search({
query: "quarterly business review",
pageSize: 10
});
results.results?.forEach(result => {
console.log(`Title: ${result.title}`);
console.log(`URL: ${result.url}`);
});
Framework Integrations
Next.js API Route
// app/api/chat/route.ts
import { NextRequest, NextResponse } from 'next/server';
import { Glean } from '@gleanwork/api-client';
export async function POST(request: NextRequest) {
const { message } = await request.json();
const client = new Glean({
apiToken: process.env.GLEAN_API_TOKEN!,
instance: process.env.GLEAN_INSTANCE!,
});
const response = await client.client.chat.create({
messages: [{ fragments: [{ text: message }] }]
});
return NextResponse.json({ response: response.text });
}
React Component
import React, { useState } from 'react';
import { Glean } from '@gleanwork/api-client';
export function ChatComponent({ apiToken, instance }) {
const [input, setInput] = useState('');
const [response, setResponse] = useState('');
const client = new Glean({ apiToken, instance });
const handleSubmit = async (e) => {
e.preventDefault();
const result = await client.client.chat.create({
messages: [{ fragments: [{ text: input }] }]
});
setResponse(result.text || '');
};
return (
<form onSubmit={handleSubmit}>
<input
value={input}
onChange={(e) => setInput(e.target.value)}
placeholder="Ask a question..."
/>
<button type="submit">Send</button>
{response && <div>{response}</div>}
</form>
);
}
Express.js
import express from 'express';
import { Glean } from '@gleanwork/api-client';
const app = express();
app.use(express.json());
const client = new Glean({
apiToken: process.env.GLEAN_API_TOKEN!,
instance: process.env.GLEAN_INSTANCE!,
});
app.post('/api/chat', async (req, res) => {
const { message } = req.body;
const response = await client.client.chat.create({
messages: [{ fragments: [{ text: message }] }]
});
res.json({ response: response.text });
});
Authentication
User-Scoped Tokens (Recommended)
const client = new Glean({
apiToken: "your-user-token",
instance: "your-company"
});
Global Tokens with ActAs
const response = await client.client.chat.create({
messages: [{ fragments: [{ text: "Hello" }] }]
}, {
headers: { "X-Glean-ActAs": "user@company.com" }
});
OAuth Authentication
OAuth allows you to use access tokens from your identity provider (Google, Azure, Okta, etc.) instead of Glean-issued tokens.
Prerequisites
- OAuth enabled in Glean Admin > Third-Party OAuth
- Your OAuth Client ID registered with Glean
- See OAuth Setup Guide for admin configuration
OAuth requests require these headers:
| Header | Value |
|---|---|
Authorization | Bearer <oauth_access_token> |
X-Glean-Auth-Type | OAUTH |
Example: Authorization Code Flow
This example uses openid-client (v6+) with Express:
import express from 'express';
import session from 'express-session';
import * as client from 'openid-client';
import { Glean } from '@gleanwork/api-client';
const config = {
clientId: process.env.OAUTH_CLIENT_ID!,
clientSecret: process.env.OAUTH_CLIENT_SECRET!,
redirectUri: 'http://localhost:3000/callback',
issuer: process.env.OAUTH_ISSUER!, // e.g., https://accounts.google.com
};
const app = express();
app.use(session({ secret: 'session-secret', resave: false, saveUninitialized: false }));
let oidcConfig: client.Configuration;
// Initialize OIDC client on startup
async function init() {
oidcConfig = await client.discovery(
new URL(config.issuer),
config.clientId,
config.clientSecret
);
}
app.get('/login', async (req, res) => {
// Generate PKCE code verifier and state for security
const codeVerifier = client.randomPKCECodeVerifier();
const codeChallenge = await client.calculatePKCECodeChallenge(codeVerifier);
const state = client.randomState();
// Store in session for verification on callback
req.session.codeVerifier = codeVerifier;
req.session.state = state;
const authUrl = client.buildAuthorizationUrl(oidcConfig, {
redirect_uri: config.redirectUri,
scope: 'openid email',
code_challenge: codeChallenge,
code_challenge_method: 'S256',
state,
});
res.redirect(authUrl.href);
});
app.get('/callback', async (req, res) => {
const { codeVerifier, state } = req.session;
const callbackUrl = new URL(req.url, `http://${req.headers.host}`);
// Exchange code for tokens with PKCE and state verification
const tokens = await client.authorizationCodeGrant(oidcConfig, callbackUrl, {
pkceCodeVerifier: codeVerifier,
expectedState: state,
});
// Use OAuth token with Glean
const glean = new Glean({ instance: process.env.GLEAN_INSTANCE! });
const results = await glean.client.search.search({
query: 'quarterly reports',
pageSize: 10,
}, {
headers: {
'Authorization': `Bearer ${tokens.access_token}`,
'X-Glean-Auth-Type': 'OAUTH',
},
});
res.json(results);
});
init().then(() => app.listen(3000));
tip
Access tokens typically expire after ~1 hour. For production use, implement token refresh using tokens.refresh_token.
Error Handling
try {
const response = await client.client.chat.create({
messages: [{ fragments: [{ text: "Hello" }] }]
});
} catch (error) {
console.error('API error:', error);
}
Testing
import { jest } from '@jest/globals';
import { Glean } from '@gleanwork/api-client';
jest.mock('@gleanwork/api-client');
const MockedGlean = Glean as jest.MockedClass<typeof Glean>;
test('chat service', async () => {
const mockCreate = jest.fn().mockResolvedValue({
text: 'Test response'
});
MockedGlean.mockImplementation(() => ({
client: { chat: { create: mockCreate } }
} as any));
// Test your code here
});