@convo-lang/convo-lang
Version:
The language of AI
114 lines • 4.12 kB
JavaScript
import { BehaviorSubject } from "rxjs";
import { ConvoEmailOtpSignRequestSchema, ConvoEmailPasswordSignRequestSchema, ConvoSignInJwtSchema } from "./convo-db-auth-schemas.js";
import { ConvoDbPermissionBoundary } from "./ConvoDbPermissionBoundary.js";
const localStorageKey = 'ConvoDbAuthJwt::';
/**
* An auth helper class. Auth is not directly handled by ConvoDbAuth, it relies on stored database
* function for auth operations.
*/
export class ConvoDbAuthManager {
get jwtSubject() { return this._jwt; }
get jwt() { return this._jwt.value; }
constructor(db) {
this._jwt = new BehaviorSubject(null);
this.maxCachedBoundaries = 200;
this.boundaryCacheDropRatio = 0.3;
this.boundaryCacheCount = 0;
this.boundaryCache = {};
this.db = db;
try {
if (globalThis.localStorage) {
const key = localStorageKey + this.db.dbName;
const json = globalThis.localStorage.getItem(key);
if (json) {
const v = JSON.parse(json);
if (v) {
this._jwt.next(v);
}
}
}
}
catch (ex) {
console.error('Failed to load JWT from local storage');
}
}
async signOutAsync() {
this.setJwt(null);
}
async signInEmailOtpAsync(request) {
const r = await this.db.callFunctionWithSchemaAsync(ConvoEmailOtpSignRequestSchema, ConvoSignInJwtSchema, '/bin/sign-in-email-otp', request);
if (!r.success) {
return r;
}
this.setJwt(r.result);
return {
success: true,
result: r.result,
};
}
async signInEmailPasswordAsync(request) {
const r = await this.db.callFunctionWithSchemaAsync(ConvoEmailPasswordSignRequestSchema, ConvoSignInJwtSchema, '/bin/sign-in-email-password', request);
if (!r.success) {
return r;
}
this.setJwt(r.result);
return {
success: true,
result: r.result,
};
}
setJwt(jwt) {
this._jwt.next(jwt);
try {
if (globalThis.localStorage) {
const key = localStorageKey + this.db.dbName;
globalThis.localStorage.setItem(key, JSON.stringify(jwt));
}
}
catch (ex) {
console.error('Failed to store JWT in local storage');
}
}
/**
* Create a proxy db with all public methods permissions scoped to the given `permissionFrom`
* argument.
* @param permissionFrom The node path where to scope permissions from
* @param byPass If true no proxy will be created and the db of the auth manager will be returned.
*/
createBoundary(permissionFrom, byPass = false) {
if (byPass) {
return this.db;
}
const cached = this.boundaryCache[permissionFrom];
if (cached) {
return cached;
}
return this._createBoundary(permissionFrom);
}
_createBoundary(permissionFrom) {
const boundary = new ConvoDbPermissionBoundary({
proxiedDb: this.db,
auth: this,
identityPath: permissionFrom,
});
this.boundaryCache[permissionFrom] = boundary;
this.boundaryCacheCount++;
if (this.boundaryCacheCount > this.maxCachedBoundaries) {
const all = Object.values(this.boundaryCache);
all.sort((a, b) => a.lastUsed - b.lastUsed);
const end = Math.floor(this.maxCachedBoundaries * this.boundaryCacheDropRatio);
for (let i = 0; i < end; i++) {
const b = all[i];
if (!b || b === boundary) {
continue;
}
if (this.boundaryCache[b.identityPath]) {
delete this.boundaryCache[b.identityPath];
this.boundaryCacheCount--;
}
}
}
return boundary;
}
}
//# sourceMappingURL=ConvoDbAuthManager.js.map