diff --git a/packages/next-drupal/src/next-drupal-base.ts b/packages/next-drupal/src/next-drupal-base.ts index 2feb82c5..5d9db158 100644 --- a/packages/next-drupal/src/next-drupal-base.ts +++ b/packages/next-drupal/src/next-drupal-base.ts @@ -30,6 +30,9 @@ const DEFAULT_HEADERS = { Accept: "application/json", } +/** + * The base class for NextDrupal clients. + */ export class NextDrupalBase { accessToken?: NextDrupalBaseOptions["accessToken"] @@ -173,6 +176,13 @@ export class NextDrupalBase { return this._token } + /** + * Fetches a resource from the given input URL or path. + * + * @param {RequestInfo} input The input URL or path. + * @param {FetchOptions} init The fetch options. + * @returns {Promise} The fetch response. + */ async fetch( input: RequestInfo, { withAuth, ...init }: FetchOptions = {} @@ -215,6 +225,12 @@ export class NextDrupalBase { return await fetch(input, init) } + /** + * Gets the authorization header value based on the provided auth configuration. + * + * @param {NextDrupalAuth} auth The auth configuration. + * @returns {Promise} The authorization header value. + */ async getAuthorizationHeader(auth: NextDrupalAuth) { let header: string @@ -250,6 +266,13 @@ export class NextDrupalBase { return header } + /** + * Builds a URL with the given path and search parameters. + * + * @param {string} path The URL path. + * @param {EndpointSearchParams} searchParams The search parameters. + * @returns {URL} The constructed URL. + */ buildUrl(path: string, searchParams?: EndpointSearchParams): URL { const url = new URL(path, this.baseUrl) @@ -269,7 +292,15 @@ export class NextDrupalBase { return url } - // async so subclasses can query for endpoint discovery. + /** + * Builds an endpoint URL with the given options. + * + * @param {Object} options The options for building the endpoint. + * @param {string} options.locale The locale. + * @param {string} options.path The path. + * @param {EndpointSearchParams} options.searchParams The search parameters. + * @returns {Promise} The constructed endpoint URL. + */ async buildEndpoint({ locale = "", path = "", @@ -291,6 +322,16 @@ export class NextDrupalBase { ).toString() } + /** + * Constructs a path from the given segment and options. + * + * @param {string | string[]} segment The path segment. + * @param {Object} options The options for constructing the path. + * @param {Locale} options.locale The locale. + * @param {Locale} options.defaultLocale The default locale. + * @param {PathPrefix} options.pathPrefix The path prefix. + * @returns {string} The constructed path. + */ constructPathFromSegment( segment: string | string[], options: { @@ -338,6 +379,15 @@ export class NextDrupalBase { }) } + /** + * Adds a locale prefix to the given path. + * + * @param {string} path The path. + * @param {Object} options The options for adding the locale prefix. + * @param {Locale} options.locale The locale. + * @param {Locale} options.defaultLocale The default locale. + * @returns {string} The path with the locale prefix. + */ addLocalePrefix( path: string, options: { locale?: Locale; defaultLocale?: Locale } = {} @@ -356,6 +406,12 @@ export class NextDrupalBase { return `${localePrefix}${path}` } + /** + * Gets an access token using the provided client ID and secret. + * + * @param {NextDrupalAuthClientIdSecret} clientIdSecret The client ID and secret. + * @returns {Promise} The access token. + */ async getAccessToken( clientIdSecret?: NextDrupalAuthClientIdSecret ): Promise { @@ -435,6 +491,12 @@ export class NextDrupalBase { return result } + /** + * Validates the draft URL using the provided search parameters. + * + * @param {URLSearchParams} searchParams The search parameters. + * @returns {Promise} The validation response. + */ async validateDraftUrl(searchParams: URLSearchParams): Promise { const path = searchParams.get("path") @@ -468,10 +530,22 @@ export class NextDrupalBase { return response } + /** + * Logs a debug message if debug mode is enabled. + * + * @param {string} message The debug message. + */ debug(message) { this.isDebugEnabled && this.logger.debug(message) } + /** + * Throws an error if the response contains JSON:API errors. + * + * @param {Response} response The fetch response. + * @param {string} messagePrefix The error message prefix. + * @throws {JsonApiErrors} The JSON:API errors. + */ async throwIfJsonErrors(response: Response, messagePrefix = "") { if (!response?.ok) { const errors = await this.getErrorsFromResponse(response) @@ -479,6 +553,12 @@ export class NextDrupalBase { } } + /** + * Extracts errors from the fetch response. + * + * @param {Response} response The fetch response. + * @returns {Promise} The extracted errors. + */ async getErrorsFromResponse(response: Response) { const type = response.headers.get("content-type") let error: JsonApiResponse | { message: string } @@ -506,6 +586,12 @@ export class NextDrupalBase { } } +/** + * Checks if the provided auth configuration is basic auth. + * + * @param {NextDrupalAuth} auth The auth configuration. + * @returns {boolean} True if the auth configuration is basic auth, false otherwise. + */ export function isBasicAuth( auth: NextDrupalAuth ): auth is NextDrupalAuthUsernamePassword { @@ -515,6 +601,12 @@ export function isBasicAuth( ) } +/** + * Checks if the provided auth configuration is access token auth. + * + * @param {NextDrupalAuth} auth The auth configuration. + * @returns {boolean} True if the auth configuration is access token auth, false otherwise. + */ export function isAccessTokenAuth( auth: NextDrupalAuth ): auth is NextDrupalAuthAccessToken { @@ -524,6 +616,12 @@ export function isAccessTokenAuth( ) } +/** + * Checks if the provided auth configuration is client ID and secret auth. + * + * @param {NextDrupalAuth} auth The auth configuration. + * @returns {boolean} True if the auth configuration is client ID and secret auth, false otherwise. + */ export function isClientIdSecretAuth( auth: NextDrupalAuth ): auth is NextDrupalAuthClientIdSecret { diff --git a/packages/next-drupal/src/next-drupal-pages.ts b/packages/next-drupal/src/next-drupal-pages.ts index fd0af89a..e37d4916 100644 --- a/packages/next-drupal/src/next-drupal-pages.ts +++ b/packages/next-drupal/src/next-drupal-pages.ts @@ -27,6 +27,10 @@ import type { NextApiResponse, } from "next" +/** + * The NextDrupalPages class extends the NextDrupal class and provides methods + * for interacting with a Drupal backend in the context of Next.js pages. + */ export class NextDrupalPages extends NextDrupal { private serializer: DrupalClientOptions["serializer"] @@ -59,6 +63,13 @@ export class NextDrupalPages extends NextDrupal { ) => this.serializer.deserialize(body, options) } + /** + * Gets the entry point for a given resource type. + * + * @param {string} resourceType The resource type. + * @param {Locale} locale The locale. + * @returns {Promise} The entry point URL. + */ async getEntryForResourceType( resourceType: string, locale?: Locale @@ -74,6 +85,14 @@ export class NextDrupalPages extends NextDrupal { return new DrupalMenuTree(links, parent) } + /** + * Gets a resource from the context. + * + * @param {string | DrupalTranslatedPath} input The input path or translated path. + * @param {GetStaticPropsContext} context The static props context. + * @param {Object} options Options for the request. + * @returns {Promise} The fetched resource. + */ async getResourceFromContext( input: string | DrupalTranslatedPath, context: GetStaticPropsContext, @@ -157,6 +176,14 @@ export class NextDrupalPages extends NextDrupal { return resource } + /** + * Gets a collection of resources from the context. + * + * @param {string} type The type of the resources. + * @param {GetStaticPropsContext} context The static props context. + * @param {Object} options Options for the request. + * @returns {Promise} The fetched collection of resources. + */ async getResourceCollectionFromContext( type: string, context: GetStaticPropsContext, @@ -177,6 +204,14 @@ export class NextDrupalPages extends NextDrupal { }) } + /** + * Gets a search index from the context. + * + * @param {string} name The name of the search index. + * @param {GetStaticPropsContext} context The static props context. + * @param {Object} options Options for the request. + * @returns {Promise} The fetched search index. + */ async getSearchIndexFromContext( name: string, context: GetStaticPropsContext, @@ -189,6 +224,13 @@ export class NextDrupalPages extends NextDrupal { }) } + /** + * Translates a path from the context. + * + * @param {GetStaticPropsContext} context The static props context. + * @param {Object} options Options for the request. + * @returns {Promise} The translated path. + */ async translatePathFromContext( context: GetStaticPropsContext, options?: { @@ -208,6 +250,13 @@ export class NextDrupalPages extends NextDrupal { }) } + /** + * Gets the path from the context. + * + * @param {GetStaticPropsContext} context The static props context. + * @param {Object} options Options for the request. + * @returns {string} The constructed path. + */ getPathFromContext( context: GetStaticPropsContext, options?: { @@ -223,6 +272,14 @@ export class NextDrupalPages extends NextDrupal { getPathsFromContext = this.getStaticPathsFromContext + /** + * Gets static paths from the context. + * + * @param {string | string[]} types The types of the resources. + * @param {GetStaticPathsContext} context The static paths context. + * @param {Object} options Options for the request. + * @returns {Promise["paths"]>} The fetched static paths. + */ async getStaticPathsFromContext( types: string | string[], context: GetStaticPathsContext, @@ -291,6 +348,13 @@ export class NextDrupalPages extends NextDrupal { return paths.flat() } + /** + * Builds static paths from resources. + * + * @param {Object[]} resources The resources. + * @param {Object} options Options for the request. + * @returns {Object[]} The built static paths. + */ buildStaticPathsFromResources( resources: { path: DrupalPathAlias @@ -313,6 +377,13 @@ export class NextDrupalPages extends NextDrupal { : [] } + /** + * Builds static paths parameters from paths. + * + * @param {string[]} paths The paths. + * @param {Object} options Options for the request. + * @returns {Object[]} The built static paths parameters. + */ buildStaticPathsParamsFromPaths( paths: string[], options?: { pathPrefix?: PathPrefix; locale?: Locale } @@ -342,6 +413,13 @@ export class NextDrupalPages extends NextDrupal { }) } + /** + * Handles preview mode. + * + * @param {NextApiRequest} request The API request. + * @param {NextApiResponse} response The API response. + * @param {Object} options Options for the request. + */ async preview( request: NextApiRequest, response: NextApiResponse, @@ -411,6 +489,12 @@ export class NextDrupalPages extends NextDrupal { } } + /** + * Disables preview mode. + * + * @param {NextApiRequest} request The API request. + * @param {NextApiResponse} response The API response. + */ async previewDisable(request: NextApiRequest, response: NextApiResponse) { // Disable both preview and draft modes. response.clearPreviewData() @@ -427,6 +511,13 @@ export class NextDrupalPages extends NextDrupal { response.end() } + /** + * Gets the authentication configuration from the context and options. + * + * @param {GetStaticPropsContext} context The static props context. + * @param {JsonApiWithAuthOption} options Options for the request. + * @returns {NextDrupalAuth} The authentication configuration. + */ getAuthFromContextAndOptions( context: GetStaticPropsContext, options: JsonApiWithAuthOption diff --git a/packages/next-drupal/src/next-drupal.ts b/packages/next-drupal/src/next-drupal.ts index 1c837c7c..2041ebb5 100644 --- a/packages/next-drupal/src/next-drupal.ts +++ b/packages/next-drupal/src/next-drupal.ts @@ -44,6 +44,10 @@ export function useJsonaDeserialize() { } } +/** + * The NextDrupal class extends the NextDrupalBase class and provides methods + * for interacting with a Drupal backend. + */ export class NextDrupal extends NextDrupalBase { cache?: NextDrupalOptions["cache"] @@ -86,6 +90,14 @@ export class NextDrupal extends NextDrupalBase { } } + /** + * Creates a new resource of the specified type. + * + * @param {string} type The type of the resource. + * @param {JsonApiCreateResourceBody} body The body of the resource. + * @param {JsonApiOptions} options Options for the request. + * @returns {Promise} The created resource. + */ async createResource( type: string, body: JsonApiCreateResourceBody, @@ -126,6 +138,14 @@ export class NextDrupal extends NextDrupalBase { : /* c8 ignore next */ json } + /** + * Creates a new file resource for the specified media type. + * + * @param {string} type The type of the media. + * @param {JsonApiCreateFileResourceBody} body The body of the file resource. + * @param {JsonApiOptions} options Options for the request. + * @returns {Promise} The created file resource. + */ async createFileResource( type: string, body: JsonApiCreateFileResourceBody, @@ -170,6 +190,15 @@ export class NextDrupal extends NextDrupalBase { return options.deserialize ? this.deserialize(json) : json } + /** + * Updates an existing resource of the specified type. + * + * @param {string} type The type of the resource. + * @param {string} uuid The UUID of the resource. + * @param {JsonApiUpdateResourceBody} body The body of the resource. + * @param {JsonApiOptions} options Options for the request. + * @returns {Promise} The updated resource. + */ async updateResource( type: string, uuid: string, @@ -213,6 +242,14 @@ export class NextDrupal extends NextDrupalBase { : /* c8 ignore next */ json } + /** + * Deletes an existing resource of the specified type. + * + * @param {string} type The type of the resource. + * @param {string} uuid The UUID of the resource. + * @param {JsonApiOptions} options Options for the request. + * @returns {Promise} True if the resource was deleted, false otherwise. + */ async deleteResource( type: string, uuid: string, @@ -246,6 +283,14 @@ export class NextDrupal extends NextDrupalBase { return response.status === 204 } + /** + * Fetches a resource of the specified type by its UUID. + * + * @param {string} type The type of the resource. + * @param {string} uuid The UUID of the resource. + * @param {JsonApiOptions & JsonApiWithCacheOptions & JsonApiWithNextFetchOptions} options Options for the request. + * @returns {Promise} The fetched resource. + */ async getResource( type: string, uuid: string, @@ -301,6 +346,13 @@ export class NextDrupal extends NextDrupalBase { return options.deserialize ? this.deserialize(json) : json } + /** + * Fetches a resource of the specified type by its path. + * + * @param {string} path The path of the resource. + * @param {JsonApiOptions & JsonApiWithNextFetchOptions} options Options for the request. + * @returns {Promise} The fetched resource. + */ async getResourceByPath( path: string, options?: { @@ -410,6 +462,13 @@ export class NextDrupal extends NextDrupalBase { return options.deserialize ? this.deserialize(data) : data } + /** + * Fetches a collection of resources of the specified type. + * + * @param {string} type The type of the resources. + * @param {JsonApiOptions & JsonApiWithNextFetchOptions} options Options for the request. + * @returns {Promise} The fetched collection of resources. + */ async getResourceCollection( type: string, options?: { @@ -447,6 +506,13 @@ export class NextDrupal extends NextDrupalBase { return options.deserialize ? this.deserialize(json) : json } + /** + * Fetches path segments for a collection of resources of the specified types. + * + * @param {string | string[]} types The types of the resources. + * @param {JsonApiOptions & JsonApiWithAuthOption & JsonApiWithNextFetchOptions} options Options for the request. + * @returns {Promise<{ path: string, type: string, locale: Locale, segments: string[] }[]>} The fetched path segments. + */ async getResourceCollectionPathSegments( types: string | string[], options?: { @@ -555,6 +621,13 @@ export class NextDrupal extends NextDrupalBase { return paths.flat(2) } + /** + * Translates a path to a DrupalTranslatedPath object. + * + * @param {string} path The path to translate. + * @param {JsonApiWithAuthOption & JsonApiWithNextFetchOptions} options Options for the request. + * @returns {Promise} The translated path. + */ async translatePath( path: string, options?: JsonApiWithAuthOption & JsonApiWithNextFetchOptions @@ -586,6 +659,13 @@ export class NextDrupal extends NextDrupalBase { return await response.json() } + /** + * Fetches the JSON:API index. + * + * @param {Locale} locale The locale for the request. + * @param {JsonApiWithNextFetchOptions} options Options for the request. + * @returns {Promise} The JSON:API index. + */ async getIndex( locale?: Locale, options?: JsonApiWithNextFetchOptions @@ -610,6 +690,12 @@ export class NextDrupal extends NextDrupalBase { return await response.json() } + /** + * Builds an endpoint URL for the specified parameters. + * + * @param {Parameters[0] & { resourceType?: string }} params The parameters for the endpoint. + * @returns {Promise} The built endpoint URL. + */ async buildEndpoint({ locale = "", resourceType = "", @@ -647,6 +733,13 @@ export class NextDrupal extends NextDrupalBase { ).toString() } + /** + * Fetches the endpoint URL for the specified resource type. + * + * @param {string} type The type of the resource. + * @param {Locale} locale The locale for the request. + * @returns {Promise} The fetched endpoint URL. + */ async fetchResourceEndpoint(type: string, locale?: Locale): Promise { const index = await this.getIndex(locale) @@ -670,6 +763,13 @@ export class NextDrupal extends NextDrupalBase { return url } + /** + * Fetches a menu by its name. + * + * @param {string} menuName The name of the menu. + * @param {JsonApiOptions & JsonApiWithCacheOptions & JsonApiWithNextFetchOptions} options Options for the request. + * @returns {Promise<{ items: T[], tree: T[] }>} The fetched menu. + */ async getMenu( menuName: string, options?: JsonApiOptions & @@ -735,6 +835,13 @@ export class NextDrupal extends NextDrupalBase { return menu } + /** + * Fetches a view by its name. + * + * @param {string} name The name of the view. + * @param {JsonApiOptions & JsonApiWithNextFetchOptions} options Options for the request. + * @returns {Promise>} The fetched view. + */ async getView( name: string, options?: JsonApiOptions & JsonApiWithNextFetchOptions @@ -776,6 +883,13 @@ export class NextDrupal extends NextDrupalBase { } } + /** + * Fetches a search index by its name. + * + * @param {string} name The name of the search index. + * @param {JsonApiOptions & JsonApiWithNextFetchOptions} options Options for the request. + * @returns {Promise} The fetched search index. + */ async getSearchIndex( name: string, options?: JsonApiOptions & JsonApiWithNextFetchOptions @@ -810,16 +924,24 @@ export class NextDrupal extends NextDrupalBase { return options.deserialize ? this.deserialize(json) : json } + /** + * Deserializes the response body. + * + * @param {any} body The response body. + * @param {any} options Options for deserialization. + * @returns {any} The deserialized response body. + */ deserialize(body, options?) { if (!body) return null return this.deserializer(body, options) } - // Error handling. - // If throwJsonApiErrors is enabled, we show errors in the Next.js overlay. - // Otherwise, we log the errors even if debugging is turned off. - // In production, errors are always logged never thrown. + /** + * Logs or throws an error based on the throwJsonApiErrors flag. + * + * @param {Error} error The error to log or throw. + */ logOrThrowError(error: Error) { if (!this.throwJsonApiErrors) { this.logger.error(error) diff --git a/www/package.json b/www/package.json index 6834ba16..1d0c3cb5 100644 --- a/www/package.json +++ b/www/package.json @@ -8,7 +8,8 @@ "scripts": { "dev": "next dev -p 4444", "build": "next build", - "preview": "next build && next start -p 4444" + "preview": "next build && next start -p 4444", + "generate:docs": "typedoc --out content/api ../packages/next-drupal/src" }, "dependencies": { "@docsearch/react": "^3.6.0", @@ -23,7 +24,9 @@ "prism-react-renderer": "^1.3.5", "react": "^18.2.0", "react-dom": "^18.2.0", - "sharp": "^0.30.7" + "sharp": "^0.30.7", + "typedoc": "^0.23.9", + "typedoc-plugin-markdown": "^3.11.0" }, "devDependencies": { "@mapbox/rehype-prism": "^0.8.0", diff --git a/www/typedoc.json b/www/typedoc.json new file mode 100644 index 00000000..a0533d78 --- /dev/null +++ b/www/typedoc.json @@ -0,0 +1,5 @@ +{ + "entryPoints": ["../packages/next-drupal/src"], + "out": "content/api", + "plugin": ["typedoc-plugin-markdown"] +}