@licht-77/dmm-sdk
Version:
DMM Affiliate API v3 SDK for Node.js/TypeScript
179 lines • 6.99 kB
JavaScript
;
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