indexnow
Version:
An IndexNow wrapper for TypeScript/JavaScript.
95 lines (94 loc) • 3.75 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.indexNow = exports.generateKey = exports.SEARCH_ENGINES = void 0;
/**
* Currently, only the following search engines are supported:
* - Bing
* - Yandex
* @see {@link https://www.indexnow.org/faq | Supported search engines}
*/
exports.SEARCH_ENGINES = {
BING: 'https://www.bing.com/indexnow',
YANDEX: 'https://yandex.com/indexnow',
};
/**
* Generate a key to be used for IndexNow.
* @returns A random string of characters to be used as a key.
*/
function generateKey() {
return crypto.randomUUID().replaceAll('-', '');
}
exports.generateKey = generateKey;
/**
* The IndexNow class is used to access the IndexNow API.
*/
class IndexNow {
/**
* Create a new IndexNow instance.
* @param engine The search engine's IndexNow url.
* @param key The key to be used for IndexNow.
* @param keyLocation Optional value for key file location.
*/
constructor(engine, key, keyLocation) {
if (!engine.startsWith('https://'))
throw new Error(`Invalid search engine url '${engine}'. Must use 'https://'`);
this.engine = engine.endsWith('/') ? engine.substr(0, engine.length - 1) : engine;
this.ownership = { key, keyLocation };
}
/**
* Submit a url to the search engine.
* @param url The url to be indexed.
* @returns A promise that resolves if the url was successfully submitted.
* @throws {Error} If the request fails.
*/
async submitUrl(url) {
const res = await fetch(`${this.engine}?url=${url}&key=${this.ownership.key}${this.ownership.keyLocation ? `&keyLocation=${this.ownership.keyLocation}` : ''}`);
if (res.status === 200)
return;
throw new Error(`Failed to submit url '${url}' to search engine. Status: ${res.status} ${await res.text()}`);
}
/**
* Submit a list of urls to the search engine IndexNow API.
* @param host The host to be indexed.
* @param urlList The list of urls to be indexed.
* @returns A promise that resolves if the urls were successfully submitted.
* @throws {Error} If no urls were supplied.
* @throws {Error} If more than 10,000 urls were supplied.
* @throws {Error} If the request fails.
*/
async submitUrls(host, urlList) {
if (urlList.length === 0)
throw new Error('No urls to submit');
if (urlList.length > 10000)
throw new Error('Cannot submit more than 10,000 urls at once');
const body = {
host,
key: this.ownership.key,
keyLocation: this.ownership.keyLocation,
urlList,
};
const res = await fetch(`${this.engine}/indexnow`, {
method: 'POST',
body: JSON.stringify(body),
});
if (res.status === 200)
return;
throw new Error(`Failed to submit urls to search engine. Status: ${res.status} ${await res.text()}`);
}
}
exports.default = IndexNow;
/**
* Perform an IndexNow request.
* @param toIndex The url or list of urls to be indexed. If a list of urls is supplied, the first url will be used as the host and not submitted.
* @param engine The search engine IndexNow url.
* @param key The key to be used for IndexNow.
* @param keyLocation Optional value for key file location.
* @returns A promise that resolves if the urls were successfully submitted.
*/
function indexNow(toIndex, engine, key, keyLocation) {
const indexNow = new IndexNow(engine, key, keyLocation);
if (typeof toIndex === 'string')
return indexNow.submitUrl(toIndex);
return indexNow.submitUrls(toIndex[0], toIndex.slice(1));
}
exports.indexNow = indexNow;