Compare commits
2 Commits
e294b8355f
...
bf60bf5901
| Author | SHA1 | Date | |
|---|---|---|---|
| bf60bf5901 | |||
| b22a787eff |
@ -34,6 +34,7 @@
|
|||||||
"@prisma/client": "^7.3.0",
|
"@prisma/client": "^7.3.0",
|
||||||
"@teacinema/common": "^1.0.0",
|
"@teacinema/common": "^1.0.0",
|
||||||
"@teacinema/contracts": "^1.0.0",
|
"@teacinema/contracts": "^1.0.0",
|
||||||
|
"@teacinema/passport": "^1.0.0",
|
||||||
"class-transformer": "^0.5.1",
|
"class-transformer": "^0.5.1",
|
||||||
"class-validator": "^0.14.3",
|
"class-validator": "^0.14.3",
|
||||||
"dotenv-expand": "^12.0.3",
|
"dotenv-expand": "^12.0.3",
|
||||||
|
|||||||
@ -17,8 +17,17 @@ model Account {
|
|||||||
isPhoneVerified Boolean @default(false) @map("is_phone_verified")
|
isPhoneVerified Boolean @default(false) @map("is_phone_verified")
|
||||||
isEmailVerified Boolean @default(false) @map("is_email_verified")
|
isEmailVerified Boolean @default(false) @map("is_email_verified")
|
||||||
|
|
||||||
|
role Role @default(USER)
|
||||||
|
|
||||||
createdAt DateTime @default(now()) @map("created_at")
|
createdAt DateTime @default(now()) @map("created_at")
|
||||||
updatedAt DateTime @updatedAt @map("updated_at")
|
updatedAt DateTime @updatedAt @map("updated_at")
|
||||||
|
|
||||||
@@map("accounts")
|
@@map("accounts")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum Role {
|
||||||
|
ADMIN
|
||||||
|
USER
|
||||||
|
|
||||||
|
@@map("roles")
|
||||||
|
}
|
||||||
|
|||||||
@ -1,9 +1,10 @@
|
|||||||
import { Module } from '@nestjs/common'
|
import { Module } from '@nestjs/common'
|
||||||
import { ConfigModule } from '@nestjs/config'
|
import { ConfigModule } from '@nestjs/config'
|
||||||
|
|
||||||
import { dabataseEnv, grpcEnv, redisEnv } from './config'
|
import { dabataseEnv, grpcEnv, passportEnv, redisEnv } from './config'
|
||||||
import { PrismaModule } from './infra/prisma/prisma.module'
|
import { PrismaModule } from './infra/prisma/prisma.module'
|
||||||
import { RedisModule } from './infra/redis/redis.module'
|
import { RedisModule } from './infra/redis/redis.module'
|
||||||
|
import { AccountModule } from './modules/account/account.module'
|
||||||
import { AuthModule } from './modules/auth/auth.module'
|
import { AuthModule } from './modules/auth/auth.module'
|
||||||
import { OtpModule } from './modules/otp/otp.module'
|
import { OtpModule } from './modules/otp/otp.module'
|
||||||
|
|
||||||
@ -11,12 +12,13 @@ import { OtpModule } from './modules/otp/otp.module'
|
|||||||
imports: [
|
imports: [
|
||||||
ConfigModule.forRoot({
|
ConfigModule.forRoot({
|
||||||
isGlobal: true,
|
isGlobal: true,
|
||||||
load: [dabataseEnv, grpcEnv, redisEnv]
|
load: [dabataseEnv, grpcEnv, redisEnv, passportEnv]
|
||||||
}),
|
}),
|
||||||
PrismaModule,
|
PrismaModule,
|
||||||
RedisModule,
|
RedisModule,
|
||||||
AuthModule,
|
AuthModule,
|
||||||
OtpModule
|
OtpModule,
|
||||||
|
AccountModule
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
export class AppModule {}
|
export class AppModule {}
|
||||||
|
|||||||
1
src/config/env/index.ts
vendored
1
src/config/env/index.ts
vendored
@ -1,3 +1,4 @@
|
|||||||
export * from './grpc.env'
|
export * from './grpc.env'
|
||||||
export * from './database.env'
|
export * from './database.env'
|
||||||
export * from './redis.env'
|
export * from './redis.env'
|
||||||
|
export * from './passport.env'
|
||||||
|
|||||||
16
src/config/env/passport.env.ts
vendored
Normal file
16
src/config/env/passport.env.ts
vendored
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
import { registerAs } from '@nestjs/config'
|
||||||
|
|
||||||
|
import { validateEnv } from '@/shared/utils'
|
||||||
|
|
||||||
|
import { PassportConfig } from '../interfaces/passport.interface'
|
||||||
|
import { PassportValidator } from '../validators'
|
||||||
|
|
||||||
|
export const passportEnv = registerAs<PassportConfig>('passport', () => {
|
||||||
|
validateEnv(process.env, PassportValidator)
|
||||||
|
|
||||||
|
return {
|
||||||
|
secretKey: process.env.PASSPORT_SECRET_KEY,
|
||||||
|
accessTtl: parseInt(process.env.PASSPORT_ACCESS_TTL),
|
||||||
|
refreshTtl: parseInt(process.env.PASSPORT_REFRESH_TTL)
|
||||||
|
}
|
||||||
|
})
|
||||||
@ -1,2 +1,3 @@
|
|||||||
export * from './env'
|
export * from './env'
|
||||||
export * from './interfaces'
|
export * from './interfaces'
|
||||||
|
export * from './loaders'
|
||||||
|
|||||||
@ -1,9 +1,11 @@
|
|||||||
import { DatabaseConfig } from './database.interface'
|
import { DatabaseConfig } from './database.interface'
|
||||||
import { GrpcConfig } from './grpc.interface'
|
import { GrpcConfig } from './grpc.interface'
|
||||||
|
import { PassportConfig } from './passport.interface'
|
||||||
import { RedisConfig } from './redis.interface'
|
import { RedisConfig } from './redis.interface'
|
||||||
|
|
||||||
export interface AllConfigs {
|
export interface AllConfigs {
|
||||||
database: DatabaseConfig
|
database: DatabaseConfig
|
||||||
grpc: GrpcConfig
|
grpc: GrpcConfig
|
||||||
redis: RedisConfig
|
redis: RedisConfig
|
||||||
|
passport: PassportConfig
|
||||||
}
|
}
|
||||||
|
|||||||
5
src/config/interfaces/passport.interface.ts
Normal file
5
src/config/interfaces/passport.interface.ts
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
export interface PassportConfig {
|
||||||
|
secretKey: string
|
||||||
|
accessTtl: number
|
||||||
|
refreshTtl: number
|
||||||
|
}
|
||||||
1
src/config/loaders/index.ts
Normal file
1
src/config/loaders/index.ts
Normal file
@ -0,0 +1 @@
|
|||||||
|
export * from './passport.config.loader'
|
||||||
12
src/config/loaders/passport.config.loader.ts
Normal file
12
src/config/loaders/passport.config.loader.ts
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
import { ConfigService } from '@nestjs/config'
|
||||||
|
import { PassportOptions } from '@teacinema/passport'
|
||||||
|
|
||||||
|
import { AllConfigs } from '@/config'
|
||||||
|
|
||||||
|
export function getPassportConfig(
|
||||||
|
configService: ConfigService<AllConfigs>
|
||||||
|
): PassportOptions {
|
||||||
|
return {
|
||||||
|
secretKey: configService.get('passport.secretKey', { infer: true })
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,3 +1,4 @@
|
|||||||
export * from './grpc.validator'
|
export * from './grpc.validator'
|
||||||
export * from './database.validator'
|
export * from './database.validator'
|
||||||
export * from './redis.validator'
|
export * from './redis.validator'
|
||||||
|
export * from './passport.validator'
|
||||||
|
|||||||
14
src/config/validators/passport.validator.ts
Normal file
14
src/config/validators/passport.validator.ts
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
import { IsInt, IsNumber, IsString } from 'class-validator'
|
||||||
|
|
||||||
|
export class PassportValidator {
|
||||||
|
@IsString()
|
||||||
|
public PASSPORT_SECRET_KEY: string
|
||||||
|
|
||||||
|
@IsInt()
|
||||||
|
@IsNumber()
|
||||||
|
public PASSPORT_ACCESS_TTL: number
|
||||||
|
|
||||||
|
@IsInt()
|
||||||
|
@IsNumber()
|
||||||
|
public PASSPORT_REFRESH_TTL: number
|
||||||
|
}
|
||||||
@ -1,8 +1,8 @@
|
|||||||
import { GrpcOptions } from '@nestjs/microservices'
|
import { GrpcOptions } from '@nestjs/microservices'
|
||||||
import { PROTO_PATHS } from '@teacinema/contracts'
|
import { PROTO_PATHS } from '@teacinema/contracts'
|
||||||
|
|
||||||
export const grpcPackages = ['auth.v1']
|
export const grpcPackages = ['auth.v1', 'account.v1']
|
||||||
export const grpcProtoPaths = [PROTO_PATHS.AUTH]
|
export const grpcProtoPaths = [PROTO_PATHS.AUTH, PROTO_PATHS.ACCOUNT]
|
||||||
export const grpcLoader: GrpcOptions['options']['loader'] = {
|
export const grpcLoader: GrpcOptions['options']['loader'] = {
|
||||||
keepCase: false,
|
keepCase: false,
|
||||||
longs: String,
|
longs: String,
|
||||||
|
|||||||
20
src/modules/account/account.controller.ts
Normal file
20
src/modules/account/account.controller.ts
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
import { Controller } from '@nestjs/common'
|
||||||
|
import { GrpcMethod } from '@nestjs/microservices'
|
||||||
|
import type {
|
||||||
|
GetAccountRequest,
|
||||||
|
GetAccountResponse
|
||||||
|
} from '@teacinema/contracts/gen/account'
|
||||||
|
|
||||||
|
import { AccountService } from './account.service'
|
||||||
|
|
||||||
|
@Controller()
|
||||||
|
export class AccountController {
|
||||||
|
constructor(private readonly accountService: AccountService) {}
|
||||||
|
|
||||||
|
@GrpcMethod('AccountService', 'GetAccount')
|
||||||
|
public async getAccount(
|
||||||
|
data: GetAccountRequest
|
||||||
|
): Promise<GetAccountResponse> {
|
||||||
|
return this.accountService.getAccount(data)
|
||||||
|
}
|
||||||
|
}
|
||||||
12
src/modules/account/account.module.ts
Normal file
12
src/modules/account/account.module.ts
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
import { Module } from '@nestjs/common'
|
||||||
|
|
||||||
|
import { AccountRepository } from '@/modules/account/account.repository'
|
||||||
|
|
||||||
|
import { AccountController } from './account.controller'
|
||||||
|
import { AccountService } from './account.service'
|
||||||
|
|
||||||
|
@Module({
|
||||||
|
controllers: [AccountController],
|
||||||
|
providers: [AccountService, AccountRepository]
|
||||||
|
})
|
||||||
|
export class AccountModule {}
|
||||||
12
src/modules/account/account.repository.ts
Normal file
12
src/modules/account/account.repository.ts
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
import { Injectable } from '@nestjs/common'
|
||||||
|
|
||||||
|
import { PrismaService } from '@/infra/prisma/prisma.service'
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class AccountRepository {
|
||||||
|
public constructor(private readonly prismaService: PrismaService) {}
|
||||||
|
|
||||||
|
public findById(id: string) {
|
||||||
|
return this.prismaService.account.findUnique({ where: { id } })
|
||||||
|
}
|
||||||
|
}
|
||||||
39
src/modules/account/account.service.ts
Normal file
39
src/modules/account/account.service.ts
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
import { Injectable } from '@nestjs/common'
|
||||||
|
import { RpcException } from '@nestjs/microservices'
|
||||||
|
import { Role } from '@prisma/generated/enums'
|
||||||
|
import { convertEnum, RpcStatus } from '@teacinema/common'
|
||||||
|
import type {
|
||||||
|
GetAccountRequest,
|
||||||
|
GetAccountResponse
|
||||||
|
} from '@teacinema/contracts/gen/account'
|
||||||
|
|
||||||
|
import { AccountRepository } from './account.repository'
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class AccountService {
|
||||||
|
public constructor(private readonly accountRepository: AccountRepository) {}
|
||||||
|
|
||||||
|
public async getAccount(
|
||||||
|
data: GetAccountRequest
|
||||||
|
): Promise<GetAccountResponse> {
|
||||||
|
const { id } = data
|
||||||
|
const account = await this.accountRepository.findById(id)
|
||||||
|
|
||||||
|
if (!account) {
|
||||||
|
throw new RpcException({
|
||||||
|
code: RpcStatus.NOT_FOUND,
|
||||||
|
details: 'Account not found'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
email: account.email,
|
||||||
|
id: account.id,
|
||||||
|
phone: account.phone,
|
||||||
|
isEmailVerified: account.isEmailVerified,
|
||||||
|
isPhoneVerified: account.isPhoneVerified,
|
||||||
|
// @ts-ignore
|
||||||
|
role: convertEnum(Role, account.role)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,6 +1,8 @@
|
|||||||
import { Controller } from '@nestjs/common'
|
import { Controller } from '@nestjs/common'
|
||||||
import { GrpcMethod } from '@nestjs/microservices'
|
import { GrpcMethod } from '@nestjs/microservices'
|
||||||
import type {
|
import type {
|
||||||
|
RefreshRequest,
|
||||||
|
RefreshResponse,
|
||||||
SendOtpRequest,
|
SendOtpRequest,
|
||||||
SendOtpResponse,
|
SendOtpResponse,
|
||||||
VerifyOtpRequest,
|
VerifyOtpRequest,
|
||||||
@ -22,4 +24,9 @@ export class AuthController {
|
|||||||
public VerifyOtp(data: VerifyOtpRequest): Promise<VerifyOtpResponse> {
|
public VerifyOtp(data: VerifyOtpRequest): Promise<VerifyOtpResponse> {
|
||||||
return this.authService.verifyOtp(data)
|
return this.authService.verifyOtp(data)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@GrpcMethod('AuthService', 'Refresh')
|
||||||
|
public refresh(data: RefreshRequest): RefreshResponse {
|
||||||
|
return this.authService.refresh(data)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,5 +1,8 @@
|
|||||||
import { Module } from '@nestjs/common'
|
import { Module } from '@nestjs/common'
|
||||||
|
import { ConfigService } from '@nestjs/config'
|
||||||
|
import { PassportModule } from '@teacinema/passport'
|
||||||
|
|
||||||
|
import { getPassportConfig } from '@/config'
|
||||||
import { OtpService } from '@/modules/otp/otp.service'
|
import { OtpService } from '@/modules/otp/otp.service'
|
||||||
|
|
||||||
import { AuthController } from './auth.controller'
|
import { AuthController } from './auth.controller'
|
||||||
@ -7,6 +10,12 @@ import { AuthRepository } from './auth.repository'
|
|||||||
import { AuthService } from './auth.service'
|
import { AuthService } from './auth.service'
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
|
imports: [
|
||||||
|
PassportModule.registerAsync({
|
||||||
|
useFactory: getPassportConfig,
|
||||||
|
inject: [ConfigService]
|
||||||
|
})
|
||||||
|
],
|
||||||
controllers: [AuthController],
|
controllers: [AuthController],
|
||||||
providers: [AuthService, AuthRepository, OtpService]
|
providers: [AuthService, AuthRepository, OtpService]
|
||||||
})
|
})
|
||||||
|
|||||||
@ -1,24 +1,41 @@
|
|||||||
import { Injectable } from '@nestjs/common'
|
import { Injectable } from '@nestjs/common'
|
||||||
|
import { ConfigService } from '@nestjs/config'
|
||||||
import { RpcException } from '@nestjs/microservices'
|
import { RpcException } from '@nestjs/microservices'
|
||||||
import { Account } from '@prisma/generated/client'
|
import { Account } from '@prisma/generated/client'
|
||||||
import { RpcStatus } from '@teacinema/common'
|
import { RpcStatus } from '@teacinema/common'
|
||||||
import {
|
import {
|
||||||
|
type RefreshRequest,
|
||||||
|
type RefreshResponse,
|
||||||
SendOtpRequest,
|
SendOtpRequest,
|
||||||
SendOtpResponse,
|
SendOtpResponse,
|
||||||
VerifyOtpRequest,
|
VerifyOtpRequest,
|
||||||
VerifyOtpResponse
|
VerifyOtpResponse
|
||||||
} from '@teacinema/contracts/gen/auth'
|
} from '@teacinema/contracts/gen/auth'
|
||||||
|
import { PassportService } from '@teacinema/passport'
|
||||||
|
|
||||||
|
import { AllConfigs } from '@/config'
|
||||||
import { OtpService } from '@/modules/otp/otp.service'
|
import { OtpService } from '@/modules/otp/otp.service'
|
||||||
|
|
||||||
import { AuthRepository } from './auth.repository'
|
import { AuthRepository } from './auth.repository'
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class AuthService {
|
export class AuthService {
|
||||||
|
private readonly ACCESS_TOKEN_TTL: number
|
||||||
|
private readonly REFRESH_TOKEN_TTL: number
|
||||||
|
|
||||||
public constructor(
|
public constructor(
|
||||||
|
private readonly configService: ConfigService<AllConfigs>,
|
||||||
private readonly authRepository: AuthRepository,
|
private readonly authRepository: AuthRepository,
|
||||||
private readonly otpService: OtpService
|
private readonly otpService: OtpService,
|
||||||
) {}
|
private readonly passportService: PassportService
|
||||||
|
) {
|
||||||
|
this.ACCESS_TOKEN_TTL = configService.get('passport.accessTtl', {
|
||||||
|
infer: true
|
||||||
|
})
|
||||||
|
this.REFRESH_TOKEN_TTL = configService.get('passport.refreshTtl', {
|
||||||
|
infer: true
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
public async sendOtp(data: SendOtpRequest): Promise<SendOtpResponse> {
|
public async sendOtp(data: SendOtpRequest): Promise<SendOtpResponse> {
|
||||||
const { identifier, type } = data
|
const { identifier, type } = data
|
||||||
@ -80,6 +97,39 @@ export class AuthService {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
return { accessToken: '123456', refreshToken: '123456' }
|
return this.generateTokens(account.id)
|
||||||
|
}
|
||||||
|
|
||||||
|
private generateTokens(userId: Account['id']) {
|
||||||
|
const payload = {
|
||||||
|
sub: userId,
|
||||||
|
iat: Date.now(),
|
||||||
|
exp: Date.now() + this.ACCESS_TOKEN_TTL
|
||||||
|
}
|
||||||
|
const accessToken = this.passportService.generate(
|
||||||
|
payload.sub,
|
||||||
|
this.ACCESS_TOKEN_TTL
|
||||||
|
)
|
||||||
|
const refreshToken = this.passportService.generate(
|
||||||
|
payload.sub,
|
||||||
|
this.REFRESH_TOKEN_TTL
|
||||||
|
)
|
||||||
|
|
||||||
|
return { accessToken, refreshToken }
|
||||||
|
}
|
||||||
|
|
||||||
|
public refresh(data: RefreshRequest): RefreshResponse {
|
||||||
|
const { refreshToken } = data
|
||||||
|
const result = this.passportService.verify(refreshToken)
|
||||||
|
|
||||||
|
if (!result.valid) {
|
||||||
|
throw new RpcException({
|
||||||
|
code: RpcStatus.UNAUTHENTICATED,
|
||||||
|
// @ts-ignore
|
||||||
|
details: result.reason
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.generateTokens(result.userId)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
45
yarn.lock
45
yarn.lock
@ -1066,6 +1066,17 @@
|
|||||||
load-esm "1.0.3"
|
load-esm "1.0.3"
|
||||||
tslib "2.8.1"
|
tslib "2.8.1"
|
||||||
|
|
||||||
|
"@nestjs/common@^11.1.12":
|
||||||
|
version "11.1.13"
|
||||||
|
resolved "https://registry.yarnpkg.com/@nestjs/common/-/common-11.1.13.tgz#3d4bcc2a593236546bc62f7801b0d4450b26a9ac"
|
||||||
|
integrity sha512-ieqWtipT+VlyDWLz5Rvz0f3E5rXcVAnaAi+D53DEHLjc1kmFxCgZ62qVfTX2vwkywwqNkTNXvBgGR72hYqV//Q==
|
||||||
|
dependencies:
|
||||||
|
uid "2.0.2"
|
||||||
|
file-type "21.3.0"
|
||||||
|
iterare "1.2.1"
|
||||||
|
load-esm "1.0.3"
|
||||||
|
tslib "2.8.1"
|
||||||
|
|
||||||
"@nestjs/config@^4.0.2":
|
"@nestjs/config@^4.0.2":
|
||||||
version "4.0.2"
|
version "4.0.2"
|
||||||
resolved "https://registry.yarnpkg.com/@nestjs/config/-/config-4.0.2.tgz#a2777a1fd2d0d594bab3953f50fbca95c14cce52"
|
resolved "https://registry.yarnpkg.com/@nestjs/config/-/config-4.0.2.tgz#a2777a1fd2d0d594bab3953f50fbca95c14cce52"
|
||||||
@ -1087,6 +1098,18 @@
|
|||||||
path-to-regexp "8.3.0"
|
path-to-regexp "8.3.0"
|
||||||
tslib "2.8.1"
|
tslib "2.8.1"
|
||||||
|
|
||||||
|
"@nestjs/core@^11.1.12":
|
||||||
|
version "11.1.13"
|
||||||
|
resolved "https://registry.yarnpkg.com/@nestjs/core/-/core-11.1.13.tgz#4444e124d255759d545a631f63e9d84fe1a1e3e5"
|
||||||
|
integrity sha512-Tq9EIKiC30EBL8hLK93tNqaToy0hzbuVGYt29V8NhkVJUsDzlmiVf6c3hSPtzx2krIUVbTgQ2KFeaxr72rEyzQ==
|
||||||
|
dependencies:
|
||||||
|
uid "2.0.2"
|
||||||
|
"@nuxt/opencollective" "0.4.1"
|
||||||
|
fast-safe-stringify "2.1.1"
|
||||||
|
iterare "1.2.1"
|
||||||
|
path-to-regexp "8.3.0"
|
||||||
|
tslib "2.8.1"
|
||||||
|
|
||||||
"@nestjs/mapped-types@*":
|
"@nestjs/mapped-types@*":
|
||||||
version "2.1.0"
|
version "2.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/@nestjs/mapped-types/-/mapped-types-2.1.0.tgz#b9b536b7c3571567aa1d0223db8baa1a51505a19"
|
resolved "https://registry.yarnpkg.com/@nestjs/mapped-types/-/mapped-types-2.1.0.tgz#b9b536b7c3571567aa1d0223db8baa1a51505a19"
|
||||||
@ -1355,14 +1378,14 @@
|
|||||||
integrity sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==
|
integrity sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==
|
||||||
|
|
||||||
"@teacinema/common@^1.0.0":
|
"@teacinema/common@^1.0.0":
|
||||||
version "1.0.0"
|
version "1.0.1"
|
||||||
resolved "https://git.ksv741.keenetic.pro/api/packages/teacinema/npm/%40teacinema%2Fcommon/-/1.0.0/common-1.0.0.tgz#3b79ae6eb46352ed1544535be094fe0ead244c36"
|
resolved "https://git.ksv741.keenetic.pro/api/packages/teacinema/npm/%40teacinema%2Fcommon/-/1.0.1/common-1.0.1.tgz#40ad9ced1522b53fa6e46d7f6797cc03193705ab"
|
||||||
integrity sha512-L006mySvhRpUlRHf3ONbXA0RG42gbQ9QAnmQuZx4zejHEsWB9702xe18MSYcBilv+lmYkQpiX/g3p8P7suLfqQ==
|
integrity sha512-q3DURJbSk3k8MNWFIYaSM4LEcBgPbWa+HJmBz/nzYT4kuYitJVSXxpZ97kr0Ea+81AZwAU3JhQKlkK0SBWUi0A==
|
||||||
|
|
||||||
"@teacinema/contracts@^1.0.0":
|
"@teacinema/contracts@^1.0.0":
|
||||||
version "1.0.4"
|
version "1.0.6"
|
||||||
resolved "https://git.ksv741.keenetic.pro/api/packages/teacinema/npm/%40teacinema%2Fcontracts/-/1.0.4/contracts-1.0.4.tgz#178dc6392aae52c4dc2b60bb1470a0a2885a8715"
|
resolved "https://git.ksv741.keenetic.pro/api/packages/teacinema/npm/%40teacinema%2Fcontracts/-/1.0.6/contracts-1.0.6.tgz#7aa97d4c3081b791908c90d2a12d771b5fb79bd5"
|
||||||
integrity sha512-3jHP4NAoH9munaN2Iegvg0X6KN/SR1rwZU7KpbuBtlcTJqsLljTaHwG+XKjEL84Y9b+sF73jGGbg/w2Y8IBQmw==
|
integrity sha512-2IU2S9hWtKeMpn4zRS9pJAaSryIODrRjS1q9QezQOXF6554vtQlMVr0fLVTGhNmXlbRfuje0f6HggApqPDFMaA==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@nestjs/microservices" "^11.1.12"
|
"@nestjs/microservices" "^11.1.12"
|
||||||
protoc "33.4.0"
|
protoc "33.4.0"
|
||||||
@ -1376,6 +1399,16 @@
|
|||||||
dependencies:
|
dependencies:
|
||||||
"@trivago/prettier-plugin-sort-imports" "^5.2.2"
|
"@trivago/prettier-plugin-sort-imports" "^5.2.2"
|
||||||
|
|
||||||
|
"@teacinema/passport@^1.0.0":
|
||||||
|
version "1.0.1"
|
||||||
|
resolved "https://git.ksv741.keenetic.pro/api/packages/teacinema/npm/%40teacinema%2Fpassport/-/1.0.1/passport-1.0.1.tgz#83a8a605534b23929d3b1090d28023626fd5cc9f"
|
||||||
|
integrity sha512-hgFHXtWgXOemAf9InBLuhHbtF8wS01HKmot0nSaUqGlQCtu74ArMMCG8mup1SR50UGz5DEpHPEL8G5CzVnTTSQ==
|
||||||
|
dependencies:
|
||||||
|
"@nestjs/common" "^11.1.12"
|
||||||
|
"@nestjs/core" "^11.1.12"
|
||||||
|
reflect-metadata "^0.2.2"
|
||||||
|
rxjs "^7.8.2"
|
||||||
|
|
||||||
"@tokenizer/inflate@^0.4.1":
|
"@tokenizer/inflate@^0.4.1":
|
||||||
version "0.4.1"
|
version "0.4.1"
|
||||||
resolved "https://registry.yarnpkg.com/@tokenizer/inflate/-/inflate-0.4.1.tgz#fa6cdb8366151b3cc8426bf9755c1ea03a2fba08"
|
resolved "https://registry.yarnpkg.com/@tokenizer/inflate/-/inflate-0.4.1.tgz#fa6cdb8366151b3cc8426bf9755c1ea03a2fba08"
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user