From glean-pack
Provides typed TypeScript client for Glean API with batch indexing, pagination, search, and error handling. Useful for production Glean integrations.
npx claudepluginhub jeremylongshore/claude-code-plugins-plus-skills --plugin glean-packThis skill is limited to using the following tools:
```typescript
Indexes documents into Glean custom datasources via Indexing API and searches using Client API. For building connectors, testing search quality, or learning patterns.
Searches and fetches Glean developer docs via MCP tools for APIs, SDKs (Python/JS), MCP config, authentication, indexing, and integrations.
Expert guidance for Next.js Cache Components and Partial Prerendering (PPR). **PROACTIVE ACTIVATION**: Use this skill automatically when working in Next.js projects that have `cacheComponents: true` in their next.config.ts/next.config.js. When this config is detected, proactively apply Cache Components patterns and best practices to all React Server Component implementations. **DETECTION**: At the start of a session in a Next.js project, check for `cacheComponents: true` in next.config. If enabled, this skill's patterns should guide all component authoring, data fetching, and caching decisions. **USE CASES**: Implementing 'use cache' directive, configuring cache lifetimes with cacheLife(), tagging cached data with cacheTag(), invalidating caches with updateTag()/revalidateTag(), optimizing static vs dynamic content boundaries, debugging cache issues, and reviewing Cache Component implementations.
Share bugs, ideas, or general feedback.
class GleanClient {
private indexUrl: string;
private searchUrl: string;
constructor(private domain: string, private indexToken: string, private clientToken: string) {
this.indexUrl = `https://${domain}/api/index/v1`;
this.searchUrl = `https://${domain}/api/client/v1`;
}
async indexDocuments(datasource: string, docs: GleanDocument[]) {
const res = await fetch(`${this.indexUrl}/indexdocuments`, {
method: 'POST',
headers: { 'Authorization': `Bearer ${this.indexToken}`, 'Content-Type': 'application/json' },
body: JSON.stringify({ datasource, documents: docs }),
});
if (!res.ok) throw new Error(`Glean index error ${res.status}: ${await res.text()}`);
return res.json();
}
async search(query: string, options: { pageSize?: number; datasource?: string } = {}) {
const res = await fetch(`${this.searchUrl}/search`, {
method: 'POST',
headers: {
'Authorization': `Bearer ${this.clientToken}`,
'X-Glean-Auth-Type': 'BEARER',
'Content-Type': 'application/json',
},
body: JSON.stringify({
query,
pageSize: options.pageSize ?? 20,
requestOptions: options.datasource ? { datasourceFilter: options.datasource } : undefined,
}),
});
if (!res.ok) throw new Error(`Glean search error ${res.status}: ${await res.text()}`);
return res.json();
}
async bulkIndex(datasource: string, docs: GleanDocument[], batchSize = 100) {
const uploadId = `bulk-${Date.now()}`;
for (let i = 0; i < docs.length; i += batchSize) {
const batch = docs.slice(i, i + batchSize);
await fetch(`${this.indexUrl}/bulkindexdocuments`, {
method: 'POST',
headers: { 'Authorization': `Bearer ${this.indexToken}`, 'Content-Type': 'application/json' },
body: JSON.stringify({
datasource, uploadId,
isFirstPage: i === 0,
isLastPage: i + batchSize >= docs.length,
documents: batch,
}),
});
}
}
}
interface GleanDocument {
id: string;
title: string;
url: string;
body: { mimeType: string; textContent: string };
author?: { email: string };
updatedAt?: string;
permissions?: { allowAnonymousAccess?: boolean; allowedUsers?: Array<{ email: string }> };
}