### Cache Example: Get and Put Data Source: https://github.com/adonisjs/content/blob/1.x/_autodocs/api-reference/cache.md Demonstrates retrieving data from cache using `get()`. If data is not found or expired, it fetches fresh data and stores it using `put()`. ```typescript import { createCache } from '@adonisjs/content' const cache = createCache({ key: 'myData', outputPath: './cache/data.json', refresh: 'daily' }) // Retrieve cached data let data = await cache.get() if (!data) { // Cache expired or doesn't exist, fetch fresh data data = await fetchDataFromAPI() // Store in cache await cache.put(data) } ``` -------------------------------- ### Usage Example with Collection and Vine Extensions Source: https://github.com/adonisjs/content/blob/1.x/_autodocs/api-reference/provider.md This example demonstrates how to use the Collection class with Vine schemas that leverage the automatically configured toVitePath() and toContents() extensions. ```typescript import { Collection } from '@adonisjs/content' import { loaders, schemas } from '@adonisjs/content/loaders' import app from '@adonisjs/core/services/app' // Collection automatically has Vite and app configured const posts = new Collection({ schema: vine.object({ title: vine.string(), image: vine.string().toVitePath(), // Works automatically content: vine.string().toContents() // Works automatically }), loader: loaders.jsonLoader(app.makePath('posts.json')), cache: true }) const query = await posts.load() ``` -------------------------------- ### Install @adonisjs/content Source: https://github.com/adonisjs/content/blob/1.x/_autodocs/README.md Install the package using npm, yarn, or pnpm. ```bash npm install @adonisjs/content yarn add @adonisjs/content pnpm add @adonisjs/content ``` -------------------------------- ### Install @adonisjs/content with Yarn Source: https://github.com/adonisjs/content/blob/1.x/README.md Install the package using Yarn. This command achieves the same result as the npm installation. ```bash yarn add @adonisjs/content ``` -------------------------------- ### Typical Application Setup with GitHub Sponsors Loader Source: https://github.com/adonisjs/content/blob/1.x/_autodocs/module-index.md Demonstrates how to set up a Collection with a GitHub Sponsors loader and load sponsor data. ```typescript import { Collection } from '@adonisjs/content' import { loaders, schemas } from '@adonisjs/content/loaders' import type { GithubSponsor } from '@adonisjs/content/types' const sponsors = new Collection({ schema: schemas.ghSponsors, loader: loaders.ghSponsors({ /* ... */ }), cache: true }) const query = await sponsors.load() const allSponsors: GithubSponsor[] = query.all() ``` -------------------------------- ### Multi-Collection Setup Source: https://github.com/adonisjs/content/blob/1.x/_autodocs/configuration.md Create multiple collections with a shared load method. Each section gets its own Collection instance with independent caching. ```typescript const collections = Collection.multi( ['guides', 'api', 'tutorials'], (section) => new Collection({ schema: docsSchema, loader: loaders.jsonLoader(`./docs/${section}.json`), cache: true }) ) // Each collection retains its own caching // Call collections.load() to load all at once const sections = await collections.load() ``` -------------------------------- ### Install @adonisjs/content with pnpm Source: https://github.com/adonisjs/content/blob/1.x/README.md Install the package using pnpm. This is an alternative package manager for installation. ```bash pnpm add @adonisjs/content ``` -------------------------------- ### Install @adonisjs/content with npm Source: https://github.com/adonisjs/content/blob/1.x/README.md Install the package using npm. This is the first step to integrate content management into your AdonisJS project. ```bash npm i @adonisjs/content ``` -------------------------------- ### Custom Loader Implementation Example Source: https://github.com/adonisjs/content/blob/1.x/_autodocs/module-index.md Shows how to implement a custom loader by extending the LoaderContract and defining a load method. ```typescript import type { LoaderContract } from '@adonisjs/content/types' import vine from '@vinejs/vine' class MyLoader implements LoaderContract { async load(schema: Schema, metadata?: any) { const data = await this.fetchData() return vine.validate({ schema, data, meta: metadata }) } } ``` -------------------------------- ### Basic Setup with Collection and Loaders Source: https://github.com/adonisjs/content/blob/1.x/_autodocs/README.md Set up a new Collection with schema validation, a JSON loader, caching, and custom views for filtering and finding data. ```typescript import { Collection } from '@adonisjs/content' import { loaders } from '@adonisjs/content/loaders' import vine from '@vinejs/vine' const schema = vine.array( vine.object({ title: vine.string(), slug: vine.string(), published: vine.boolean(), }) ) const posts = new Collection({ schema, loader: loaders.jsonLoader('./data/posts.json'), cache: true, views: { published: (posts) => posts.filter(p => p.published), findBySlug: (posts, slug: string) => posts.find(p => p.slug === slug), } }) const query = await posts.load() const allPosts = query.all() const publishedPosts = query.published() const post = query.findBySlug('hello-world') ``` -------------------------------- ### Blog or Documentation Site Collection Setup Source: https://github.com/adonisjs/content/blob/1.x/_autodocs/README.md Configure a Collection for a blog or documentation site using a JSON loader and custom views for category filtering and searching. ```typescript const docs = new Collection({ schema: docSchema, loader: loaders.jsonLoader('./docs.json'), cache: true, views: { byCategory: (docs, cat) => docs.filter(d => d.category === cat), search: (docs, term) => docs.filter(d => d.title.includes(term)) } }) ``` -------------------------------- ### Basic Collection Setup with Local JSON Source: https://github.com/adonisjs/content/blob/1.x/_autodocs/usage-patterns.md Demonstrates setting up a Collection to load and query data from a local JSON file. Ensure the schema matches your JSON structure and define custom views for common queries. ```typescript import vine from '@vinejs/vine' import { Collection } from '@adonisjs/content' import { loaders } from '@adonisjs/content/loaders' const schema = vine.array( vine.object({ id: vine.number(), title: vine.string(), slug: vine.string(), content: vine.string(), published: vine.boolean(), }) ) const posts = new Collection({ schema, loader: loaders.jsonLoader('./data/posts.json'), cache: true, views: { published: (posts) => posts.filter(p => p.published), findBySlug: (posts, slug: string) => posts.find(p => p.slug === slug), } }) const query = await posts.load() const allPosts = query.all() const published = query.published() const post = query.findBySlug('my-post') ``` -------------------------------- ### ViewsToQueryMethods Example Source: https://github.com/adonisjs/content/blob/1.x/_autodocs/types.md Demonstrates how ViewsToQueryMethods transforms a Views object into a QueryMethods object with corresponding function signatures. ```typescript type Views = { published: ViewFn findBySlug: ViewFn } type QueryMethods = ViewsToQueryMethods // Results in: // { // published: () => Post[] // findBySlug: (slug: string) => Post | undefined // } ``` -------------------------------- ### GraphQL Cursor-Based Pagination Example Source: https://github.com/adonisjs/content/blob/1.x/_autodocs/api-reference/github-queries.md Demonstrates a common pattern for handling cursor-based pagination in GraphQL queries. It iteratively fetches data until no more pages are available. ```typescript let hasNext = true let cursor = null while (hasNext) { const result = await graphql(query, { cursor, /* variables */ }) const pageInfo = result.pageInfo hasNext = pageInfo.hasNextPage cursor = pageInfo.endCursor } ``` -------------------------------- ### Example Cache File Structure Source: https://github.com/adonisjs/content/blob/1.x/_autodocs/configuration.md Cache files are stored as JSON at the configured outputPath. The key name matches the loader's cache key and is automatically managed. ```json { "lastFetched": "2024-01-15T10:30:00.000Z", "sponsors": [ /* cached data */ ] } ``` -------------------------------- ### ViewFn Examples Source: https://github.com/adonisjs/content/blob/1.x/_autodocs/types.md Illustrates how to define specific view function types for filtering posts or finding a post by its slug, using the generic ViewFn type. ```typescript type PublishedView = ViewFn const published: PublishedView = (posts) => posts.filter(p => p.published) type SearchView = ViewFn const search: SearchView = (posts, slug) => posts.find(p => p.slug === slug) ``` -------------------------------- ### Managing GitHub Tokens with Environment Variables Source: https://github.com/adonisjs/content/blob/1.x/_autodocs/configuration.md Example of how to manage sensitive tokens like GITHUB_TOKEN using environment variables within a Collection configuration. ```typescript const sponsors = new Collection({ schema: schemas.ghSponsors, loader: loaders.ghSponsors({ login: 'adonisjs', isOrg: true, ghToken: process.env.GITHUB_TOKEN!, // From .env file outputPath: app.makePath('cache/sponsors.json'), refresh: 'daily' }), cache: true }) ``` -------------------------------- ### npm Source Configuration Source: https://github.com/adonisjs/content/blob/1.x/_autodocs/configuration.md Configure an npm source to aggregate downloads for specified packages. Requires package names and start dates for counting. ```typescript { type: 'npm', packages: [ { name: string, // npm package name (e.g., '@adonisjs/core') startDate: string // Start date for counting (YYYY-MM-DD) } ] } ``` -------------------------------- ### REST API Page-Based Pagination Example with Octokit Source: https://github.com/adonisjs/content/blob/1.x/_autodocs/api-reference/github-queries.md Illustrates how to use Octokit's `paginate` helper for handling page-based pagination with GitHub REST API endpoints, specifically for listing contributors. ```typescript const octokit = new Octokit({ auth: token }) const items = await octokit.paginate( octokit.repos.listContributors, { owner, repo, per_page: 100 }, (response) => response.data ) ``` -------------------------------- ### aggregateInstalls Source: https://github.com/adonisjs/content/blob/1.x/_autodocs/api-reference/utilities.md Aggregates total npm package downloads across multiple packages from their start dates to today. ```APIDOC ## aggregateInstalls ### Description Aggregates total npm package downloads across multiple packages from their start dates to today. ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Method Signature ```typescript async function aggregateInstalls(packages: { name: string startDate: string }[]): Promise ``` ### Parameters - **packages** (Array) - Required - Array of package tracking objects - **packages[].name** (string) - Required - npm package name - **packages[].startDate** (string) - Required - Start date for counting (YYYY-MM-DD) ### Returns - `Promise` — Total download count ### Example ```typescript const totalDownloads = await aggregateInstalls([ { name: '@adonisjs/core', startDate: '2020-01-01' }, { name: '@adonisjs/lucid', startDate: '2021-06-15' } ]) console.log(`Total downloads: ${totalDownloads}`) ``` ``` -------------------------------- ### Custom Loader with Cache Source: https://github.com/adonisjs/content/blob/1.x/_autodocs/api-reference/cache.md Example of implementing a custom loader that utilizes `createCache` for data persistence. It fetches data from the cache or an API and stores it if necessary. ```typescript import { createCache } from '@adonisjs/content' class CustomLoader implements LoaderContract { #cache = createCache({ key: 'myData', outputPath: './cache/data.json', refresh: 'daily' }) async load(schema, metadata) { let data = await this.#cache.get() if (!data) { data = await this.fetchData() await this.#cache.put(data) } return vine.validate({ schema, data, meta: metadata }) } } ``` -------------------------------- ### Custom Processing with toContents Source: https://github.com/adonisjs/content/blob/1.x/_autodocs/api-reference/vine-extensions.md Demonstrates applying custom transformations after reading file contents using `toContents`. The example shows slicing the first 5 lines of a file's content. ```typescript const schema = vine.object({ title: vine.string(), // Read file and apply custom processing processed: vine.string() .toContents() .transform((value) => { // Process the file contents return value.split('\n').slice(0, 5).join('\n') }) }) ``` -------------------------------- ### get Method Source: https://github.com/adonisjs/content/blob/1.x/_autodocs/api-reference/cache.md Retrieves cached data from disk if it exists and hasn't expired based on the `lastFetched` timestamp. ```APIDOC ## get Method ### Description Retrieves cached data from disk if it exists and hasn't expired based on the `lastFetched` timestamp. ### Signature ```typescript async get(): Promise ``` ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Request Example ```typescript const cachedSponsors = await cache.get() if (cachedSponsors === null) { console.log('Cache expired or not found, fetching fresh data') const freshSponsors = await fetchFromGitHub() await cache.put(freshSponsors) } ``` ### Response #### Success Response (200) Cached data of type `T`, or `null` if cache doesn't exist, is expired, or file cannot be read. #### Response Example None (returns cached data or null) ``` -------------------------------- ### GitHub Sponsors Collection Setup Source: https://github.com/adonisjs/content/blob/1.x/_autodocs/usage-patterns.md Configures a Collection to fetch GitHub Sponsors data. Requires a GitHub token and specifies caching and refresh intervals. Custom views allow filtering by active sponsors, tier, or top sponsors. ```typescript import { Collection } from '@adonisjs/content' import { loaders, schemas } from '@adonisjs/content/loaders' import app from '@adonisjs/core/services/app' const sponsors = new Collection({ schema: schemas.ghSponsors, loader: loaders.ghSponsors({ login: 'adonisjs', isOrg: true, ghToken: process.env.GITHUB_TOKEN!, outputPath: app.makePath('cache/sponsors.json'), refresh: 'daily', includeInactive: false, }), cache: true, views: { active: (sponsors) => sponsors.filter(s => s.isActive), byTier: (sponsors, tierName: string) => sponsors.filter(s => s.tierName === tierName), topTiers: (sponsors) => sponsors .sort((a, b) => (b.tierMonthlyPriceInCents ?? 0) - (a.tierMonthlyPriceInCents ?? 0)) .slice(0, 10) } }) const query = await sponsors.load() const activeSponsors = query.active() const goldSponsors = query.byTier('Gold') const topSponsors = query.topTiers() ``` -------------------------------- ### Handle Non-Existent GitHub Organizations Source: https://github.com/adonisjs/content/blob/1.x/_autodocs/errors-and-edge-cases.md GraphQL queries for non-existent organizations or users return null. This example shows how to handle such cases, which result in an empty array for releases. ```typescript const releases = await fetchReleases({ org: 'non-existent-org', ghToken: process.env.GITHUB_TOKEN }) // Returns [] (empty array, no error thrown) ``` -------------------------------- ### Robust Error Handling for Collection Loading Source: https://github.com/adonisjs/content/blob/1.x/_autodocs/errors-and-edge-cases.md This example demonstrates comprehensive error handling for loading a collection, including specific checks for validation errors, file not found errors, authentication errors, and generic errors. It also includes a fallback mechanism. ```typescript import { Collection } from '@adonisjs/content' import { loaders, schemas } from '@adonisjs/content/loaders' async function safeLoadCollection() { try { const posts = new Collection({ schema: schemas.ghSponsors, loader: loaders.ghSponsors({ login: 'adonisjs', isOrg: true, ghToken: process.env.GITHUB_TOKEN!, outputPath: './cache/sponsors.json', refresh: 'daily' }), cache: true }) const query = await posts.load() return query.all() } catch (error) { if (error instanceof Error) { if ('messages' in error) { // Validation error console.error('Validation error:', error.messages) } else if (error.code === 'ENOENT') { // File not found console.error('Cache file not found') } else if (error.status === 401) { // Auth error console.error('GitHub authentication failed') } else { // Generic error console.error('Failed to load collection:', error.message) } } // Fallback to empty data or cached backup return [] } } ``` -------------------------------- ### Create and Load a JSON Collection Source: https://github.com/adonisjs/content/blob/1.x/README.md Define a type-safe collection using VineJS schema and a JSON loader. This example demonstrates loading posts from a local JSON file and querying them. ```typescript import vine from '@vinejs/vine' import app from '@adonisjs/core/services/app' import { Collection } from '@adonisjs/content' import { loaders } from '@adonisjs/content/loaders' const postSchema = vine.object({ title: vine.string(), slug: vine.string(), content: vine.string(), published: vine.boolean(), }) const posts = new Collection({ schema: vine.array(postSchema), loader: loaders.jsonLoader(app.makePath('data/posts.json')), cache: true, views: { published: (posts) => posts.filter((p) => p.published), findBySlug: (posts, slug: string) => posts.find((p) => p.slug === slug), }, }) const query = await posts.load() const allPosts = query.all() const publishedPosts = query.published() const post = query.findBySlug('hello-world') ``` -------------------------------- ### GitHub Contributors Collection Setup Source: https://github.com/adonisjs/content/blob/1.x/_autodocs/usage-patterns.md Configures a Collection to fetch GitHub Contributors data, with options for caching and weekly refresh. Custom views allow sorting by contributions, filtering by minimum contributions, and identifying contributors with avatars. ```typescript import { Collection } from '@adonisjs/content' import { loaders, schemas } from '@adonisjs/content/loaders' import app from '@adonisjs/core/services/app' const contributors = new Collection({ schema: schemas.ghContributors, loader: loaders.ghContributors({ org: 'adonisjs', ghToken: process.env.GITHUB_TOKEN!, outputPath: app.makePath('cache/contributors.json'), refresh: 'weekly', }), cache: true, views: { top: (contributors, limit: number = 10) => contributors .sort((a, b) => b.contributions - a.contributions) .slice(0, limit), byContributions: (contributors, minCount: number) => contributors.filter(c => c.contributions >= minCount), withAvatars: (contributors) => contributors.filter(c => c.avatar_url) } }) const query = await contributors.load() const topTen = query.top(10) const prolific = query.byContributions(50) const withPhotos = query.withAvatars() ``` -------------------------------- ### Content Provider Boot Method Source: https://github.com/adonisjs/content/blob/1.x/_autodocs/api-reference/provider.md The boot method is called automatically during the application boot phase. It configures the Collection class, checks for Vite integration, and registers Vine extensions. ```typescript // The boot method is called automatically; no manual invocation needed const app = await createApp() await app.boot() // Collection now has access to Vite and is ready to use const posts = new Collection({ /* options */ }) ``` -------------------------------- ### Get Cached Data Source: https://github.com/adonisjs/content/blob/1.x/_autodocs/api-reference/cache.md The `get()` method retrieves data from the cache. It returns `null` if the cache is non-existent, expired, or unreadable. Errors other than file-not-found are re-thrown. ```typescript const cachedSponsors = await cache.get() if (cachedSponsors === null) { console.log('Cache expired or not found, fetching fresh data') const freshSponsors = await fetchFromGitHub() await cache.put(freshSponsors) } ``` -------------------------------- ### Cache Manager Interface Source: https://github.com/adonisjs/content/blob/1.x/_autodocs/module-index.md Defines the asynchronous methods for interacting with the cache manager, including getting and putting cached content. ```typescript { async get(): Promise async put(contents: T): Promise } ``` -------------------------------- ### Registering Content Provider in adonisrc.ts Source: https://github.com/adonisjs/content/blob/1.x/_autodocs/api-reference/provider.md This snippet shows how to add the ContentProvider to your application's adonisrc.ts file. Ensure you have installed the necessary peer dependencies. ```typescript // adonisrc.ts import { defineConfig } from '@adonisjs/core/build/config' export default defineConfig({ providers: [ () => import('@adonisjs/core/providers/app_provider'), () => import('@adonisjs/core/providers/hash_provider'), () => import('@adonisjs/vite/vite_provider'), () => import('@adonisjs/content/content_provider'), ] }) ``` -------------------------------- ### Configure GitHub Project Loader Source: https://github.com/adonisjs/content/blob/1.x/README.md Initialize the GitHub Project Loader with project details, authentication, and caching options. Custom views can be defined to filter and organize cards. ```typescript import app from '@adonisjs/core/services/app' import { Collection } from '@adonisjs/content' import { loaders, schemas } from '@adonisjs/content/loaders' const board = new Collection({ schema: schemas.ghProject, loader: loaders.ghProject({ login: 'adonisjs', isOrg: true, projectNumber: 8, ghToken: process.env.GITHUB_TOKEN!, outputPath: app.makePath('cache/board.json'), refresh: 'daily', skipStatuses: ['Backlog', 'Done'], summary: (description) => description.split('')[0], }), cache: true, views: { inProgress: (cards) => cards.filter((c) => c.status === 'In Progress'), byAssignee: (cards, login: string) => cards.filter((c) => c.assignees.some((a) => a.login === login)), }, }) ``` -------------------------------- ### Load OSS Statistics from GitHub and NPM Source: https://github.com/adonisjs/content/blob/1.x/README.md Aggregates GitHub stars and npm package downloads. Requires GITHUB_TOKEN environment variable. Custom sources can be added as async functions. ```typescript import app from '@adonisjs/core/services/app' import { Collection } from '@adonisjs/content' import { loaders, schemas } from '@adonisjs/content/loaders' const ossStats = new Collection({ schema: schemas.ossStats, loader: loaders.ossStats({ outputPath: app.makePath('cache/oss-stats.json'), refresh: 'daily', sources: [ { type: 'github', org: 'adonisjs', ghToken: process.env.GITHUB_TOKEN!, }, { type: 'npm', packages: [ { name: '@adonisjs/core', startDate: '2020-01-01' }, { name: '@adonisjs/lucid', startDate: '2020-01-01' }, ], }, // Custom source: any async function returning { key, count } async () => ({ key: 'discordMembers', count: await fetchDiscordMembers() }), ], }), cache: true, }) const query = await ossStats.load() const stats = query.all() console.log(`Total GitHub stars: ${stats.stars}`) console.log(`Total npm downloads: ${stats.installs}`) ``` -------------------------------- ### Collection Static Vite Configuration Source: https://github.com/adonisjs/content/blob/1.x/_autodocs/README.md Illustrates how to configure Vite integration with the Collection class using the static `useVite` method, essential for frontend asset handling. ```typescript Collection.useVite(vite) ``` -------------------------------- ### Create a New Collection Instance Source: https://github.com/adonisjs/content/blob/1.x/_autodocs/api-reference/collection.md Instantiate a new Collection with schema, loader, cache settings, and custom views. Ensure the schema and loader are correctly defined for your data structure. ```typescript import vine from '@vinejs/vine' import { Collection } from '@adonisjs/content' import { loaders } from '@adonisjs/content/loaders' const schema = vine.array( vine.object({ title: vine.string(), slug: vine.string(), published: vine.boolean(), }) ) const posts = new Collection({ schema, loader: loaders.jsonLoader('./posts.json'), cache: true, views: { published: (posts) => posts.filter(p => p.published), findBySlug: (posts, slug: string) => posts.find(p => p.slug === slug) } }) ``` -------------------------------- ### Multi-Section Collections Source: https://github.com/adonisjs/content/blob/1.x/_autodocs/usage-patterns.md Define and load multiple collections from different sections, such as guides, API docs, and tutorials. Supports custom schemas and views for each section. ```typescript import vine from '@vinejs/vine' import { Collection } from '@adonisjs/content' import { loaders } from '@adonisjs/content/loaders' import app from '@adonisjs/core/services/app' const docSchema = vine.array( vine.object({ title: vine.string(), slug: vine.string(), category: vine.string(), content: vine.string(), }) ) const docs = Collection.multi( ['guides', 'api', 'tutorials'] as const, (section) => new Collection({ schema: docSchema, loader: loaders.jsonLoader(app.makePath(`docs/${section}.json`)), cache: true, views: { byCategory: (docs, category: string) => docs.filter(d => d.category === category), findBySlug: (docs, slug: string) => docs.find(d => d.slug === slug) } }) ) // Access individual collections const guidesCollection = docs.guides // Load all sections at once const sections = await docs.load() const allGuides = sections.guides.all() const apiDocs = sections.api.all() const gettingStarted = sections.guides.byCategory('getting-started') const authGuide = sections.guides.findBySlug('authentication') ``` -------------------------------- ### Create Cache Manager Source: https://github.com/adonisjs/content/blob/1.x/_autodocs/api-reference/cache.md Use `createCache` to initialize a cache manager. Configure a unique key, the output path for the cache file, and the refresh interval (daily, weekly, or monthly). ```typescript import { createCache } from '@adonisjs/content' function createCache(options: { key: string outputPath: string refresh: 'daily' | 'weekly' | 'monthly' }): { get(): Promise put(contents: T): Promise } ``` -------------------------------- ### Create GitHub Sponsors Loader Source: https://github.com/adonisjs/content/blob/1.x/_autodocs/api-reference/loaders.md Creates a GitHub sponsors loader instance for fetching sponsor data. Requires GitHub token and specifies output path and refresh interval. ```typescript import { loaders } from '@adonisjs/content/loaders' const loader = loaders.ghSponsors({ login: 'adonisjs', isOrg: true, ghToken: process.env.GITHUB_TOKEN, outputPath: './cache/sponsors.json', refresh: 'daily' }) ``` -------------------------------- ### Aggregate npm Package Downloads Source: https://github.com/adonisjs/content/blob/1.x/_autodocs/api-reference/utilities.md Aggregates the total npm package downloads for a list of packages from their specified start dates to the current date. Fetches data from the npm registry API. ```typescript async function aggregateInstalls(packages: { name: string startDate: string }[]): Promise ``` ```typescript const totalDownloads = await aggregateInstalls([ { name: '@adonisjs/core', startDate: '2020-01-01' }, { name: '@adonisjs/lucid', startDate: '2021-06-15' } ]) console.log(`Total downloads: ${totalDownloads}`) ``` -------------------------------- ### Preventing Circular References in Views Source: https://github.com/adonisjs/content/blob/1.x/_autodocs/errors-and-edge-cases.md Views that create circular object references can lead to memory issues. This snippet shows an example of a bad practice with circular references and a good practice without them. ```typescript // Bad: Circular reference const views = { withSelf: (items) => items.map(item => ({ ...item, parent: items })) } // Good: No circular references const views = { grouped: (items) => items.reduce((acc, item) => { // No circular refs return acc }, {}) } ``` -------------------------------- ### Create GitHub Project Loader Source: https://github.com/adonisjs/content/blob/1.x/_autodocs/api-reference/loaders.md Creates a GitHub Projects v2 loader for fetching cards from a project board. Requires project number, GitHub token, and specifies output path and refresh interval. Can skip certain statuses. ```typescript const loader = loaders.ghProject({ login: 'adonisjs', isOrg: true, projectNumber: 5, ghToken: process.env.GITHUB_TOKEN, outputPath: './cache/board.json', refresh: 'daily', skipStatuses: ['Backlog', 'Done'] }) ``` -------------------------------- ### Custom Remote API Loader Implementation Source: https://github.com/adonisjs/content/blob/1.x/README.md Implement the `LoaderContract` interface to create a custom loader for fetching data from a remote API. This example demonstrates loading JSON data from a given endpoint and validating it with VineJS. ```typescript import vine from '@vinejs/vine' import { type SchemaTypes, type Infer } from '@vinejs/vine/types' import { type LoaderContract } from '@adonisjs/content/types' class RemoteApiLoader implements LoaderContract { constructor(private endpoint: string) {} async load(schema: Schema, metadata?: any): Promise> { const response = await fetch(this.endpoint) const data = await response.json() return vine.validate({ schema, data, meta: metadata }) } } ``` -------------------------------- ### Import Main Module Exports Source: https://github.com/adonisjs/content/blob/1.x/_autodocs/module-index.md Demonstrates how to import core components like Collection, createCache, and configure from the main @adonisjs/content module. ```typescript import { Collection, createCache, configure } from '@adonisjs/content' ``` -------------------------------- ### loaders.ossStats Source: https://github.com/adonisjs/content/blob/1.x/_autodocs/api-reference/loaders.md Creates an OSS statistics loader for aggregating stars and downloads from multiple sources. It requires an output path, refresh interval, and a list of sources, which can include GitHub and npm statistics. ```APIDOC ## loaders.ossStats ### Description Creates an OSS statistics loader for aggregating stars and downloads from multiple sources. It requires an output path, refresh interval, and a list of sources, which can include GitHub and npm statistics. ### Method Signature ```typescript loaders.ossStats(options: OssStatsOptions): OssStatsLoader ``` ### Parameters #### Path Parameters This method does not have path parameters. #### Query Parameters This method does not have query parameters. #### Request Body This method does not have a request body. ### Parameters - **options** (`OssStatsOptions`) - Required - Configuration options for the OSS statistics loader. ### Request Example ```typescript const loader = loaders.ossStats({ outputPath: './cache/oss-stats.json', refresh: 'daily', sources: [ { type: 'github', org: 'adonisjs', ghToken: process.env.GITHUB_TOKEN }, { type: 'npm', packages: [ { name: '@adonisjs/core', startDate: '2020-01-01' } ] } ] }) ``` ### Response This method returns an `OssStatsLoader` instance. #### Success Response N/A #### Response Example N/A ``` -------------------------------- ### Create GitHub Releases Loader Source: https://github.com/adonisjs/content/blob/1.x/_autodocs/api-reference/loaders.md Creates a GitHub releases loader instance for fetching releases from an organization's repositories. Allows filtering releases and specifies output path and refresh interval. ```typescript const loader = loaders.ghReleases({ org: 'adonisjs', ghToken: process.env.GITHUB_TOKEN, outputPath: './cache/releases.json', refresh: 'daily', filters: { nameDoesntInclude: ['alpha', 'beta', 'rc'] } }) ``` -------------------------------- ### loaders.ghReleases Source: https://github.com/adonisjs/content/blob/1.x/_autodocs/api-reference/loaders.md Creates a GitHub releases loader instance for fetching releases from an organization's repositories. It accepts configuration options including the organization name, GitHub token, output path, refresh interval, and filters for release names. ```APIDOC ## loaders.ghReleases ### Description Creates a GitHub releases loader instance for fetching releases from an organization's repositories. It accepts configuration options including the organization name, GitHub token, output path, refresh interval, and filters for release names. ### Method Signature ```typescript loaders.ghReleases(options: GithubReleasesOptions): GithubReleasesLoader ``` ### Parameters #### Path Parameters This method does not have path parameters. #### Query Parameters This method does not have query parameters. #### Request Body This method does not have a request body. ### Parameters - **options** (`GithubReleasesOptions`) - Required - Configuration options for the GitHub releases loader. ### Request Example ```typescript const loader = loaders.ghReleases({ org: 'adonisjs', ghToken: process.env.GITHUB_TOKEN, outputPath: './cache/releases.json', refresh: 'daily', filters: { nameDoesntInclude: ['alpha', 'beta', 'rc'] } }) ``` ### Response This method returns a `GithubReleasesLoader` instance. #### Success Response N/A #### Response Example N/A ``` -------------------------------- ### Collection Class Constructor Source: https://github.com/adonisjs/content/blob/1.x/_autodocs/README.md Illustrates the instantiation of the Collection class with generic options for schema and views. This is the primary way to create a new content collection instance. ```typescript new Collection(options: CollectionOptions) ``` -------------------------------- ### loaders.ghProject Source: https://github.com/adonisjs/content/blob/1.x/_autodocs/api-reference/loaders.md Creates a GitHub Projects v2 loader for fetching cards from a project board. Options include login, organization status, project number, GitHub token, output path, refresh interval, and statuses to skip. ```APIDOC ## loaders.ghProject ### Description Creates a GitHub Projects v2 loader for fetching cards from a project board. Options include login, organization status, project number, GitHub token, output path, refresh interval, and statuses to skip. ### Method Signature ```typescript loaders.ghProject(options: GithubProjectOptions): GithubProjectLoader ``` ### Parameters #### Path Parameters This method does not have path parameters. #### Query Parameters This method does not have query parameters. #### Request Body This method does not have a request body. ### Parameters - **options** (`GithubProjectOptions`) - Required - Configuration options for the GitHub project loader. ### Request Example ```typescript const loader = loaders.ghProject({ login: 'adonisjs', isOrg: true, projectNumber: 5, ghToken: process.env.GITHUB_TOKEN, outputPath: './cache/board.json', refresh: 'daily', skipStatuses: ['Backlog', 'Done'] }) ``` ### Response This method returns a `GithubProjectLoader` instance. #### Success Response N/A #### Response Example N/A ``` -------------------------------- ### fetchProjectItems Source: https://github.com/adonisjs/content/blob/1.x/_autodocs/api-reference/utilities.md Fetches all items from a GitHub Projects v2 (kanban) board. It resolves status, priority, effort, labels, assignees, and custom fields. ```APIDOC ## fetchProjectItems ### Description Fetches all items from a GitHub Projects v2 (kanban) board. Resolves status, priority, effort, labels, assignees, and custom fields. ### Method `async` ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None #### Function Parameters - **options** (`GithubProjectOptions`) - Required - Project fetching options ### Request Example ```typescript const cards = await fetchProjectItems({ login: 'adonisjs', isOrg: true, projectNumber: 5, ghToken: process.env.GITHUB_TOKEN, skipStatuses: ['Backlog', 'Done'], summary: (desc) => desc.split('\n')[0] }) ``` ### Response #### Success Response - **`Promise`** — Array of project cards #### Response Example ```json [ { "id": "card_id_1", "title": "Implement Feature X", "status": "In Progress", "priority": "High", "effort": 5, "labels": ["bug", "enhancement"], "assignees": ["user1", "user2"], "summary": "This is a summary of the card." } ] ``` ### Behavior - Uses GraphQL to fetch project items (100 per request) - Extracts Status, Priority, Effort columns (case-insensitive field matching) - Collects labels and assignees - Applies status-based filtering (case-insensitive) - Derives summary from description using custom function or first paragraph - Includes custom fields not in well-known set - Handles Issue, PullRequest, and DraftIssue types ``` -------------------------------- ### Using Default Schemas with Loaders Source: https://github.com/adonisjs/content/blob/1.x/_autodocs/configuration.md Demonstrates using pre-built default schemas provided by '@adonisjs/content/loaders' for common data shapes, such as GitHub sponsors. ```typescript import { schemas } from '@adonisjs/content/loaders' const sponsors = new Collection({ schema: schemas.ghSponsors, // Pre-built schema loader: loaders.ghSponsors({ ... }), cache: true }) ``` -------------------------------- ### Create a Collection using the Static Factory Method Source: https://github.com/adonisjs/content/blob/1.x/_autodocs/api-reference/collection.md Use the static `create` method as an alternative to the constructor for creating a Collection instance. This is functionally identical to using `new Collection()`. ```typescript const posts = Collection.create({ schema: postsSchema, loader: loaders.jsonLoader('./posts.json'), cache: true }) ``` -------------------------------- ### Conditional Vite Integration in Boot Method Source: https://github.com/adonisjs/content/blob/1.x/_autodocs/api-reference/provider.md This snippet shows how the ContentProvider gracefully handles applications without Vite configured. It checks for the Vite binding before attempting to use it. ```typescript async boot() { Collection.useApp(this.app) // Only configure Vite if it's registered if (this.app.container.hasBinding('vite')) { const vite = await this.app.container.make('vite') Collection.useVite(vite) } // App functionality still works without Vite // toVitePath() will fail, but other extensions work } ``` -------------------------------- ### load() Source: https://github.com/adonisjs/content/blob/1.x/_autodocs/api-reference/collection.md Loads the collection and returns a query interface with an `all()` method and any configured view methods. This is the primary method for accessing collection data and is typically used instead of `hydrate()`. ```APIDOC ## Instance Method: load ### Description Loads the collection and returns a query interface with an `all()` method and any configured view methods. This is the primary method for accessing collection data and is typically used instead of `hydrate()`. ### Returns Promise resolving to query object with `all()` method and all view methods ### Example ```typescript const query = await posts.load() // Get all data const allPosts = query.all() // Use custom view methods const publishedPosts = query.published() const post = query.findBySlug('hello-world') const postsByYear = query.byYear() ``` ``` -------------------------------- ### Configure Content Package via CLI Source: https://github.com/adonisjs/content/blob/1.x/_autodocs/README.md Provides the command-line interface command to automatically configure the @adonisjs/content package within an AdonisJS project. ```bash node ace configure @adonisjs/content ``` -------------------------------- ### Create OSS Statistics Loader Source: https://github.com/adonisjs/content/blob/1.x/_autodocs/api-reference/loaders.md Creates an OSS statistics loader for aggregating stars and downloads from multiple sources like GitHub and npm. Specifies output path and refresh interval. ```typescript const loader = loaders.ossStats({ outputPath: './cache/oss-stats.json', refresh: 'daily', sources: [ { type: 'github', org: 'adonisjs', ghToken: process.env.GITHUB_TOKEN }, { type: 'npm', packages: [ { name: '@adonisjs/core', startDate: '2020-01-01' } ] } ] }) ``` -------------------------------- ### Collection Static App Configuration Source: https://github.com/adonisjs/content/blob/1.x/_autodocs/README.md Demonstrates configuring the underlying AdonisJS application instance with the Collection class via the static `useApp` method. ```typescript Collection.useApp(app) ``` -------------------------------- ### Custom Database Loader Implementation Source: https://github.com/adonisjs/content/blob/1.x/_autodocs/usage-patterns.md Implement a custom loader to fetch and validate content directly from a database table. Ensure your database service is correctly configured. ```typescript import vine from '@vinejs/vine' import type { LoaderContract } from '@adonisjs/content/types' import type { SchemaTypes } from '@vinejs/vine/types' class DatabaseLoader implements LoaderContract { constructor(private table: string, private database: Database) {} async load(schema: Schema, metadata?: any) { const rows = await this.database .from(this.table) .select('*') return vine.validate({ schema, data: rows, meta: metadata }) } } // Usage import { Collection } from '@adonisjs/content' import Database from '@adonisjs/lucid/services/db' const users = new Collection({ schema: userSchema, loader: new DatabaseLoader('users', Database), cache: false, views: { active: (users) => users.filter(u => u.active) } }) const query = await users.load() const activeUsers = query.active() ``` -------------------------------- ### GithubSponsorsOptions Type Source: https://github.com/adonisjs/content/blob/1.x/_autodocs/types.md Defines the configuration options for loading GitHub sponsors. Specify the GitHub login, token, output path, and refresh interval. Optionally include inactive sponsorships. ```typescript type GithubSponsorsOptions = { login: string isOrg: boolean ghToken: string outputPath: string refresh: 'daily' | 'weekly' | 'monthly' includeInactive?: boolean } ``` -------------------------------- ### Registering Vine Extensions Source: https://github.com/adonisjs/content/blob/1.x/_autodocs/api-reference/vine-extensions.md Automatically available after registering `@adonisjs/content/content_provider` in `adonisrc.ts`. ```typescript VineString.prototype.toVitePath(): this ``` -------------------------------- ### Configure Vite Service for Asset Paths Source: https://github.com/adonisjs/content/blob/1.x/_autodocs/api-reference/collection.md Call the static `useVite` method once during application initialization to configure the Vite service instance for resolving asset paths, if you are using Vite integration. ```typescript import { Collection } from '@adonisjs/content' Collection.useVite(vite) ``` -------------------------------- ### Collection Instance Methods Source: https://github.com/adonisjs/content/blob/1.x/_autodocs/README.md Details the primary asynchronous instance methods of the Collection class used for loading and hydrating data. ```APIDOC ## Collection Instance Methods ```typescript async load(): Promise<{ all(), ...views }> async hydrate(): Promise<{ data, views }> ``` - `load()`: The primary method to asynchronously load all data and apply view transformations. - `hydrate()`: A lower-level method for asynchronously loading raw data and views. ``` -------------------------------- ### Handle Cache Directory Creation Failure Source: https://github.com/adonisjs/content/blob/1.x/_autodocs/errors-and-edge-cases.md Catch `EACCES` errors when the cache directory cannot be created due to insufficient permissions or an invalid path specified in `outputPath`. ```typescript const cache = createCache({ key: 'data', outputPath: '/read-only/cache.json', // Permission denied refresh: 'daily' }) try { await cache.put(data) // Throws EACCES error } catch (error) { if (error.code === 'EACCES') { console.error('Permission denied for cache directory') } } ``` -------------------------------- ### put Method Source: https://github.com/adonisjs/content/blob/1.x/_autodocs/api-reference/cache.md Saves data to the cache file with the current timestamp. Creates directory structure if it doesn't exist. ```APIDOC ## put Method ### Description Saves data to the cache file with the current timestamp. Creates directory structure if it doesn't exist. ### Signature ```typescript async put(contents: T): Promise ``` ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body - **contents** (T) - Required - The data to cache ### Request Example ```typescript const freshData = await fetchDataFromAPI() const cached = await cache.put(freshData) // cached === freshData ``` ### Response #### Success Response (200) The same data that was passed in (for chaining). #### Response Example None (returns the cached data) ``` -------------------------------- ### loaders.ghSponsors Source: https://github.com/adonisjs/content/blob/1.x/_autodocs/api-reference/loaders.md Creates a GitHub sponsors loader instance for fetching sponsor data. This loader can be configured with options such as the GitHub login, organization status, token, output path, and refresh interval. ```APIDOC ## loaders.ghSponsors ### Description Creates a GitHub sponsors loader instance for fetching sponsor data. This loader can be configured with options such as the GitHub login, organization status, token, output path, and refresh interval. ### Method Signature ```typescript loaders.ghSponsors(options: GithubSponsorsOptions): GithubSponsorsLoader ``` ### Parameters #### Path Parameters This method does not have path parameters. #### Query Parameters This method does not have query parameters. #### Request Body This method does not have a request body. ### Parameters - **options** (`GithubSponsorsOptions`) - Required - Configuration options for the GitHub sponsors loader. ### Request Example ```typescript import { loaders } from '@adonisjs/content/loaders' const loader = loaders.ghSponsors({ login: 'adonisjs', isOrg: true, ghToken: process.env.GITHUB_TOKEN, outputPath: './cache/sponsors.json', refresh: 'daily' }) ``` ### Response This method returns a `GithubSponsorsLoader` instance. #### Success Response N/A #### Response Example N/A ``` -------------------------------- ### Collection Class Constructor Source: https://github.com/adonisjs/content/blob/1.x/_autodocs/README.md Describes the constructor for the Collection class, which is used to instantiate a new collection with specified schema and loader options. ```APIDOC ## Collection Class Constructor ```typescript new Collection(options: CollectionOptions) ``` Instantiates a new Collection with the provided options, including schema definition, data loader configuration, caching settings, and view transformations. ``` -------------------------------- ### Collection.useVite Source: https://github.com/adonisjs/content/blob/1.x/_autodocs/api-reference/collection.md Configures the Vite service instance for resolving asset paths. This method should be called once during application initialization if Vite integration is being used. ```APIDOC ## Static Method: useVite Configures the Vite service instance for resolving asset paths. Must be called once during application initialization if using Vite integration. ### Signature ```typescript static useVite(vite: Vite): void ``` ### Parameters #### vite (`Vite`) - Required - The Vite service instance from @adonisjs/vite ### Example ```typescript import { Collection } from '@adonisjs/content' Collection.useVite(vite) ``` -------------------------------- ### Collection Static Methods Source: https://github.com/adonisjs/content/blob/1.x/_autodocs/README.md Lists the static methods available on the Collection class for creating and configuring collections, such as factory methods and utility functions. ```APIDOC ## Collection Static Methods ```typescript Collection.create(options) Collection.multi(sections, fn) Collection.useVite(vite) Collection.useApp(app) ``` - `create(options)`: A factory method for creating collections. - `multi(sections, fn)`: Used for creating multi-section collections. - `useVite(vite)`: Configures the collection to work with Vite. - `useApp(app)`: Configures the collection with the application instance. ``` -------------------------------- ### Ensuring menuFileRoot in Custom Loaders Source: https://github.com/adonisjs/content/blob/1.x/_autodocs/api-reference/vine-extensions.md Shows how to ensure `menuFileRoot` is included in the metadata when implementing a custom loader to support path resolution for Vine extensions. ```typescript class CustomLoader implements LoaderContract { async load(schema, metadata) { const data = await this.fetchData() return vine.validate({ schema, data, meta: { menuFileRoot: '/path/to/data/directory', ...metadata } }) } } ```