"use strict";
var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
    if (kind === "m") throw new TypeError("Private method is not writable");
    if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
    if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
    return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
};
var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
    if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
    if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
    return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
};
var _Client_auth, _Client_logLevel, _Client_logger, _Client_prefixUrl, _Client_timeoutMs, _Client_notionVersion, _Client_fetch, _Client_agent, _Client_userAgent;
Object.defineProperty(exports, "__esModule", { value: true });
const logging_1 = require("./logging");
const errors_1 = require("./errors");
const utils_1 = require("./utils");
const api_endpoints_1 = require("./api-endpoints");
const package_json_1 = require("../package.json");
class Client {
    constructor(options) {
        var _a, _b, _c, _d, _e, _f;
        _Client_auth.set(this, void 0);
        _Client_logLevel.set(this, void 0);
        _Client_logger.set(this, void 0);
        _Client_prefixUrl.set(this, void 0);
        _Client_timeoutMs.set(this, void 0);
        _Client_notionVersion.set(this, void 0);
        _Client_fetch.set(this, void 0);
        _Client_agent.set(this, void 0);
        _Client_userAgent.set(this, void 0);
        /*
         * Notion API endpoints
         */
        this.blocks = {
            /**
             * Retrieve block
             */
            retrieve: (args) => {
                return this.request({
                    path: api_endpoints_1.getBlock.path(args),
                    method: api_endpoints_1.getBlock.method,
                    query: (0, utils_1.pick)(args, api_endpoints_1.getBlock.queryParams),
                    body: (0, utils_1.pick)(args, api_endpoints_1.getBlock.bodyParams),
                    auth: args === null || args === void 0 ? void 0 : args.auth,
                });
            },
            /**
             * Update block
             */
            update: (args) => {
                return this.request({
                    path: api_endpoints_1.updateBlock.path(args),
                    method: api_endpoints_1.updateBlock.method,
                    query: (0, utils_1.pick)(args, api_endpoints_1.updateBlock.queryParams),
                    body: (0, utils_1.pick)(args, api_endpoints_1.updateBlock.bodyParams),
                    auth: args === null || args === void 0 ? void 0 : args.auth,
                });
            },
            /**
             * Delete block
             */
            delete: (args) => {
                return this.request({
                    path: api_endpoints_1.deleteBlock.path(args),
                    method: api_endpoints_1.deleteBlock.method,
                    query: (0, utils_1.pick)(args, api_endpoints_1.deleteBlock.queryParams),
                    body: (0, utils_1.pick)(args, api_endpoints_1.deleteBlock.bodyParams),
                    auth: args === null || args === void 0 ? void 0 : args.auth,
                });
            },
            children: {
                /**
                 * Append block children
                 */
                append: (args) => {
                    return this.request({
                        path: api_endpoints_1.appendBlockChildren.path(args),
                        method: api_endpoints_1.appendBlockChildren.method,
                        query: (0, utils_1.pick)(args, api_endpoints_1.appendBlockChildren.queryParams),
                        body: (0, utils_1.pick)(args, api_endpoints_1.appendBlockChildren.bodyParams),
                        auth: args === null || args === void 0 ? void 0 : args.auth,
                    });
                },
                /**
                 * Retrieve block children
                 */
                list: (args) => {
                    return this.request({
                        path: api_endpoints_1.listBlockChildren.path(args),
                        method: api_endpoints_1.listBlockChildren.method,
                        query: (0, utils_1.pick)(args, api_endpoints_1.listBlockChildren.queryParams),
                        body: (0, utils_1.pick)(args, api_endpoints_1.listBlockChildren.bodyParams),
                        auth: args === null || args === void 0 ? void 0 : args.auth,
                    });
                },
            },
        };
        this.databases = {
            /**
             * List databases
             *
             * @deprecated Please use `search`
             */
            list: (args) => {
                return this.request({
                    path: api_endpoints_1.listDatabases.path(),
                    method: api_endpoints_1.listDatabases.method,
                    query: (0, utils_1.pick)(args, api_endpoints_1.listDatabases.queryParams),
                    body: (0, utils_1.pick)(args, api_endpoints_1.listDatabases.bodyParams),
                    auth: args === null || args === void 0 ? void 0 : args.auth,
                });
            },
            /**
             * Retrieve a database
             */
            retrieve: (args) => {
                return this.request({
                    path: api_endpoints_1.getDatabase.path(args),
                    method: api_endpoints_1.getDatabase.method,
                    query: (0, utils_1.pick)(args, api_endpoints_1.getDatabase.queryParams),
                    body: (0, utils_1.pick)(args, api_endpoints_1.getDatabase.bodyParams),
                    auth: args === null || args === void 0 ? void 0 : args.auth,
                });
            },
            /**
             * Query a database
             */
            query: (args) => {
                return this.request({
                    path: api_endpoints_1.queryDatabase.path(args),
                    method: api_endpoints_1.queryDatabase.method,
                    query: (0, utils_1.pick)(args, api_endpoints_1.queryDatabase.queryParams),
                    body: (0, utils_1.pick)(args, api_endpoints_1.queryDatabase.bodyParams),
                    auth: args === null || args === void 0 ? void 0 : args.auth,
                });
            },
            /**
             * Create a database
             */
            create: (args) => {
                return this.request({
                    path: api_endpoints_1.createDatabase.path(),
                    method: api_endpoints_1.createDatabase.method,
                    query: (0, utils_1.pick)(args, api_endpoints_1.createDatabase.queryParams),
                    body: (0, utils_1.pick)(args, api_endpoints_1.createDatabase.bodyParams),
                    auth: args === null || args === void 0 ? void 0 : args.auth,
                });
            },
            /**
             * Update a database
             */
            update: (args) => {
                return this.request({
                    path: api_endpoints_1.updateDatabase.path(args),
                    method: api_endpoints_1.updateDatabase.method,
                    query: (0, utils_1.pick)(args, api_endpoints_1.updateDatabase.queryParams),
                    body: (0, utils_1.pick)(args, api_endpoints_1.updateDatabase.bodyParams),
                    auth: args === null || args === void 0 ? void 0 : args.auth,
                });
            },
        };
        this.pages = {
            /**
             * Create a page
             */
            create: (args) => {
                return this.request({
                    path: api_endpoints_1.createPage.path(),
                    method: api_endpoints_1.createPage.method,
                    query: (0, utils_1.pick)(args, api_endpoints_1.createPage.queryParams),
                    body: (0, utils_1.pick)(args, api_endpoints_1.createPage.bodyParams),
                    auth: args === null || args === void 0 ? void 0 : args.auth,
                });
            },
            /**
             * Retrieve a page
             */
            retrieve: (args) => {
                return this.request({
                    path: api_endpoints_1.getPage.path(args),
                    method: api_endpoints_1.getPage.method,
                    query: (0, utils_1.pick)(args, api_endpoints_1.getPage.queryParams),
                    body: (0, utils_1.pick)(args, api_endpoints_1.getPage.bodyParams),
                    auth: args === null || args === void 0 ? void 0 : args.auth,
                });
            },
            /**
             * Update page properties
             */
            update: (args) => {
                return this.request({
                    path: api_endpoints_1.updatePage.path(args),
                    method: api_endpoints_1.updatePage.method,
                    query: (0, utils_1.pick)(args, api_endpoints_1.updatePage.queryParams),
                    body: (0, utils_1.pick)(args, api_endpoints_1.updatePage.bodyParams),
                    auth: args === null || args === void 0 ? void 0 : args.auth,
                });
            },
            properties: {
                /**
                 * Retrieve page property
                 */
                retrieve: (args) => {
                    return this.request({
                        path: api_endpoints_1.getPageProperty.path(args),
                        method: api_endpoints_1.getPageProperty.method,
                        query: (0, utils_1.pick)(args, api_endpoints_1.getPageProperty.queryParams),
                        body: (0, utils_1.pick)(args, api_endpoints_1.getPageProperty.bodyParams),
                        auth: args === null || args === void 0 ? void 0 : args.auth,
                    });
                },
            },
        };
        this.users = {
            /**
             * Retrieve a user
             */
            retrieve: (args) => {
                return this.request({
                    path: api_endpoints_1.getUser.path(args),
                    method: api_endpoints_1.getUser.method,
                    query: (0, utils_1.pick)(args, api_endpoints_1.getUser.queryParams),
                    body: (0, utils_1.pick)(args, api_endpoints_1.getUser.bodyParams),
                    auth: args === null || args === void 0 ? void 0 : args.auth,
                });
            },
            /**
             * List all users
             */
            list: (args) => {
                return this.request({
                    path: api_endpoints_1.listUsers.path(),
                    method: api_endpoints_1.listUsers.method,
                    query: (0, utils_1.pick)(args, api_endpoints_1.listUsers.queryParams),
                    body: (0, utils_1.pick)(args, api_endpoints_1.listUsers.bodyParams),
                    auth: args === null || args === void 0 ? void 0 : args.auth,
                });
            },
            /**
             * Get details about bot
             */
            me: (args) => {
                return this.request({
                    path: api_endpoints_1.getSelf.path(),
                    method: api_endpoints_1.getSelf.method,
                    query: (0, utils_1.pick)(args, api_endpoints_1.getSelf.queryParams),
                    body: (0, utils_1.pick)(args, api_endpoints_1.getSelf.bodyParams),
                    auth: args === null || args === void 0 ? void 0 : args.auth,
                });
            },
        };
        this.comments = {
            /**
             * Create a comment
             */
            create: (args) => {
                return this.request({
                    path: api_endpoints_1.createComment.path(),
                    method: api_endpoints_1.createComment.method,
                    query: (0, utils_1.pick)(args, api_endpoints_1.createComment.queryParams),
                    body: (0, utils_1.pick)(args, api_endpoints_1.createComment.bodyParams),
                    auth: args === null || args === void 0 ? void 0 : args.auth,
                });
            },
            /**
             * List comments
             */
            list: (args) => {
                return this.request({
                    path: api_endpoints_1.listComments.path(),
                    method: api_endpoints_1.listComments.method,
                    query: (0, utils_1.pick)(args, api_endpoints_1.listComments.queryParams),
                    body: (0, utils_1.pick)(args, api_endpoints_1.listComments.bodyParams),
                    auth: args === null || args === void 0 ? void 0 : args.auth,
                });
            },
        };
        this.fileUploads = {
            /**
             * Create a file upload
             */
            create: (args) => {
                return this.request({
                    path: api_endpoints_1.createFileUpload.path(),
                    method: api_endpoints_1.createFileUpload.method,
                    query: (0, utils_1.pick)(args, api_endpoints_1.createFileUpload.queryParams),
                    body: (0, utils_1.pick)(args, api_endpoints_1.createFileUpload.bodyParams),
                    auth: args === null || args === void 0 ? void 0 : args.auth,
                });
            },
            /**
             * Retrieve a file upload
             */
            retrieve: (args) => {
                return this.request({
                    path: api_endpoints_1.getFileUpload.path(args),
                    method: api_endpoints_1.getFileUpload.method,
                    query: (0, utils_1.pick)(args, api_endpoints_1.getFileUpload.queryParams),
                    auth: args === null || args === void 0 ? void 0 : args.auth,
                });
            },
            /**
             * List file uploads
             */
            list: (args) => {
                return this.request({
                    path: api_endpoints_1.listFileUploads.path(),
                    method: api_endpoints_1.listFileUploads.method,
                    query: (0, utils_1.pick)(args, api_endpoints_1.listFileUploads.queryParams),
                    auth: args === null || args === void 0 ? void 0 : args.auth,
                });
            },
            /**
             * Send a file upload
             *
             * Requires a `file_upload_id`, obtained from the `id` of the Create File
             * Upload API response.
             *
             * The `file` parameter contains the raw file contents or Blob/File object
             * under `file.data`, and an optional `file.filename` string.
             *
             * Supply a stringified `part_number` parameter when using file uploads
             * in multi-part mode.
             *
             * This endpoint sends HTTP multipart/form-data instead of JSON parameters.
             */
            send: (args) => {
                return this.request({
                    path: api_endpoints_1.sendFileUpload.path(args),
                    method: api_endpoints_1.sendFileUpload.method,
                    query: (0, utils_1.pick)(args, api_endpoints_1.sendFileUpload.queryParams),
                    formDataParams: (0, utils_1.pick)(args, api_endpoints_1.sendFileUpload.formDataParams),
                    auth: args === null || args === void 0 ? void 0 : args.auth,
                });
            },
            /**
             * Complete a file upload
             */
            complete: (args) => {
                return this.request({
                    path: api_endpoints_1.completeFileUpload.path(args),
                    method: api_endpoints_1.completeFileUpload.method,
                    query: (0, utils_1.pick)(args, api_endpoints_1.completeFileUpload.queryParams),
                    auth: args === null || args === void 0 ? void 0 : args.auth,
                });
            },
        };
        /**
         * Search
         */
        this.search = (args) => {
            return this.request({
                path: api_endpoints_1.search.path(),
                method: api_endpoints_1.search.method,
                query: (0, utils_1.pick)(args, api_endpoints_1.search.queryParams),
                body: (0, utils_1.pick)(args, api_endpoints_1.search.bodyParams),
                auth: args === null || args === void 0 ? void 0 : args.auth,
            });
        };
        this.oauth = {
            /**
             * Get token
             */
            token: (args) => {
                return this.request({
                    path: api_endpoints_1.oauthToken.path(),
                    method: api_endpoints_1.oauthToken.method,
                    query: (0, utils_1.pick)(args, api_endpoints_1.oauthToken.queryParams),
                    body: (0, utils_1.pick)(args, api_endpoints_1.oauthToken.bodyParams),
                    auth: {
                        client_id: args.client_id,
                        client_secret: args.client_secret,
                    },
                });
            },
            /**
             * Introspect token
             */
            introspect: (args) => {
                return this.request({
                    path: api_endpoints_1.oauthIntrospect.path(),
                    method: api_endpoints_1.oauthIntrospect.method,
                    query: (0, utils_1.pick)(args, api_endpoints_1.oauthIntrospect.queryParams),
                    body: (0, utils_1.pick)(args, api_endpoints_1.oauthIntrospect.bodyParams),
                    auth: {
                        client_id: args.client_id,
                        client_secret: args.client_secret,
                    },
                });
            },
            /**
             * Revoke token
             */
            revoke: (args) => {
                return this.request({
                    path: api_endpoints_1.oauthRevoke.path(),
                    method: api_endpoints_1.oauthRevoke.method,
                    query: (0, utils_1.pick)(args, api_endpoints_1.oauthRevoke.queryParams),
                    body: (0, utils_1.pick)(args, api_endpoints_1.oauthRevoke.bodyParams),
                    auth: {
                        client_id: args.client_id,
                        client_secret: args.client_secret,
                    },
                });
            },
        };
        __classPrivateFieldSet(this, _Client_auth, options === null || options === void 0 ? void 0 : options.auth, "f");
        __classPrivateFieldSet(this, _Client_logLevel, (_a = options === null || options === void 0 ? void 0 : options.logLevel) !== null && _a !== void 0 ? _a : logging_1.LogLevel.WARN, "f");
        __classPrivateFieldSet(this, _Client_logger, (_b = options === null || options === void 0 ? void 0 : options.logger) !== null && _b !== void 0 ? _b : (0, logging_1.makeConsoleLogger)(package_json_1.name), "f");
        __classPrivateFieldSet(this, _Client_prefixUrl, `${(_c = options === null || options === void 0 ? void 0 : options.baseUrl) !== null && _c !== void 0 ? _c : "https://api.notion.com"}/v1/`, "f");
        __classPrivateFieldSet(this, _Client_timeoutMs, (_d = options === null || options === void 0 ? void 0 : options.timeoutMs) !== null && _d !== void 0 ? _d : 60000, "f");
        __classPrivateFieldSet(this, _Client_notionVersion, (_e = options === null || options === void 0 ? void 0 : options.notionVersion) !== null && _e !== void 0 ? _e : Client.defaultNotionVersion, "f");
        __classPrivateFieldSet(this, _Client_fetch, (_f = options === null || options === void 0 ? void 0 : options.fetch) !== null && _f !== void 0 ? _f : fetch, "f");
        __classPrivateFieldSet(this, _Client_agent, options === null || options === void 0 ? void 0 : options.agent, "f");
        __classPrivateFieldSet(this, _Client_userAgent, `notionhq-client/${package_json_1.version}`, "f");
    }
    /**
     * Sends a request.
     */
    async request(args) {
        const { path, method, query, body, formDataParams, auth } = args;
        this.log(logging_1.LogLevel.INFO, "request start", { method, path });
        // If the body is empty, don't send the body in the HTTP request
        const bodyAsJsonString = !body || Object.entries(body).length === 0
            ? undefined
            : JSON.stringify(body);
        const url = new URL(`${__classPrivateFieldGet(this, _Client_prefixUrl, "f")}${path}`);
        if (query) {
            for (const [key, value] of Object.entries(query)) {
                if (value !== undefined) {
                    if (Array.isArray(value)) {
                        for (const val of value) {
                            url.searchParams.append(key, decodeURIComponent(val));
                        }
                    }
                    else {
                        url.searchParams.append(key, String(value));
                    }
                }
            }
        }
        // Allow both client ID / client secret based auth as well as token based auth.
        let authorizationHeader;
        if (typeof auth === "object") {
            // Client ID and secret based auth is **ONLY** supported when using the
            // `/oauth/token` endpoint. If this is the case, handle formatting the
            // authorization header as required by `Basic` auth.
            const unencodedCredential = `${auth.client_id}:${auth.client_secret}`;
            const encodedCredential = Buffer.from(unencodedCredential).toString("base64");
            authorizationHeader = { authorization: `Basic ${encodedCredential}` };
        }
        else {
            // Otherwise format authorization header as `Bearer` token auth.
            authorizationHeader = this.authAsHeaders(auth);
        }
        const headers = {
            ...authorizationHeader,
            "Notion-Version": __classPrivateFieldGet(this, _Client_notionVersion, "f"),
            "user-agent": __classPrivateFieldGet(this, _Client_userAgent, "f"),
        };
        if (bodyAsJsonString !== undefined) {
            headers["content-type"] = "application/json";
        }
        let formData;
        if (formDataParams) {
            delete headers["content-type"];
            formData = new FormData();
            for (const [key, value] of Object.entries(formDataParams)) {
                if (typeof value === "string") {
                    formData.append(key, value);
                }
                else if (typeof value === "object") {
                    formData.append(key, typeof value.data === "object"
                        ? value.data
                        : new Blob([value.data]), value.filename);
                }
            }
        }
        try {
            const response = await errors_1.RequestTimeoutError.rejectAfterTimeout(__classPrivateFieldGet(this, _Client_fetch, "f").call(this, url.toString(), {
                method: method.toUpperCase(),
                headers,
                body: bodyAsJsonString !== null && bodyAsJsonString !== void 0 ? bodyAsJsonString : formData,
                agent: __classPrivateFieldGet(this, _Client_agent, "f"),
            }), __classPrivateFieldGet(this, _Client_timeoutMs, "f"));
            const responseText = await response.text();
            if (!response.ok) {
                throw (0, errors_1.buildRequestError)(response, responseText);
            }
            const responseJson = JSON.parse(responseText);
            this.log(logging_1.LogLevel.INFO, "request success", { method, path });
            return responseJson;
        }
        catch (error) {
            if (!(0, errors_1.isNotionClientError)(error)) {
                throw error;
            }
            // Log the error if it's one of our known error types
            this.log(logging_1.LogLevel.WARN, "request fail", {
                code: error.code,
                message: error.message,
            });
            if ((0, errors_1.isHTTPResponseError)(error)) {
                // The response body may contain sensitive information so it is logged separately at the DEBUG level
                this.log(logging_1.LogLevel.DEBUG, "failed response body", {
                    body: error.body,
                });
            }
            throw error;
        }
    }
    /**
     * Emits a log message to the console.
     *
     * @param level The level for this message
     * @param args Arguments to send to the console
     */
    log(level, message, extraInfo) {
        if ((0, logging_1.logLevelSeverity)(level) >= (0, logging_1.logLevelSeverity)(__classPrivateFieldGet(this, _Client_logLevel, "f"))) {
            __classPrivateFieldGet(this, _Client_logger, "f").call(this, level, message, extraInfo);
        }
    }
    /**
     * Transforms an API key or access token into a headers object suitable for an HTTP request.
     *
     * This method uses the instance's value as the default when the input is undefined. If neither are defined, it returns
     * an empty object
     *
     * @param auth API key or access token
     * @returns headers key-value object
     */
    authAsHeaders(auth) {
        const headers = {};
        const authHeaderValue = auth !== null && auth !== void 0 ? auth : __classPrivateFieldGet(this, _Client_auth, "f");
        if (authHeaderValue !== undefined) {
            headers["authorization"] = `Bearer ${authHeaderValue}`;
        }
        return headers;
    }
}
exports.default = Client;
_Client_auth = new WeakMap(), _Client_logLevel = new WeakMap(), _Client_logger = new WeakMap(), _Client_prefixUrl = new WeakMap(), _Client_timeoutMs = new WeakMap(), _Client_notionVersion = new WeakMap(), _Client_fetch = new WeakMap(), _Client_agent = new WeakMap(), _Client_userAgent = new WeakMap();
Client.defaultNotionVersion = "2022-06-28";
//# sourceMappingURL=Client.js.map