assistant-cloud
Version:
Cloud integration for assistant-ui
168 lines (167 loc) • 5.72 kB
JavaScript
import { CloudResponseError, readCloudRecord, readCloudString } from "./cloudResponse.js";
//#region src/AssistantCloudAuthStrategy.ts
const getJwtExpiry = (jwt) => {
try {
const bodyPart = jwt.split(".")[1];
if (!bodyPart) throw new Error("Invalid JWT format");
let base64 = bodyPart.replace(/-/g, "+").replace(/_/g, "/");
while (base64.length % 4 !== 0) base64 += "=";
const payload = atob(base64);
const exp = JSON.parse(payload).exp;
if (!exp || typeof exp !== "number") throw new Error("JWT does not contain a valid \"exp\" field");
return exp * 1e3;
} catch (error) {
throw new Error(`Unable to determine the token expiry: ${error}`);
}
};
const readNonEmptyCloudString = (value, field) => {
const result = readCloudString(value, field);
if (result.length === 0) throw new CloudResponseError(`Invalid Assistant Cloud response for "${field}": expected a non-empty string`);
return result;
};
const readRefreshTokenResponse = (value, field) => {
const refreshToken = readCloudRecord(value, field);
return {
token: readNonEmptyCloudString(refreshToken.token, `${field}.token`),
expires_at: readNonEmptyCloudString(refreshToken.expires_at, `${field}.expires_at`)
};
};
const readAuthTokenResponse = async (response, field) => {
let value;
try {
value = await response.json();
} catch {
throw new CloudResponseError(`Invalid Assistant Cloud response for "${field}": expected valid JSON`);
}
const data = readCloudRecord(value, field);
return {
data,
accessToken: readNonEmptyCloudString(data.access_token, `${field}.access_token`)
};
};
var AssistantCloudJWTAuthStrategy = class {
strategy = "jwt";
cachedToken = null;
tokenExpiry = null;
tokenRequest = null;
#authTokenCallback;
constructor(authTokenCallback) {
this.#authTokenCallback = authTokenCallback;
}
async getAuthHeaders() {
const currentTime = Date.now();
if (this.cachedToken && this.tokenExpiry && this.tokenExpiry - currentTime > 30 * 1e3) return { Authorization: `Bearer ${this.cachedToken}` };
if (!this.tokenRequest) this.tokenRequest = this.fetchAuthHeaders();
const tokenRequest = this.tokenRequest;
try {
return await tokenRequest;
} finally {
if (this.tokenRequest === tokenRequest) this.tokenRequest = null;
}
}
async fetchAuthHeaders() {
const token = await this.#authTokenCallback();
if (!token) return false;
this.cachedToken = token;
this.tokenExpiry = getJwtExpiry(token);
return { Authorization: `Bearer ${token}` };
}
readAuthHeaders(headers) {
const authHeader = headers.get("Authorization");
if (!authHeader) return;
const [scheme, token] = authHeader.split(" ");
if (scheme !== "Bearer" || !token) throw new Error("Invalid auth header received");
this.cachedToken = token;
this.tokenExpiry = getJwtExpiry(token);
}
};
var AssistantCloudAPIKeyAuthStrategy = class {
strategy = "api-key";
#apiKey;
#userId;
#workspaceId;
constructor(apiKey, userId, workspaceId) {
this.#apiKey = apiKey;
this.#userId = userId;
this.#workspaceId = workspaceId;
}
async getAuthHeaders() {
return {
Authorization: `Bearer ${this.#apiKey}`,
"Aui-User-Id": this.#userId,
"Aui-Workspace-Id": this.#workspaceId
};
}
readAuthHeaders() {}
};
const AUI_REFRESH_TOKEN_NAME = "aui:refresh_token";
const getLocalStorage = () => {
if (!("localStorage" in globalThis)) return null;
try {
return globalThis.localStorage;
} catch {
return null;
}
};
const readRefreshToken = () => {
const storage = getLocalStorage();
if (!storage) return void 0;
try {
const value = storage.getItem(AUI_REFRESH_TOKEN_NAME);
return value ? JSON.parse(value) : void 0;
} catch {
return;
}
};
const writeRefreshToken = (refreshToken) => {
const storage = getLocalStorage();
if (!storage) return;
try {
storage.setItem(AUI_REFRESH_TOKEN_NAME, JSON.stringify(refreshToken));
} catch {}
};
const removeRefreshToken = () => {
const storage = getLocalStorage();
if (!storage) return;
try {
storage.removeItem(AUI_REFRESH_TOKEN_NAME);
} catch {}
};
var AssistantCloudAnonymousAuthStrategy = class {
strategy = "anon";
baseUrl;
jwtStrategy;
constructor(baseUrl) {
this.baseUrl = baseUrl;
this.jwtStrategy = new AssistantCloudJWTAuthStrategy(async () => {
const currentTime = Date.now();
const storedRefreshToken = readRefreshToken();
if (storedRefreshToken) if (new Date(storedRefreshToken.expires_at).getTime() - currentTime > 30 * 1e3) {
const response = await fetch(`${this.baseUrl}/v1/auth/tokens/refresh`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ refresh_token: storedRefreshToken.token })
});
if (response.ok) {
const { data, accessToken } = await readAuthTokenResponse(response, "refresh auth token response");
if (data.refresh_token != null) writeRefreshToken(readRefreshTokenResponse(data.refresh_token, "refresh auth token response.refresh_token"));
return accessToken;
}
} else removeRefreshToken();
const response = await fetch(`${this.baseUrl}/v1/auth/tokens/anonymous`, { method: "POST" });
if (!response.ok) return null;
const { data, accessToken } = await readAuthTokenResponse(response, "anonymous auth token response");
writeRefreshToken(readRefreshTokenResponse(data.refresh_token, "anonymous auth token response.refresh_token"));
return accessToken;
});
}
async getAuthHeaders() {
return this.jwtStrategy.getAuthHeaders();
}
readAuthHeaders(headers) {
this.jwtStrategy.readAuthHeaders(headers);
}
};
//#endregion
export { AssistantCloudAPIKeyAuthStrategy, AssistantCloudAnonymousAuthStrategy, AssistantCloudJWTAuthStrategy };
//# sourceMappingURL=AssistantCloudAuthStrategy.js.map