npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

@inheritage-foundation/sdk

v0.2.0

Published

TypeScript SDK for the Inheritage API — India's open cultural heritage dataset.

Downloads

13

Readme

@inheritage-foundation/sdk

npm version License CI

Official TypeScript SDK for the Inheritage Foundation public API. Access India's documented heritage programmatically—temples, monuments, cultural sites—with zero gatekeeping, full attribution, and production-grade ergonomics.

License: Apache 2.0 (SDK code) | Data under CC BY 4.0
Data Attribution: Required per CC BY 4.0 — see AI Usage Policy


Features

  • 🏛️ 5000+ Heritage Sites: Temples, forts, monuments across India
  • 🗺️ GeoJSON Support: EPSG:4326, bbox queries, native geospatial APIs
  • 🤖 AI-Ready: 1536-d embeddings, semantic search, LangChain/LangGraph adapters
  • ⚛️ React Hooks: useHeritage, useAIContext, useSimilarSites with auto-caching
  • 🎨 Attribution Component: <InheritageCitation /> for CC BY 4.0 compliance
  • 📦 Tree-shakeable: ESM/CJS dual build, zero runtime dependencies (except React for hooks)
  • 🔒 Type-Safe: Full TypeScript definitions generated from OpenAPI spec
  • Smart Caching: ETag, If-None-Match, stale-while-revalidate support
  • 🚦 Rate Limit Aware: Automatic retry headers, exponential backoff utilities
  • 🌐 Multi-Format: JSON, GeoJSON, NDJSON vector feeds

Installation

npm install @inheritage-foundation/sdk
# or
yarn add @inheritage-foundation/sdk
# or
pnpm add @inheritage-foundation/sdk

Quick Start

Basic Usage

import { InheritageClient } from '@inheritage-foundation/sdk'

const client = new InheritageClient({
  baseUrl: 'https://inheritage.foundation/api/v1', // optional, this is default
  attribution: 'visible', // required for CC BY 4.0 compliance
})

// Fetch a heritage site
const site = await client.getHeritage('hoysaleswara-temple')
console.log(site.data.name) // "Hoysaleswara Temple"
console.log(site.data.state) // "Karnataka"

// List heritage sites with filters
const sites = await client.listHeritage({
  state: 'Karnataka',
  category: 'Temple',
  limit: 10,
  offset: 0,
})
console.log(sites.data.data.length) // 10
console.log(sites.data.meta.total) // 450

// Nearby search (GeoJSON)
const nearby = await client.getGeoNearby({
  lat: 28.6139,
  lon: 77.2090,
  radius: 10, // km
  limit: 5,
})
console.log(nearby.data.type) // "FeatureCollection"
console.log(nearby.data.features[0].properties.name) // "Qutb Minar"

React Hooks

import { useHeritage, useAIContext, InheritageCitation } from '@inheritage-foundation/sdk'

function HeritagePage({ slug }: { slug: string }) {
  const { data, loading, error } = useHeritage(slug)
  const { data: aiContext } = useAIContext(slug)

  if (loading) return <div>Loading...</div>
  if (error) return <div>Error: {error.message}</div>
  if (!data) return <div>Not found</div>

  return (
    <div>
      <h1>{data.name}</h1>
      <p>{data.description}</p>
      
      {aiContext && (
        <div>
          <h2>AI Context</h2>
          <p>{aiContext.context}</p>
          <small>Embedding dimensions: {aiContext.embedding_dimensions}</small>
        </div>
      )}
      
      <InheritageCitation citation={data.citations} display="block" showBadge />
    </div>
  )
}

AI & Semantic Search

// Get AI context and embeddings
const context = await client.getAIContext('taj-mahal')
console.log(context.data.context) // "The Taj Mahal is a 17th-century mausoleum..."
console.log(context.data.embedding.length) // 1536
console.log(context.data.embedding_checksum) // "a1b2c3d4..."

// Find similar sites
const similar = await client.findSimilar({
  slug: 'taj-mahal',
  limit: 5,
})
similar.data.data.forEach(entry => {
  console.log(`${entry.score.toFixed(3)} - ${entry.site.name}`)
})
// Output:
// 0.987 - Humayun's Tomb
// 0.954 - Red Fort
// 0.932 - Agra Fort

// Get AI metadata bundle
const metadata = await client.getAIMetadata('taj-mahal')
console.log(metadata.data.model) // "inheritage-d1"
console.log(metadata.data.model_version) // "2025-01-15"
console.log(metadata.data.license_url) // "https://inheritage.foundation/license/ai"

// Stream vector index for database sync
const vectors = await client.getAIVectorIndex({ limit: 100, offset: 0 })
vectors.data.forEach(record => {
  console.log(record.slug, record.vector.length, record.embedding_checksum)
})

LangChain Integration

