UNPKG

@licht-77/dmm-sdk

Version:

DMM Affiliate API v3 SDK for Node.js/TypeScript

179 lines 6.99 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.DmmApiClient = void 0; const node_url_1 = require("node:url"); /** * DMM Affiliate API v3 Client. */ class DmmApiClient { baseUrl; static ItemListEndpoint = '/ItemList'; static FloorListEndpoint = '/FloorList'; static ActressSearchEndpoint = '/ActressSearch'; static GenreSearchEndpoint = '/GenreSearch'; static MakerSearchEndpoint = '/MakerSearch'; static SeriesSearchEndpoint = '/SeriesSearch'; static AuthorSearchEndpoint = '/AuthorSearch'; static DefaultHitsPerPageForGetAllItems = 100; apiId; affiliateId; /** * Creates an instance of DmmApiClient. * @param {DmmApiClientOptions} options - Client options. * @throws {Error} if apiId or affiliateId is missing. */ constructor(options) { if (!options.apiId || !options.affiliateId) { throw new Error('API ID and Affiliate ID are required.'); } this.apiId = options.apiId; this.affiliateId = options.affiliateId; let tempBaseUrl = options.baseUrl ?? 'https://api.dmm.com/affiliate/v3'; if (tempBaseUrl.endsWith('/')) { tempBaseUrl = tempBaseUrl.slice(0, -1); } this.baseUrl = tempBaseUrl; } /** * Sends a request to the API endpoint. * @protected * @template T The expected response type. * @param {string} endpoint - The API endpoint path (e.g., '/ItemList'). * @param {Record<string, string | number | undefined>} [params] - API parameters. * @returns {Promise<T>} The 'result' part of the API response. * @throws {Error} if the request fails, times out, or the response format is invalid. */ async request(endpoint, params) { const url = new node_url_1.URL(`${this.baseUrl}${endpoint}`); const searchParams = new node_url_1.URLSearchParams({ api_id: this.apiId, affiliate_id: this.affiliateId, }); if (params) { for (const key in params) { if (key === 'api_id' || key === 'affiliate_id') continue; const value = params[key]; if (value === undefined || value === null) continue; if (Array.isArray(value)) { value.forEach((entry, index) => { if (entry === undefined || entry === null) return; searchParams.append(`${key}[${index}]`, String(entry)); }); } else { searchParams.set(key, String(value)); } } } url.search = searchParams.toString(); const response = await fetch(url.toString()); if (response.ok) { const data = await response.json(); if (!data || typeof data !== 'object' || !('result' in data)) { throw new Error('Invalid API response format: "result" field is missing.'); } return data.result; } // Non-2xx: throw the raw response body without extra formatting const rawBody = await response.text(); throw new Error(rawBody || response.statusText); } /** * Calls the Item List API. * @param {Partial<ItemListRequestParams}} params - Search parameters. * @returns {Promise<ItemListResponse>} Item search results. */ async getItemList(params) { const apiParams = { ...params }; return this.request(DmmApiClient.ItemListEndpoint, apiParams); } /** * Calls the Floor List API. * @returns {Promise<FloorListResponse>} Floor list. */ async getFloorList() { // This API does not take additional parameters. return this.request(DmmApiClient.FloorListEndpoint); } /** * Calls the Actress Search API. * @param {ActressSearchRequestParams} params - Search parameters. * @returns {Promise<ActressSearchResponse>} Actress search results. */ async searchActress(params) { return this.request(DmmApiClient.ActressSearchEndpoint, { ...params }); } /** * Calls the Genre Search API. * @param {GenreSearchRequestParams} params - Search parameters. * @returns {Promise<GenreSearchResponse>} Genre search results. */ async searchGenre(params) { return this.request(DmmApiClient.GenreSearchEndpoint, { ...params }); } /** * Calls the Maker Search API. * @param {MakerSearchRequestParams} params - Search parameters. * @returns {Promise<MakerSearchResponse>} Maker search results. */ async searchMaker(params) { return this.request(DmmApiClient.MakerSearchEndpoint, { ...params }); } /** * Calls the Series Search API. * @param {SeriesSearchRequestParams} params - Search parameters. * @returns {Promise<SeriesSearchResponse>} Series search results. */ async searchSeries(params) { return this.request(DmmApiClient.SeriesSearchEndpoint, { ...params }); } /** * Calls the Author Search API. * @param {AuthorSearchRequestParams} params - Search parameters. * @returns {Promise<AuthorSearchResponse>} Author search results. */ async searchAuthor(params) { return this.request(DmmApiClient.AuthorSearchEndpoint, { ...params }); } /** * Retrieves all items matching the given criteria using the Item List API with an async generator. * Suitable for efficiently processing a large number of items. * @param {Omit<ItemListRequestParams, 'hits' | 'offset'>} params - Search parameters (hits and offset are managed internally and will be ignored). * @yields {Item} Matched item information. * @throws {Error} if an error occurs during API calls. */ async *getAllItems(params) { let currentOffset = 1; const hitsPerPage = DmmApiClient.DefaultHitsPerPageForGetAllItems; let totalCount = -1; const requestParams = { ...params, hits: hitsPerPage, offset: currentOffset, }; while (totalCount === -1 || currentOffset <= totalCount) { requestParams.offset = currentOffset; const response = await this.getItemList(requestParams); if (totalCount === -1) { totalCount = response.total_count; if (totalCount === 0) { return; } } if (response.items && response.items.length > 0) { for (const item of response.items) { yield item; } currentOffset = response.first_position + response.items.length; } else { break; } } } } exports.DmmApiClient = DmmApiClient; //# sourceMappingURL=client.js.map