picnic-api
Version:
Unofficial wrapper for the API of the online supermarket Picnic
73 lines • 3.23 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
/**
* Base HTTP client that handles request construction, authentication headers,
* and error handling for the Picnic API.
*/
class HttpClient {
constructor(options) {
this.countryCode = options?.countryCode || "NL";
this.apiVersion = options?.apiVersion || "15";
this.authKey = options?.authKey || null;
this.url = options?.url || `https://storefront-prod.${this.countryCode.toLowerCase()}.picnicinternational.com/api/${this.apiVersion}`;
this.deviceId = options?.deviceId || "3C417201548B2E3B";
this.agent = options?.agent || "30100;1.236.1-15553;";
}
get baseHeaders() {
return {
"User-Agent": "okhttp/4.9.0",
"Content-Type": "application/json; charset=UTF-8",
"Accept-Language": this.countryCode === "DE" ? "de" : (this.countryCode === "FR" ? "fr" : "nl"),
...(this.authKey && { "x-picnic-auth": this.authKey }),
};
}
get picnicHeaders() {
return {
"x-picnic-agent": this.agent,
"x-picnic-did": this.deviceId,
};
}
/**
* Can be used to send custom requests that are not covered by the domain services.
* @param {string} method The HTTP method to use: GET, POST, PUT or DELETE.
* @param {string} path The path, optionally including query params. Example: `/cart/set_delivery_slot` or `/my_store?depth=0`.
* @param {TRequestData|null} [data=null] The request body, typically for POST or PUT requests.
* @param {boolean} [includePicnicHeaders=false] Whether to include x-picnic-agent and x-picnic-did headers.
* @param {boolean} [isImageRequest=false] When true, returns an ArrayBuffer instead of JSON.
*/
async sendRequest(method, path, data = null, includePicnicHeaders = false, isImageRequest = false) {
const headers = new Headers({
...this.baseHeaders,
...(includePicnicHeaders && this.picnicHeaders),
});
// `path` may be an absolute URL (e.g. image requests target a different base
// than the API), in which case it must be used as-is rather than prefixed.
const requestUrl = /^https?:\/\//.test(path) ? path : `${this.url}${path}`;
const response = await fetch(requestUrl, {
method,
headers,
body: data ? JSON.stringify(data) : null,
});
if (!response.ok) {
const body = await response.text();
try {
const errorData = JSON.parse(body);
throw new Error(`${errorData.error?.message || response.statusText}`);
}
catch (e) {
if (e instanceof Error && !(e instanceof SyntaxError))
throw e;
throw new Error(`${response.status} ${response.statusText}${body ? ` - ${body}` : ""}`);
}
}
if (isImageRequest) {
return response.arrayBuffer();
}
if (response.body !== null) {
return response.json();
}
return undefined;
}
}
exports.default = HttpClient;
//# sourceMappingURL=http-client.js.map