@entityauth/auth-client
Version:
TypeScript/JavaScript client SDK for Entity Auth - complete authentication infrastructure with organizations, sessions, and real-time security
510 lines (509 loc) • 16.8 kB
JavaScript
;
var __defProp = Object.defineProperty;
var __defProps = Object.defineProperties;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __propIsEnum = Object.prototype.propertyIsEnumerable;
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
var __spreadValues = (a, b) => {
for (var prop in b || (b = {}))
if (__hasOwnProp.call(b, prop))
__defNormalProp(a, prop, b[prop]);
if (__getOwnPropSymbols)
for (var prop of __getOwnPropSymbols(b)) {
if (__propIsEnum.call(b, prop))
__defNormalProp(a, prop, b[prop]);
}
return a;
};
var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
var __objRest = (source, exclude) => {
var target = {};
for (var prop in source)
if (__hasOwnProp.call(source, prop) && exclude.indexOf(prop) < 0)
target[prop] = source[prop];
if (source != null && __getOwnPropSymbols)
for (var prop of __getOwnPropSymbols(source)) {
if (exclude.indexOf(prop) < 0 && __propIsEnum.call(source, prop))
target[prop] = source[prop];
}
return target;
};
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
// src/index.ts
var index_exports = {};
__export(index_exports, {
EntityAuthClient: () => EntityAuthClient,
SDK: () => SDK,
init: () => init
});
module.exports = __toCommonJS(index_exports);
var TRAILING_SLASH_REGEX = /\/$/;
var HTTP_UNAUTHORIZED = 401;
var PROCESS_ENV = typeof process !== "undefined" && process.env ? process.env : void 0;
var ENV_BASE_URL = PROCESS_ENV ? PROCESS_ENV.NEXT_PUBLIC_ENTITY_AUTH_URL || PROCESS_ENV.ENTITY_AUTH_URL || PROCESS_ENV.NEXT_PUBLIC_EA_BASE_URL || PROCESS_ENV.EA_BASE_URL || PROCESS_ENV.NEXT_PUBLIC_EA_URL || "" : "";
var DEFAULT_BASE_URL = ENV_BASE_URL || "https://entity-auth.com";
var SDK_CONFIG = {
baseURL: DEFAULT_BASE_URL,
tenantId: null
};
function init(options) {
if (!(options == null ? void 0 : options.tenantId)) {
throw new Error(
"EntityAuth.init({ tenantId }) is required. Never ask users for tenantId in forms; configure it once from env."
);
}
SDK_CONFIG.tenantId = options.tenantId;
const base = options.baseURL || resolveBaseURL();
if (base) {
SDK_CONFIG.baseURL = base.replace(TRAILING_SLASH_REGEX, "");
}
}
function resolveTenantId() {
const tid = SDK_CONFIG.tenantId || (PROCESS_ENV ? PROCESS_ENV.NEXT_PUBLIC_ENTITY_AUTH_TENANT_ID || PROCESS_ENV.ENTITY_AUTH_TENANT_ID || PROCESS_ENV.NEXT_PUBLIC_EA_TENANT_ID || PROCESS_ENV.EA_TENANT_ID || "" : "");
if (!tid) {
throw new Error(
"Missing tenantId. Call EntityAuth.init({ tenantId }) or set NEXT_PUBLIC_ENTITY_AUTH_TENANT_ID."
);
}
return tid;
}
function resolveBaseURL() {
const base = SDK_CONFIG.baseURL || ENV_BASE_URL;
return base ? base.replace(TRAILING_SLASH_REGEX, "") : DEFAULT_BASE_URL;
}
function getDeprecatedTenantId(value) {
if (!value || typeof value !== "object") return null;
if (!("tenantId" in value)) return null;
const tid = value.tenantId;
return typeof tid === "string" && tid.length > 0 ? tid : null;
}
function join(baseURL, path) {
const url = baseURL || DEFAULT_BASE_URL;
const base = url.replace(TRAILING_SLASH_REGEX, "");
const p = path.startsWith("/") ? path : `/${path}`;
return `${base}${p}`;
}
async function request(path, init2) {
const url = join(init2 == null ? void 0 : init2.baseURL, path);
const _a = init2 || {}, { baseURL: _ignored } = _a, rest = __objRest(_a, ["baseURL"]);
const res = await fetch(url, __spreadProps(__spreadValues({}, rest), { credentials: "include" }));
if (!res.ok) {
const text = await res.text();
throw new Error(text || `HTTP ${res.status}`);
}
return res.json();
}
var EntityAuthClient = class {
constructor(options) {
this.accessToken = null;
this.tokenListeners = /* @__PURE__ */ new Set();
this.refreshInFlight = null;
const configuredBase = (options == null ? void 0 : options.baseURL) || resolveBaseURL();
this.baseURL = configuredBase.replace(TRAILING_SLASH_REGEX, "");
}
// Token management
getAccessToken() {
return this.accessToken;
}
onTokenChange(listener) {
this.tokenListeners.add(listener);
return () => {
this.tokenListeners.delete(listener);
};
}
setAccessToken(token) {
this.accessToken = token;
for (const l of this.tokenListeners) {
try {
l(token);
} catch (e) {
}
}
}
// Allow external flows (e.g. passkey verify) to apply a new access token
applyAccessToken(token) {
this.setAccessToken(token || null);
}
// Auth-aware fetch with auto-refresh via cookie (web)
async fetch(input, init2) {
const url = join(this.baseURL, input);
const headers = new Headers((init2 == null ? void 0 : init2.headers) || {});
const token = this.getAccessToken();
if (token) {
headers.set("authorization", `Bearer ${token}`);
}
let res = await globalThis.fetch(url, __spreadProps(__spreadValues({}, init2), { headers }));
if (res.status === HTTP_UNAUTHORIZED) {
try {
await this.refreshSingleFlight();
} catch (e) {
this.setAccessToken(null);
return res;
}
const retryHeaders = new Headers((init2 == null ? void 0 : init2.headers) || {});
const newToken = this.getAccessToken();
if (newToken) {
retryHeaders.set("authorization", `Bearer ${newToken}`);
}
res = await globalThis.fetch(url, __spreadProps(__spreadValues({}, init2), { headers: retryHeaders }));
}
return res;
}
refreshSingleFlight() {
if (!this.refreshInFlight) {
this.refreshInFlight = this.refresh().then((data) => {
const access = data == null ? void 0 : data.accessToken;
if (!access) {
throw new Error("No access token after refresh");
}
return access;
}).finally(() => {
this.refreshInFlight = null;
});
}
return this.refreshInFlight;
}
register(input) {
if (getDeprecatedTenantId(input)) {
console.warn(
"[EntityAuth] Passing tenantId to register() is deprecated. Configure it once via init({ tenantId })."
);
}
const tenantId = input.tenantId || resolveTenantId();
return request("/api/auth/register", {
baseURL: this.baseURL,
method: "POST",
headers: { "content-type": "application/json" },
body: JSON.stringify({ email: input.email, password: input.password, tenantId })
});
}
login(input) {
const headers = {
"content-type": "application/json"
};
return request("/api/auth/login", {
baseURL: this.baseURL,
method: "POST",
headers,
body: JSON.stringify({
email: input.email,
password: input.password,
// Back-compat: accept input.tenantId if present but prefer configured tenant
tenantId: (() => {
const deprecated = getDeprecatedTenantId(input);
if (deprecated) {
console.warn(
"[EntityAuth] Passing tenantId to login() is deprecated. Configure it once via init({ tenantId })."
);
return deprecated;
}
return resolveTenantId();
})()
})
}).then((out) => {
const access = out.accessToken;
if (access) {
this.setAccessToken(access);
} else {
this.setAccessToken(null);
}
return out;
});
}
refresh(headerRefreshToken) {
return request("/api/auth/refresh", {
baseURL: this.baseURL,
method: "POST",
headers: headerRefreshToken ? { "x-refresh-token": headerRefreshToken } : void 0
}).then((out) => {
const access = out.accessToken;
if (access) {
this.setAccessToken(access);
}
return out;
});
}
logout() {
return request("/api/auth/logout", {
baseURL: this.baseURL,
method: "POST"
}).finally(() => {
this.setAccessToken(null);
});
}
// OpenAPI metadata discovery
getOpenAPI() {
return request("/api/openapi", { baseURL: this.baseURL, method: "GET" });
}
// GraphQL helper
async graphql(query, variables) {
var _a;
const res = await this.fetch("/api/graphql", {
method: "POST",
headers: { "content-type": "application/json" },
body: JSON.stringify({ query, variables })
});
const json = await res.json();
if (json.errors) {
throw new Error("GraphQL error");
}
return (_a = json.data) != null ? _a : {};
}
createOrg(input) {
var _a;
const headers = new Headers({ "content-type": "application/json" });
return this.fetch("/api/org/create", {
method: "POST",
headers,
body: JSON.stringify({
tenantId: (_a = input.tenantId) != null ? _a : resolveTenantId(),
name: input.name,
slug: input.slug,
ownerId: input.ownerId
})
}).then((r) => r.json());
}
addMember(input) {
const headers = new Headers({ "content-type": "application/json" });
return this.fetch("/api/org/add-member", {
method: "POST",
headers,
body: JSON.stringify(input)
}).then((r) => r.json());
}
switchOrg(input) {
const headers = new Headers({ "content-type": "application/json" });
return this.fetch("/api/org/switch", {
method: "POST",
headers,
body: JSON.stringify(input)
}).then((r) => r.json());
}
getUserOrganizations() {
return this.fetch("/api/org/list", {
method: "GET"
}).then((r) => r.json());
}
getCurrentTenantId() {
return this.fetch("/api/user/me", {
method: "GET"
}).then((r) => r.json()).then((data) => data.tenantId);
}
// Users
setUsername(input) {
const headers = new Headers({ "content-type": "application/json" });
return this.fetch("/api/user/username/set", {
method: "POST",
headers,
body: JSON.stringify(input)
}).then((r) => r.json());
}
checkUsername(input) {
const query = new URLSearchParams({ value: input.value }).toString();
return this.fetch(`/api/user/username/check?${query}`, {
method: "GET"
}).then((r) => r.json());
}
getUserMe() {
return this.fetch("/api/user/me", { method: "GET" }).then((r) => r.json());
}
userByUsername(input) {
const query = new URLSearchParams({ username: input.username }).toString();
return this.fetch(`/api/user/by-username?${query}`, { method: "GET" }).then(
(r) => r.json()
);
}
userByEmail(input) {
const headers = new Headers({ "content-type": "application/json" });
return this.fetch("/api/user/by-email", {
method: "POST",
headers,
body: JSON.stringify(input)
}).then((r) => r.json());
}
// Misc
getConvexConfig() {
return this.fetch("/api/convex", { method: "GET" }).then((r) => r.json());
}
openapi() {
return request("/api/openapi", { baseURL: this.baseURL, method: "GET" });
}
// Sessions
getCurrentSession() {
return this.fetch("/api/session/current", { method: "GET" }).then(
(r) => r.json()
);
}
listSessions(options) {
const params = new URLSearchParams();
if (options == null ? void 0 : options.includeRevoked) params.set("includeRevoked", "true");
const path = `/api/session/list${params.toString() ? `?${params.toString()}` : ""}`;
return this.fetch(path, { method: "GET" }).then((r) => r.json());
}
getSessionById(input) {
const params = new URLSearchParams({ id: input.id }).toString();
return this.fetch(`/api/session/by-id?${params}`, { method: "GET" }).then((r) => r.json());
}
revokeSession(input) {
const headers = new Headers({ "content-type": "application/json" });
return this.fetch("/api/session/revoke", {
method: "POST",
headers,
body: JSON.stringify(input)
}).then((r) => r.json());
}
revokeSessionsByUser(input) {
const headers = new Headers({ "content-type": "application/json" });
return this.fetch("/api/session/revoke-by-user", {
method: "POST",
headers,
body: JSON.stringify(input)
}).then((r) => r.json());
}
};
var SDK = {
// Back-compat static helpers defaulting to same-origin
register(input) {
const tenantId = (() => {
const deprecated = getDeprecatedTenantId(input);
if (deprecated) {
console.warn(
"[EntityAuth] Passing tenantId to SDK.register() is deprecated. Configure it once via init({ tenantId })."
);
return deprecated;
}
return resolveTenantId();
})();
if (getDeprecatedTenantId(input)) {
console.warn("[EntityAuth] tenantId on SDK.register() is deprecated.");
}
return request("/api/auth/register", {
method: "POST",
headers: { "content-type": "application/json" },
body: JSON.stringify({ email: input.email, password: input.password, tenantId })
});
},
login(input) {
const headers = {
"content-type": "application/json"
};
return request("/api/auth/login", {
method: "POST",
headers,
body: JSON.stringify({
email: input.email,
password: input.password,
tenantId: (() => {
const deprecated = getDeprecatedTenantId(input);
if (deprecated) {
console.warn(
"[EntityAuth] Passing tenantId to SDK.login() is deprecated. Configure it once via init({ tenantId })."
);
return deprecated;
}
return resolveTenantId();
})()
})
});
},
refresh(headerRefreshToken) {
return request("/api/auth/refresh", {
method: "POST",
headers: headerRefreshToken ? { "x-refresh-token": headerRefreshToken } : void 0
});
},
logout() {
return request("/api/auth/logout", { method: "POST" });
},
createOrg(input) {
var _a;
return request("/api/org/create", {
method: "POST",
headers: { "content-type": "application/json" },
body: JSON.stringify({
tenantId: (_a = input.tenantId) != null ? _a : resolveTenantId(),
name: input.name,
slug: input.slug,
ownerId: input.ownerId
})
});
},
addMember(input) {
return request("/api/org/add-member", {
method: "POST",
headers: { "content-type": "application/json" },
body: JSON.stringify(input)
});
},
switchOrg(input) {
return request("/api/org/switch", {
method: "POST",
headers: { "content-type": "application/json" },
body: JSON.stringify(input)
});
},
getUserOrganizations() {
return request("/api/org/list", {
method: "GET"
});
},
getCurrentTenantId() {
return request("/api/user/me", {
method: "GET"
}).then((data) => data.tenantId);
},
openapi() {
return request("/api/openapi", { method: "GET" });
},
// Sessions (static helpers)
getCurrentSession() {
return request("/api/session/current", { method: "GET" });
},
listSessions(options) {
const params = new URLSearchParams();
if (options == null ? void 0 : options.includeRevoked) params.set("includeRevoked", "true");
const path = `/api/session/list${params.toString() ? `?${params.toString()}` : ""}`;
return request(path, { method: "GET" });
},
getSessionById(input) {
const params = new URLSearchParams({ id: input.id }).toString();
return request(`/api/session/by-id?${params}`, { method: "GET" });
},
revokeSession(input) {
return request("/api/session/revoke", {
method: "POST",
headers: { "content-type": "application/json" },
body: JSON.stringify(input)
});
},
revokeSessionsByUser(input) {
return request("/api/session/revoke-by-user", {
method: "POST",
headers: { "content-type": "application/json" },
body: JSON.stringify(input)
});
}
};
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
EntityAuthClient,
SDK,
init
});
//# sourceMappingURL=index.cjs.map