@proofkit/fmodata
Version:
FileMaker OData API client
181 lines (180 loc) • 6.36 kB
JavaScript
var __defProp = Object.defineProperty;
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
import createClient, { TimeoutError, AbortError, NetworkError, RetryLimitError, CircuitOpenError } from "@fetchkit/ffetch";
import { SchemaLockedError, ODataError, HTTPError } from "../errors.js";
import { Database } from "./database.js";
class FMServerConnection {
constructor(config) {
__publicField(this, "fetchClient");
__publicField(this, "serverUrl");
__publicField(this, "auth");
__publicField(this, "useEntityIds", false);
this.fetchClient = createClient({
retries: 0,
...config.fetchClientOptions
});
const url = new URL(config.serverUrl);
if (url.protocol !== "https:") {
url.protocol = "https:";
}
url.pathname = url.pathname.replace(/\/+$/, "");
this.serverUrl = url.toString().replace(/\/+$/, "");
this.auth = config.auth;
}
/**
* @internal
* Sets whether to use FileMaker entity IDs (FMFID/FMTID) in requests
*/
_setUseEntityIds(useEntityIds) {
this.useEntityIds = useEntityIds;
}
/**
* @internal
* Gets whether to use FileMaker entity IDs (FMFID/FMTID) in requests
*/
_getUseEntityIds() {
return this.useEntityIds;
}
/**
* @internal
* Gets the base URL for OData requests
*/
_getBaseUrl() {
return `${this.serverUrl}${"apiKey" in this.auth ? `/otto` : ""}/fmi/odata/v4`;
}
/**
* @internal
*/
async _makeRequest(url, options) {
var _a, _b, _c, _d, _e, _f;
const baseUrl = `${this.serverUrl}${"apiKey" in this.auth ? `/otto` : ""}/fmi/odata/v4`;
const fullUrl = baseUrl + url;
const useEntityIds = (options == null ? void 0 : options.useEntityIds) ?? this.useEntityIds;
const headers = {
Authorization: "apiKey" in this.auth ? `Bearer ${this.auth.apiKey}` : `Basic ${btoa(`${this.auth.username}:${this.auth.password}`)}`,
"Content-Type": "application/json",
Accept: "application/json",
...useEntityIds ? { Prefer: "fmodata.entity-ids" } : {},
...(options == null ? void 0 : options.headers) || {}
};
const fetchHandler = options == null ? void 0 : options.fetchHandler;
const {
headers: _headers,
fetchHandler: _fetchHandler,
...restOptions
} = options || {};
const clientToUse = fetchHandler ? createClient({ retries: 0, fetchHandler }) : this.fetchClient;
try {
const finalOptions = {
...restOptions,
headers
};
const resp = url.includes("/$batch") ? await fetch(fullUrl, {
method: finalOptions.method,
headers: finalOptions.headers,
body: finalOptions.body
}) : await clientToUse(fullUrl, finalOptions);
if (!resp.ok) {
let errorBody;
try {
if ((_a = resp.headers.get("content-type")) == null ? void 0 : _a.includes("application/json")) {
errorBody = await resp.json();
}
} catch {
}
if (errorBody == null ? void 0 : errorBody.error) {
const errorCode = errorBody.error.code;
const errorMessage = errorBody.error.message || resp.statusText;
if (errorCode === "303" || errorCode === 303) {
return {
data: void 0,
error: new SchemaLockedError(
fullUrl,
errorMessage,
errorBody.error
)
};
}
return {
data: void 0,
error: new ODataError(
fullUrl,
errorMessage,
errorCode,
errorBody.error
)
};
}
return {
data: void 0,
error: new HTTPError(
fullUrl,
resp.status,
resp.statusText,
errorBody
)
};
}
const affectedRows = resp.headers.get("fmodata.affected_rows");
if (affectedRows !== null) {
return { data: parseInt(affectedRows, 10), error: void 0 };
}
if (resp.status === 204) {
const locationHeader = ((_c = (_b = resp.headers) == null ? void 0 : _b.get) == null ? void 0 : _c.call(_b, "Location")) || ((_e = (_d = resp.headers) == null ? void 0 : _d.get) == null ? void 0 : _e.call(_d, "location"));
if (locationHeader) {
return { data: { _location: locationHeader }, error: void 0 };
}
return { data: 0, error: void 0 };
}
if ((_f = resp.headers.get("content-type")) == null ? void 0 : _f.includes("application/json")) {
const data = await resp.json();
if (data.error) {
const errorCode = data.error.code;
const errorMessage = data.error.message || "Unknown OData error";
if (errorCode === "303" || errorCode === 303) {
return {
data: void 0,
error: new SchemaLockedError(fullUrl, errorMessage, data.error)
};
}
return {
data: void 0,
error: new ODataError(fullUrl, errorMessage, errorCode, data.error)
};
}
return { data, error: void 0 };
}
return { data: await resp.text(), error: void 0 };
} catch (err) {
if (err instanceof TimeoutError || err instanceof AbortError || err instanceof NetworkError || err instanceof RetryLimitError || err instanceof CircuitOpenError) {
return { data: void 0, error: err };
}
return {
data: void 0,
error: new NetworkError(fullUrl, err)
};
}
}
database(name, config) {
return new Database(name, this, config);
}
/**
* Lists all available databases from the FileMaker OData service.
* @returns Promise resolving to an array of database names
*/
async listDatabaseNames() {
const result = await this._makeRequest("/");
if (result.error) {
throw result.error;
}
if (result.data.value && Array.isArray(result.data.value)) {
return result.data.value.map((item) => item.name);
}
return [];
}
}
export {
FMServerConnection
};
//# sourceMappingURL=filemaker-odata.js.map