mirror of
https://github.com/IT4Change/gradido.git
synced 2026-02-06 09:56:05 +00:00
update with hiero changes and other changes
This commit is contained in:
parent
832f2f6ce5
commit
eb3bf5e904
@ -1,46 +1,7 @@
|
||||
import { Transaction as DbTransaction } from 'database'
|
||||
import { Decimal } from 'decimal.js-light'
|
||||
import { DataSource } from 'typeorm'
|
||||
|
||||
import { cleanDB, testEnvironment } from '@test/helpers'
|
||||
|
||||
import { CONFIG } from '@/config'
|
||||
import { LogError } from '@/server/LogError'
|
||||
|
||||
import { DltConnectorClient } from './DltConnectorClient'
|
||||
|
||||
let con: DataSource
|
||||
|
||||
let testEnv: {
|
||||
con: DataSource
|
||||
}
|
||||
|
||||
// Mock the GraphQLClient
|
||||
jest.mock('graphql-request', () => {
|
||||
const originalModule = jest.requireActual('graphql-request')
|
||||
|
||||
return {
|
||||
__esModule: true,
|
||||
...originalModule,
|
||||
GraphQLClient: jest.fn().mockImplementation((url: string) => {
|
||||
if (url === 'invalid') {
|
||||
throw new Error('invalid url')
|
||||
}
|
||||
return {
|
||||
// why not using mockResolvedValueOnce or mockReturnValueOnce?
|
||||
// I have tried, but it didn't work and return every time the first value
|
||||
request: jest.fn().mockImplementation(() => {
|
||||
return Promise.resolve({
|
||||
transmitTransaction: {
|
||||
succeed: true,
|
||||
},
|
||||
})
|
||||
}),
|
||||
}
|
||||
}),
|
||||
}
|
||||
})
|
||||
|
||||
describe('undefined DltConnectorClient', () => {
|
||||
it('invalid url', () => {
|
||||
CONFIG.DLT_CONNECTOR_URL = 'invalid'
|
||||
@ -58,90 +19,4 @@ describe('undefined DltConnectorClient', () => {
|
||||
})
|
||||
})
|
||||
|
||||
/*
|
||||
describe.skip('transmitTransaction, without db connection', () => {
|
||||
const transaction = new DbTransaction()
|
||||
transaction.typeId = 2 // Example transaction type ID
|
||||
transaction.amount = new Decimal('10.00') // Example amount
|
||||
transaction.balanceDate = new Date() // Example creation date
|
||||
transaction.id = 1 // Example transaction ID
|
||||
|
||||
it('cannot query for transaction id', async () => {
|
||||
const result = await DltConnectorClient.getInstance()?.transmitTransaction(transaction)
|
||||
expect(result).toBe(false)
|
||||
})
|
||||
})
|
||||
*/
|
||||
|
||||
describe('transmitTransaction', () => {
|
||||
beforeAll(async () => {
|
||||
testEnv = await testEnvironment()
|
||||
con = testEnv.con
|
||||
await cleanDB()
|
||||
})
|
||||
|
||||
afterAll(async () => {
|
||||
await cleanDB()
|
||||
await con.destroy()
|
||||
})
|
||||
|
||||
const transaction = new DbTransaction()
|
||||
transaction.typeId = 2 // Example transaction type ID
|
||||
transaction.amount = new Decimal('10.00') // Example amount
|
||||
transaction.balanceDate = new Date() // Example creation date
|
||||
transaction.id = 1 // Example transaction ID
|
||||
|
||||
// data needed to let save succeed
|
||||
transaction.memo = "I'm a dummy memo"
|
||||
transaction.userId = 1
|
||||
transaction.userGradidoID = 'dummy gradido id'
|
||||
|
||||
/*
|
||||
it.skip('cannot find transaction in db', async () => {
|
||||
const result = await DltConnectorClient.getInstance()?.transmitTransaction(transaction)
|
||||
expect(result).toBe(false)
|
||||
})
|
||||
*/
|
||||
|
||||
it('invalid transaction type', async () => {
|
||||
const localTransaction = new DbTransaction()
|
||||
localTransaction.typeId = 12
|
||||
try {
|
||||
await DltConnectorClient.getInstance()?.transmitTransaction(localTransaction)
|
||||
} catch (e) {
|
||||
expect(e).toMatchObject(
|
||||
new LogError(`invalid transaction type id: ${localTransaction.typeId.toString()}`),
|
||||
)
|
||||
}
|
||||
})
|
||||
|
||||
/*
|
||||
it.skip('should transmit the transaction and update the dltTransactionId in the database', async () => {
|
||||
await transaction.save()
|
||||
|
||||
const result = await DltConnectorClient.getInstance()?.transmitTransaction(transaction)
|
||||
expect(result).toBe(true)
|
||||
})
|
||||
|
||||
it.skip('invalid dltTransactionId (maximal 32 Bytes in Binary)', async () => {
|
||||
await transaction.save()
|
||||
|
||||
const result = await DltConnectorClient.getInstance()?.transmitTransaction(transaction)
|
||||
expect(result).toBe(false)
|
||||
})
|
||||
*/
|
||||
})
|
||||
|
||||
/*
|
||||
describe.skip('try transmitTransaction but graphql request failed', () => {
|
||||
it('graphql request should throw', async () => {
|
||||
const transaction = new DbTransaction()
|
||||
transaction.typeId = 2 // Example transaction type ID
|
||||
transaction.amount = new Decimal('10.00') // Example amount
|
||||
transaction.balanceDate = new Date() // Example creation date
|
||||
transaction.id = 1 // Example transaction ID
|
||||
const result = await DltConnectorClient.getInstance()?.transmitTransaction(transaction)
|
||||
expect(result).toBe(false)
|
||||
})
|
||||
})
|
||||
*/
|
||||
|
||||
@ -3,29 +3,10 @@ import { LOG4JS_BASE_CATEGORY_NAME } from '@/config/const'
|
||||
import { getLogger } from 'log4js'
|
||||
|
||||
import { TransactionDraft } from './model/TransactionDraft'
|
||||
import { TransactionResult } from './model/TransactionResult'
|
||||
import { GraphQLClient } from 'graphql-request'
|
||||
import { gql } from 'graphql-request'
|
||||
import { IRestResponse, RestClient } from 'typed-rest-client'
|
||||
|
||||
const logger = getLogger(`${LOG4JS_BASE_CATEGORY_NAME}.apis.dltConnector`)
|
||||
|
||||
const sendTransaction = gql`
|
||||
mutation ($input: TransactionDraft!) {
|
||||
sendTransaction(data: $input) {
|
||||
error {
|
||||
message
|
||||
name
|
||||
}
|
||||
succeed
|
||||
recipe {
|
||||
createdAt
|
||||
type
|
||||
messageIdHex
|
||||
}
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
// Source: https://refactoring.guru/design-patterns/singleton/typescript/example
|
||||
// and ../federation/client/FederationClientFactory.ts
|
||||
/**
|
||||
@ -35,7 +16,7 @@ const sendTransaction = gql`
|
||||
|
||||
export class DltConnectorClient {
|
||||
private static instance: DltConnectorClient
|
||||
client: GraphQLClient
|
||||
client: RestClient
|
||||
/**
|
||||
* The Singleton's constructor should always be private to prevent direct
|
||||
* construction calls with the `new` operator.
|
||||
@ -59,16 +40,12 @@ export class DltConnectorClient {
|
||||
}
|
||||
if (!DltConnectorClient.instance.client) {
|
||||
try {
|
||||
DltConnectorClient.instance.client = new GraphQLClient(CONFIG.DLT_CONNECTOR_URL, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
jsonSerializer: {
|
||||
parse: JSON.parse,
|
||||
stringify: JSON.stringify,
|
||||
},
|
||||
})
|
||||
DltConnectorClient.instance.client = new RestClient(
|
||||
'gradido-backend',
|
||||
CONFIG.DLT_CONNECTOR_URL,
|
||||
undefined,
|
||||
{ keepAlive: true }
|
||||
)
|
||||
} catch (e) {
|
||||
logger.error("couldn't connect to dlt-connector: ", e)
|
||||
return
|
||||
@ -78,16 +55,11 @@ export class DltConnectorClient {
|
||||
}
|
||||
|
||||
/**
|
||||
* transmit transaction via dlt-connector to iota
|
||||
* and update dltTransactionId of transaction in db with iota message id
|
||||
* transmit transaction via dlt-connector to hiero
|
||||
* and update dltTransactionId of transaction in db with hiero transaction id
|
||||
*/
|
||||
public async sendTransaction(input: TransactionDraft): Promise<TransactionResult | undefined> {
|
||||
public async sendTransaction(input: TransactionDraft): Promise<IRestResponse<string>> {
|
||||
logger.debug('transmit transaction or user to dlt connector', input)
|
||||
const {
|
||||
data: { sendTransaction: result },
|
||||
} = await this.client.rawRequest<{ sendTransaction: TransactionResult }>(sendTransaction, {
|
||||
input,
|
||||
})
|
||||
return result
|
||||
return await this.client.create<string>('/sendTransaction', input)
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,55 @@
|
||||
import { CONFIG } from '@/config'
|
||||
import { LOG4JS_BASE_CATEGORY_NAME } from '@/config/const'
|
||||
import { getLogger } from 'log4js'
|
||||
|
||||
import { TransactionDraft } from '@/apis/dltConnector/model/TransactionDraft'
|
||||
import { IRestResponse } from 'typed-rest-client'
|
||||
|
||||
const logger = getLogger(`${LOG4JS_BASE_CATEGORY_NAME}.apis.dltConnector`)
|
||||
|
||||
// Source: https://refactoring.guru/design-patterns/singleton/typescript/example
|
||||
// and ../federation/client/FederationClientFactory.ts
|
||||
/**
|
||||
* A Singleton class defines the `getInstance` method that lets clients access
|
||||
* the unique singleton instance.
|
||||
*/
|
||||
|
||||
export class DltConnectorClient {
|
||||
private static instance: DltConnectorClient
|
||||
/**
|
||||
* The Singleton's constructor should always be private to prevent direct
|
||||
* construction calls with the `new` operator.
|
||||
*/
|
||||
|
||||
private constructor() {}
|
||||
|
||||
/**
|
||||
* The static method that controls the access to the singleton instance.
|
||||
*
|
||||
* This implementation let you subclass the Singleton class while keeping
|
||||
* just one instance of each subclass around.
|
||||
*/
|
||||
public static getInstance(): DltConnectorClient | undefined {
|
||||
if (!CONFIG.DLT_CONNECTOR || !CONFIG.DLT_CONNECTOR_URL) {
|
||||
logger.info(`dlt-connector are disabled via config...`)
|
||||
return
|
||||
}
|
||||
if (!DltConnectorClient.instance) {
|
||||
DltConnectorClient.instance = new DltConnectorClient()
|
||||
}
|
||||
return DltConnectorClient.instance
|
||||
}
|
||||
|
||||
/**
|
||||
* transmit transaction via dlt-connector to hiero
|
||||
* and update dltTransactionId of transaction in db with hiero transaction id
|
||||
*/
|
||||
public async sendTransaction(input: TransactionDraft): Promise<IRestResponse<string>> {
|
||||
logger.debug('transmit transaction or user to dlt connector', input)
|
||||
return Promise.resolve({
|
||||
statusCode: 200,
|
||||
result: 'test',
|
||||
headers: {},
|
||||
})
|
||||
}
|
||||
}
|
||||
@ -3,8 +3,7 @@ import { ObjectLiteral, OrderByCondition, SelectQueryBuilder } from 'typeorm'
|
||||
import { DltTransaction } from 'database'
|
||||
|
||||
import { TransactionDraft } from '@dltConnector/model/TransactionDraft'
|
||||
import { getLogger, Logger } from 'log4js'
|
||||
import { LOG4JS_BASE_CATEGORY_NAME } from '@/config/const'
|
||||
import { Logger } from 'log4js'
|
||||
|
||||
export abstract class AbstractTransactionToDltRole<T extends ObjectLiteral> {
|
||||
protected self: T | null
|
||||
|
||||
@ -2,14 +2,14 @@ import { DltTransaction, TransactionLink } from 'database'
|
||||
|
||||
import { DltTransactionType } from '@dltConnector/enum/DltTransactionType'
|
||||
import { TransactionType } from '@dltConnector/enum/TransactionType'
|
||||
import { CommunityUser } from '@dltConnector/model/CommunityUser'
|
||||
import { IdentifierSeed } from '@dltConnector/model/IdentifierSeed'
|
||||
import { TransactionDraft } from '@dltConnector/model/TransactionDraft'
|
||||
import { UserIdentifier } from '@dltConnector/model/UserIdentifier'
|
||||
import { AccountIdentifier } from '@dltConnector/model/AccountIdentifier'
|
||||
|
||||
import { LogError } from '@/server/LogError'
|
||||
|
||||
import { AbstractTransactionToDltRole } from './AbstractTransactionToDlt.role'
|
||||
import { CommunityAccountIdentifier } from '@dltConnector/model/CommunityAccountIdentifier'
|
||||
|
||||
/**
|
||||
* redeem deferred transfer transaction by creator, so "deleting" it
|
||||
@ -17,7 +17,10 @@ import { AbstractTransactionToDltRole } from './AbstractTransactionToDlt.role'
|
||||
export class TransactionLinkDeleteToDltRole extends AbstractTransactionToDltRole<TransactionLink> {
|
||||
async initWithLast(): Promise<this> {
|
||||
const queryBuilder = this.createQueryForPendingItems(
|
||||
TransactionLink.createQueryBuilder().leftJoinAndSelect('TransactionLink.user', 'user'),
|
||||
TransactionLink
|
||||
.createQueryBuilder()
|
||||
.leftJoinAndSelect('TransactionLink.user', 'user')
|
||||
.leftJoinAndSelect('user.community', 'community'),
|
||||
'TransactionLink.id = dltTransaction.transactionLinkId and dltTransaction.type_id <> 4',
|
||||
// eslint-disable-next-line camelcase
|
||||
{ TransactionLink_deletedAt: 'ASC', User_id: 'ASC' },
|
||||
@ -67,8 +70,15 @@ export class TransactionLinkDeleteToDltRole extends AbstractTransactionToDltRole
|
||||
const draft = new TransactionDraft()
|
||||
draft.amount = this.self.amount.abs().toString()
|
||||
const user = this.self.user
|
||||
draft.user = new UserIdentifier(user.communityUuid, new IdentifierSeed(this.self.code))
|
||||
draft.linkedUser = new UserIdentifier(user.communityUuid, new CommunityUser(user.gradidoID, 1))
|
||||
if (!user.community) {
|
||||
throw new LogError(`missing community for user ${user.id}`)
|
||||
}
|
||||
const topicId = user.community.hieroTopicId
|
||||
if (!topicId) {
|
||||
throw new LogError(`missing topicId for community ${user.community.id}`)
|
||||
}
|
||||
draft.user = new AccountIdentifier(topicId, new IdentifierSeed(this.self.code))
|
||||
draft.linkedUser = new AccountIdentifier(topicId, new CommunityAccountIdentifier(user.gradidoID))
|
||||
draft.createdAt = this.self.deletedAt.toISOString()
|
||||
draft.type = TransactionType.GRADIDO_REDEEM_DEFERRED_TRANSFER
|
||||
return draft
|
||||
|
||||
@ -2,14 +2,14 @@ import { DltTransaction, TransactionLink } from 'database'
|
||||
|
||||
import { DltTransactionType } from '@dltConnector/enum/DltTransactionType'
|
||||
import { TransactionType } from '@dltConnector/enum/TransactionType'
|
||||
import { CommunityUser } from '@dltConnector/model/CommunityUser'
|
||||
import { IdentifierSeed } from '@dltConnector/model/IdentifierSeed'
|
||||
import { TransactionDraft } from '@dltConnector/model/TransactionDraft'
|
||||
import { UserIdentifier } from '@dltConnector/model/UserIdentifier'
|
||||
import { AccountIdentifier } from '@dltConnector/model/AccountIdentifier'
|
||||
|
||||
import { LogError } from '@/server/LogError'
|
||||
|
||||
import { AbstractTransactionToDltRole } from './AbstractTransactionToDlt.role'
|
||||
import { CommunityAccountIdentifier } from '../../model/CommunityAccountIdentifier'
|
||||
|
||||
/**
|
||||
* send transactionLink as Deferred Transfers
|
||||
@ -17,7 +17,10 @@ import { AbstractTransactionToDltRole } from './AbstractTransactionToDlt.role'
|
||||
export class TransactionLinkToDltRole extends AbstractTransactionToDltRole<TransactionLink> {
|
||||
async initWithLast(): Promise<this> {
|
||||
this.self = await this.createQueryForPendingItems(
|
||||
TransactionLink.createQueryBuilder().leftJoinAndSelect('TransactionLink.user', 'user'),
|
||||
TransactionLink
|
||||
.createQueryBuilder()
|
||||
.leftJoinAndSelect('TransactionLink.user', 'user')
|
||||
.leftJoinAndSelect('user.community', 'community'),
|
||||
'TransactionLink.id = dltTransaction.transactionLinkId',
|
||||
// eslint-disable-next-line camelcase
|
||||
{ TransactionLink_createdAt: 'ASC', User_id: 'ASC' },
|
||||
@ -39,8 +42,15 @@ export class TransactionLinkToDltRole extends AbstractTransactionToDltRole<Trans
|
||||
const draft = new TransactionDraft()
|
||||
draft.amount = this.self.amount.abs().toString()
|
||||
const user = this.self.user
|
||||
draft.user = new UserIdentifier(user.communityUuid, new CommunityUser(user.gradidoID, 1))
|
||||
draft.linkedUser = new UserIdentifier(user.communityUuid, new IdentifierSeed(this.self.code))
|
||||
if (!user.community) {
|
||||
throw new LogError(`missing community for user ${user.id}`)
|
||||
}
|
||||
const topicId = user.community.hieroTopicId
|
||||
if (!topicId) {
|
||||
throw new LogError(`missing topicId for community ${user.community.id}`)
|
||||
}
|
||||
draft.user = new AccountIdentifier(topicId, new CommunityAccountIdentifier(user.gradidoID, 1))
|
||||
draft.linkedUser = new AccountIdentifier(topicId, new IdentifierSeed(this.self.code))
|
||||
draft.createdAt = this.self.createdAt.toISOString()
|
||||
draft.timeoutDuration = (this.self.validUntil.getTime() - this.self.createdAt.getTime()) / 1000
|
||||
draft.memo = this.self.memo
|
||||
|
||||
@ -5,7 +5,7 @@ import { TransactionType } from '@dltConnector/enum/TransactionType'
|
||||
import { CommunityUser } from '@dltConnector/model/CommunityUser'
|
||||
import { IdentifierSeed } from '@dltConnector/model/IdentifierSeed'
|
||||
import { TransactionDraft } from '@dltConnector/model/TransactionDraft'
|
||||
import { UserIdentifier } from '@dltConnector/model/UserIdentifier'
|
||||
import { UserIdentifier } from '@/apis/dltConnector/model/AccountIdentifier'
|
||||
|
||||
import { TransactionTypeId } from '@/graphql/enum/TransactionTypeId'
|
||||
import { LogError } from '@/server/LogError'
|
||||
|
||||
@ -3,13 +3,13 @@ import { DltTransaction, User } from 'database'
|
||||
import { AccountType } from '@dltConnector/enum/AccountType'
|
||||
import { DltTransactionType } from '@dltConnector/enum/DltTransactionType'
|
||||
import { TransactionType } from '@dltConnector/enum/TransactionType'
|
||||
import { CommunityUser } from '@dltConnector/model/CommunityUser'
|
||||
import { TransactionDraft } from '@dltConnector/model/TransactionDraft'
|
||||
import { UserIdentifier } from '@dltConnector/model/UserIdentifier'
|
||||
import { AccountIdentifier } from '@/apis/dltConnector/model/AccountIdentifier'
|
||||
|
||||
import { LogError } from '@/server/LogError'
|
||||
|
||||
import { AbstractTransactionToDltRole } from './AbstractTransactionToDlt.role'
|
||||
import { CommunityAccountIdentifier } from '../../model/CommunityAccountIdentifier'
|
||||
|
||||
/**
|
||||
* send new user to dlt connector, will be made to RegisterAddress Transaction
|
||||
@ -17,7 +17,7 @@ import { AbstractTransactionToDltRole } from './AbstractTransactionToDlt.role'
|
||||
export class UserToDltRole extends AbstractTransactionToDltRole<User> {
|
||||
async initWithLast(): Promise<this> {
|
||||
this.self = await this.createQueryForPendingItems(
|
||||
User.createQueryBuilder(),
|
||||
User.createQueryBuilder().leftJoinAndSelect('User.community', 'community'),
|
||||
'User.id = dltTransaction.userId',
|
||||
// eslint-disable-next-line camelcase
|
||||
{ User_created_at: 'ASC', User_id: 'ASC' },
|
||||
@ -36,8 +36,15 @@ export class UserToDltRole extends AbstractTransactionToDltRole<User> {
|
||||
if (!this.self) {
|
||||
throw new LogError('try to create dlt entry for empty transaction')
|
||||
}
|
||||
if (!this.self.community) {
|
||||
throw new LogError(`missing community for user ${this.self.id}`)
|
||||
}
|
||||
const topicId = this.self.community.hieroTopicId
|
||||
if (!topicId) {
|
||||
throw new LogError(`missing topicId for community ${this.self.community.id}`)
|
||||
}
|
||||
const draft = new TransactionDraft()
|
||||
draft.user = new UserIdentifier(this.self.communityUuid, new CommunityUser(this.self.gradidoID))
|
||||
draft.user = new AccountIdentifier(topicId, new CommunityAccountIdentifier(this.self.gradidoID))
|
||||
draft.createdAt = this.self.createdAt.toISOString()
|
||||
draft.accountType = AccountType.COMMUNITY_HUMAN
|
||||
draft.type = TransactionType.REGISTER_ADDRESS
|
||||
|
||||
@ -1,14 +1,13 @@
|
||||
import { Transaction, TransactionLink, User } from 'database'
|
||||
|
||||
import { DltConnectorClient } from '@/apis/dltConnector/DltConnectorClient'
|
||||
import { TransactionResult } from '@/apis/dltConnector/model/TransactionResult'
|
||||
|
||||
import { AbstractTransactionToDltRole } from './AbstractTransactionToDlt.role'
|
||||
import { TransactionLinkDeleteToDltRole } from './TransactionLinkDeleteToDlt.role'
|
||||
import { TransactionLinkToDltRole } from './TransactionLinkToDlt.role'
|
||||
import { TransactionToDltRole } from './TransactionToDlt.role'
|
||||
import { UserToDltRole } from './UserToDlt.role'
|
||||
import { getLogger } from 'log4js'
|
||||
import { getLogger, Logger } from 'log4js'
|
||||
import { LOG4JS_BASE_CATEGORY_NAME } from '@/config/const'
|
||||
|
||||
/**
|
||||
@ -16,10 +15,9 @@ import { LOG4JS_BASE_CATEGORY_NAME } from '@/config/const'
|
||||
* Context for sending transactions to dlt connector, always the oldest not sended transaction first
|
||||
*/
|
||||
export async function transactionToDlt(dltConnector: DltConnectorClient): Promise<void> {
|
||||
async function findNextPendingTransaction(): Promise<
|
||||
async function findNextPendingTransaction(logger: Logger): Promise<
|
||||
AbstractTransactionToDltRole<Transaction | User | TransactionLink>
|
||||
> {
|
||||
const logger = getLogger(`${LOG4JS_BASE_CATEGORY_NAME}/apis/dltConnector/interaction/transactionToDlt`)
|
||||
// collect each oldest not sended entity from db and choose oldest
|
||||
const results = await Promise.all([
|
||||
new TransactionToDltRole(logger).initWithLast(),
|
||||
@ -34,18 +32,28 @@ export async function transactionToDlt(dltConnector: DltConnectorClient): Promis
|
||||
})
|
||||
return results[0]
|
||||
}
|
||||
|
||||
const logger = getLogger(`${LOG4JS_BASE_CATEGORY_NAME}.apis.dltConnector.interaction.transactionToDlt`)
|
||||
while (true) {
|
||||
const pendingTransactionRole = await findNextPendingTransaction()
|
||||
const pendingTransactionRole = await findNextPendingTransaction(logger)
|
||||
const pendingTransaction = pendingTransactionRole.getEntity()
|
||||
if (!pendingTransaction) {
|
||||
break
|
||||
}
|
||||
let messageId = ''
|
||||
let error: string | null = null
|
||||
let result: TransactionResult | undefined
|
||||
try {
|
||||
result = await dltConnector.sendTransaction(pendingTransactionRole.convertToGraphqlInput())
|
||||
const result = await dltConnector.sendTransaction(
|
||||
pendingTransactionRole.convertToGraphqlInput()
|
||||
)
|
||||
if (result.statusCode === 200 && result.result) {
|
||||
messageId = result.result
|
||||
} else {
|
||||
error = `empty result with status code ${result.statusCode}`
|
||||
logger.error('error from dlt-connector', result)
|
||||
}
|
||||
} catch (e) {
|
||||
logger.debug(e)
|
||||
if (e instanceof Error) {
|
||||
error = e.message
|
||||
} else if (typeof e === 'string') {
|
||||
@ -54,13 +62,6 @@ export async function transactionToDlt(dltConnector: DltConnectorClient): Promis
|
||||
throw e
|
||||
}
|
||||
}
|
||||
if (result?.succeed && result.recipe) {
|
||||
messageId = result.recipe.messageIdHex
|
||||
} else if (result?.error) {
|
||||
error = result.error.message
|
||||
logger.error('error from dlt-connector', result.error)
|
||||
}
|
||||
|
||||
await pendingTransactionRole.saveTransactionResult(messageId, error)
|
||||
}
|
||||
}
|
||||
|
||||
17
backend/src/apis/dltConnector/model/AccountIdentifier.ts
Normal file
17
backend/src/apis/dltConnector/model/AccountIdentifier.ts
Normal file
@ -0,0 +1,17 @@
|
||||
import { CommunityAccountIdentifier } from './CommunityAccountIdentifier'
|
||||
import { IdentifierSeed } from './IdentifierSeed'
|
||||
|
||||
export class AccountIdentifier {
|
||||
communityTopicId: string
|
||||
account?: CommunityAccountIdentifier
|
||||
seed?: IdentifierSeed // used for deferred transfers
|
||||
|
||||
constructor(communityTopicId: string, input: CommunityAccountIdentifier | IdentifierSeed) {
|
||||
if (input instanceof CommunityAccountIdentifier) {
|
||||
this.account = input
|
||||
} else if (input instanceof IdentifierSeed) {
|
||||
this.seed = input
|
||||
}
|
||||
this.communityTopicId = communityTopicId
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,10 @@
|
||||
export class CommunityAccountIdentifier {
|
||||
// for community user, uuid and communityUuid used
|
||||
userUuid: string
|
||||
accountNr?: number
|
||||
|
||||
constructor(userUuid: string, accountNr?: number) {
|
||||
this.userUuid = userUuid
|
||||
this.accountNr = accountNr
|
||||
}
|
||||
}
|
||||
@ -1,10 +0,0 @@
|
||||
export class CommunityUser {
|
||||
// for community user, uuid and communityUuid used
|
||||
uuid: string
|
||||
accountNr?: number
|
||||
|
||||
constructor(uuid: string, accountNr?: number) {
|
||||
this.uuid = uuid
|
||||
this.accountNr = accountNr
|
||||
}
|
||||
}
|
||||
@ -2,12 +2,12 @@
|
||||
import { AccountType } from '@dltConnector/enum/AccountType'
|
||||
import { TransactionType } from '@dltConnector/enum/TransactionType'
|
||||
|
||||
import { UserIdentifier } from './UserIdentifier'
|
||||
import { AccountIdentifier } from './AccountIdentifier'
|
||||
|
||||
export class TransactionDraft {
|
||||
user: UserIdentifier
|
||||
user: AccountIdentifier
|
||||
// not used for simply register address
|
||||
linkedUser?: UserIdentifier
|
||||
linkedUser?: AccountIdentifier
|
||||
// not used for register address
|
||||
amount?: string
|
||||
memo?: string
|
||||
|
||||
@ -1,7 +0,0 @@
|
||||
import { TransactionErrorType } from '@dltConnector/enum/TransactionErrorType'
|
||||
|
||||
export interface TransactionError {
|
||||
type: TransactionErrorType
|
||||
message: string
|
||||
name: string
|
||||
}
|
||||
@ -1,7 +0,0 @@
|
||||
import { TransactionType } from '@dltConnector/enum/TransactionType'
|
||||
|
||||
export interface TransactionRecipe {
|
||||
createdAt: string
|
||||
type: TransactionType
|
||||
messageIdHex: string
|
||||
}
|
||||
@ -1,8 +0,0 @@
|
||||
import { TransactionError } from './TransactionError'
|
||||
import { TransactionRecipe } from './TransactionRecipe'
|
||||
|
||||
export interface TransactionResult {
|
||||
error?: TransactionError
|
||||
recipe?: TransactionRecipe
|
||||
succeed: boolean
|
||||
}
|
||||
@ -1,17 +0,0 @@
|
||||
import { CommunityUser } from './CommunityUser'
|
||||
import { IdentifierSeed } from './IdentifierSeed'
|
||||
|
||||
export class UserIdentifier {
|
||||
communityUuid: string
|
||||
communityUser?: CommunityUser
|
||||
seed?: IdentifierSeed // used for deferred transfers
|
||||
|
||||
constructor(communityUuid: string, input: CommunityUser | IdentifierSeed) {
|
||||
if (input instanceof CommunityUser) {
|
||||
this.communityUser = input
|
||||
} else if (input instanceof IdentifierSeed) {
|
||||
this.seed = input
|
||||
}
|
||||
this.communityUuid = communityUuid
|
||||
}
|
||||
}
|
||||
@ -1,9 +1,5 @@
|
||||
import { ApolloServerTestClient } from 'apollo-server-testing'
|
||||
import { Community, DltTransaction, Transaction } from 'database'
|
||||
import { Decimal } from 'decimal.js-light'
|
||||
// import { GraphQLClient } from 'graphql-request'
|
||||
// import { Response } from 'graphql-request/dist/types'
|
||||
import { GraphQLClient } from 'graphql-request'
|
||||
import { Response } from 'graphql-request/dist/types'
|
||||
import { DataSource } from 'typeorm'
|
||||
import { v4 as uuidv4 } from 'uuid'
|
||||
@ -15,11 +11,11 @@ import { CONFIG } from '@/config'
|
||||
import { TransactionTypeId } from '@/graphql/enum/TransactionTypeId'
|
||||
import { creations } from '@/seeds/creation'
|
||||
import { creationFactory } from '@/seeds/factory/creation'
|
||||
import { userFactory } from '@/seeds/factory/user'
|
||||
import { bibiBloxberg } from '@/seeds/users/bibi-bloxberg'
|
||||
import { bobBaumeister } from '@/seeds/users/bob-baumeister'
|
||||
import { peterLustig } from '@/seeds/users/peter-lustig'
|
||||
import { raeuberHotzenplotz } from '@/seeds/users/raeuber-hotzenplotz'
|
||||
import { userFactory } from 'database/src/seeds/factory/user'
|
||||
import { bibiBloxberg } from 'database/src/seeds/users/bibi-bloxberg'
|
||||
import { bobBaumeister } from 'database/src/seeds/users/bob-baumeister'
|
||||
import { peterLustig } from 'database/src/seeds/users/peter-lustig'
|
||||
import { raeuberHotzenplotz } from 'database/src/seeds/users/raeuber-hotzenplotz'
|
||||
import { getLogger } from 'config-schema/test/testSetup'
|
||||
import { LOG4JS_BASE_CATEGORY_NAME } from '@/config/const'
|
||||
|
||||
@ -31,63 +27,6 @@ const logger = getLogger(
|
||||
`${LOG4JS_BASE_CATEGORY_NAME}.graphql.resolver.util.sendTransactionsToDltConnector`,
|
||||
)
|
||||
|
||||
/*
|
||||
// Mock the GraphQLClient
|
||||
jest.mock('graphql-request', () => {
|
||||
const originalModule = jest.requireActual('graphql-request')
|
||||
|
||||
let testCursor = 0
|
||||
|
||||
return {
|
||||
__esModule: true,
|
||||
...originalModule,
|
||||
GraphQLClient: jest.fn().mockImplementation((url: string) => {
|
||||
if (url === 'invalid') {
|
||||
throw new Error('invalid url')
|
||||
}
|
||||
return {
|
||||
// why not using mockResolvedValueOnce or mockReturnValueOnce?
|
||||
// I have tried, but it didn't work and return every time the first value
|
||||
request: jest.fn().mockImplementation(() => {
|
||||
testCursor++
|
||||
if (testCursor === 4) {
|
||||
return Promise.resolve(
|
||||
// invalid, is 33 Bytes long as binary
|
||||
{
|
||||
transmitTransaction: {
|
||||
dltTransactionIdHex:
|
||||
'723e3fab62c5d3e2f62fd72ba4e622bcd53eff35262e3f3526327fe41bc516212A',
|
||||
},
|
||||
},
|
||||
)
|
||||
} else if (testCursor === 5) {
|
||||
throw Error('Connection error')
|
||||
} else {
|
||||
return Promise.resolve(
|
||||
// valid, is 32 Bytes long as binary
|
||||
{
|
||||
transmitTransaction: {
|
||||
dltTransactionIdHex:
|
||||
'723e3fab62c5d3e2f62fd72ba4e622bcd53eff35262e3f3526327fe41bc51621',
|
||||
},
|
||||
},
|
||||
)
|
||||
}
|
||||
}),
|
||||
}
|
||||
}),
|
||||
}
|
||||
})
|
||||
let mutate: ApolloServerTestClient['mutate'],
|
||||
query: ApolloServerTestClient['query'],
|
||||
con: Connection
|
||||
let testEnv: {
|
||||
mutate: ApolloServerTestClient['mutate']
|
||||
query: ApolloServerTestClient['query']
|
||||
con: Connection
|
||||
}
|
||||
*/
|
||||
|
||||
async function createHomeCommunity(): Promise<Community> {
|
||||
const homeCommunity = Community.create()
|
||||
homeCommunity.foreign = false
|
||||
@ -336,8 +275,6 @@ async function createTxReceive1FromSend3(verified: boolean): Promise<Transaction
|
||||
|
||||
let con: DataSource
|
||||
let testEnv: {
|
||||
mutate: ApolloServerTestClient['mutate']
|
||||
query: ApolloServerTestClient['query']
|
||||
con: DataSource
|
||||
}
|
||||
|
||||
@ -446,14 +383,6 @@ describe('create and send Transactions to DltConnector', () => {
|
||||
|
||||
CONFIG.DLT_CONNECTOR = true
|
||||
|
||||
jest.spyOn(GraphQLClient.prototype, 'rawRequest').mockImplementation(async () => {
|
||||
return {
|
||||
data: {
|
||||
sendTransaction: { succeed: true },
|
||||
},
|
||||
} as Response<unknown>
|
||||
})
|
||||
|
||||
await sendTransactionsToDltConnector()
|
||||
|
||||
expect(logger.info).toBeCalledWith('sendTransactionsToDltConnector...')
|
||||
|
||||
@ -16,7 +16,7 @@ import { transactionToDlt } from './interaction/transactionToDlt/transactionToDl
|
||||
import { getLogger } from 'log4js'
|
||||
import { LOG4JS_BASE_CATEGORY_NAME } from '@/config/const'
|
||||
|
||||
const logger = getLogger(`${LOG4JS_BASE_CATEGORY_NAME}/apis/dltConnector/sendTransactionsToDltConnector`)
|
||||
const logger = getLogger(`${LOG4JS_BASE_CATEGORY_NAME}.apis.dltConnector.sendTransactionsToDltConnector`)
|
||||
|
||||
let isLoopRunning = true
|
||||
|
||||
|
||||
8
bun.lock
8
bun.lock
@ -113,10 +113,10 @@
|
||||
"await-semaphore": "^0.1.3",
|
||||
"axios": "^0.21.1",
|
||||
"class-validator": "^0.13.1",
|
||||
"config-schema": "workspace:*",
|
||||
"core": "workspace:*",
|
||||
"config-schema": "*",
|
||||
"core": "*",
|
||||
"cors": "^2.8.5",
|
||||
"database": "workspace:*",
|
||||
"database": "*",
|
||||
"decimal.js-light": "^2.5.1",
|
||||
"dotenv": "^10.0.0",
|
||||
"esbuild": "^0.25.2",
|
||||
@ -146,7 +146,7 @@
|
||||
"random-bigint": "^0.0.1",
|
||||
"reflect-metadata": "^0.1.13",
|
||||
"regenerator-runtime": "^0.14.1",
|
||||
"shared": "workspace:*",
|
||||
"shared": "*",
|
||||
"source-map-support": "^0.5.21",
|
||||
"ts-jest": "29.4.0",
|
||||
"ts-node": "^10.9.2",
|
||||
|
||||
@ -1,36 +0,0 @@
|
||||
import { BaseEntity, Entity, PrimaryGeneratedColumn, Column, OneToOne, JoinColumn } from 'typeorm'
|
||||
import { Transaction } from '../Transaction'
|
||||
|
||||
@Entity('dlt_transactions', { engine: 'InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci' })
|
||||
export class DltTransaction extends BaseEntity {
|
||||
@PrimaryGeneratedColumn('increment', { unsigned: true })
|
||||
id: number
|
||||
|
||||
@Column({ name: 'transaction_id', type: 'int', unsigned: true, nullable: false })
|
||||
transactionId: number
|
||||
|
||||
@Column({
|
||||
name: 'message_id',
|
||||
length: 64,
|
||||
nullable: true,
|
||||
default: null,
|
||||
collation: 'utf8mb4_unicode_ci',
|
||||
})
|
||||
messageId: string
|
||||
|
||||
@Column({ name: 'verified', type: 'bool', nullable: false, default: false })
|
||||
verified: boolean
|
||||
|
||||
@Column({ name: 'created_at', default: () => 'CURRENT_TIMESTAMP(3)', nullable: false })
|
||||
createdAt: Date
|
||||
|
||||
@Column({ name: 'verified_at', nullable: true, default: null, type: 'datetime' })
|
||||
verifiedAt: Date | null
|
||||
|
||||
@Column({ name: 'error', type: 'text', nullable: true })
|
||||
error: string | null
|
||||
|
||||
@OneToOne(() => Transaction, (transaction) => transaction.dltTransaction)
|
||||
@JoinColumn({ name: 'transaction_id' })
|
||||
transaction?: Transaction | null
|
||||
}
|
||||
@ -1,37 +0,0 @@
|
||||
import { BaseEntity, Entity, PrimaryGeneratedColumn, Column, OneToOne, JoinColumn } from 'typeorm'
|
||||
// this Entity was removed in current code and isn't any longer compatible with user
|
||||
import { User } from './User'
|
||||
|
||||
@Entity('dlt_users', { engine: 'InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci' })
|
||||
export class DltUser extends BaseEntity {
|
||||
@PrimaryGeneratedColumn('increment', { unsigned: true })
|
||||
id: number
|
||||
|
||||
@Column({ name: 'user_id', type: 'int', unsigned: true, nullable: false })
|
||||
userId: number
|
||||
|
||||
@Column({
|
||||
name: 'message_id',
|
||||
length: 64,
|
||||
nullable: true,
|
||||
default: null,
|
||||
collation: 'utf8mb4_unicode_ci',
|
||||
})
|
||||
messageId: string
|
||||
|
||||
@Column({ name: 'verified', type: 'bool', nullable: false, default: false })
|
||||
verified: boolean
|
||||
|
||||
@Column({ name: 'created_at', default: () => 'CURRENT_TIMESTAMP(3)', nullable: false })
|
||||
createdAt: Date
|
||||
|
||||
@Column({ name: 'verified_at', nullable: true, default: null, type: 'datetime' })
|
||||
verifiedAt: Date | null
|
||||
|
||||
@Column({ name: 'error', type: 'text', nullable: true })
|
||||
error: string | null
|
||||
|
||||
@OneToOne(() => User, (user) => user.dltUser)
|
||||
@JoinColumn({ name: 'user_id' })
|
||||
user?: User | null
|
||||
}
|
||||
@ -1,182 +0,0 @@
|
||||
import {
|
||||
BaseEntity,
|
||||
Entity,
|
||||
PrimaryGeneratedColumn,
|
||||
Column,
|
||||
DeleteDateColumn,
|
||||
OneToMany,
|
||||
JoinColumn,
|
||||
OneToOne,
|
||||
Geometry,
|
||||
ManyToOne,
|
||||
} from 'typeorm'
|
||||
import { Contribution } from '../Contribution'
|
||||
import { ContributionMessage } from '../ContributionMessage'
|
||||
import { UserContact } from '../UserContact'
|
||||
import { UserRole } from '../UserRole'
|
||||
import { GeometryTransformer } from '../../src/typeorm/GeometryTransformer'
|
||||
import { Community } from '../Community'
|
||||
// removed in current version
|
||||
import { DltUser } from './DltUser'
|
||||
|
||||
@Entity('users', { engine: 'InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci' })
|
||||
export class User extends BaseEntity {
|
||||
@PrimaryGeneratedColumn('increment', { unsigned: true })
|
||||
id: number
|
||||
|
||||
@Column({ type: 'bool', default: false })
|
||||
foreign: boolean
|
||||
|
||||
@Column({
|
||||
name: 'gradido_id',
|
||||
length: 36,
|
||||
nullable: false,
|
||||
collation: 'utf8mb4_unicode_ci',
|
||||
})
|
||||
gradidoID: string
|
||||
|
||||
@Column({
|
||||
name: 'community_uuid',
|
||||
type: 'char',
|
||||
length: 36,
|
||||
nullable: true,
|
||||
collation: 'utf8mb4_unicode_ci',
|
||||
})
|
||||
communityUuid: string
|
||||
|
||||
@ManyToOne(() => Community, (community) => community.users)
|
||||
@JoinColumn({ name: 'community_uuid', referencedColumnName: 'communityUuid' })
|
||||
community: Community | null
|
||||
|
||||
@Column({
|
||||
name: 'alias',
|
||||
length: 20,
|
||||
nullable: true,
|
||||
default: null,
|
||||
collation: 'utf8mb4_unicode_ci',
|
||||
})
|
||||
alias: string
|
||||
|
||||
@OneToOne(() => UserContact, (emailContact: UserContact) => emailContact.user)
|
||||
@JoinColumn({ name: 'email_id' })
|
||||
emailContact: UserContact
|
||||
|
||||
@Column({ name: 'email_id', type: 'int', unsigned: true, nullable: true, default: null })
|
||||
emailId: number | null
|
||||
|
||||
@Column({
|
||||
name: 'first_name',
|
||||
length: 255,
|
||||
nullable: true,
|
||||
default: null,
|
||||
collation: 'utf8mb4_unicode_ci',
|
||||
})
|
||||
firstName: string
|
||||
|
||||
@Column({
|
||||
name: 'last_name',
|
||||
length: 255,
|
||||
nullable: true,
|
||||
default: null,
|
||||
collation: 'utf8mb4_unicode_ci',
|
||||
})
|
||||
lastName: string
|
||||
|
||||
@Column({ name: 'gms_publish_name', type: 'int', unsigned: true, nullable: false, default: 0 })
|
||||
gmsPublishName: number
|
||||
|
||||
@Column({ name: 'humhub_publish_name', type: 'int', unsigned: true, nullable: false, default: 0 })
|
||||
humhubPublishName: number
|
||||
|
||||
@Column({ name: 'created_at', default: () => 'CURRENT_TIMESTAMP(3)', nullable: false })
|
||||
createdAt: Date
|
||||
|
||||
@DeleteDateColumn({ name: 'deleted_at', nullable: true })
|
||||
deletedAt: Date | null
|
||||
|
||||
@Column({ type: 'bigint', default: 0, unsigned: true })
|
||||
password: BigInt
|
||||
|
||||
@Column({
|
||||
name: 'password_encryption_type',
|
||||
type: 'int',
|
||||
unsigned: true,
|
||||
nullable: false,
|
||||
default: 0,
|
||||
})
|
||||
passwordEncryptionType: number
|
||||
|
||||
@Column({ length: 4, default: 'de', collation: 'utf8mb4_unicode_ci', nullable: false })
|
||||
language: string
|
||||
|
||||
@Column({ type: 'bool', default: false })
|
||||
hideAmountGDD: boolean
|
||||
|
||||
@Column({ type: 'bool', default: false })
|
||||
hideAmountGDT: boolean
|
||||
|
||||
@OneToMany(() => UserRole, (userRole) => userRole.user)
|
||||
@JoinColumn({ name: 'user_id' })
|
||||
userRoles: UserRole[]
|
||||
|
||||
@Column({ name: 'referrer_id', type: 'int', unsigned: true, nullable: true, default: null })
|
||||
referrerId?: number | null
|
||||
|
||||
@Column({
|
||||
name: 'contribution_link_id',
|
||||
type: 'int',
|
||||
unsigned: true,
|
||||
nullable: true,
|
||||
default: null,
|
||||
})
|
||||
contributionLinkId?: number | null
|
||||
|
||||
@Column({ name: 'publisher_id', default: 0 })
|
||||
publisherId: number
|
||||
|
||||
@Column({ name: 'gms_allowed', type: 'bool', default: true })
|
||||
gmsAllowed: boolean
|
||||
|
||||
@Column({
|
||||
name: 'location',
|
||||
type: 'geometry',
|
||||
default: null,
|
||||
nullable: true,
|
||||
transformer: GeometryTransformer,
|
||||
})
|
||||
location: Geometry | null
|
||||
|
||||
@Column({
|
||||
name: 'gms_publish_location',
|
||||
type: 'int',
|
||||
unsigned: true,
|
||||
nullable: false,
|
||||
default: 2,
|
||||
})
|
||||
gmsPublishLocation: number
|
||||
|
||||
@Column({ name: 'gms_registered', type: 'bool', default: false })
|
||||
gmsRegistered: boolean
|
||||
|
||||
@Column({ name: 'gms_registered_at', type: 'datetime', default: null, nullable: true })
|
||||
gmsRegisteredAt: Date | null
|
||||
|
||||
@Column({ name: 'humhub_allowed', type: 'bool', default: false })
|
||||
humhubAllowed: boolean
|
||||
|
||||
@OneToMany(() => Contribution, (contribution) => contribution.user)
|
||||
@JoinColumn({ name: 'user_id' })
|
||||
contributions?: Contribution[]
|
||||
|
||||
@OneToMany(() => ContributionMessage, (message) => message.user)
|
||||
@JoinColumn({ name: 'user_id' })
|
||||
messages?: ContributionMessage[]
|
||||
|
||||
@OneToMany(() => UserContact, (userContact: UserContact) => userContact.user)
|
||||
@JoinColumn({ name: 'user_id' })
|
||||
userContacts?: UserContact[]
|
||||
|
||||
@OneToOne(() => DltUser, (dlt) => dlt.userId)
|
||||
@JoinColumn({ name: 'id', referencedColumnName: 'userId' })
|
||||
dltUser?: DltUser | null
|
||||
}
|
||||
@ -1,55 +0,0 @@
|
||||
import { BaseEntity, Entity, PrimaryGeneratedColumn, Column, OneToOne, JoinColumn } from 'typeorm'
|
||||
import { Transaction } from '../Transaction'
|
||||
import { User } from '../User'
|
||||
import { TransactionLink } from '../TransactionLink'
|
||||
|
||||
@Entity('dlt_transactions', { engine: 'InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci' })
|
||||
export class DltTransaction extends BaseEntity {
|
||||
@PrimaryGeneratedColumn('increment', { unsigned: true })
|
||||
id: number
|
||||
|
||||
@Column({ name: 'transaction_id', type: 'int', unsigned: true, nullable: true })
|
||||
transactionId?: number | null
|
||||
|
||||
@Column({ name: 'user_id', type: 'int', unsigned: true, nullable: true })
|
||||
userId?: number | null
|
||||
|
||||
@Column({ name: 'transaction_link_id', type: 'int', unsigned: true, nullable: true })
|
||||
transactionLinkId?: number | null
|
||||
|
||||
@Column({ name: 'type_id', unsigned: true, nullable: false })
|
||||
typeId: number
|
||||
|
||||
@Column({
|
||||
name: 'message_id',
|
||||
length: 64,
|
||||
nullable: true,
|
||||
default: null,
|
||||
collation: 'utf8mb4_unicode_ci',
|
||||
})
|
||||
messageId: string
|
||||
|
||||
@Column({ name: 'verified', type: 'bool', nullable: false, default: false })
|
||||
verified: boolean
|
||||
|
||||
@Column({ name: 'created_at', default: () => 'CURRENT_TIMESTAMP(3)', nullable: false })
|
||||
createdAt: Date
|
||||
|
||||
@Column({ name: 'verified_at', nullable: true, default: null, type: 'datetime' })
|
||||
verifiedAt: Date | null
|
||||
|
||||
@Column({ name: 'error', type: 'text', nullable: true })
|
||||
error: string | null
|
||||
|
||||
@OneToOne(() => Transaction, (transaction) => transaction.dltTransaction)
|
||||
@JoinColumn({ name: 'transaction_id' })
|
||||
transaction?: Transaction | null
|
||||
|
||||
@OneToOne(() => User, (user) => user.dltTransaction)
|
||||
@JoinColumn({ name: 'user_id' })
|
||||
user?: User | null
|
||||
|
||||
@OneToOne(() => TransactionLink, (transactionLink) => transactionLink.dltTransaction)
|
||||
@JoinColumn({ name: 'transaction_link_id' })
|
||||
transactionLink?: TransactionLink | null
|
||||
}
|
||||
@ -1,176 +0,0 @@
|
||||
/* eslint-disable no-use-before-define */
|
||||
import { Decimal } from 'decimal.js-light'
|
||||
import {
|
||||
BaseEntity,
|
||||
Entity,
|
||||
PrimaryGeneratedColumn,
|
||||
Column,
|
||||
OneToOne,
|
||||
JoinColumn,
|
||||
ManyToOne,
|
||||
} from 'typeorm'
|
||||
import { DecimalTransformer } from '../../src/typeorm/DecimalTransformer'
|
||||
import { Contribution } from '../Contribution'
|
||||
import { DltTransaction } from '../DltTransaction'
|
||||
import { TransactionLink } from '../TransactionLink'
|
||||
|
||||
@Entity('transactions')
|
||||
export class Transaction extends BaseEntity {
|
||||
@PrimaryGeneratedColumn('increment', { unsigned: true })
|
||||
id: number
|
||||
|
||||
@Column({ type: 'int', unsigned: true, unique: true, nullable: true, default: null })
|
||||
previous: number | null
|
||||
|
||||
@Column({ name: 'type_id', unsigned: true, nullable: false })
|
||||
typeId: number
|
||||
|
||||
@Column({
|
||||
name: 'transaction_link_id',
|
||||
type: 'int',
|
||||
unsigned: true,
|
||||
nullable: true,
|
||||
default: null,
|
||||
})
|
||||
transactionLinkId?: number | null
|
||||
|
||||
@Column({
|
||||
type: 'decimal',
|
||||
precision: 40,
|
||||
scale: 20,
|
||||
nullable: false,
|
||||
transformer: DecimalTransformer,
|
||||
})
|
||||
amount: Decimal
|
||||
|
||||
@Column({
|
||||
type: 'decimal',
|
||||
precision: 40,
|
||||
scale: 20,
|
||||
nullable: false,
|
||||
transformer: DecimalTransformer,
|
||||
})
|
||||
balance: Decimal
|
||||
|
||||
@Column({
|
||||
name: 'balance_date',
|
||||
type: 'datetime',
|
||||
default: () => 'CURRENT_TIMESTAMP',
|
||||
nullable: false,
|
||||
})
|
||||
balanceDate: Date
|
||||
|
||||
@Column({
|
||||
type: 'decimal',
|
||||
precision: 40,
|
||||
scale: 20,
|
||||
nullable: false,
|
||||
transformer: DecimalTransformer,
|
||||
})
|
||||
decay: Decimal
|
||||
|
||||
@Column({
|
||||
name: 'decay_start',
|
||||
type: 'datetime',
|
||||
nullable: true,
|
||||
default: null,
|
||||
})
|
||||
decayStart: Date | null
|
||||
|
||||
@Column({ length: 255, nullable: false, collation: 'utf8mb4_unicode_ci' })
|
||||
memo: string
|
||||
|
||||
@Column({ name: 'creation_date', type: 'datetime', nullable: true, default: null })
|
||||
creationDate: Date | null
|
||||
|
||||
@Column({ name: 'user_id', unsigned: true, nullable: false })
|
||||
userId: number
|
||||
|
||||
@Column({
|
||||
name: 'user_community_uuid',
|
||||
type: 'varchar',
|
||||
length: 36,
|
||||
nullable: true,
|
||||
collation: 'utf8mb4_unicode_ci',
|
||||
})
|
||||
userCommunityUuid: string | null
|
||||
|
||||
@Column({
|
||||
name: 'user_gradido_id',
|
||||
type: 'varchar',
|
||||
length: 36,
|
||||
nullable: false,
|
||||
collation: 'utf8mb4_unicode_ci',
|
||||
})
|
||||
userGradidoID: string
|
||||
|
||||
@Column({
|
||||
name: 'user_name',
|
||||
type: 'varchar',
|
||||
length: 512,
|
||||
nullable: true,
|
||||
collation: 'utf8mb4_unicode_ci',
|
||||
})
|
||||
userName: string | null
|
||||
|
||||
@Column({
|
||||
name: 'linked_user_id',
|
||||
type: 'int',
|
||||
unsigned: true,
|
||||
nullable: true,
|
||||
default: null,
|
||||
})
|
||||
linkedUserId?: number | null
|
||||
|
||||
@Column({
|
||||
name: 'linked_user_community_uuid',
|
||||
type: 'varchar',
|
||||
length: 36,
|
||||
nullable: true,
|
||||
collation: 'utf8mb4_unicode_ci',
|
||||
})
|
||||
linkedUserCommunityUuid: string | null
|
||||
|
||||
@Column({
|
||||
name: 'linked_user_gradido_id',
|
||||
type: 'varchar',
|
||||
length: 36,
|
||||
nullable: true,
|
||||
collation: 'utf8mb4_unicode_ci',
|
||||
})
|
||||
linkedUserGradidoID: string | null
|
||||
|
||||
@Column({
|
||||
name: 'linked_user_name',
|
||||
type: 'varchar',
|
||||
length: 512,
|
||||
nullable: true,
|
||||
collation: 'utf8mb4_unicode_ci',
|
||||
})
|
||||
linkedUserName: string | null
|
||||
|
||||
@Column({
|
||||
name: 'linked_transaction_id',
|
||||
type: 'int',
|
||||
unsigned: true,
|
||||
nullable: true,
|
||||
default: null,
|
||||
})
|
||||
linkedTransactionId?: number | null
|
||||
|
||||
@OneToOne(() => Contribution, (contribution) => contribution.transaction)
|
||||
@JoinColumn({ name: 'id', referencedColumnName: 'transactionId' })
|
||||
contribution?: Contribution | null
|
||||
|
||||
@OneToOne(() => DltTransaction, (dlt) => dlt.transactionId)
|
||||
@JoinColumn({ name: 'id', referencedColumnName: 'transactionId' })
|
||||
dltTransaction?: DltTransaction | null
|
||||
|
||||
@OneToOne(() => Transaction)
|
||||
@JoinColumn({ name: 'previous' })
|
||||
previousTransaction?: Transaction | null
|
||||
|
||||
@ManyToOne(() => TransactionLink, (transactionLink) => transactionLink.transactions)
|
||||
@JoinColumn({ name: 'transaction_link_id' })
|
||||
transactionLink?: TransactionLink | null
|
||||
}
|
||||
@ -1,85 +0,0 @@
|
||||
import { Decimal } from 'decimal.js-light'
|
||||
import {
|
||||
BaseEntity,
|
||||
Entity,
|
||||
PrimaryGeneratedColumn,
|
||||
Column,
|
||||
DeleteDateColumn,
|
||||
OneToOne,
|
||||
JoinColumn,
|
||||
OneToMany,
|
||||
} from 'typeorm'
|
||||
import { DecimalTransformer } from '../../src/typeorm/DecimalTransformer'
|
||||
import { DltTransaction } from '../DltTransaction'
|
||||
import { User } from '../User'
|
||||
import { Transaction } from '../Transaction'
|
||||
|
||||
@Entity('transaction_links')
|
||||
export class TransactionLink extends BaseEntity {
|
||||
@PrimaryGeneratedColumn('increment', { unsigned: true })
|
||||
id: number
|
||||
|
||||
@Column({ unsigned: true, nullable: false })
|
||||
userId: number
|
||||
|
||||
@Column({
|
||||
type: 'decimal',
|
||||
precision: 40,
|
||||
scale: 20,
|
||||
nullable: false,
|
||||
transformer: DecimalTransformer,
|
||||
})
|
||||
amount: Decimal
|
||||
|
||||
@Column({
|
||||
type: 'decimal',
|
||||
name: 'hold_available_amount',
|
||||
precision: 40,
|
||||
scale: 20,
|
||||
nullable: false,
|
||||
transformer: DecimalTransformer,
|
||||
})
|
||||
holdAvailableAmount: Decimal
|
||||
|
||||
@Column({ length: 255, nullable: false, collation: 'utf8mb4_unicode_ci' })
|
||||
memo: string
|
||||
|
||||
@Column({ length: 24, nullable: false, collation: 'utf8mb4_unicode_ci' })
|
||||
code: string
|
||||
|
||||
@Column({
|
||||
type: 'datetime',
|
||||
nullable: false,
|
||||
})
|
||||
createdAt: Date
|
||||
|
||||
@DeleteDateColumn()
|
||||
deletedAt: Date | null
|
||||
|
||||
@Column({
|
||||
type: 'datetime',
|
||||
nullable: false,
|
||||
})
|
||||
validUntil: Date
|
||||
|
||||
@Column({
|
||||
type: 'datetime',
|
||||
nullable: true,
|
||||
})
|
||||
redeemedAt: Date | null
|
||||
|
||||
@Column({ type: 'int', unsigned: true, nullable: true })
|
||||
redeemedBy: number | null
|
||||
|
||||
@OneToOne(() => DltTransaction, (dlt) => dlt.transactionLinkId)
|
||||
@JoinColumn({ name: 'id', referencedColumnName: 'transactionLinkId' })
|
||||
dltTransaction?: DltTransaction | null
|
||||
|
||||
@OneToOne(() => User, (user) => user.transactionLink)
|
||||
@JoinColumn({ name: 'userId' })
|
||||
user: User
|
||||
|
||||
@OneToMany(() => Transaction, (transaction) => transaction.transactionLink)
|
||||
@JoinColumn({ referencedColumnName: 'transaction_link_id' })
|
||||
transactions: Transaction[]
|
||||
}
|
||||
@ -1,186 +0,0 @@
|
||||
import {
|
||||
BaseEntity,
|
||||
Entity,
|
||||
PrimaryGeneratedColumn,
|
||||
Column,
|
||||
DeleteDateColumn,
|
||||
OneToMany,
|
||||
JoinColumn,
|
||||
OneToOne,
|
||||
Geometry,
|
||||
ManyToOne,
|
||||
} from 'typeorm'
|
||||
import { Contribution } from '../Contribution'
|
||||
import { ContributionMessage } from '../ContributionMessage'
|
||||
import { UserContact } from '../UserContact'
|
||||
import { UserRole } from '../UserRole'
|
||||
import { GeometryTransformer } from '../../src/typeorm/GeometryTransformer'
|
||||
import { Community } from '../Community'
|
||||
import { DltTransaction } from '../DltTransaction'
|
||||
import { TransactionLink } from './TransactionLink'
|
||||
|
||||
@Entity('users', { engine: 'InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci' })
|
||||
export class User extends BaseEntity {
|
||||
@PrimaryGeneratedColumn('increment', { unsigned: true })
|
||||
id: number
|
||||
|
||||
@Column({ type: 'bool', default: false })
|
||||
foreign: boolean
|
||||
|
||||
@Column({
|
||||
name: 'gradido_id',
|
||||
length: 36,
|
||||
nullable: false,
|
||||
collation: 'utf8mb4_unicode_ci',
|
||||
})
|
||||
gradidoID: string
|
||||
|
||||
@Column({
|
||||
name: 'community_uuid',
|
||||
type: 'char',
|
||||
length: 36,
|
||||
nullable: true,
|
||||
collation: 'utf8mb4_unicode_ci',
|
||||
})
|
||||
communityUuid: string
|
||||
|
||||
@ManyToOne(() => Community, (community) => community.users)
|
||||
@JoinColumn({ name: 'community_uuid', referencedColumnName: 'communityUuid' })
|
||||
community: Community | null
|
||||
|
||||
@Column({
|
||||
name: 'alias',
|
||||
length: 20,
|
||||
nullable: true,
|
||||
default: null,
|
||||
collation: 'utf8mb4_unicode_ci',
|
||||
})
|
||||
alias: string
|
||||
|
||||
@OneToOne(() => UserContact, (emailContact: UserContact) => emailContact.user)
|
||||
@JoinColumn({ name: 'email_id' })
|
||||
emailContact: UserContact
|
||||
|
||||
@Column({ name: 'email_id', type: 'int', unsigned: true, nullable: true, default: null })
|
||||
emailId: number | null
|
||||
|
||||
@Column({
|
||||
name: 'first_name',
|
||||
length: 255,
|
||||
nullable: true,
|
||||
default: null,
|
||||
collation: 'utf8mb4_unicode_ci',
|
||||
})
|
||||
firstName: string
|
||||
|
||||
@Column({
|
||||
name: 'last_name',
|
||||
length: 255,
|
||||
nullable: true,
|
||||
default: null,
|
||||
collation: 'utf8mb4_unicode_ci',
|
||||
})
|
||||
lastName: string
|
||||
|
||||
@Column({ name: 'gms_publish_name', type: 'int', unsigned: true, nullable: false, default: 0 })
|
||||
gmsPublishName: number
|
||||
|
||||
@Column({ name: 'humhub_publish_name', type: 'int', unsigned: true, nullable: false, default: 0 })
|
||||
humhubPublishName: number
|
||||
|
||||
@Column({ name: 'created_at', default: () => 'CURRENT_TIMESTAMP(3)', nullable: false })
|
||||
createdAt: Date
|
||||
|
||||
@DeleteDateColumn({ name: 'deleted_at', nullable: true })
|
||||
deletedAt: Date | null
|
||||
|
||||
@Column({ type: 'bigint', default: 0, unsigned: true })
|
||||
password: BigInt
|
||||
|
||||
@Column({
|
||||
name: 'password_encryption_type',
|
||||
type: 'int',
|
||||
unsigned: true,
|
||||
nullable: false,
|
||||
default: 0,
|
||||
})
|
||||
passwordEncryptionType: number
|
||||
|
||||
@Column({ length: 4, default: 'de', collation: 'utf8mb4_unicode_ci', nullable: false })
|
||||
language: string
|
||||
|
||||
@Column({ type: 'bool', default: false })
|
||||
hideAmountGDD: boolean
|
||||
|
||||
@Column({ type: 'bool', default: false })
|
||||
hideAmountGDT: boolean
|
||||
|
||||
@OneToMany(() => UserRole, (userRole) => userRole.user)
|
||||
@JoinColumn({ name: 'user_id' })
|
||||
userRoles: UserRole[]
|
||||
|
||||
@Column({ name: 'referrer_id', type: 'int', unsigned: true, nullable: true, default: null })
|
||||
referrerId?: number | null
|
||||
|
||||
@Column({
|
||||
name: 'contribution_link_id',
|
||||
type: 'int',
|
||||
unsigned: true,
|
||||
nullable: true,
|
||||
default: null,
|
||||
})
|
||||
contributionLinkId?: number | null
|
||||
|
||||
@Column({ name: 'publisher_id', default: 0 })
|
||||
publisherId: number
|
||||
|
||||
@Column({ name: 'gms_allowed', type: 'bool', default: true })
|
||||
gmsAllowed: boolean
|
||||
|
||||
@Column({
|
||||
name: 'location',
|
||||
type: 'geometry',
|
||||
default: null,
|
||||
nullable: true,
|
||||
transformer: GeometryTransformer,
|
||||
})
|
||||
location: Geometry | null
|
||||
|
||||
@Column({
|
||||
name: 'gms_publish_location',
|
||||
type: 'int',
|
||||
unsigned: true,
|
||||
nullable: false,
|
||||
default: 2,
|
||||
})
|
||||
gmsPublishLocation: number
|
||||
|
||||
@Column({ name: 'gms_registered', type: 'bool', default: false })
|
||||
gmsRegistered: boolean
|
||||
|
||||
@Column({ name: 'gms_registered_at', type: 'datetime', default: null, nullable: true })
|
||||
gmsRegisteredAt: Date | null
|
||||
|
||||
@Column({ name: 'humhub_allowed', type: 'bool', default: false })
|
||||
humhubAllowed: boolean
|
||||
|
||||
@OneToMany(() => Contribution, (contribution) => contribution.user)
|
||||
@JoinColumn({ name: 'user_id' })
|
||||
contributions?: Contribution[]
|
||||
|
||||
@OneToMany(() => ContributionMessage, (message) => message.user)
|
||||
@JoinColumn({ name: 'user_id' })
|
||||
messages?: ContributionMessage[]
|
||||
|
||||
@OneToMany(() => UserContact, (userContact: UserContact) => userContact.user)
|
||||
@JoinColumn({ name: 'user_id' })
|
||||
userContacts?: UserContact[]
|
||||
|
||||
@OneToOne(() => DltTransaction, (dlt) => dlt.userId)
|
||||
@JoinColumn({ name: 'id', referencedColumnName: 'userId' })
|
||||
dltTransaction?: DltTransaction | null
|
||||
|
||||
@OneToOne(() => TransactionLink, (transactionLink) => transactionLink.userId)
|
||||
@JoinColumn({ name: 'id', referencedColumnName: 'userId' })
|
||||
transactionLink?: TransactionLink | null
|
||||
}
|
||||
@ -1 +0,0 @@
|
||||
export { DltTransaction } from './0089-merge_dlt_tables/DltTransaction'
|
||||
@ -1 +0,0 @@
|
||||
export { Transaction } from './0089-merge_dlt_tables/Transaction'
|
||||
@ -1 +0,0 @@
|
||||
export { TransactionLink } from './0089-merge_dlt_tables/TransactionLink'
|
||||
@ -1 +0,0 @@
|
||||
export { User } from './0089-merge_dlt_tables/User'
|
||||
@ -75,6 +75,8 @@ export class HieroClient {
|
||||
this.logger.info(
|
||||
`message sent to topic ${topicId}, status: ${sendReceipt.status.toString()}, transaction id: ${sendResponse.transactionId.toString()}`,
|
||||
)
|
||||
const record = await sendResponse.getRecordWithSigner(this.wallet)
|
||||
this.logger.info(`message sent, cost: ${record.transactionFee.toString()}`)
|
||||
return { receipt: sendReceipt, response: sendResponse }
|
||||
}
|
||||
|
||||
@ -120,6 +122,8 @@ export class HieroClient {
|
||||
const createReceipt = await createResponse.getReceiptWithSigner(this.wallet)
|
||||
this.logger.debug(createReceipt.toString())
|
||||
this.logger.addContext('topicId', createReceipt.topicId?.toString())
|
||||
const record = await createResponse.getRecordWithSigner(this.wallet)
|
||||
this.logger.info(`topic created, cost: ${record.transactionFee.toString()}`)
|
||||
return parse(hieroIdSchema, createReceipt.topicId?.toString())
|
||||
}
|
||||
|
||||
@ -133,5 +137,7 @@ export class HieroClient {
|
||||
const updateResponse = await transaction.executeWithSigner(this.wallet)
|
||||
const updateReceipt = await updateResponse.getReceiptWithSigner(this.wallet)
|
||||
this.logger.debug(updateReceipt.toString())
|
||||
const record = await updateResponse.getRecordWithSigner(this.wallet)
|
||||
this.logger.info(`topic updated, cost: ${record.transactionFee.toString()}`)
|
||||
}
|
||||
}
|
||||
|
||||
@ -87,7 +87,8 @@ async function homeCommunitySetup({ backend, hiero }: Clients, logger: Logger):
|
||||
} else {
|
||||
// if topic exist, check if we need to update it
|
||||
let topicInfo = await hiero.getTopicInfo(homeCommunity.hieroTopicId)
|
||||
if (
|
||||
console.log(`topicInfo: ${JSON.stringify(topicInfo, null, 2)}`)
|
||||
/*if (
|
||||
topicInfo.expirationTime.getTime() - new Date().getTime() <
|
||||
MIN_TOPIC_EXPIRE_MILLISECONDS_FOR_UPDATE
|
||||
) {
|
||||
@ -96,7 +97,7 @@ async function homeCommunitySetup({ backend, hiero }: Clients, logger: Logger):
|
||||
logger.info(
|
||||
`updated topic info, new expiration time: ${topicInfo.expirationTime.toLocaleDateString()}`,
|
||||
)
|
||||
}
|
||||
}*/
|
||||
}
|
||||
if (!homeCommunity.hieroTopicId) {
|
||||
throw new Error('still no topic id, after creating topic and update community in backend.')
|
||||
|
||||
@ -88,19 +88,19 @@ export async function SendToHieroContext(
|
||||
if (builder.isCrossCommunityTransaction()) {
|
||||
const outboundTransaction = builder.buildOutbound()
|
||||
validate(outboundTransaction)
|
||||
const outboundIotaMessageId = await sendViaHiero(
|
||||
const outboundHieroTransactionId = await sendViaHiero(
|
||||
outboundTransaction,
|
||||
role.getSenderCommunityTopicId(),
|
||||
)
|
||||
builder.setParentMessageId(MemoryBlock.createPtr(new MemoryBlock(outboundIotaMessageId)))
|
||||
builder.setParentMessageId(MemoryBlock.createPtr(new MemoryBlock(outboundHieroTransactionId)))
|
||||
const inboundTransaction = builder.buildInbound()
|
||||
validate(inboundTransaction)
|
||||
await sendViaHiero(inboundTransaction, role.getRecipientCommunityTopicId())
|
||||
return parse(hieroTransactionIdSchema, outboundIotaMessageId)
|
||||
return parse(hieroTransactionIdSchema, outboundHieroTransactionId)
|
||||
} else {
|
||||
const transaction = builder.build()
|
||||
validate(transaction)
|
||||
const iotaMessageId = await sendViaHiero(transaction, role.getSenderCommunityTopicId())
|
||||
return parse(hieroTransactionIdSchema, iotaMessageId)
|
||||
const hieroTransactionId = await sendViaHiero(transaction, role.getSenderCommunityTopicId())
|
||||
return parse(hieroTransactionIdSchema, hieroTransactionId)
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
import { TypeBoxFromValibot } from '@sinclair/typemap'
|
||||
import { Type } from '@sinclair/typebox'
|
||||
import { Elysia, status } from 'elysia'
|
||||
import { AddressType_NONE } from 'gradido-blockchain-js'
|
||||
import { getLogger } from 'log4js'
|
||||
@ -46,11 +47,30 @@ export const appRoutes = new Elysia()
|
||||
)
|
||||
.post(
|
||||
'/sendTransaction',
|
||||
async ({ body }) => await SendToHieroContext(parse(transactionSchema, body)),
|
||||
async ({ body }) => {
|
||||
console.log("sendTransaction was called")
|
||||
return "0.0.123"
|
||||
console.log(body)
|
||||
console.log(parse(transactionSchema, body))
|
||||
const transaction = parse(transactionSchema, body)
|
||||
return await SendToHieroContext(transaction)
|
||||
},
|
||||
// validation schemas
|
||||
{
|
||||
body: TypeBoxFromValibot(transactionSchema),
|
||||
response: TypeBoxFromValibot(hieroTransactionIdSchema),
|
||||
// body: TypeBoxFromValibot(transactionSchema),
|
||||
body: Type.Object({
|
||||
user: Type.Object({
|
||||
communityUser: Type.Object({
|
||||
uuid: Type.String({ format: 'uuid' }),
|
||||
accountNr: Type.Optional(Type.String()), // optional/undefined
|
||||
}),
|
||||
communityUuid: Type.String({ format: 'uuid' }),
|
||||
}),
|
||||
createdAt: Type.String({ format: 'date-time' }),
|
||||
accountType: Type.Literal('COMMUNITY_HUMAN'),
|
||||
type: Type.Literal('REGISTER_ADDRESS'),
|
||||
})
|
||||
// response: TypeBoxFromValibot(hieroTransactionIdSchema),
|
||||
},
|
||||
)
|
||||
|
||||
@ -76,3 +96,4 @@ async function isAccountExist(identifierAccount: IdentifierAccount): Promise<boo
|
||||
}
|
||||
return addressType !== AddressType_NONE
|
||||
}
|
||||
export type DltRoutes = typeof appRoutes
|
||||
@ -2667,6 +2667,11 @@
|
||||
resolved "https://registry.npmjs.org/@types/node/-/node-10.17.60.tgz"
|
||||
integrity sha512-F0KIgDJfy2nA3zMLmWGKxcH2ZVEtCZXHHdOQs2gSaQ27+lNeEfGxzkIw90aXswATX7AZ33tahPbzy6KAfUreVw==
|
||||
|
||||
"@types/node@^14.11.2":
|
||||
version "14.18.63"
|
||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-14.18.63.tgz#1788fa8da838dbb5f9ea994b834278205db6ca2b"
|
||||
integrity sha512-fAtCfv4jJg+ExtXhvCkCqUKZ+4ok/JQk01qDKhL5BDDoS3AxKXhV5/MAVUZyQnSEd2GT92fkgZl0pz0Q0AzcIQ==
|
||||
|
||||
"@types/node@^17.0.21", "@types/node@^17.0.45":
|
||||
version "17.0.45"
|
||||
resolved "https://registry.npmjs.org/@types/node/-/node-17.0.45.tgz"
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user