streambird
Version:
Node.js library for the Streambird API
698 lines (678 loc) • 28.2 kB
JavaScript
;
Object.defineProperty(exports, '__esModule', { value: true });
function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; }
var axios = _interopDefault(require('axios'));
var jose = require('jose');
var version = "1.0.9";
class StreambirdError extends Error {
constructor(code, message) {
let msg = `(${code}):${message}`;
super(msg);
this.code = code;
this.name = "StreambirdError";
}
}
class StreambirdApiError extends StreambirdError {
constructor(errorMessage, statusCode, errorType) {
super(errorMessage);
this.name = "StreambirdApiError";
this.errorMessage = errorMessage;
this.statusCode = statusCode;
this.errorType = errorType;
}
static fromResponse(responseBody) {
const innerErrorData = responseBody instanceof Object ? responseBody : {};
const innerError = innerErrorData instanceof Object ? innerErrorData : {};
const errorType = `${innerError.error_type || "unknown"}`;
const errorMessage = `${innerError.error_message || responseBody}`;
const statusCode = innerError.status_code || 0;
return new StreambirdApiError(errorMessage, statusCode, errorType);
}
isClientError() {
return this.statusCode < 500;
}
}
const snakeCase = (camelCaseString) => camelCaseString.replace(/[A-Z]/g, char => `_${char.toLowerCase()}`);
const camelCase = (snakeCaseString) => snakeCaseString
.replace(/_[0-9]/g, underscoreDigit => underscoreDigit[1])
.replace(/_[a-z]/g, underscoreChar => underscoreChar[1].toUpperCase());
const deepMapObjectKeys = (value, f) => {
if (!(value instanceof Object)) {
return value;
}
else if (Array.isArray(value)) {
return value.map(item => deepMapObjectKeys(item, f));
}
else {
return Object.keys(value).reduce((acc, key) => {
acc[f(key)] = deepMapObjectKeys(value[key], f);
return acc;
}, {});
}
};
const convertObjectToSnakeCase = (requestBody) => {
// Converting to JSON and back first handles things like dates, circular references etc.
requestBody = JSON.parse(JSON.stringify(requestBody));
return deepMapObjectKeys(requestBody, snakeCase);
};
const convertObjectToCamelCase = (responseBody) => deepMapObjectKeys(responseBody, camelCase);
var Method;
(function (Method) {
Method["GET"] = "get";
Method["POST"] = "post";
Method["PUT"] = "put";
Method["DELETE"] = "delete";
})(Method || (Method = {}));
const isJson = (response) => (response.headers["content-type"] || "").includes("application/json");
const convertAxiosErrorToStreambirdError = async (error) => {
if (!error.response) {
return new StreambirdError("axios_convert", error.message || "An unknown error occurred making the request");
}
// Received a 4XX or 5XX response.
const response = error.response;
const data = response.data;
return StreambirdApiError.fromResponse(data);
};
const handleResponse = async (request) => {
try {
const response = await request;
const data = response.data;
return isJson(response) ? convertObjectToCamelCase(data) : data;
}
catch (error) {
throw await convertAxiosErrorToStreambirdError(error);
}
};
class Resource {
constructor(name, axiosInstance) {
this.name = name;
this.axiosInstance = axiosInstance;
}
async request({ method, path = "", body, query }) {
const request = this.axiosInstance({
method,
url: `${this.name}/${path}`,
data: body && convertObjectToSnakeCase(body),
params: query && convertObjectToSnakeCase(query)
});
return handleResponse(request);
}
}
class MagicLinks extends Resource {
constructor(axiosInstance) {
super("auth/magic_links", axiosInstance);
}
async loginOrCreate(loginOrCreateRequest) {
let bodyData = {
'email': loginOrCreateRequest.email
};
if (loginOrCreateRequest.loginRedirectUrl && loginOrCreateRequest.loginRedirectUrl.length > 0) {
bodyData['login_redirect_url'] = loginOrCreateRequest.loginRedirectUrl;
}
if (loginOrCreateRequest.registrationRedirectUrl && loginOrCreateRequest.registrationRedirectUrl.length > 0) {
bodyData['registration_redirect_url'] = loginOrCreateRequest.registrationRedirectUrl;
}
if (loginOrCreateRequest.loginExpiresIn && loginOrCreateRequest.loginExpiresIn > 0) {
bodyData['login_expires_in'] = loginOrCreateRequest.loginExpiresIn;
}
if (loginOrCreateRequest.registrationExpiresIn && loginOrCreateRequest.registrationExpiresIn > 0) {
bodyData['registration_expires_in'] = loginOrCreateRequest.registrationExpiresIn;
}
if (loginOrCreateRequest.deviceFingerprint) {
bodyData['device_fingerprint'] = loginOrCreateRequest.deviceFingerprint;
}
if (loginOrCreateRequest.requiresVerification !== null && loginOrCreateRequest.requiresVerification !== undefined) {
bodyData['requires_verification'] = loginOrCreateRequest.requiresVerification;
}
return this.request({ method: Method.POST, body: bodyData, path: 'email/login_or_create' });
}
async invite(inviteRequest) {
let bodyData = {
'email': inviteRequest.email
};
if (inviteRequest.firstName && inviteRequest.firstName.length > 0) {
bodyData['first_name'] = inviteRequest.firstName;
}
if (inviteRequest.lastName && inviteRequest.lastName.length > 0) {
bodyData['last_name'] = inviteRequest.lastName;
}
if (inviteRequest.middleName && inviteRequest.middleName.length > 0) {
bodyData['middle_name'] = inviteRequest.middleName;
}
if (inviteRequest.inviteRedirectUrl) {
bodyData['invite_redirect_url'] = inviteRequest.inviteRedirectUrl;
}
if (inviteRequest.inviteExpiresIn) {
bodyData['invite_expires_in'] = inviteRequest.inviteExpiresIn;
}
if (inviteRequest.deviceFingerprint) {
bodyData['device_fingerprint'] = inviteRequest.deviceFingerprint;
}
return this.request({ method: Method.POST, body: bodyData, path: 'email/invite' });
}
async create(embeddableRequest) {
let bodyData = {
'user_id': embeddableRequest.userId
};
if (embeddableRequest.expiresIn) {
bodyData['expires_in'] = embeddableRequest.expiresIn;
}
if (embeddableRequest.deviceFingerprint) {
bodyData['device_fingerprint'] = embeddableRequest.deviceFingerprint;
}
return this.request({ method: Method.POST, body: bodyData, path: 'create' });
}
async verify(verifyRequest) {
let bodyData = {
'token': verifyRequest.token
};
if (verifyRequest.sessionToken && verifyRequest.sessionToken.length > 0) {
bodyData['session_token'] = verifyRequest.sessionToken;
}
if (verifyRequest.sessionJwt && verifyRequest.sessionJwt.length > 0) {
bodyData['session_jwt'] = verifyRequest.sessionJwt;
}
if (verifyRequest.sessionExpiresIn) {
bodyData['session_expires_in'] = verifyRequest.sessionExpiresIn;
}
if (verifyRequest.deviceFingerprint) {
bodyData['device_fingerprint'] = verifyRequest.deviceFingerprint;
}
return this.request({ method: Method.POST, body: bodyData, path: 'verify' });
}
}
class OAuth extends Resource {
constructor(axiosInstance) {
super("auth/oauth", axiosInstance);
}
async google(request) {
let params = `public_token=${request.publicToken}`;
if (request.redirect) {
params += `&redirect=${request.redirect}`;
}
if (request.loginRedirectUrl) {
params += `&login_redirect_url=${request.loginRedirectUrl}`;
}
if (request.registrationRedirectUrl) {
params += `®istration_redirect_url=${request.registrationRedirectUrl}`;
}
return this.request({ method: Method.GET, path: `google/begin?${params}` });
}
async apple(request) {
let params = `public_token=${request.publicToken}`;
if (request.redirect) {
params += `&redirect=${request.redirect}`;
}
if (request.loginRedirectUrl) {
params += `&login_redirect_url=${request.loginRedirectUrl}`;
}
if (request.registrationRedirectUrl) {
params += `®istration_redirect_url=${request.registrationRedirectUrl}`;
}
return this.request({ method: Method.GET, path: `apple/begin?${params}` });
}
async microsoft(request) {
let params = `public_token=${request.publicToken}`;
if (request.redirect) {
params += `&redirect=${request.redirect}`;
}
if (request.loginRedirectUrl) {
params += `&login_redirect_url=${request.loginRedirectUrl}`;
}
if (request.registrationRedirectUrl) {
params += `®istration_redirect_url=${request.registrationRedirectUrl}`;
}
return this.request({ method: Method.GET, path: `microsoft/begin?${params}` });
}
async discord(request) {
let params = `public_token=${request.publicToken}`;
if (request.redirect) {
params += `&redirect=${request.redirect}`;
}
if (request.loginRedirectUrl) {
params += `&login_redirect_url=${request.loginRedirectUrl}`;
}
if (request.registrationRedirectUrl) {
params += `®istration_redirect_url=${request.registrationRedirectUrl}`;
}
return this.request({ method: Method.GET, path: `discord/begin?${params}` });
}
async github(request) {
let params = `public_token=${request.publicToken}`;
if (request.redirect) {
params += `&redirect=${request.redirect}`;
}
if (request.loginRedirectUrl) {
params += `&login_redirect_url=${request.loginRedirectUrl}`;
}
if (request.registrationRedirectUrl) {
params += `®istration_redirect_url=${request.registrationRedirectUrl}`;
}
return this.request({ method: Method.GET, path: `github/begin?${params}` });
}
async verify(oauthRequest) {
let bodyData = {
'token': oauthRequest.token
};
if (oauthRequest.sessionType) {
bodyData['session_type'] = oauthRequest.sessionType;
}
if (oauthRequest.sessionToken) {
bodyData['session_token'] = oauthRequest.sessionToken;
}
if (oauthRequest.sessionExpiresIn) {
bodyData['session_expires_in'] = oauthRequest.sessionExpiresIn;
}
if (oauthRequest.sessionJwt) {
bodyData['session_jwt'] = oauthRequest.sessionJwt;
}
return this.request({ method: Method.POST, body: bodyData, path: 'verify' });
}
}
class Email extends Resource {
constructor(axiosInstance) {
super("auth/otps", axiosInstance);
}
async loginOrCreate(loginOrCreateRequest) {
let bodyData = {
email: loginOrCreateRequest.email
};
if (loginOrCreateRequest.expiresIn && loginOrCreateRequest.expiresIn > 0) {
bodyData['expires_in'] = loginOrCreateRequest.expiresIn;
}
if (loginOrCreateRequest.deviceFingerprint) {
bodyData['device_fingerprint'] = loginOrCreateRequest.deviceFingerprint;
}
if (loginOrCreateRequest.requiresVerification !== null && loginOrCreateRequest.requiresVerification !== undefined) {
bodyData['requires_verification'] = loginOrCreateRequest.requiresVerification;
}
return this.request({ method: Method.POST, body: bodyData, path: 'email/login_or_create' });
}
async send(sendRequest) {
let bodyData = {
email: sendRequest.email,
};
if (sendRequest.expiresIn && sendRequest.expiresIn > 0) {
bodyData['expires_in'] = sendRequest.expiresIn;
}
if (sendRequest.deviceFingerprint) {
bodyData['device_fingerprint'] = sendRequest.deviceFingerprint;
}
return this.request({ method: Method.POST, body: bodyData, path: 'email/send' });
}
}
class SMS extends Resource {
constructor(axiosInstance) {
super("auth/otps", axiosInstance);
}
async loginOrCreate(sendRequest) {
let bodyData = {
phone_number: sendRequest.phoneNumber
};
if (sendRequest.expiresIn && sendRequest.expiresIn > 0) {
bodyData['expires_in'] = sendRequest.expiresIn;
}
if (sendRequest.deviceFingerprint) {
bodyData['device_fingerprint'] = sendRequest.deviceFingerprint;
}
if (sendRequest.requiresVerification !== null && sendRequest.requiresVerification !== undefined) {
bodyData['requires_verification'] = sendRequest.requiresVerification;
}
return this.request({ method: Method.POST, body: bodyData, path: 'sms/login_or_create' });
}
async send(sendRequest) {
let bodyData = {
phone_number: sendRequest.phoneNumber,
};
if (sendRequest.expiresIn && sendRequest.expiresIn > 0) {
bodyData['expires_in'] = sendRequest.expiresIn;
}
if (sendRequest.deviceFingerprint) {
bodyData['device_fingerprint'] = sendRequest.deviceFingerprint;
}
return this.request({ method: Method.POST, body: bodyData, path: 'sms/send' });
}
}
class OTPs extends Resource {
constructor(axiosInstance) {
super("auth/otps", axiosInstance);
this.email = new Email(axiosInstance);
this.sms = new SMS(axiosInstance);
}
async verify(otpVerifyRequest) {
let bodyData = {
otp: otpVerifyRequest.otp,
method_id: otpVerifyRequest.methodId,
};
if (otpVerifyRequest.deviceFingerprint) {
bodyData['device_fingerprint'] = otpVerifyRequest.deviceFingerprint;
}
if (otpVerifyRequest.sessionExpiresIn && otpVerifyRequest.sessionExpiresIn > 0) {
bodyData['session_expires_in'] = otpVerifyRequest.sessionExpiresIn;
}
return this.request({ method: Method.POST, body: bodyData, path: 'verify' });
}
}
class Sessions extends Resource {
constructor(axiosInstance, jwkConfig) {
super("", axiosInstance);
this.sessionRequest = "https://streambird.io/jwt/session";
this.jwksGetKey = jwkConfig.jwksGetKey;
}
async list(userId) {
return this.request({ method: Method.GET, path: `auth/sessions/list?user_id=${userId}` });
}
async verify(verifyRequest) {
let bodyData = {};
if (verifyRequest.sessionToken) {
bodyData['session_expires_in'] = verifyRequest.sessionExpiresIn;
}
if (verifyRequest.sessionToken) {
bodyData['session_token'] = verifyRequest.sessionToken;
}
if (verifyRequest.sessionJwt) {
bodyData['session_jwt'] = verifyRequest.sessionJwt;
}
return this.request({ method: Method.POST, body: bodyData, path: 'auth/sessions/verify' });
}
async delete(deleteRequest) {
let bodyData = {};
if (deleteRequest.sessionId) {
bodyData['session_id'] = deleteRequest.sessionId;
}
if (deleteRequest.sessionToken) {
bodyData['session_token'] = deleteRequest.sessionToken;
}
if (deleteRequest.sessionJwt) {
bodyData['session_jwt'] = deleteRequest.sessionJwt;
}
return this.request({ method: Method.DELETE, body: bodyData, path: 'auth/sessions/delete' });
}
async jwks() {
return this.request({ method: Method.GET, path: 'auth/jwks/default' });
}
async verifyJwt(jwt, options) {
try {
const session = await this.verifyLocalJwt(jwt, options);
return {
session,
sessionJwt: jwt,
};
}
catch (err) {
if (err instanceof StreambirdError && err.code === "jwt_stale" /* JWT_STALE */) {
return this.verify({ sessionJwt: jwt });
}
throw err;
}
}
async verifyLocalJwt(jwt, options) {
const dateNow = (options === null || options === void 0 ? void 0 : options.currentDate) || new Date();
let payload;
try {
let jwtVerifyResult = await jose.jwtVerify(jwt, this.jwksGetKey, {
clockTolerance: options === null || options === void 0 ? void 0 : options.clockTolerance,
currentDate: dateNow
});
payload = jwtVerifyResult.payload;
}
catch (error) {
throw new StreambirdError("jwt_error" /* JWT_ERROR */, "Could not verify JWT");
}
if (options === null || options === void 0 ? void 0 : options.maxTokenAge) {
const iat = payload.iat;
if (!iat) {
throw new StreambirdError("jwt_error" /* JWT_ERROR */, "JWT was missing iat claim");
}
const currentEpoch = +dateNow / 1000;
if (currentEpoch - iat >= options.maxTokenAge) {
throw new StreambirdError("jwt_stale" /* JWT_STALE */, `JWT issued ${iat} > ${options.maxTokenAge}`);
}
}
return payload[this.sessionRequest];
}
}
class TOTPs extends Resource {
constructor(axiosInstance) {
super("auth/totps", axiosInstance);
}
async create(createRequest) {
let bodyData = {
user_id: createRequest.userId
};
if (createRequest.expiresIn) {
bodyData.expires_in = createRequest.expiresIn;
}
return this.request({ method: Method.POST, body: bodyData, path: 'create' });
}
async verify(updateRequest) {
let bodyData = {
user_id: updateRequest.userId,
totp: updateRequest.totp
};
if (updateRequest.sessionExpiresIn) {
bodyData['session_expires_in'] = updateRequest.sessionExpiresIn;
}
if (updateRequest.sessionToken) {
bodyData['session_token'] = updateRequest.sessionToken;
}
if (updateRequest.sessionJwt) {
bodyData['session_jwt'] = updateRequest.sessionJwt;
}
if (updateRequest.deviceFingerprint) {
bodyData['device_fingerprint'] = updateRequest.deviceFingerprint;
}
return this.request({ method: Method.POST, body: bodyData, path: 'verify' });
}
async recoveryCodes(codeRequest) {
let bodyData = {
user_id: codeRequest.userId
};
return this.request({ method: Method.POST, body: bodyData, path: 'recovery_codes' });
}
async recovery(recoveryRequest) {
let bodyData = {
user_id: recoveryRequest.userId,
totp: recoveryRequest.totp
};
if (recoveryRequest.sessionExpiresIn) {
bodyData['session_expires_in'] = recoveryRequest.sessionExpiresIn;
}
if (recoveryRequest.sessionToken) {
bodyData['session_token'] = recoveryRequest.sessionToken;
}
if (recoveryRequest.sessionJwt) {
bodyData['session_jwt'] = recoveryRequest.sessionJwt;
}
if (recoveryRequest.deviceFingerprint) {
bodyData['device_fingerprint'] = recoveryRequest.deviceFingerprint;
}
return this.request({ method: Method.POST, body: bodyData, path: 'recovery' });
}
}
class Users extends Resource {
constructor(axiosInstance) {
super("auth/users", axiosInstance);
}
async create(userRequest) {
let bodyData = {
'requires_verification': userRequest.requiresVerification,
'include_user': userRequest.includeUser
};
if (userRequest.email && userRequest.email.length > 0) {
bodyData['email'] = userRequest.email;
}
if (userRequest.phoneNumber && userRequest.phoneNumber.length > 0) {
bodyData['phone_number'] = userRequest.phoneNumber;
}
if (userRequest.firstName && userRequest.firstName.length > 0) {
bodyData['first_name'] = userRequest.firstName;
}
if (userRequest.middleName && userRequest.middleName.length > 0) {
bodyData['middle_name'] = userRequest.middleName;
}
if (userRequest.lastName && userRequest.lastName.length > 0) {
bodyData['last_name'] = userRequest.lastName;
}
if (userRequest.walletType && userRequest.walletType.length > 0) {
bodyData['wallet_type'] = userRequest.walletType;
}
return this.request({ method: Method.POST, body: bodyData, path: 'create' });
}
async update(userId, options) {
let bodyData = {};
if (options.firstName && options.firstName.trim().length > 0) {
bodyData['first_name'] = options.firstName;
}
if (options.middleName && options.middleName.trim().length > 0) {
bodyData['middle_name'] = options.middleName;
}
if (options.lastName && options.lastName.trim().length > 0) {
bodyData['last_name'] = options.lastName;
}
if (options.emails) {
bodyData['emails'] = [];
options.emails && options.emails.map((email) => {
bodyData['emails'].push({ email: email });
});
}
if (options.phoneNumbers) {
bodyData['phone_numbers'] = [];
options.phoneNumbers && options.phoneNumbers.map((phoneNumber) => {
bodyData['phone_numbers'].push({ phone_number: phoneNumber });
});
}
return this.request({
method: Method.PUT,
path: `${userId}/update`,
body: bodyData
});
}
async get(userId) {
return this.request({ method: Method.GET, path: `${userId}` });
}
async delete(userId) {
return this.request({ method: Method.DELETE, path: `${userId}/delete` });
}
async deleteEmail(emailId) {
return this.request({ method: Method.DELETE, path: `emails/${emailId}/delete` });
}
async deletePhoneNumber(phoneNumberId) {
return this.request({ method: Method.DELETE, path: `phone_numbers/${phoneNumberId}/delete` });
}
async deleteWallet(walletId) {
return this.request({ method: Method.DELETE, path: `wallets/${walletId}/delete` });
}
async search(searchRequest) {
let bodyData = {};
bodyData['limit'] = searchRequest.limit;
if (searchRequest.startingAfter) {
bodyData['starting_after'] = searchRequest.startingAfter;
}
if (searchRequest && searchRequest.filters) {
bodyData['filters'] = {};
bodyData['filters']['operator'] = searchRequest.filters.operator;
if (searchRequest.filters.fields) {
let fieldsToAdd = [];
searchRequest.filters.fields.map((field) => {
let fieldObj = {};
fieldObj['field'] = field.field;
fieldObj['operator'] = field.operator;
if (field.value) {
fieldObj['value'] = field.value;
}
if (field.secondValue) {
fieldObj['second_value'] = field.secondValue;
}
if (field.values) {
fieldObj['values'] = field.values;
}
fieldsToAdd.push(fieldObj);
});
if (fieldsToAdd.length > 0) {
bodyData['filters']['fields'] = fieldsToAdd;
}
}
}
return this.request({ method: Method.POST, body: bodyData, path: 'search' });
}
async deleteWebAuthn(webauthnCredentialId) {
return this.request({ method: Method.DELETE, path: `webauthn_credentials/${webauthnCredentialId}/delete` });
}
async deleteTOTP(totpId) {
return this.request({ method: Method.DELETE, path: `totps/${totpId}/delete` });
}
}
class Wallets extends Resource {
constructor(axiosInstance) {
super("auth/wallets", axiosInstance);
}
async beginRegistration(registrationRequest) {
let bodyData = {
'wallet_type': registrationRequest.walletType,
'public_address': registrationRequest.publicAddress
};
if (registrationRequest.userId) {
bodyData['user_id'] = registrationRequest.userId;
}
return this.request({ method: Method.POST, body: bodyData, path: 'registrations/begin' });
}
async verify(verifyRequest) {
let bodyData = {
'wallet_type': verifyRequest.walletType,
'public_address': verifyRequest.publicAddress,
'signature': verifyRequest.signature
};
if (verifyRequest.sessionToken) {
bodyData['session_token'] = verifyRequest.sessionToken;
}
if (verifyRequest.sessionExpiresIn) {
bodyData['session_expires_in'] = verifyRequest.sessionExpiresIn;
}
if (verifyRequest.sessionJwt) {
bodyData['session_jwt'] = verifyRequest.sessionJwt;
}
return this.request({ method: Method.POST, body: bodyData, path: 'verify' });
}
async create(createRequest) {
let bodyData = {
'wallet_type': createRequest.walletType,
'user_id': createRequest.userId,
};
return this.request({ method: Method.POST, body: bodyData, path: 'create' });
}
}
class Streambird {
constructor({ apiKey, timeout = 30000, apiHostUrl }) {
if (!apiKey) {
throw new Error("No API key provided");
}
const apiUrl = `https://api.streambird.io/v1/`;
const baseURL = apiHostUrl || apiUrl;
let jwkConfig = {
jwksGetKey: jose.createRemoteJWKSet(new URL(`${baseURL}auth/jwks/default?api_key=${apiKey}`))
};
//const JWKS = jose.createRemoteJWKSet(new URL('http://localhost:11019/v1/auth/jwks/default?api_key=sk_pRqweh3wvWmJAAVYv7Z0T5iPLzFM4ql0muoyQcjOxGeN3p1r'))
this.axiosInstance = axios.create({
baseURL: baseURL,
headers: {
"Content-Type": "application/json",
"User-Agent": `streambird-node/${version}`,
"Authorization": `Bearer ${apiKey}`
},
timeout
});
this.users = new Users(this.axiosInstance);
this.magicLinks = new MagicLinks(this.axiosInstance);
this.otps = new OTPs(this.axiosInstance);
this.wallets = new Wallets(this.axiosInstance);
this.sessions = new Sessions(this.axiosInstance, jwkConfig);
this.oauth = new OAuth(this.axiosInstance);
this.totps = new TOTPs(this.axiosInstance);
}
}
exports.Streambird = Streambird;
exports.StreambirdApiError = StreambirdApiError;
exports.StreambirdError = StreambirdError;
exports.Users = Users;
//# sourceMappingURL=index.js.map