import { InheritageClient, createHeritageContextRunnable, createInheritageToolkit } from '@inheritage-foundation/sdk/langchain'
import { ChatOpenAI } from '@langchain/openai'

const client = new InheritageClient({ attribution: 'visible' })

// Create a runnable for AI context retrieval
const heritageContextChain = createHeritageContextRunnable({ 
  client,
  includeHeaders: false, // set true to include API metadata
})

const result = await heritageContextChain.invoke({ slug: 'khajuraho' })
console.log(result.context)
console.log(result.embedding_dimensions) // 1536

// Create tools for LangChain agents
const tools = createInheritageToolkit(client)
const llm = new ChatOpenAI({ modelName: 'gpt-4-turbo' })

// Agent can now use:
// - get_heritage_ai_context
// - find_similar_heritage_sites
// - get_heritage_ai_metadata
// - get_heritage_ai_license

API Coverage

Heritage API

Endpoints: GET /heritage/:slug, GET /heritage, GET /heritage/featured, GET /heritage/top

Fetch detailed information about cultural heritage sites including:

  • Name, description, historical context
  • Location (state, coordinates, geolocation)
  • Architecture (style, materials, construction)
  • Visitor information (hours, fees, facilities)
  • Media (images, videos, 360° panoramas, floor plans)
  • Timeline events, references, analytics

Example:

const site = await client.getHeritage('ram-mandir-ayodhya')
console.log(site.data.architecture.style) // "Nagara Style"
console.log(site.data.visitor_info.entry_fee) // "Free"
console.log(site.data.media.primary_image) // "https://cdn.inheritage.foundation/..."

Geospatial API

Endpoints: GET /geo/nearby, GET /geo/region, GET /geo/:slug

GeoJSON-first geospatial queries:

  • Nearby search by lat/lon with radius
  • Region/bounding box queries
  • Single-site GeoJSON feature
  • EPSG:4326 coordinates, Accept: application/geo+json header support

Example:

const nearby = await client.getGeoNearby({
  lat: 19.0760,
  lon: 72.8777,
  radius: 5, // km
  limit: 10,
})
nearby.data.features.forEach(feature => {
  console.log(feature.properties.name, feature.geometry.coordinates)
})

Media API

Endpoints: GET /media/:slug

Fetch media bundles including:

  • Primary images, galleries, panoramas
  • 360° virtual tours, floor plans, site plans
  • Point clouds, mesh data, CAD files
  • Videos, documents

Example:

const media = await client.getMedia('hoysaleswara-temple')
console.log(media.data.primary_image) // "https://cdn.inheritage.foundation/..."
console.log(media.data.gallery.length) // 24
console.log(media.data.panoramas[0].url) // "https://cdn.inheritage.foundation/..."

Citation API

Endpoints: GET /citation/:entityId

Retrieve attribution metadata for any entity:

const citation = await client.getCitation('taj-mahal')
console.log(citation.data.required_display) // "Data © Inheritage Foundation"
console.log(citation.data.license) // "CC BY 4.0"

AI Context, Metadata & Federation

Endpoints: GET /ai/context/:slug, /ai/embedding/:slug, POST /ai/similar, GET /ai/meta/:slug, POST /ai/vision/context, GET /ai/vector-index.ndjson, GET /license/ai

Features:

  • Deterministic narratives + 1536-d embeddings with checksum + model version headers
  • Similarity endpoint accepts either slug or a custom embedding array, returning cosine-ranked matches with reference metadata
  • Metadata endpoint mirrors the production schema (embedding_checksum, sources, same_as) for LangChain/LangGraph ingestion
  • Vision ingress classifies an image (URL/Base64) into probable heritage sites with captions + style predictions
  • Vector feed emits NDJSON slices for Pinecone/Weaviate/Chroma syncing; use getAIVectorIndex with limit/offset pagination
  • AI license endpoint provides the JSON addendum required for policy auditors and automated agents

Example:

// AI Context
const context = await client.getAIContext('ajanta-caves-maharashtra')
console.log(context.data.context) // "The Ajanta Caves are a UNESCO World Heritage Site..."
console.log(context.data.embedding_checksum) // SHA-256 checksum for reproducibility

// Similar Sites
const similar = await client.findSimilar({ slug: 'ajanta-caves-maharashtra', limit: 5 })
console.table(similar.data.data.map(entry => ({
  score: entry.score.toFixed(3),
  slug: entry.site.slug,
  state: entry.site.state
})))

// AI Metadata
const metadata = await client.getAIMetadata('ajanta-caves-maharashtra')
console.log(metadata.data.embedding_checksum) // Stable SHA-256 checksum
console.log(metadata.data.license_url) // "https://inheritage.foundation/license/ai"

// Vector Index Feed
const vectorFeed = await client.getAIVectorIndex({ limit: 100 })
vectorFeed.data.forEach(record => {
  console.log(record.slug, record.embedding_checksum)
})

