@adonisjs/content 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,280 @@
1
+ import { type Infer, type SchemaTypes } from '@vinejs/vine/types';
2
+ /**
3
+ * Contract for loading and validating content data using a VineJS schema.
4
+ *
5
+ * @example
6
+ * ```ts
7
+ * const loader: LoaderContract<typeof mySchema> = {
8
+ * async load(schema) {
9
+ * const data = await fetchData()
10
+ * return vine.validate({ schema, data })
11
+ * }
12
+ * }
13
+ * ```
14
+ */
15
+ export interface LoaderContract<Schema extends SchemaTypes> {
16
+ /**
17
+ * Loads and validates data against the provided schema.
18
+ *
19
+ * @param schema - VineJS schema to validate the loaded data against
20
+ */
21
+ load(schema: Schema, validatorMetaData?: any): Promise<Infer<Schema>>;
22
+ }
23
+ /**
24
+ * A function type that transforms or queries collection data.
25
+ *
26
+ * @example
27
+ * ```ts
28
+ * const filterByStatus: ViewFn<typeof schema, [string], Item[]> = (data, status) => {
29
+ * return data.filter(item => item.status === status)
30
+ * }
31
+ * ```
32
+ */
33
+ export type ViewFn<Schema extends SchemaTypes, Args extends any[], Result> = (input: Infer<Schema>, ...args: Args) => Result;
34
+ /**
35
+ * Transforms a record of view functions into query method signatures.
36
+ * Extracts the arguments and return type from each ViewFn to create method signatures.
37
+ *
38
+ * @example
39
+ * ```ts
40
+ * type Views = {
41
+ * filterByStatus: ViewFn<typeof schema, [string], Item[]>
42
+ * findById: ViewFn<typeof schema, [number], Item | undefined>
43
+ * }
44
+ *
45
+ * type Methods = ViewsToQueryMethods<Views>
46
+ * // Results in:
47
+ * // {
48
+ * // filterByStatus: (status: string) => Item[]
49
+ * // findById: (id: number) => Item | undefined
50
+ * // }
51
+ * ```
52
+ */
53
+ export type ViewsToQueryMethods<Views> = {
54
+ [K in keyof Views]: Views[K] extends ViewFn<any, infer Args, infer Result> ? (...args: Args) => Result : never;
55
+ };
56
+ /**
57
+ * Configuration options for creating a Collection instance.
58
+ *
59
+ * @example
60
+ * ```ts
61
+ * const options: CollectionOptions<typeof postsSchema, typeof postViews> = {
62
+ * schema: postsSchema,
63
+ * loader: fileLoader,
64
+ * cache: true,
65
+ * views: {
66
+ * published: (posts) => posts.filter(p => p.published),
67
+ * findBySlug: (posts, slug) => posts.find(p => p.slug === slug)
68
+ * }
69
+ * }
70
+ * ```
71
+ */
72
+ export type CollectionOptions<Schema extends SchemaTypes, Views extends {
73
+ [name: string]: ViewFn<NoInfer<Schema>, any, any>;
74
+ }> = {
75
+ validatorMetaData?: any;
76
+ /** VineJS schema for validating loaded data */
77
+ schema: Schema;
78
+ /** Loader implementation for fetching and validating data */
79
+ loader: LoaderContract<NoInfer<Schema>>;
80
+ /** Whether to cache loaded data after first hydration */
81
+ cache: boolean;
82
+ /** Optional view functions for querying/transforming the collection */
83
+ views?: Views;
84
+ };
85
+ /**
86
+ * Configuration options for loading GitHub releases from an organization.
87
+ *
88
+ * @example
89
+ * ```ts
90
+ * const options: GithubReleasesOptions = {
91
+ * org: 'adonisjs',
92
+ * ghToken: process.env.GITHUB_TOKEN,
93
+ * outputPath: './cache/releases.json',
94
+ * refresh: 'daily',
95
+ * filters: {
96
+ * nameDoesntInclude: ['alpha', 'beta']
97
+ * }
98
+ * }
99
+ * ```
100
+ */
101
+ export type GithubReleasesOptions = {
102
+ /** GitHub organization name */
103
+ org: string;
104
+ /** GitHub personal access token for authentication */
105
+ ghToken: string;
106
+ /** Path where cached data will be stored */
107
+ outputPath: string;
108
+ /** How often to refresh the cached data */
109
+ refresh: 'daily' | 'weekly' | 'monthly';
110
+ /** Optional filters to include/exclude releases by name patterns */
111
+ filters?: {
112
+ /** Array of substrings that release names must contain */
113
+ nameIncludes?: string[];
114
+ /** Array of substrings that release names must not contain */
115
+ nameDoesntInclude?: string[];
116
+ };
117
+ };
118
+ /**
119
+ * Represents a GitHub sponsor with their details and sponsorship information.
120
+ *
121
+ * @example
122
+ * ```ts
123
+ * const sponsor: GithubSponsor = {
124
+ * id: 'sp_123',
125
+ * createdAt: '2023-01-15T10:00:00Z',
126
+ * privacyLevel: 'PUBLIC',
127
+ * tierName: 'Gold Sponsor',
128
+ * tierMonthlyPriceInCents: 10000,
129
+ * sponsorType: 'User',
130
+ * sponsorLogin: 'johndoe',
131
+ * sponsorName: 'John Doe',
132
+ * sponsorAvatarUrl: 'https://avatars.githubusercontent.com/u/123',
133
+ * sponsorUrl: 'https://github.com/johndoe'
134
+ * }
135
+ * ```
136
+ */
137
+ export type GithubSponsor = {
138
+ /** Unique identifier for the sponsorship */
139
+ id: string;
140
+ /** ISO 8601 timestamp when the sponsorship was created */
141
+ createdAt: string;
142
+ /** Privacy level of the sponsorship (PUBLIC, PRIVATE, etc.) */
143
+ privacyLevel: string | null;
144
+ /** Name of the sponsorship tier */
145
+ tierName: string | null;
146
+ /** Monthly price of the tier in cents */
147
+ tierMonthlyPriceInCents: number | null;
148
+ /** Type of sponsor entity: "User" or "Organization" */
149
+ sponsorType: string;
150
+ /** GitHub username of the sponsor */
151
+ sponsorLogin: string;
152
+ /** Display name of the sponsor */
153
+ sponsorName?: string | null;
154
+ /** Avatar URL of the sponsor */
155
+ sponsorAvatarUrl?: string | null;
156
+ /** Profile URL of the sponsor */
157
+ sponsorUrl?: string | null;
158
+ };
159
+ /**
160
+ * Configuration options for loading GitHub sponsors for a user or organization.
161
+ *
162
+ * @example
163
+ * ```ts
164
+ * const options: GithubSponsorsOptions = {
165
+ * login: 'adonisjs',
166
+ * isOrg: true,
167
+ * ghToken: process.env.GITHUB_TOKEN,
168
+ * outputPath: './cache/sponsors.json',
169
+ * refresh: 'daily'
170
+ * }
171
+ * ```
172
+ */
173
+ export type GithubSponsorsOptions = {
174
+ /** GitHub username or organization name */
175
+ login: string;
176
+ /** Whether the login is an organization (true) or user (false) */
177
+ isOrg: boolean;
178
+ /** GitHub personal access token for authentication */
179
+ ghToken: string;
180
+ /** Path where cached sponsors will be stored */
181
+ outputPath: string;
182
+ /** How often to refresh the cached data */
183
+ refresh: 'daily' | 'weekly' | 'monthly';
184
+ };
185
+ /**
186
+ * Represents a GitHub release with its metadata.
187
+ *
188
+ * @example
189
+ * ```ts
190
+ * const release: GithubRelease = {
191
+ * name: 'v5.0.0',
192
+ * tagName: 'v5.0.0',
193
+ * publishedAt: '2023-12-01T10:00:00Z',
194
+ * url: 'https://github.com/adonisjs/core/releases/tag/v5.0.0',
195
+ * description: 'Major release with breaking changes'
196
+ * }
197
+ * ```
198
+ */
199
+ export type GithubRelease = {
200
+ /** Name of the release */
201
+ name: string;
202
+ /** Git tag name associated with the release */
203
+ tagName: string;
204
+ /** ISO 8601 timestamp when the release was published */
205
+ publishedAt: string;
206
+ /** URL to the release page on GitHub */
207
+ url: string;
208
+ /** Markdown description/notes for the release */
209
+ description: string | null;
210
+ };
211
+ /**
212
+ * GitHub release with repository information.
213
+ * Extends GithubRelease to include the repository name.
214
+ *
215
+ * @example
216
+ * ```ts
217
+ * const release: GithubReleaseWithRepo = {
218
+ * repo: 'core',
219
+ * name: 'v5.0.0',
220
+ * tagName: 'v5.0.0',
221
+ * publishedAt: '2023-12-01T10:00:00Z',
222
+ * url: 'https://github.com/adonisjs/core/releases/tag/v5.0.0',
223
+ * description: 'Major release with breaking changes'
224
+ * }
225
+ * ```
226
+ */
227
+ export type GithubReleaseWithRepo = GithubRelease & {
228
+ /** Name of the repository this release belongs to */
229
+ repo: string;
230
+ };
231
+ /**
232
+ * Configuration options for loading GitHub contributors from an organization.
233
+ *
234
+ * @example
235
+ * ```ts
236
+ * const options: GithubContributorsOptions = {
237
+ * org: 'adonisjs',
238
+ * ghToken: process.env.GITHUB_TOKEN,
239
+ * outputPath: './cache/contributors.json',
240
+ * refresh: 'weekly'
241
+ * }
242
+ * ```
243
+ */
244
+ export type GithubContributorsOptions = {
245
+ /** GitHub organization name */
246
+ org: string;
247
+ /** GitHub personal access token for authentication */
248
+ ghToken: string;
249
+ /** Path where cached contributors will be stored */
250
+ outputPath: string;
251
+ /** How often to refresh the cached data */
252
+ refresh: 'daily' | 'weekly' | 'monthly';
253
+ };
254
+ /**
255
+ * Represents a GitHub contributor with their profile information and contribution count.
256
+ * This matches the shape returned by GitHub REST API /contributors endpoint.
257
+ *
258
+ * @example
259
+ * ```ts
260
+ * const contributor: GithubContributorNode = {
261
+ * login: 'thetutlage',
262
+ * id: 103858,
263
+ * avatar_url: 'https://avatars.githubusercontent.com/u/103858',
264
+ * html_url: 'https://github.com/thetutlage',
265
+ * contributions: 250
266
+ * }
267
+ * ```
268
+ */
269
+ export type GithubContributorNode = {
270
+ /** GitHub username of the contributor */
271
+ login: string;
272
+ /** Unique GitHub user ID */
273
+ id?: number;
274
+ /** Avatar URL of the contributor */
275
+ avatar_url?: string | null;
276
+ /** Profile URL of the contributor */
277
+ html_url?: string | null;
278
+ /** Number of contributions made to the repository */
279
+ contributions: number;
280
+ };
@@ -0,0 +1,82 @@
1
+ import { type GithubSponsor, type GithubReleasesOptions, type GithubReleaseWithRepo, type GithubSponsorsOptions, type GithubContributorNode, type GithubContributorsOptions } from './types.ts';
2
+ /**
3
+ * Fetches all sponsors for a GitHub user or organization using GraphQL API.
4
+ * Handles pagination automatically to retrieve all sponsors across multiple requests.
5
+ *
6
+ * @param options - Configuration options for fetching sponsors
7
+ * @param options.login - GitHub username or organization name
8
+ * @param options.isOrg - Whether the login is an organization (true) or user (false)
9
+ * @param options.ghToken - GitHub personal access token for authentication
10
+ *
11
+ * @example
12
+ * ```ts
13
+ * const sponsors = await fetchAllSponsors({
14
+ * login: 'adonisjs',
15
+ * isOrg: true,
16
+ * ghToken: process.env.GITHUB_TOKEN
17
+ * })
18
+ * ```
19
+ */
20
+ export declare function fetchAllSponsors({ login, isOrg, ghToken, }: GithubSponsorsOptions): Promise<GithubSponsor[]>;
21
+ /**
22
+ * Fetches all releases from public repositories of a GitHub organization.
23
+ * Handles pagination and supports filtering releases by name patterns.
24
+ *
25
+ * @param options - Configuration options for fetching releases
26
+ * @param options.org - GitHub organization name
27
+ * @param options.ghToken - GitHub personal access token for authentication
28
+ * @param options.filters - Optional filters to include/exclude releases by name patterns
29
+ * @param options.filters.nameIncludes - Array of substrings that release names must contain
30
+ * @param options.filters.nameDoesntInclude - Array of substrings that release names must not contain
31
+ *
32
+ * @example
33
+ * ```ts
34
+ * const releases = await fetchReleases({
35
+ * org: 'adonisjs',
36
+ * ghToken: process.env.GITHUB_TOKEN,
37
+ * filters: {
38
+ * nameIncludes: ['v'],
39
+ * nameDoesntInclude: ['alpha', 'beta']
40
+ * }
41
+ * })
42
+ * ```
43
+ */
44
+ export declare function fetchReleases({ org, ghToken, filters, }: GithubReleasesOptions): Promise<GithubReleaseWithRepo[]>;
45
+ /**
46
+ * Fetches all contributors from all public, non-archived repositories in a GitHub organization.
47
+ * Uses the GitHub REST API with pagination to retrieve contributors from each repository.
48
+ * Handles errors gracefully by logging warnings for failed repositories.
49
+ *
50
+ * @param options - Configuration options for fetching contributors
51
+ * @param options.org - GitHub organization name
52
+ * @param options.ghToken - GitHub personal access token for authentication
53
+ *
54
+ * @example
55
+ * ```ts
56
+ * const contributors = await fetchContributorsForOrg({
57
+ * org: 'adonisjs',
58
+ * ghToken: process.env.GITHUB_TOKEN,
59
+ * outputPath: './cache/contributors.json',
60
+ * refresh: 'weekly'
61
+ * })
62
+ * ```
63
+ */
64
+ export declare function fetchContributorsForOrg({ org, ghToken, }: GithubContributorsOptions): Promise<GithubContributorNode[]>;
65
+ /**
66
+ * Merges two arrays by removing duplicates based on a specified key.
67
+ * Items from the existing array are preserved, and only new unique items
68
+ * from the fresh array are added.
69
+ *
70
+ * @param existing - The existing array to merge into
71
+ * @param fresh - The new array containing potentially duplicate items
72
+ * @param key - The property key to use for identifying duplicates
73
+ *
74
+ * @example
75
+ * ```ts
76
+ * const existing = [{ id: 1, name: 'foo' }, { id: 2, name: 'bar' }]
77
+ * const fresh = [{ id: 2, name: 'bar' }, { id: 3, name: 'baz' }]
78
+ * const merged = mergeArrays(existing, fresh, 'id')
79
+ * // Result: [{ id: 1, name: 'foo' }, { id: 2, name: 'bar' }, { id: 3, name: 'baz' }]
80
+ * ```
81
+ */
82
+ export declare function mergeArrays<T, K extends keyof T>(existing: T[], fresh: T[], key: K): T[];
package/package.json ADDED
@@ -0,0 +1,146 @@
1
+ {
2
+ "name": "@adonisjs/content",
3
+ "description": "Content management for AdonisJS with schema validation, GitHub loaders, and custom queries",
4
+ "version": "1.1.0",
5
+ "engines": {
6
+ "node": ">=24.0.0"
7
+ },
8
+ "type": "module",
9
+ "files": [
10
+ "build",
11
+ "!build/bin",
12
+ "!build/tests"
13
+ ],
14
+ "main": "build/index.js",
15
+ "exports": {
16
+ "./loaders": "./build/loaders/main.js",
17
+ "./types": "./build/types.js",
18
+ "./content_provider": "./build/providers/content_provider.js",
19
+ ".": "./build/index.js"
20
+ },
21
+ "scripts": {
22
+ "pretest": "npm run lint",
23
+ "test": "c8 npm run quick:test",
24
+ "lint": "eslint .",
25
+ "format": "prettier --write .",
26
+ "typecheck": "tsc --noEmit",
27
+ "precompile": "npm run lint",
28
+ "compile": "tsup-node && tsc --emitDeclarationOnly --declaration",
29
+ "build": "npm run compile",
30
+ "version": "npm run build",
31
+ "prepublishOnly": "npm run build",
32
+ "release": "release-it",
33
+ "quick:test": "node --import=@poppinss/ts-exec --enable-source-maps bin/test.ts"
34
+ },
35
+ "devDependencies": {
36
+ "@adonisjs/assembler": "^8.0.0-next.19",
37
+ "@adonisjs/core": "^7.0.0-next.10",
38
+ "@adonisjs/eslint-config": "^3.0.0-next.4",
39
+ "@adonisjs/prettier-config": "^1.4.5",
40
+ "@adonisjs/tsconfig": "^2.0.0-next.3",
41
+ "@adonisjs/vite": "^5.1.0-next.1",
42
+ "@japa/assert": "^4.1.1",
43
+ "@japa/expect-type": "^2.0.3",
44
+ "@japa/file-system": "^2.3.2",
45
+ "@japa/runner": "^4.4.0",
46
+ "@poppinss/ts-exec": "^1.4.1",
47
+ "@release-it/conventional-changelog": "^10.0.1",
48
+ "@types/node": "^24.10.1",
49
+ "@vinejs/vine": "^4.1.0",
50
+ "c8": "^10.1.3",
51
+ "eslint": "^9.39.1",
52
+ "prettier": "^3.6.2",
53
+ "release-it": "^19.0.6",
54
+ "tsup": "^8.5.1",
55
+ "typescript": "^5.9.3"
56
+ },
57
+ "dependencies": {
58
+ "@octokit/graphql": "^9.0.3",
59
+ "@octokit/rest": "^22.0.1",
60
+ "dayjs": "^1.11.19"
61
+ },
62
+ "peerDependencies": {
63
+ "@adonisjs/core": "^7.0.0-next.10",
64
+ "@adonisjs/assembler": "^8.0.0-next.19",
65
+ "@adonisjs/vite": "^5.1.0-next.1",
66
+ "@vinejs/vine": "^4.1.0"
67
+ },
68
+ "peerDependenciesMeta": {
69
+ "@adonisjs/assembler": {
70
+ "optional": true
71
+ }
72
+ },
73
+ "homepage": "https://github.com/adonisjs/content#readme",
74
+ "repository": {
75
+ "type": "git",
76
+ "url": "git+https://github.com/adonisjs/content.git"
77
+ },
78
+ "bugs": {
79
+ "url": "https://github.com/adonisjs/content/issues"
80
+ },
81
+ "keywords": [
82
+ "adonisjs",
83
+ "content",
84
+ "collection",
85
+ "schema",
86
+ "validation",
87
+ "github",
88
+ "sponsors",
89
+ "contributors",
90
+ "releases",
91
+ "cms"
92
+ ],
93
+ "author": "Harminder Virk <virk@adonisjs.com>",
94
+ "license": "MIT",
95
+ "publishConfig": {
96
+ "access": "public",
97
+ "provenance": true
98
+ },
99
+ "tsup": {
100
+ "entry": [
101
+ "index.ts",
102
+ "providers/content_provider.ts",
103
+ "src/loaders/main.ts"
104
+ ],
105
+ "outDir": "./build",
106
+ "clean": true,
107
+ "format": "esm",
108
+ "dts": false,
109
+ "sourcemap": false,
110
+ "target": "esnext"
111
+ },
112
+ "release-it": {
113
+ "git": {
114
+ "requireCleanWorkingDir": true,
115
+ "requireUpstream": true,
116
+ "commitMessage": "chore(release): ${version}",
117
+ "tagAnnotation": "v${version}",
118
+ "push": true,
119
+ "tagName": "v${version}"
120
+ },
121
+ "github": {
122
+ "release": true
123
+ },
124
+ "npm": {
125
+ "publish": true,
126
+ "skipChecks": true
127
+ },
128
+ "plugins": {
129
+ "@release-it/conventional-changelog": {
130
+ "preset": {
131
+ "name": "angular"
132
+ }
133
+ }
134
+ }
135
+ },
136
+ "c8": {
137
+ "reporter": [
138
+ "text",
139
+ "html"
140
+ ],
141
+ "exclude": [
142
+ "tests/**"
143
+ ]
144
+ },
145
+ "prettier": "@adonisjs/prettier-config"
146
+ }