@nestjs-mod/supabase
Version:
NestJS JavaScript Client for Supabase (Wrapper for https://www.npmjs.com/package/@supabase/supabase-js)
161 lines • 7.95 kB
JavaScript
"use strict";
var SupabaseService_1;
Object.defineProperty(exports, "__esModule", { value: true });
exports.SupabaseService = void 0;
const tslib_1 = require("tslib");
const common_1 = require("@nestjs-mod/common");
const common_2 = require("@nestjs/common");
const core_1 = require("@nestjs/core");
const supabase_js_1 = require("@supabase/supabase-js");
const supabase_configuration_1 = require("./supabase.configuration");
const supabase_decorators_1 = require("./supabase.decorators");
const supabase_environments_1 = require("./supabase.environments");
const supabase_errors_1 = require("./supabase.errors");
let SupabaseService = SupabaseService_1 = class SupabaseService {
constructor(reflector, supabaseConfiguration, supabaseStaticEnvironments) {
this.reflector = reflector;
this.supabaseConfiguration = supabaseConfiguration;
this.supabaseStaticEnvironments = supabaseStaticEnvironments;
this.logger = new common_2.Logger(SupabaseService_1.name);
}
onModuleInit() {
this.supabaseClient = new supabase_js_1.SupabaseClient(this.supabaseStaticEnvironments.url, this.supabaseStaticEnvironments.key, {
...this.supabaseConfiguration.clientOptions,
global: {
...this.supabaseConfiguration.clientOptions,
headers: {
...this.supabaseConfiguration.extraHeaders,
...this.supabaseConfiguration.clientOptions?.global?.headers
}
}
});
}
getSupabaseClient() {
return this.supabaseClient;
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
async getUserFromRequest(ctx, checkAccess = true) {
await this.tryGetOrCreateCurrentUserWithExternalUserId(ctx);
await this.checkAccessValidator(checkAccess, ctx);
const req = this.getRequestFromExecutionContext(ctx);
this.setInfoOfExternalUserIdToRequest(req);
this.setSkippedBySupabaseIfUserIsEmpty(req);
return req.supabaseUser;
}
setSkippedBySupabaseIfUserIsEmpty(req) {
req.skippedBySupabase =
req.supabaseUser === undefined || req.supabaseUser?.id === undefined;
}
setInfoOfExternalUserIdToRequest(req) {
if (req.supabaseUser?.id &&
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
!req?.headers?.[this.supabaseConfiguration.externalUserIdHeaderName]) {
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
req.headers[this.supabaseConfiguration.externalUserIdHeaderName] =
req.supabaseUser?.id;
req.externalUserId =
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
req?.headers?.[this.supabaseConfiguration.externalUserIdHeaderName];
}
}
async checkAccessValidator(checkAccess, ctx) {
const { checkAccessMetadata, allowEmptyUserMetadata } = this.getHandlersReflectMetadata(ctx);
const req = this.getRequestFromExecutionContext(ctx);
if (allowEmptyUserMetadata) {
req.skipEmptySupabaseUser = true;
}
if (checkAccess) {
// check access by custom logic
const checkAccessValidatorResult = this.supabaseConfiguration
.checkAccessValidator
? await this.supabaseConfiguration.checkAccessValidator(req.supabaseUser, checkAccessMetadata, ctx)
: false;
// check access by roles
if (!req.skipEmptySupabaseUser &&
!checkAccessValidatorResult &&
!req.supabaseUser?.id) {
throw new supabase_errors_1.SupabaseError(supabase_errors_1.SupabaseErrorEnum.UNAUTHORIZED);
}
}
}
async tryGetOrCreateCurrentUserWithExternalUserId(ctx) {
const req = this.getRequestFromExecutionContext(ctx);
if (!req.supabaseUser?.id) {
const token = req.headers?.authorization?.split(' ')[1];
if (token && token !== 'undefined') {
// check user in supabase
try {
const getProfileResult = await this.supabaseClient.auth.getUser(token);
if (!getProfileResult.error) {
req.supabaseUser = {
email: getProfileResult.data.user.email,
id: getProfileResult.data.user.id,
created_at: (+new Date(getProfileResult.data.user.created_at)).toString(),
updated_at: getProfileResult.data.user.updated_at
? (+new Date(getProfileResult.data.user.updated_at)).toString()
: '0',
role: 'user',
picture: getProfileResult.data.user.user_metadata['picture'],
};
}
else {
this.logger.debug({ token });
this.logger.error(getProfileResult.error.message, getProfileResult.error.stack);
throw new supabase_errors_1.SupabaseError(getProfileResult.error.message);
}
}
catch (err) {
req.supabaseUser = { id: undefined };
}
}
// check external user id
if (!req.supabaseUser) {
req.externalUserId =
req?.headers?.[
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
this.supabaseConfiguration.externalUserIdHeaderName];
req.externalAppId =
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
req?.headers?.[this.supabaseConfiguration.externalAppIdHeaderName];
if (req.externalAppId &&
!this.supabaseStaticEnvironments.allowedExternalAppIds?.includes(req.externalAppId)) {
req.supabaseUser = {
id: req.externalUserId
? (await this.supabaseConfiguration.getSupabaseUserFromExternalUserId?.(req.externalUserId, req.externalAppId, ctx))?.id
: undefined,
};
}
}
}
req.supabaseUser = req.supabaseUser || { id: undefined };
}
getRequestFromExecutionContext(ctx) {
const req = (0, common_1.getRequestFromExecutionContext)(ctx);
req.headers = req.headers || {};
return req;
}
getHandlersReflectMetadata(ctx) {
const allowEmptyUserMetadata = Boolean((typeof ctx.getHandler === 'function' &&
this.reflector.get(supabase_decorators_1.AllowEmptySupabaseUser, ctx.getHandler())) ||
(typeof ctx.getClass === 'function' &&
this.reflector.get(supabase_decorators_1.AllowEmptySupabaseUser, ctx.getClass())) ||
undefined);
const checkAccessMetadata = (typeof ctx.getHandler === 'function' &&
this.reflector.get(supabase_decorators_1.CheckSupabaseAccess, ctx.getHandler())) ||
(typeof ctx.getClass === 'function' &&
this.reflector.get(supabase_decorators_1.CheckSupabaseAccess, ctx.getClass())) ||
undefined;
return {
checkAccessMetadata,
allowEmptyUserMetadata,
};
}
};
exports.SupabaseService = SupabaseService;
exports.SupabaseService = SupabaseService = SupabaseService_1 = tslib_1.__decorate([
(0, common_2.Injectable)(),
tslib_1.__metadata("design:paramtypes", [core_1.Reflector,
supabase_configuration_1.SupabaseConfiguration,
supabase_environments_1.SupabaseStaticEnvironments])
], SupabaseService);
//# sourceMappingURL=supabase.service.js.map