// Vision Context
const vision = await client.getAIVisionContext({ 
  image_url: 'https://cdn.inheritage.foundation/hoysaleswara/front.jpg' 
})
console.log(vision.data.caption) // "A detailed view of the Hoysaleswara Temple facade."
console.log(vision.data.architectural_style_prediction) // "Hoysala"

// AI License
const license = await client.getAILicense()
console.log(license.data.requirements.ai_headers['AI-Use-Allowed']) // "true"

React Hooks Reference

useHeritage(slug, options?)

Fetch a single heritage site with automatic loading/error states.

const { data, loading, error, refetch } = useHeritage('taj-mahal', {
  client: customClient, // optional
  enabled: true, // optional, default true
})

useHeritageList(params?, options?)

Fetch paginated heritage sites with filters.

const { data, loading, error, refetch } = useHeritageList({
  state: 'Karnataka',
  category: 'Temple',
  limit: 20,
}, { enabled: true })

useGeoNearby(params, options?)

Fetch nearby heritage sites as GeoJSON.

const { data, loading, error, refetch } = useGeoNearby({
  lat: 28.6139,
  lon: 77.2090,
  radius: 10,
})

useAIContext(slug, options?)

Fetch AI context and embeddings.

const { data, loading, error, refetch } = useAIContext('khajuraho')

useSimilarSites(params, options?)

Find semantically similar sites.

const { data, loading, error, refetch } = useSimilarSites({
  slug: 'taj-mahal',
  limit: 5,
})

useAIVectorIndex(params?, options?)

Paginate through the vector index with infinite scroll support.

const { data, loading, error, hasMore, loadMore } = useAIVectorIndex({
  limit: 100,
})

// Call loadMore() to fetch next page

Components Reference

<InheritageCitation />

Renders CC BY 4.0 attribution for Inheritage data.

Props:

  • citation (CitationEntry): Citation data from API response
  • display ('inline' | 'block'): Display mode (default: 'inline')
  • className (string): Custom CSS class
  • style (CSSProperties): Custom inline styles
  • showBadge (boolean): Show CC BY 4.0 badge (default: false)
  • showLegal (boolean): Show full legal text (default: false)

Examples:

// Inline (compact)
<InheritageCitation citation={response.citations} />

// Block with badge
<InheritageCitation 
  citation={response.citations} 
  display="block" 
  showBadge 
/>

// Full legal notice
<InheritageCitation 
  citation={response.citations} 
  display="block" 
  showBadge 
  showLegal 
/>

Advanced Features

Caching & Conditional Requests

// Use ETag for conditional requests
const response1 = await client.getHeritage('taj-mahal')
const etag = response1.headers?.get('ETag')

const response2 = await client.getHeritage('taj-mahal', { ifNoneMatch: etag })
if (response2.notModified) {
  console.log('Use cached data')
} else {
  console.log('Fresh data:', response2.data)
}

// If-Modified-Since
const lastModified = response1.headers?.get('Last-Modified')
const response3 = await client.getHeritage('taj-mahal', { ifModifiedSince: lastModified })

Rate Limit Handling

const response = await client.getHeritage('taj-mahal')
if (response.rateLimit) {
  console.log(`${response.rateLimit.remaining}/${response.rateLimit.limit} requests remaining`)
  console.log(`Resets at: ${new Date(response.rateLimit.reset * 1000)}`)
}

// Handle 429 errors
try {
  await client.listHeritage({ limit: 1000 })
} catch (error) {
  if (error.statusCode === 429) {
    const retryAfter = error.retryAfter // seconds
    console.log(`Retry after ${retryAfter} seconds`)
  }
}

Abort Requests

const controller = new AbortController()
const promise = client.getHeritage('taj-mahal', { signal: controller.signal })

// Cancel after 5 seconds
setTimeout(() => controller.abort(), 5000)

try {
  await promise
} catch (error) {
  if (error.name === 'AbortError') {
    console.log('Request cancelled')
  }
}

Testing

The SDK includes comprehensive test coverage:

# Run all tests
npm test

# Watch mode
npm run test:watch

# Unit tests only
npm test -- --grep "unit"

# Integration tests only
npm test -- --grep "integration"

# E2E tests only
npm test -- --grep "e2e"

Contributing

We welcome contributions! See CONTRIBUTING.md for guidelines.


License & Attribution

  • SDK Code: Apache 2.0
  • API Data: CC BY 4.0 (requires attribution: "Data © Inheritage Foundation")
  • AI Usage: See AI Usage Policy

When using this SDK, you must provide visible attribution per CC BY 4.0. The SDK automatically includes required headers. For web applications, use the <InheritageCitation /> component.


Resources


Support


Built with ❤️ by Inheritage Foundation | Preserving India's cultural heritage through open data