UNPKG

@lokalise/node-api

Version:
1,579 lines (1,519 loc) 64.8 kB
import { readFile } from "node:fs/promises"; //#region src/models/base_model.ts var BaseModel = class { constructor(params) { Object.assign(this, params); } }; //#endregion //#region src/models/branch.ts var Branch = class extends BaseModel {}; //#endregion //#region src/lokalise/pkg.ts /** * Returns the relative path to the package.json file. * Adjust this if your directory structure changes. */ function pkgPath() { return "../../package.json"; } /** * Attempts to read and parse the local package.json file to retrieve the version. * If the file cannot be read or parsed, returns "unknown". * * @returns {Promise<string>} The package version string or "unknown" if unavailable. */ async function getVersion() { try { const data = await readFile(new URL(pkgPath(), import.meta.url)); const pkg = JSON.parse(data.toString()); return String(pkg.version); } catch { return "unknown"; } } //#endregion //#region src/models/api_error.ts /** * Represents an API error with a specific code and optional details. */ var ApiError = class extends Error { /** * The error code representing the type of API error. */ code; /** * Additional details about the error (optional). */ details; /** * Creates an instance of ApiError. * * @param {string} message - The error message. * @param {number} code - The error code. * @param {Record<string, string | number | boolean>} [details] - Additional details about the error. */ constructor(message, code, details) { super(message); this.code = code; if (details) this.details = details; } /** * Returns a string representation of the error, including code and details. * * @returns The formatted error message. */ toString() { let baseMessage = `LokaliseError: ${this.message}`; baseMessage += ` (Code: ${this.code})`; if (this.details) { const formattedDetails = Object.entries(this.details).map(([key, value]) => `${key}: ${value}`).join(", "); baseMessage += ` | Details: ${formattedDetails}`; } return baseMessage; } }; //#endregion //#region src/http_client/base.ts /** * Represents a single API request to the Lokalise API. * Handles URL construction, request initiation, response processing, and error handling. */ var ApiRequest = class ApiRequest { /** * The default base URL for the Lokalise API. */ static urlRoot = "https://api.lokalise.com/api2/"; /** * The resolved response from the API request. */ response; /** * Query and path parameters used to construct the request URL. * This object is modified during URL construction, removing parameters used in path segments. */ params = {}; /** * Constructs a new ApiRequest instance. * @param params - Query and/or path parameters. */ constructor(params) { this.params = { ...params }; } /** * Static async factory method to create an ApiRequest instance with a fully resolved response. * @param uri - The endpoint URI (versioned path expected). * @param method - The HTTP method (GET, POST, PUT, DELETE, etc). * @param body - The request payload, if applicable. * @param params - Query and/or path parameters. * @param clientData - Authentication and configuration data for the request. * @returns A promise that resolves to a fully constructed ApiRequest instance with the `response` set. */ static async create(uri, method, body, params, clientData) { const apiRequest = new ApiRequest(params); apiRequest.response = await apiRequest.createPromise(uri, method, body, clientData); return apiRequest; } /** * Creates the request promise by composing the URL, building headers, and executing the fetch. * @param uri - The endpoint URI. * @param method - The HTTP method. * @param body - The request payload. * @param clientData - Client configuration and auth data. * @returns A promise resolving to an ApiResponse or rejecting with an ApiError. */ async createPromise(uri, method, body, clientData) { const url = this.composeURI(`/${clientData.version}/${uri}`); const prefixUrl = clientData.host ?? ApiRequest.urlRoot; const options = { method, headers: await this.buildHeaders(clientData, method, body), ...method !== "GET" && body ? { body: JSON.stringify(body) } : {} }; const target = new URL(url, prefixUrl); const stringifiedParams = Object.fromEntries(Object.entries(this.params).filter(([, value]) => value !== void 0 && value !== null).map(([key, value]) => [key, String(value)])); target.search = new URLSearchParams(stringifiedParams).toString(); return this.fetchAndHandleResponse(target, options, clientData.requestTimeout); } /** * Executes the fetch request and handles network-level errors. * Applies a request timeout if specified. * @param target - The fully constructed request URL. * @param options - The fetch request options. * @param requestTimeout - Optional timeout in milliseconds. * @returns A promise resolving to an ApiResponse or rejecting with an ApiError. */ async fetchAndHandleResponse(target, options, requestTimeout = 0) { const signal = requestTimeout > 0 ? AbortSignal.timeout(requestTimeout) : void 0; try { const response = await fetch(target, { ...options, ...signal ? { signal } : {} }); return this.processResponse(response); } catch (err) { if (err instanceof Error) { if (err.name === "TimeoutError") return Promise.reject(new ApiError(`Request timed out after ${requestTimeout}ms`, 408, { reason: "timeout" })); return Promise.reject(new ApiError(err.message, 500, { reason: "network or fetch error" })); } return Promise.reject(new ApiError("An unknown error occurred", 500, { reason: String(err) })); } } /** * Processes the fetch response. * Attempts to parse JSON unless the status is 204 (No Content). * @param response - The raw fetch Response object. * @returns A promise resolving to an ApiResponse if successful, or rejecting with ApiError otherwise. */ async processResponse(response) { let responseJSON = null; try { if (response.status !== 204) responseJSON = await response.json(); } catch (error) { return Promise.reject(new ApiError(error.message, response.status, { statusText: response.statusText, reason: "JSON parsing error" })); } if (response.ok) return { json: responseJSON, headers: response.headers }; return Promise.reject(this.getErrorFromResp(responseJSON)); } /** * Derives an ApiError instance from the response JSON, which may follow various patterns. * @param respJson - The parsed JSON response from the server. * @returns An ApiError representing the server error. */ getErrorFromResp(respJson) { if (!respJson || typeof respJson !== "object") return new ApiError("An unknown error occurred", 500, { reason: "unexpected response format" }); const errorObj = respJson; if (typeof errorObj.message === "string" && typeof errorObj.statusCode === "number" && typeof errorObj.error === "string") return new ApiError(errorObj.message, errorObj.statusCode, { reason: errorObj.error }); if (errorObj.error && typeof errorObj.error === "object") { const { message = "Unknown error", code = 500, details } = errorObj.error; return new ApiError(String(message), typeof code === "number" ? code : 500, typeof details === "object" && details !== null ? details : { reason: "server error without details" }); } if (typeof errorObj.message === "string" && (typeof errorObj.code === "number" || typeof errorObj.errorCode === "number")) { const statusCode = typeof errorObj.code === "number" ? errorObj.code : errorObj.errorCode; const rawDetails = errorObj.details; const safeDetails = typeof rawDetails === "object" && rawDetails !== null ? rawDetails : { reason: "server error without details" }; return new ApiError(errorObj.message, statusCode, safeDetails); } return new ApiError("An unknown error occurred", 500, { reason: "unhandled error format", data: JSON.stringify(respJson) }); } /** * Builds the request headers, including authentication, compression, and JSON headers as needed. * @param clientData - Client configuration and auth data. * @param method - The HTTP method. * @param body - The request payload. * @returns A promise resolving to the constructed Headers. */ async buildHeaders(clientData, method, body) { const userAgent = clientData.userAgent?.trim() || `node-lokalise-api/${await getVersion()}`; const headers = new Headers({ Accept: "application/json", "User-Agent": userAgent }); headers.append(clientData.authHeader, clientData.tokenType.length > 0 ? `${clientData.tokenType} ${clientData.token}` : clientData.token); if (clientData.enableCompression) headers.append("Accept-Encoding", "gzip,deflate"); if (method !== "GET" && body) headers.append("Content-Type", "application/json"); return headers; } /** * Composes the final URI by replacing placeholders of the form `/{!:{paramName}}` * with the corresponding parameter values. * @param rawUri - The raw URI template. * @returns The final composed URI string. * @throws Error if a required parameter is missing. */ composeURI(rawUri) { const uri = rawUri.replace(/\{(!?):(\w+)\}/g, this.mapUriParams()); return uri.endsWith("/") ? uri.slice(0, -1) : uri; } /** * Returns a function that maps URI parameters from placeholders. * @returns A function used as a replacement callback in `composeURI`. * @throws Error if a required parameter is missing. */ mapUriParams() { return (_substring, isMandatory, paramName) => { if (this.params[paramName] != null) { const paramValue = String(this.params[paramName]); delete this.params[paramName]; return paramValue; } if (isMandatory === "!") throw new Error(`Missing required parameter: ${paramName}`); return ""; }; } }; //#endregion //#region src/models/paginated_result.ts var PaginatedResult = class { totalResults; totalPages; resultsPerPage; currentPage; responseTooBig; items; constructor(items, headers) { this.totalResults = this.safeParseInt(headers.get("x-pagination-total-count")); this.totalPages = this.safeParseInt(headers.get("x-pagination-page-count")); this.resultsPerPage = this.safeParseInt(headers.get("x-pagination-limit")); this.currentPage = this.safeParseInt(headers.get("x-pagination-page")); this.responseTooBig = headers.has("x-response-too-big"); this.items = items; } hasNextPage() { return this.currentPage > 0 && this.currentPage < this.totalPages; } hasPrevPage() { return this.currentPage > 1; } isLastPage() { return !this.hasNextPage(); } isFirstPage() { return !this.hasPrevPage(); } nextPage() { if (this.isLastPage()) return this.currentPage; return this.currentPage + 1; } prevPage() { if (this.isFirstPage()) return this.currentPage; return this.currentPage - 1; } safeParseInt(str) { if (!str || Number.isNaN(Number(str))) return 0; return Number.parseInt(str, 10); } }; //#endregion //#region src/models/cursor_paginated_result.ts var CursorPaginatedResult = class extends PaginatedResult { nextCursor; constructor(items, headers) { super(items, headers); this.nextCursor = headers.get("x-pagination-next-cursor"); } hasNextCursor() { return this.nextCursor !== null; } }; //#endregion //#region src/collections/base_collection.ts /** * An abstract base class that provides generic CRUD (Create, Read, Update, Delete) operations * and handling for pagination, cursor pagination, and bulk operations. Other "collection" classes * should extend this class and provide specific implementations for resource endpoints. * * Expected usage: * - Subclasses define `rootElementName` and/or `rootElementNameSingular` to indicate the JSON fields * that contain the desired data. * - `elementClass` and optionally `secondaryElementClass` should be overridden to map raw JSON * objects to strongly typed model instances. * - `endpoint` and `prefixURI` should be set as static properties in subclasses to specify resource paths. */ var BaseCollection = class { /** * Client data containing authentication and configuration details. * Provided by a `BaseClient` or similar client instance. */ clientData; /** * Static endpoint property that subclasses can define to indicate the API endpoint * for this collection. If not set, ensure `prefixURI` or `uri` parameters are passed. */ static endpoint; /** * Static prefixURI property that subclasses can define to indicate a base path. * If `uri` is not passed explicitly, this prefix is used to construct the request URL. */ static prefixURI; /** * Constructs a new BaseCollection instance. * @param clientData - Client data for making authenticated requests. */ constructor(clientData) { this.clientData = clientData; } /** * Getter that must be overridden by subclasses to return the root element name * for array-based JSON responses. * @throws Error if not defined by the subclass. */ get rootElementName() { throw new Error("rootElementName is not defined. Subclasses must override `rootElementName`."); } /** * Getter that may be overridden by subclasses to return the root element name * for single-item JSON responses. * @throws Error if not defined by the subclass. */ get rootElementNameSingular() { throw new Error("rootElementNameSingular is not defined. Subclasses must override `rootElementNameSingular`."); } /** * Getter that may be overridden by subclasses if a secondary model type is returned. * By default, this throws an error. If needed, override it in the subclass. */ get secondaryElementClass() { throw new Error("Secondary elements are not supported by this collection. Override `secondaryElementClass` if needed."); } /** * Getter that must be overridden if `secondaryElementClass` is used. * Returns the JSON property name for the secondary element. * @throws Error if not defined by the subclass that uses secondary elements. */ get secondaryElementNameSingular() { throw new Error("secondaryElementNameSingular is not defined. Subclasses must override this if secondary elements are used."); } /** * Perform a GET request that expects a list of items. * @param params Optional query or request parameters. * @returns A promise resolving to either a paginated result or an array of ElementType. */ doList(params) { return this.createPromise("GET", params, this.populateArrayFromJson, null); } /** * Perform a GET request that expects a cursor-paginated list of items. * @param params Optional query or request parameters. * @returns A promise resolving to a CursorPaginatedResult of ElementType. */ doListCursor(params) { return this.createPromise("GET", params, this.populateArrayFromJsonCursor, null); } /** * Perform a GET request to retrieve a single item by its ID. * @param id The ID of the item to retrieve. * @param params Optional query or request parameters. * @returns A promise resolving to a single ElementType instance. */ doGet(id, params = {}) { return this.createPromise("GET", { ...params, id }, this.populateObjectFromJsonRoot, null); } /** * Perform a DELETE request to remove a single item by its ID. * @param id The ID of the item to delete. * @param params Optional query or request parameters. * @returns A promise resolving to JSON representing the deletion result. */ doDelete(id, params = {}) { return this.createPromise("DELETE", { ...params, id }, this.returnBareJSON, null); } /** * Perform a POST request to create a new resource. * @param body The object or array of objects to send in the request body. * @param params Optional query or request parameters. * @param resolveFn Optional custom resolve handler to parse the response. * @returns A promise resolving to an ElementType or SecondaryType instance. */ doCreate(body, params = {}, resolveFn = this.populateObjectFromJson) { return this.createPromise("POST", params, resolveFn, body); } /** * Perform a POST request to create multiple resources at once. * @param body The object or array of objects to send in the request body. * @param params Optional query or request parameters. * @param resolveFn Optional custom resolve handler to parse the response array. * @returns A promise resolving to an array of ElementType. */ doCreateArray(body, params, resolveFn = this.populateArray) { return this.createPromise("POST", params, resolveFn, body); } /** * Perform an UPDATE (PUT/PATCH) request to modify an existing resource by its ID. * @param id The ID of the item to update. * @param body The updated fields to send in the request body. * @param params Optional query or request parameters. * @param resolveFn Optional custom resolve handler to parse the response object. * @param method The HTTP method to use, typically PUT or PATCH. * @returns A promise resolving to the updated ElementType instance. */ doUpdate(id, body, params, resolveFn = this.populateObjectFromJsonRoot, method = "PUT") { return this.createPromise(method, { ...params, id }, resolveFn, body); } /** * Parse a JSON response that contains a single item under a known root element name. * @param json The raw JSON object returned by the API. * @param headers The response headers. * @returns The parsed ElementType instance. * @throws Error if the expected root element name is missing. */ populateObjectFromJsonRoot(json, headers) { let jsonData = json; const rootElementName = this.rootElementNameSingular; if (rootElementName) { const picked = jsonData[rootElementName]; if (!this.isRecord(picked)) throw new Error(`Missing property '${rootElementName}' in JSON object`); jsonData = picked; } return this.populateObjectFromJson(jsonData, headers); } /** * Parse a JSON response that contains a secondary item under a known secondary root element name. * @param json The raw JSON object returned by the API. * @param headers The response headers. * @returns The parsed SecondaryType instance. * @throws Error if the expected secondary element name is missing. */ populateSecondaryObjectFromJsonRoot(json, headers) { const root = this.secondaryElementNameSingular; const itemJson = json[root]; if (typeof itemJson !== "object" || itemJson === null) throw new Error(`Missing expected secondary property '${root}' in JSON response.`); return this.populateObjectFromJson(itemJson, headers, true); } /** * Parse a JSON response that contains a secondary item. * @param json The raw JSON object returned by the API. * @param headers The response headers. * @returns The parsed SecondaryType instance. */ populateSecondaryObjectFromJson(json, headers) { return this.populateObjectFromJson(json, headers, true); } /** * Parse a JSON response that contains an array of items along with bulk result details. * @param json The raw JSON object returned by the API. * @param headers The response headers. * @returns A BulkResult object containing items and potential errors. * @throws Error if the expected root element is missing or not an array. */ populateArrayFromJsonBulk(json, headers) { const root = this.rootElementName; const jsonArray = json[root]; if (!Array.isArray(jsonArray)) throw new Error(`Expected an array under '${root}' but received: ${typeof jsonArray}`); const items = jsonArray.map((obj) => this.populateObjectFromJson(obj, headers)); return { errors: Array.isArray(json.errors) ? json.errors : [], items }; } /** * Parse a JSON response that contains an array of items. * If pagination headers are detected, returns a PaginatedResult. * Otherwise, returns a plain array of ElementType. * @param json The raw JSON object returned by the API. * @param headers The response headers. */ populateArrayFromJson(json, headers) { const array = this.populateArray(json, headers); return this.isPaginated(headers) ? new PaginatedResult(array, headers) : array; } /** * Parse a JSON response that contains an array of items. * This method returns a plain array and does not consider pagination. * @param json The raw JSON object returned by the API. * @param headers The response headers. */ populateArray(json, headers) { const root = this.rootElementName; const jsonArray = json[root]; if (!Array.isArray(jsonArray)) throw new Error(`Expected an array under '${root}' but received: ${typeof jsonArray}`); return jsonArray.map((obj) => this.populateObjectFromJson(obj, headers)); } /** * Parse a JSON response that contains a cursor-paginated array of items. * @param json The raw JSON object returned by the API. * @param headers The response headers. */ populateArrayFromJsonCursor(json, headers) { const root = this.rootElementName; const jsonArray = json[root]; if (!Array.isArray(jsonArray)) throw new Error(`Expected an array under '${root}' for cursor pagination but received: ${typeof jsonArray}`); return new CursorPaginatedResult(jsonArray.map((obj) => this.populateObjectFromJson(obj, headers)), headers); } /** * Parse a JSON object into either an ElementType or a SecondaryType instance. * @param json The raw JSON object returned by the API. * @param _headers The response headers (if needed). * @param secondary If true, use the secondaryElementClass instead of elementClass. */ populateObjectFromJson(json, _headers, secondary = false) { return new (secondary ? this.secondaryElementClass : this.elementClass)(json); } /** * Return the raw JSON as-is. * @param json The raw JSON object or array returned by the API. * @param _headers The response headers (if needed). */ returnBareJSON(json, _headers) { return json; } /** * Convert a single object into an array if it's not already an array. * @param raw_body The raw request body. */ objToArray(raw_body) { return Array.isArray(raw_body) ? raw_body : [raw_body]; } /** * Create a Promise that sends an HTTP request and resolves with a parsed response. * @param method The HTTP method (GET, POST, PUT, DELETE, etc.). * @param params Query or request parameters. * @param resolveFn A function to resolve and parse the JSON response. * @param body The request body, if applicable. * @param uri An explicit URI to use for the request. If not provided, prefixURI is used. */ async createPromise(method, params, resolveFn, body, uri = null) { const request = await this.prepareRequest(method, body, params, uri); return resolveFn.call(this, request.response.json, request.response.headers); } /** * Prepare the API request by creating a new ApiRequest instance using the static async factory method. * @param method The HTTP method. * @param body The request body. * @param params The request parameters. * @param uri An explicit URI for the request or null. */ async prepareRequest(method, body, params, uri) { return await ApiRequest.create(this.getUri(uri), method, body, params, this.clientData); } /** * Determine the URI for the request. If uri is not provided, use prefixURI. * @param uri An explicit URI or null. * @throws Error if no URI or prefixURI is provided. */ getUri(uri) { const childClass = this.constructor; const resolvedUri = uri ?? childClass.prefixURI; if (!resolvedUri) throw new Error("No URI or prefixURI provided. Ensure the subclass defines a static prefixURI or pass a URI explicitly."); return resolvedUri; } isResponseTooBig(headers) { return headers.has("x-response-too-big"); } /** * Determine if the response headers indicate pagination. * @param headers The response headers. */ isPaginated(headers) { return headers.has("x-pagination-total-count") && headers.has("x-pagination-page"); } /** * Runtime type guard for narrowing `unknown` to `Record<string, unknown>`. * * @param value The value to test. */ isRecord(value) { return value !== null && typeof value === "object" && !Array.isArray(value); } }; //#endregion //#region src/collections/branches.ts var Branches = class extends BaseCollection { static prefixURI = "projects/{!:project_id}/branches/{:id}"; get elementClass() { return Branch; } get rootElementName() { return "branches"; } get rootElementNameSingular() { return "branch"; } list(request_params) { return this.doList(request_params); } create(branch_params, request_params) { return this.doCreate(branch_params, request_params, this.populateObjectFromJsonRoot); } get(branch_id, request_params) { return this.doGet(branch_id, request_params); } update(branch_id, branch_params, request_params) { return this.doUpdate(branch_id, branch_params, request_params); } delete(branch_id, request_params) { return this.doDelete(branch_id, request_params); } merge(branch_id, request_params, body = {}) { const params = { ...request_params, id: branch_id }; return this.createPromise("POST", params, this.returnBareJSON, body, "projects/{!:project_id}/branches/{:id}/merge"); } }; //#endregion //#region src/models/comment.ts var Comment = class extends BaseModel {}; //#endregion //#region src/collections/comments.ts var Comments = class extends BaseCollection { static prefixURI = "projects/{!:project_id}/keys/{!:key_id}/comments/{:id}"; get elementClass() { return Comment; } get rootElementName() { return "comments"; } get rootElementNameSingular() { return "comment"; } list(request_params) { return this.doList(request_params); } create(comment_params, request_params) { const body = { comments: this.objToArray(comment_params) }; return this.doCreateArray(body, request_params); } get(comment_id, request_params) { return this.doGet(comment_id, request_params); } delete(comment_id, request_params) { return this.doDelete(comment_id, request_params); } list_project_comments(params) { return this.createPromise("GET", params, this.populateArrayFromJson, null, "projects/{!:project_id}/comments"); } }; //#endregion //#region src/models/contributor.ts var Contributor = class extends BaseModel {}; //#endregion //#region src/collections/contributors.ts var Contributors = class extends BaseCollection { static prefixURI = "projects/{!:project_id}/contributors/{:id}"; get elementClass() { return Contributor; } get rootElementName() { return "contributors"; } get rootElementNameSingular() { return "contributor"; } list(request_params) { return this.doList(request_params); } create(contributor_params, request_params) { const body = { contributors: this.objToArray(contributor_params) }; return this.doCreateArray(body, request_params); } get(contributor_id, request_params) { return this.doGet(contributor_id, request_params); } me(request_params) { return this.doGet("me", request_params); } update(contributor_id, contributor_params, request_params) { return this.doUpdate(contributor_id, contributor_params, request_params); } delete(contributor_id, request_params) { return this.doDelete(contributor_id, request_params); } }; //#endregion //#region src/models/file.ts var File = class extends BaseModel {}; //#endregion //#region src/models/queued_process.ts var QueuedProcess = class extends BaseModel {}; //#endregion //#region src/utils/logger.ts /** * Emits a warning to the console unless `silent` is true. * * @param silent - If true, suppresses the log output. * @param args - The items to log, passed to `console.warn`. */ function warn(silent, ...args) { if (silent) return; console.warn(...args); } //#endregion //#region src/collections/files.ts var Files = class extends BaseCollection { static prefixURI = "projects/{!:project_id}/files/{:id}"; get elementClass() { return File; } get rootElementName() { return "files"; } get secondaryElementClass() { return QueuedProcess; } get secondaryElementNameSingular() { return "process"; } returnBareJSON(json, headers) { if (this.isResponseTooBig(headers)) warn(this.clientData.silent, "\x1B[33m\x1B[1mWarning:\x1B[0m Project too big for sync export. Please use our async export lokaliseApi.files().async_download() method."); return { ...super.returnBareJSON(json, headers), responseTooBig: this.isResponseTooBig(headers) }; } list(request_params) { return this.doList(request_params); } upload(project_id, upload) { return this.createPromise("POST", { project_id }, this.populateSecondaryObjectFromJsonRoot, upload, "projects/{!:project_id}/files/upload"); } download(project_id, download) { return this.createPromise("POST", { project_id }, this.returnBareJSON, download, "projects/{!:project_id}/files/download"); } async_download(project_id, download) { return this.createPromise("POST", { project_id }, this.populateSecondaryObjectFromJson, download, "projects/{!:project_id}/files/async-download"); } delete(file_id, request_params) { return this.doDelete(file_id, request_params); } }; //#endregion //#region src/models/glossary_term.ts var GlossaryTerm = class extends BaseModel {}; //#endregion //#region src/collections/glossary_terms.ts var GlossaryTerms = class extends BaseCollection { static prefixURI = "projects/{!:project_id}/glossary-terms/{:id}"; get elementClass() { return GlossaryTerm; } get rootElementName() { return "data"; } get rootElementNameSingular() { return "data"; } get(term_id, request_params) { return this.doGet(term_id, request_params); } list(request_params) { return this.doListCursor(request_params); } create(term_params, request_params) { return this.createPromise("POST", request_params, this.populateArrayFromJsonBulk, term_params); } update(term_params, request_params) { return this.createPromise("PUT", request_params, this.populateArrayFromJsonBulk, term_params, "projects/{!:project_id}/glossary-terms"); } delete(term_ids, request_params) { const keys = { terms: term_ids }; return this.createPromise("DELETE", request_params, this.populateFromBulkDelete, keys, "projects/{!:project_id}/glossary-terms"); } populateFromBulkDelete(json, _headers) { return json.data; } }; //#endregion //#region src/models/jwt.ts var Jwt$1 = class extends BaseModel {}; //#endregion //#region src/collections/jwt.ts var Jwt = class extends BaseCollection { static prefixURI = "projects/{!:project_id}/tokens"; get elementClass() { return Jwt$1; } create(project_id, body = { service: "ota" }) { const request_params = { project_id }; return this.doCreate(body, request_params, this.populateObjectFromJson); } }; //#endregion //#region src/models/key.ts var Key = class extends BaseModel {}; //#endregion //#region src/collections/keys.ts var Keys = class extends BaseCollection { static prefixURI = "projects/{!:project_id}/keys/{:id}"; get elementClass() { return Key; } get rootElementName() { return "keys"; } get rootElementNameSingular() { return "key"; } list(request_params) { return this.doListCursor(request_params); } create(key_params, request_params) { return this.createPromise("POST", request_params, this.populateArrayFromJsonBulk, key_params); } get(key_id, request_params) { return this.doGet(key_id, request_params); } update(key_id, key_params, request_params) { return this.doUpdate(key_id, key_params, request_params); } delete(key_id, request_params) { return this.doDelete(key_id, request_params); } bulk_update(key_params, request_params) { return this.createPromise("PUT", request_params, this.populateArrayFromJsonBulk, key_params, "projects/{!:project_id}/keys"); } bulk_delete(key_ids, request_params) { const keys = { keys: key_ids }; return this.createPromise("DELETE", request_params, this.returnBareJSON, keys, "projects/{!:project_id}/keys"); } }; //#endregion //#region src/models/language.ts var Language = class extends BaseModel {}; //#endregion //#region src/collections/languages.ts var Languages = class extends BaseCollection { static prefixURI = "projects/{!:project_id}/languages/{:id}"; get elementClass() { return Language; } get rootElementName() { return "languages"; } get rootElementNameSingular() { return "language"; } system_languages(params = {}) { return this.createPromise("GET", params, this.populateArrayFromJson, null, "system/languages"); } list(request_params) { return this.doList(request_params); } create(raw_body, request_params) { const body = { languages: this.objToArray(raw_body) }; return this.createPromise("POST", request_params, this.populateArrayFromJsonBulk, body); } get(lang_id, request_params) { return this.doGet(lang_id, request_params); } update(lang_id, lang_params, request_params) { return this.doUpdate(lang_id, lang_params, request_params); } delete(lang_id, request_params) { return super.doDelete(lang_id, request_params); } }; //#endregion //#region src/models/order.ts var Order = class extends BaseModel {}; //#endregion //#region src/collections/orders.ts var Orders = class extends BaseCollection { static prefixURI = "teams/{!:team_id}/orders/{:id}"; get elementClass() { return Order; } get rootElementName() { return "orders"; } get rootElementNameSingular() { return null; } list(request_params) { return this.doList(request_params); } create(order_params, request_params) { return this.doCreate(order_params, request_params, this.populateObjectFromJsonRoot); } get(order_id, request_params) { return this.doGet(order_id, request_params); } }; //#endregion //#region src/models/payment_card.ts var PaymentCard = class extends BaseModel {}; //#endregion //#region src/collections/payment_cards.ts var PaymentCards = class extends BaseCollection { static prefixURI = "payment_cards/{:id}"; get elementClass() { return PaymentCard; } get rootElementName() { return "payment_cards"; } get rootElementNameSingular() { return "payment_card"; } list(request_params = {}) { return this.doList(request_params); } create(card_params) { return this.doCreate(card_params); } get(card_id) { return this.doGet(card_id); } delete(card_id) { return this.doDelete(card_id); } }; //#endregion //#region src/models/permission_template.ts var PermissionTemplate = class extends BaseModel {}; //#endregion //#region src/collections/permission_templates.ts var PermissionTemplates = class extends BaseCollection { static prefixURI = "teams/{!:team_id}/roles"; get elementClass() { return PermissionTemplate; } get rootElementName() { return "roles"; } list(request_params) { return this.doList(request_params); } }; //#endregion //#region src/models/project.ts var Project = class extends BaseModel {}; //#endregion //#region src/collections/projects.ts var Projects = class extends BaseCollection { static prefixURI = "projects/{:id}"; get elementClass() { return Project; } get rootElementName() { return "projects"; } get rootElementNameSingular() { return null; } list(request_params = {}) { return this.doList(request_params); } create(project_params) { return this.doCreate(project_params); } get(project_id) { return this.doGet(project_id); } update(project_id, project_params) { return this.doUpdate(project_id, project_params, {}, this.populateObjectFromJson); } delete(project_id) { return this.doDelete(project_id); } empty(project_id) { return this.createPromise("PUT", { project_id }, this.returnBareJSON, null, "projects/{!:project_id}/empty"); } }; //#endregion //#region src/collections/queued_processes.ts var QueuedProcesses = class extends BaseCollection { static prefixURI = "projects/{!:project_id}/processes/{:id}"; get elementClass() { return QueuedProcess; } get rootElementName() { return "processes"; } get rootElementNameSingular() { return "process"; } list(request_params) { return this.doList(request_params); } get(process_id, request_params) { return this.doGet(process_id, request_params); } }; //#endregion //#region src/models/screenshot.ts var Screenshot = class extends BaseModel {}; //#endregion //#region src/collections/screenshots.ts var Screenshots = class extends BaseCollection { static prefixURI = "projects/{!:project_id}/screenshots/{:id}"; get elementClass() { return Screenshot; } get rootElementName() { return "screenshots"; } get rootElementNameSingular() { return "screenshot"; } list(request_params) { return this.doList(request_params); } create(raw_body, request_params) { const body = { screenshots: this.objToArray(raw_body) }; return this.createPromise("POST", request_params, this.populateArrayFromJsonBulk, body); } get(screnshot_id, request_params) { return this.doGet(screnshot_id, request_params); } update(screenshot_id, screenshot_params, request_params) { return this.doUpdate(screenshot_id, screenshot_params, request_params); } delete(screenshot_id, request_params) { return this.doDelete(screenshot_id, request_params); } }; //#endregion //#region src/models/segment.ts var Segment = class extends BaseModel {}; //#endregion //#region src/collections/segments.ts var Segments = class extends BaseCollection { static prefixURI = "projects/{!:project_id}/keys/{!:key_id}/segments/{!:language_iso}/{:id}"; get elementClass() { return Segment; } get rootElementName() { return "segments"; } get rootElementNameSingular() { return "segment"; } list(request_params) { return this.doList(request_params); } get(segment_number, request_params) { return this.doGet(segment_number, request_params); } update(segment_number, segment_params, request_params) { return this.doUpdate(segment_number, segment_params, request_params); } }; //#endregion //#region src/models/snapshot.ts var Snapshot = class extends BaseModel {}; //#endregion //#region src/collections/snapshots.ts var Snapshots = class extends BaseCollection { static prefixURI = "projects/{!:project_id}/snapshots/{:id}"; get elementClass() { return Snapshot; } get rootElementName() { return "snapshots"; } get rootElementNameSingular() { return "snapshot"; } list(request_params) { return this.doList(request_params); } create(snapshot_params, request_params) { return this.doCreate(snapshot_params, request_params, this.populateObjectFromJsonRoot); } restore(snapshot_id, request_params) { const params = { ...request_params, id: snapshot_id }; return this.createPromise("POST", params, this.returnBareJSON, {}); } delete(snapshot_id, request_params) { return this.doDelete(snapshot_id, request_params); } }; //#endregion //#region src/models/task.ts var Task = class extends BaseModel {}; //#endregion //#region src/collections/tasks.ts var Tasks = class extends BaseCollection { static prefixURI = "projects/{!:project_id}/tasks/{:id}"; get elementClass() { return Task; } get rootElementName() { return "tasks"; } get rootElementNameSingular() { return "task"; } list(request_params) { return this.doList(request_params); } create(task_params, request_params) { return this.doCreate(task_params, request_params, this.populateObjectFromJsonRoot); } get(task_id, request_params) { return this.doGet(task_id, request_params); } update(task_id, task_params, request_params) { return this.doUpdate(task_id, task_params, request_params); } delete(task_id, request_params) { return this.doDelete(task_id, request_params); } }; //#endregion //#region src/models/team_user_billing_details.ts var TeamUserBillingDetails$1 = class extends BaseModel {}; //#endregion //#region src/collections/team_user_billing_details.ts var TeamUserBillingDetails = class extends BaseCollection { static prefixURI = "teams/{!:team_id}/billing_details"; get elementClass() { return TeamUserBillingDetails$1; } get(team_id) { const params = { team_id }; return this.createPromise("GET", params, this.populateObjectFromJson, null); } create(billing_details_params, request_params) { return this.doCreate(billing_details_params, request_params); } update(team_id, billing_details_params) { const params = { team_id }; return this.createPromise("PUT", params, this.populateObjectFromJson, billing_details_params); } }; //#endregion //#region src/models/team_user.ts var TeamUser = class extends BaseModel {}; //#endregion //#region src/collections/team_users.ts var TeamUsers = class extends BaseCollection { static prefixURI = "teams/{!:team_id}/users/{:id}"; get elementClass() { return TeamUser; } get rootElementName() { return "team_users"; } get rootElementNameSingular() { return "team_user"; } list(request_params) { return this.doList(request_params); } get(team_user_id, request_params) { return this.doGet(team_user_id, request_params); } update(team_user_id, team_user_params, request_params) { return this.doUpdate(team_user_id, team_user_params, request_params); } delete(team_user_id, request_params) { return this.doDelete(team_user_id, request_params); } }; //#endregion //#region src/models/team.ts var Team = class extends BaseModel {}; //#endregion //#region src/collections/teams.ts var Teams = class extends BaseCollection { static prefixURI = "teams/{:id}"; get elementClass() { return Team; } get rootElementName() { return "teams"; } get rootElementNameSingular() { return "team"; } list(request_params = {}) { return this.doList(request_params); } get(id) { return this.doGet(id); } }; //#endregion //#region src/models/translation_provider.ts var TranslationProvider = class extends BaseModel {}; //#endregion //#region src/collections/translation_providers.ts var TranslationProviders = class extends BaseCollection { static prefixURI = "teams/{!:team_id}/translation_providers/{:id}"; get elementClass() { return TranslationProvider; } get rootElementName() { return "translation_providers"; } get rootElementNameSingular() { return null; } list(request_params) { return this.doList(request_params); } get(provider_id, request_params) { return this.doGet(provider_id, request_params); } }; //#endregion //#region src/models/translation_status.ts var TranslationStatus = class extends BaseModel {}; //#endregion //#region src/collections/translation_statuses.ts var TranslationStatuses = class extends BaseCollection { static prefixURI = "projects/{!:project_id}/custom_translation_statuses/{:id}"; get elementClass() { return TranslationStatus; } get rootElementName() { return "custom_translation_statuses"; } get rootElementNameSingular() { return "custom_translation_status"; } list(request_params) { return this.doList(request_params); } create(translation_status_params, request_params) { return this.doCreate(translation_status_params, request_params, this.populateObjectFromJsonRoot); } get(translation_status_id, request_params) { return this.doGet(translation_status_id, request_params); } update(translation_status_id, translation_status_params, request_params) { return this.doUpdate(translation_status_id, translation_status_params, request_params); } delete(translation_status_id, request_params) { return this.doDelete(translation_status_id, request_params); } available_colors(request_params) { return this.createPromise("GET", request_params, this.returnBareJSON, {}, "projects/{!:project_id}/custom_translation_statuses/colors"); } }; //#endregion //#region src/models/translation.ts var Translation = class extends BaseModel {}; //#endregion //#region src/collections/translations.ts var Translations = class extends BaseCollection { static prefixURI = "projects/{!:project_id}/translations/{:id}"; get elementClass() { return Translation; } get rootElementName() { return "translations"; } get rootElementNameSingular() { return "translation"; } list(request_params) { return this.doListCursor(request_params); } get(translation_id, request_params) { return this.doGet(translation_id, request_params); } update(translation_id, translation_params, request_params) { return this.doUpdate(translation_id, translation_params, request_params); } }; //#endregion //#region src/models/user_group.ts var UserGroup = class extends BaseModel {}; //#endregion //#region src/collections/user_groups.ts var UserGroups = class extends BaseCollection { static prefixURI = "teams/{!:team_id}/groups/{:id}"; get elementClass() { return UserGroup; } get rootElementName() { return "user_groups"; } get rootElementNameSingular() { return null; } list(request_params) { return this.doList(request_params); } create(user_group_params, request_params) { return this.doCreate(user_group_params, request_params, this.populateGroupFromJsonRoot); } get(user_group_id, request_params) { return this.doGet(user_group_id, request_params); } update(user_group_id, user_group_params, request_params) { return this.doUpdate(user_group_id, user_group_params, request_params, this.populateGroupFromJsonRoot); } delete(user_group_id, request_params) { return this.doDelete(user_group_id, request_params); } add_members_to_group(team_id, group_id, user_ids) { const params = { team_id, group_id }; const body = { users: user_ids }; return this.createPromise("PUT", params, this.populateGroupFromJsonRoot, body, "teams/{!:team_id}/groups/{!:group_id}/members/add"); } remove_members_from_group(team_id, group_id, user_ids) { const params = { team_id, group_id }; const body = { users: user_ids }; return this.createPromise("PUT", params, this.populateGroupFromJsonRoot, body, "teams/{!:team_id}/groups/{!:group_id}/members/remove"); } add_projects_to_group(team_id, group_id, project_ids) { const params = { team_id, group_id }; const body = { projects: project_ids }; return this.createPromise("PUT", params, this.populateGroupFromJsonRoot, body, "teams/{!:team_id}/groups/{!:group_id}/projects/add"); } remove_projects_from_group(team_id, group_id, project_ids) { const params = { team_id, group_id }; const body = { projects: project_ids }; return this.createPromise("PUT", params, this.populateGroupFromJsonRoot, body, "teams/{!:team_id}/groups/{!:group_id}/projects/remove"); } populateGroupFromJsonRoot(json, headers) { const formatted_json = json.group; return this.populateObjectFromJson(formatted_json, headers); } }; //#endregion //#region src/models/webhook.ts var Webhook = class extends BaseModel {}; //#endregion //#region src/collections/webhooks.ts var Webhooks = class extends BaseCollection { static prefixURI = "projects/{!:project_id}/webhooks/{:id}"; get elementClass() { return Webhook; } get rootElementName() { return "webhooks"; } get rootElementNameSingular() { return "webhook"; } list(request_params) { return this.doList(request_params); } create(webhook_params, request_params) { return this.doCreate(webhook_params, request_params, this.populateObjectFromJsonRoot); } get(webhook_id, request_params) { return this.doGet(webhook_id, request_params); } update(webhook_id, webhook_params, request_params) { return this.doUpdate(webhook_id, webhook_params, request_params); } delete(webhook_id, request_params) { return this.doDelete(webhook_id, request_params); } regenerate_secret(webhook_id, request_params) { const params = { ...request_params, id: webhook_id }; return this.createPromise("PATCH", params, this.returnBareJSON, null, "projects/{!:project_id}/webhooks/{:id}/secret/regenerate"); } }; //#endregion //#region src/lokalise/base_client.ts /** * A foundational client class that establishes authentication and configuration data. * Other specialized clients can inherit from this class to leverage the configured * authentication, compression, host, and timeout settings. */ var BaseClient = class { /** * Internal client data including token, token type, host, compression, and timeouts. */ clientData = { token: "", tokenType: "", authHeader: "x-api-token", enableCompression: false, requestTimeout: 0, silent: false }; /** * Constructs a new BaseClient instance. * @param params - Configuration parameters including API key and optional features. * @throws Error if the API key is not provided or is empty. */ constructor({ apiKey, enableCompression = false, silent = false, tokenType = "", host, requestTimeout, userAgent }) { if (typeof apiKey !== "string" || apiKey.trim().length === 0) throw new Error("Instantiation failed: A non-empty API key or JWT must be provided."); this.clientData = { token: apiKey, tokenType: tokenType.trim(), authHeader: "x-api-token", enableCompression, host, requestTimeout: requestTimeout ?? 0, silent, userAgent }; } }; //#endregion //#region src/lokalise/lokalise_api.ts /** * A main entry point for interacting with the Lokalise API. * Provides easy access to various resource collections (Branches, Comments, Projects, etc.) * through dedicated methods. */ var LokaliseApi = class extends BaseClient { /** * Creates a new instance of the LokaliseApi client. * @param params - Configuration parameters including `apiKey` and optional `version`, `host`, etc. */ constructor(params) { super(params); this.clientData.version = params.version ?? "api2"; this.clientData.authHeader = params.header ?? this.clientData.authHeader; } /** * Access Branch-related endpoints. */ branches() { return new Branches(this.clientData); } /** * Access Comment-related endpoints. */ comments() { return new Comments(this.clientData); } /** * Access Contributor-related endpoints. */ contributors() { return new Contributors(this.clientData); } /** * Access File-related endpoints. */ files() { return new Files(this.clientData); } /** * Access Glossary-related endpoints. */ glossaryTerms() { return new GlossaryTerms(this.clientData); } /** * Access JWT-related endpoints. */ jwt() { return new Jwt(this.clientData); } /** * Access Key-related endpoints. */ keys() { return new Keys(this.clientData); } /** * Access Language-related endpo