@nextplus/js-sdk
Version:
A TypeScript SDK for interacting with the NextPlus API, automatically generated from OpenAPI specifications.
224 lines (222 loc) • 7.79 kB
JavaScript
import {
sdk_exports
} from "./chunk-TU3VOZVD.js";
import {
UserModelService
} from "./chunk-VAV5HKXV.js";
import {
__publicField,
createClient
} from "./chunk-FXXZNC42.js";
// src/index.ts
import debug from "debug";
var log = debug("nextplus:sdk");
var accessToken = {
token: null,
created: null,
ttl: 0
};
var setAccessToken = (token, created = /* @__PURE__ */ new Date(), ttl = 1209600) => {
accessToken.token = token;
accessToken.created = created;
accessToken.ttl = ttl;
};
var getAccessToken = () => {
return accessToken;
};
var isTokenValid = () => {
if (!accessToken.token || !accessToken.created) {
return false;
}
const now = /* @__PURE__ */ new Date();
const tokenAge = now.getTime() - accessToken.created.getTime();
const tokenTtlMs = accessToken.ttl * 1e3;
return tokenAge < tokenTtlMs;
};
var NextPlusSDK = class {
constructor(options) {
__publicField(this, "client");
__publicField(this, "credentials");
__publicField(this, "returnType", "data");
if (!options.email && !options.username) {
throw new Error("Either email or username must be provided");
}
if (options.email && options.username) {
throw new Error("Provide either email or username, not both");
}
this.credentials = {
email: options.email,
username: options.username,
password: options.password
};
this.returnType = options.returnType || "data";
if (options.baseURL.endsWith("/")) {
options.baseURL = options.baseURL.slice(0, -1);
}
if (!options.baseURL.endsWith("/api")) {
options.baseURL = options.baseURL + "/api";
}
this.client = createClient({
baseUrl: options.baseURL
});
this.client.interceptors.request.use(this.authRequestInterceptor.bind(this));
this.createServiceProxies();
}
// Wrap plain developer inputs into the right container (body/query)
// and stringify complex query params when required by LoopBack (filter/where)
normalizeOptions(methodName, rawOptions) {
const options = rawOptions && typeof rawOptions === "object" ? { ...rawOptions } : {};
const method = methodName.toString().toLowerCase();
const isFind = method.includes("find") && !method.includes("count");
const isCount = method.includes("count");
const shouldUseBody = /(create|update|replace|patch|login|upsert)/i.test(methodName.toString());
const topLevelKeys = ["filter", "where", "fields", "order", "limit", "offset", "include"];
const hasTopLevelFilterBits = topLevelKeys.some((k) => Object.prototype.hasOwnProperty.call(options, k));
if (isFind) {
options.query = options.query || {};
if (options.filter && typeof options.filter === "object") {
options.query.filter = JSON.stringify(options.filter);
delete options.filter;
} else if (hasTopLevelFilterBits) {
const filterObject = {};
if (options.where !== void 0) filterObject.where = options.where;
if (options.fields !== void 0) filterObject.fields = options.fields;
if (options.order !== void 0) filterObject.order = options.order;
if (options.limit !== void 0) filterObject.limit = options.limit;
if (options.offset !== void 0) filterObject.offset = options.offset;
if (options.include !== void 0) filterObject.include = options.include;
if (Object.keys(filterObject).length > 0) {
options.query.filter = typeof filterObject === "string" ? filterObject : JSON.stringify(filterObject);
}
topLevelKeys.forEach((k) => delete options[k]);
}
} else if (isCount) {
options.query = options.query || {};
if (options.where !== void 0) {
const whereVal = options.where;
options.query.where = typeof whereVal === "string" ? whereVal : JSON.stringify(whereVal);
delete options.where;
}
} else if (shouldUseBody) {
if (options.body === void 0) {
const bodyCandidate = { ...options };
delete bodyCandidate.client;
delete bodyCandidate.query;
delete bodyCandidate.path;
if (Object.keys(bodyCandidate).length > 0) {
options.body = bodyCandidate;
Object.keys(options).forEach((k) => {
if (!["body", "client", "query", "path"].includes(k)) delete options[k];
});
}
}
}
if (options.query && typeof options.query === "object") {
Object.keys(options.query).forEach((key) => {
const val = options.query[key];
if (val && (Array.isArray(val) || typeof val === "object")) {
options.query[key] = JSON.stringify(val);
}
});
}
return options;
}
async authRequestInterceptor(request, _options) {
if (request.url.includes("/UserModels/login")) {
return request;
}
await this.ensureValidToken();
const token = getAccessToken();
if (token.token) {
request.headers.set("Authorization", token.token);
}
return request;
}
async ensureValidToken() {
if (!isTokenValid()) {
log("Token expired or missing, refreshing...");
await this.login();
}
}
async login() {
try {
const loginBody = {
password: this.credentials.password,
forceLogin: true
};
if (this.credentials.email) {
loginBody.email = this.credentials.email;
} else if (this.credentials.username) {
loginBody.username = this.credentials.username;
}
const response = await UserModelService.login({
client: this.client,
body: loginBody
});
if (response.data) {
const token = response.data.id;
const ttl = response.data.ttl || 1209600;
if (token) {
setAccessToken(token, /* @__PURE__ */ new Date(), ttl);
log("Login successful, access token set");
return true;
}
}
throw new Error("Login failed - no token received");
} catch (error) {
console.error("Login failed:", error);
throw error;
}
}
createServiceProxies() {
const serviceNames = Object.keys(sdk_exports).filter(
(key) => key.endsWith("Service") && typeof sdk_exports[key] === "function"
);
serviceNames.forEach((serviceName) => {
const ServiceClass = sdk_exports[serviceName];
this[serviceName] = this.createServiceProxy(ServiceClass);
});
}
createServiceProxy(ServiceClass) {
const self = this;
return new Proxy(ServiceClass, {
get(target, prop) {
if (typeof target[prop] === "function") {
return async function(...args) {
if (!args[0]) args[0] = {};
args[0] = self.normalizeOptions(String(prop), args[0]);
if (!args[0].client) args[0].client = self.client;
const result = await target[prop].apply(target, args);
if (self.returnType === "data" && result && typeof result === "object" && "data" in result) {
return result.data;
}
if (self.returnType === "data" && result && typeof result === "object" && "error" in result) {
const error = new Error(result.error.error.message || result.error.error.code || "Unknown error");
if (result.error.error.details) {
error.details = result.error.error.details;
}
throw error;
}
return result;
};
}
return target[prop];
}
});
}
// Manual login method (optional, for explicit control)
async manualLogin() {
return this.login();
}
};
var configure = (options) => {
return new NextPlusSDK(options);
};
var createSDK = (options) => {
return new NextPlusSDK(options);
};
export {
NextPlusSDK,
configure,
createSDK
};