Post Tipping
This commit is contained in:
parent
e6b2d0f896
commit
c8dc984469
8 changed files with 267 additions and 43 deletions
|
|
@ -48,7 +48,7 @@
|
||||||
"request-promise": "^4.2.2",
|
"request-promise": "^4.2.2",
|
||||||
"response-time": "^2.3.2",
|
"response-time": "^2.3.2",
|
||||||
"shelljs": "^0.8.2",
|
"shelljs": "^0.8.2",
|
||||||
"shock-common": "8.0.0",
|
"shock-common": "shocknet/shock-common#49aa269c723b2c2ee803662c98ba2ddd1f68f57e",
|
||||||
"socket.io": "2.1.1",
|
"socket.io": "2.1.1",
|
||||||
"text-encoding": "^0.7.0",
|
"text-encoding": "^0.7.0",
|
||||||
"tingodb": "^0.6.1",
|
"tingodb": "^0.6.1",
|
||||||
|
|
|
||||||
|
|
@ -935,7 +935,8 @@ const sendSpontaneousPayment = async (to, amount, memo, feeLimit) => {
|
||||||
amount: amount.toString(),
|
amount: amount.toString(),
|
||||||
from: getUser()._.sea.pub,
|
from: getUser()._.sea.pub,
|
||||||
memo: memo || 'no memo',
|
memo: memo || 'no memo',
|
||||||
timestamp: Date.now()
|
timestamp: Date.now(),
|
||||||
|
targetType: 'user'
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.info(JSON.stringify(order))
|
logger.info(JSON.stringify(order))
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
* @format
|
* @format
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
const { performance } = require('perf_hooks')
|
||||||
const logger = require('winston')
|
const logger = require('winston')
|
||||||
const isFinite = require('lodash/isFinite')
|
const isFinite = require('lodash/isFinite')
|
||||||
const isNumber = require('lodash/isNumber')
|
const isNumber = require('lodash/isNumber')
|
||||||
|
|
@ -38,9 +39,18 @@ const ordersProcessed = new Set()
|
||||||
* @prop {boolean} private
|
* @prop {boolean} private
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {object} InvoiceResponse
|
||||||
|
* @prop {string} payment_request
|
||||||
|
* @prop {Buffer} r_hash
|
||||||
|
*/
|
||||||
|
|
||||||
let currentOrderAddr = ''
|
let currentOrderAddr = ''
|
||||||
|
|
||||||
/** @param {InvoiceRequest} invoiceReq */
|
/**
|
||||||
|
* @param {InvoiceRequest} invoiceReq
|
||||||
|
* @returns {Promise<InvoiceResponse>}
|
||||||
|
*/
|
||||||
const _addInvoice = invoiceReq =>
|
const _addInvoice = invoiceReq =>
|
||||||
new Promise((resolve, rej) => {
|
new Promise((resolve, rej) => {
|
||||||
const {
|
const {
|
||||||
|
|
@ -49,12 +59,12 @@ const _addInvoice = invoiceReq =>
|
||||||
|
|
||||||
lightning.addInvoice(invoiceReq, (
|
lightning.addInvoice(invoiceReq, (
|
||||||
/** @type {any} */ error,
|
/** @type {any} */ error,
|
||||||
/** @type {{ payment_request: string }} */ response
|
/** @type {InvoiceResponse} */ response
|
||||||
) => {
|
) => {
|
||||||
if (error) {
|
if (error) {
|
||||||
rej(error)
|
rej(error)
|
||||||
} else {
|
} else {
|
||||||
resolve(response.payment_request)
|
resolve(response)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
@ -85,7 +95,7 @@ const listenerForAddr = (addr, SEA) => async (order, orderID) => {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
const listenerStartTime = Date.now()
|
const listenerStartTime = performance.now()
|
||||||
|
|
||||||
ordersProcessed.add(orderID)
|
ordersProcessed.add(orderID)
|
||||||
|
|
||||||
|
|
@ -95,7 +105,7 @@ const listenerForAddr = (addr, SEA) => async (order, orderID) => {
|
||||||
)} -- addr: ${addr}`
|
)} -- addr: ${addr}`
|
||||||
)
|
)
|
||||||
|
|
||||||
const orderAnswerStartTime = Date.now()
|
const orderAnswerStartTime = performance.now()
|
||||||
|
|
||||||
const alreadyAnswered = await getUser()
|
const alreadyAnswered = await getUser()
|
||||||
.get(Key.ORDER_TO_RESPONSE)
|
.get(Key.ORDER_TO_RESPONSE)
|
||||||
|
|
@ -107,11 +117,11 @@ const listenerForAddr = (addr, SEA) => async (order, orderID) => {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
const orderAnswerEndTime = Date.now() - orderAnswerStartTime
|
const orderAnswerEndTime = performance.now() - orderAnswerStartTime
|
||||||
|
|
||||||
logger.info(`[PERF] Order Already Answered: ${orderAnswerEndTime}ms`)
|
logger.info(`[PERF] Order Already Answered: ${orderAnswerEndTime}ms`)
|
||||||
|
|
||||||
const decryptStartTime = Date.now()
|
const decryptStartTime = performance.now()
|
||||||
|
|
||||||
const senderEpub = await Utils.pubToEpub(order.from)
|
const senderEpub = await Utils.pubToEpub(order.from)
|
||||||
const secret = await SEA.secret(senderEpub, getUser()._.sea)
|
const secret = await SEA.secret(senderEpub, getUser()._.sea)
|
||||||
|
|
@ -121,7 +131,7 @@ const listenerForAddr = (addr, SEA) => async (order, orderID) => {
|
||||||
SEA.decrypt(order.memo, secret)
|
SEA.decrypt(order.memo, secret)
|
||||||
])
|
])
|
||||||
|
|
||||||
const decryptEndTime = Date.now() - decryptStartTime
|
const decryptEndTime = performance.now() - decryptStartTime
|
||||||
|
|
||||||
logger.info(`[PERF] Decrypt invoice info: ${decryptEndTime}ms`)
|
logger.info(`[PERF] Decrypt invoice info: ${decryptEndTime}ms`)
|
||||||
|
|
||||||
|
|
@ -156,14 +166,11 @@ const listenerForAddr = (addr, SEA) => async (order, orderID) => {
|
||||||
`onOrders() -> Will now create an invoice : ${JSON.stringify(invoiceReq)}`
|
`onOrders() -> Will now create an invoice : ${JSON.stringify(invoiceReq)}`
|
||||||
)
|
)
|
||||||
|
|
||||||
const invoiceStartTime = Date.now()
|
const invoiceStartTime = performance.now()
|
||||||
|
|
||||||
/**
|
|
||||||
* @type {string}
|
|
||||||
*/
|
|
||||||
const invoice = await _addInvoice(invoiceReq)
|
const invoice = await _addInvoice(invoiceReq)
|
||||||
|
|
||||||
const invoiceEndTime = Date.now() - invoiceStartTime
|
const invoiceEndTime = performance.now() - invoiceStartTime
|
||||||
|
|
||||||
logger.info(`[PERF] LND Invoice created in ${invoiceEndTime}ms`)
|
logger.info(`[PERF] LND Invoice created in ${invoiceEndTime}ms`)
|
||||||
|
|
||||||
|
|
@ -171,11 +178,11 @@ const listenerForAddr = (addr, SEA) => async (order, orderID) => {
|
||||||
'onOrders() -> Successfully created the invoice, will now encrypt it'
|
'onOrders() -> Successfully created the invoice, will now encrypt it'
|
||||||
)
|
)
|
||||||
|
|
||||||
const invoiceEncryptStartTime = Date.now()
|
const invoiceEncryptStartTime = performance.now()
|
||||||
|
|
||||||
const encInvoice = await SEA.encrypt(invoice, secret)
|
const encInvoice = await SEA.encrypt(invoice.payment_request, secret)
|
||||||
|
|
||||||
const invoiceEncryptEndTime = Date.now() - invoiceEncryptStartTime
|
const invoiceEncryptEndTime = performance.now() - invoiceEncryptStartTime
|
||||||
|
|
||||||
logger.info(`[PERF] Invoice encrypted in ${invoiceEncryptEndTime}ms`)
|
logger.info(`[PERF] Invoice encrypted in ${invoiceEncryptEndTime}ms`)
|
||||||
|
|
||||||
|
|
@ -189,7 +196,7 @@ const listenerForAddr = (addr, SEA) => async (order, orderID) => {
|
||||||
type: 'invoice'
|
type: 'invoice'
|
||||||
}
|
}
|
||||||
|
|
||||||
const invoicePutStartTime = Date.now()
|
const invoicePutStartTime = performance.now()
|
||||||
|
|
||||||
await new Promise((res, rej) => {
|
await new Promise((res, rej) => {
|
||||||
getUser()
|
getUser()
|
||||||
|
|
@ -209,13 +216,35 @@ const listenerForAddr = (addr, SEA) => async (order, orderID) => {
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
const invoicePutEndTime = Date.now() - invoicePutStartTime
|
const invoicePutEndTime = performance.now() - invoicePutStartTime
|
||||||
|
|
||||||
logger.info(`[PERF] Added invoice to GunDB in ${invoicePutEndTime}ms`)
|
logger.info(`[PERF] Added invoice to GunDB in ${invoicePutEndTime}ms`)
|
||||||
|
|
||||||
const listenerEndTime = Date.now() - listenerStartTime
|
const listenerEndTime = performance.now() - listenerStartTime
|
||||||
|
|
||||||
logger.info(`[PERF] Invoice generation completed in ${listenerEndTime}ms`)
|
logger.info(`[PERF] Invoice generation completed in ${listenerEndTime}ms`)
|
||||||
|
|
||||||
|
const hash = invoice.r_hash.toString('base64')
|
||||||
|
|
||||||
|
if (order.targetType === 'post') {
|
||||||
|
getUser()
|
||||||
|
.get(Key.TIPS_PAYMENT_STATUS)
|
||||||
|
.get(hash)
|
||||||
|
.put(
|
||||||
|
{
|
||||||
|
hash,
|
||||||
|
state: 'OPEN',
|
||||||
|
targetType: order.targetType,
|
||||||
|
// @ts-ignore
|
||||||
|
postID: order.postID,
|
||||||
|
// @ts-ignore
|
||||||
|
postPage: order.postPage
|
||||||
|
},
|
||||||
|
response => {
|
||||||
|
console.log(response)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
logger.error(
|
logger.error(
|
||||||
`error inside onOrders, orderAddr: ${addr}, orderID: ${orderID}, order: ${JSON.stringify(
|
`error inside onOrders, orderAddr: ${addr}, orderID: ${orderID}, order: ${JSON.stringify(
|
||||||
|
|
|
||||||
|
|
@ -55,3 +55,8 @@ exports.CONTENT_ITEMS = 'contentItems'
|
||||||
exports.FOLLOWS = 'follows'
|
exports.FOLLOWS = 'follows'
|
||||||
|
|
||||||
exports.POSTS = 'posts'
|
exports.POSTS = 'posts'
|
||||||
|
|
||||||
|
// Tips counter for posts
|
||||||
|
exports.TOTAL_TIPS = 'totalTips'
|
||||||
|
|
||||||
|
exports.TIPS_PAYMENT_STATUS = 'tipsPaymentStatus'
|
||||||
|
|
|
||||||
|
|
@ -35,6 +35,7 @@ const {
|
||||||
sendPaymentV2Invoice,
|
sendPaymentV2Invoice,
|
||||||
listPayments
|
listPayments
|
||||||
} = require('../utils/lightningServices/v2')
|
} = require('../utils/lightningServices/v2')
|
||||||
|
const { startTipStatusJob } = require('../utils/lndJobs')
|
||||||
|
|
||||||
const DEFAULT_MAX_NUM_ROUTES_TO_QUERY = 10
|
const DEFAULT_MAX_NUM_ROUTES_TO_QUERY = 10
|
||||||
const SESSION_ID = uuid()
|
const SESSION_ID = uuid()
|
||||||
|
|
@ -686,6 +687,7 @@ module.exports = async (
|
||||||
}
|
}
|
||||||
|
|
||||||
onNewChannelBackup()
|
onNewChannelBackup()
|
||||||
|
startTipStatusJob()
|
||||||
|
|
||||||
// Generate auth token and send it as a JSON response
|
// Generate auth token and send it as a JSON response
|
||||||
const token = await auth.generateToken()
|
const token = await auth.generateToken()
|
||||||
|
|
|
||||||
|
|
@ -26,15 +26,16 @@ const server = program => {
|
||||||
sensitiveRoutes,
|
sensitiveRoutes,
|
||||||
nonEncryptedRoutes
|
nonEncryptedRoutes
|
||||||
} = require('../utils/protectedRoutes')
|
} = require('../utils/protectedRoutes')
|
||||||
|
|
||||||
// load app default configuration data
|
// load app default configuration data
|
||||||
const defaults = require('../config/defaults')(program.mainnet)
|
const defaults = require('../config/defaults')(program.mainnet)
|
||||||
const rootFolder = process.resourcesPath || __dirname
|
const rootFolder = process.resourcesPath || __dirname
|
||||||
// define useful global variables ======================================
|
|
||||||
|
// define env variables
|
||||||
Dotenv.config()
|
Dotenv.config()
|
||||||
module.useTLS = program.usetls
|
|
||||||
module.serverPort = program.serverport || defaults.serverPort
|
const serverPort = program.serverport || defaults.serverPort
|
||||||
module.httpsPort = module.serverPort
|
const serverHost = program.serverhost || defaults.serverHost
|
||||||
module.serverHost = program.serverhost || defaults.serverHost
|
|
||||||
|
|
||||||
// setup winston logging ==========
|
// setup winston logging ==========
|
||||||
const logger = require('../config/log')(
|
const logger = require('../config/log')(
|
||||||
|
|
@ -274,8 +275,8 @@ const server = program => {
|
||||||
const Sockets = require('./sockets')(io)
|
const Sockets = require('./sockets')(io)
|
||||||
|
|
||||||
require('./routes')(app, defaults, Sockets, {
|
require('./routes')(app, defaults, Sockets, {
|
||||||
serverHost: module.serverHost,
|
serverHost,
|
||||||
serverPort: module.serverPort,
|
serverPort,
|
||||||
usetls: program.usetls,
|
usetls: program.usetls,
|
||||||
CA,
|
CA,
|
||||||
CA_KEY
|
CA_KEY
|
||||||
|
|
@ -290,20 +291,11 @@ const server = program => {
|
||||||
app.use(modifyResponseBody)
|
app.use(modifyResponseBody)
|
||||||
}
|
}
|
||||||
|
|
||||||
serverInstance.listen(module.serverPort, module.serverhost)
|
serverInstance.listen(serverPort, serverHost)
|
||||||
|
|
||||||
logger.info(
|
logger.info('App listening on ' + serverHost + ' port ' + serverPort)
|
||||||
'App listening on ' + module.serverHost + ' port ' + module.serverPort
|
|
||||||
)
|
|
||||||
|
|
||||||
module.server = serverInstance
|
module.server = serverInstance
|
||||||
|
|
||||||
// const localtunnel = require('localtunnel');
|
|
||||||
//
|
|
||||||
// const tunnel = localtunnel(port, (err, t) => {
|
|
||||||
// logger.info('err', err);
|
|
||||||
// logger.info('t', t.url);
|
|
||||||
// });
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
logger.info(err)
|
logger.info(err)
|
||||||
logger.info('Restarting server in 30 seconds...')
|
logger.info('Restarting server in 30 seconds...')
|
||||||
|
|
|
||||||
196
utils/lndJobs.js
Normal file
196
utils/lndJobs.js
Normal file
|
|
@ -0,0 +1,196 @@
|
||||||
|
/**
|
||||||
|
* @prettier
|
||||||
|
*/
|
||||||
|
const Logger = require('winston')
|
||||||
|
const Key = require('../services/gunDB/contact-api/key')
|
||||||
|
const { getUser } = require('../services/gunDB/Mediator')
|
||||||
|
const LightningServices = require('./lightningServices')
|
||||||
|
|
||||||
|
const ERROR_TRIES_THRESHOLD = 3
|
||||||
|
const INVOICE_STATE = {
|
||||||
|
OPEN: 'OPEN',
|
||||||
|
SETTLED: 'SETTLED',
|
||||||
|
CANCELLED: 'CANCELLED',
|
||||||
|
ACCEPTED: 'ACCEPTED'
|
||||||
|
}
|
||||||
|
|
||||||
|
const _lookupInvoice = hash =>
|
||||||
|
new Promise((resolve, reject) => {
|
||||||
|
const { lightning } = LightningServices.services
|
||||||
|
lightning.lookupInvoice({ r_hash: hash }, (err, response) => {
|
||||||
|
if (err) {
|
||||||
|
Logger.error(
|
||||||
|
'[TIP] An error has occurred while trying to lookup invoice:',
|
||||||
|
err,
|
||||||
|
'\nInvoice Hash:',
|
||||||
|
hash
|
||||||
|
)
|
||||||
|
reject(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
Logger.info('[TIP] Invoice lookup result:', response)
|
||||||
|
resolve(response)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
const _getPostTipInfo = ({ postID, page }) =>
|
||||||
|
new Promise((resolve, reject) => {
|
||||||
|
getUser()
|
||||||
|
.get(Key.WALL)
|
||||||
|
.get(Key.PAGES)
|
||||||
|
.get(page)
|
||||||
|
.get(Key.POSTS)
|
||||||
|
.get(postID)
|
||||||
|
.once(post => {
|
||||||
|
if (post && post.date) {
|
||||||
|
const { tipCounter, tipValue } = post
|
||||||
|
console.log(post)
|
||||||
|
resolve({
|
||||||
|
tipCounter: typeof tipCounter === 'number' ? tipCounter : 0,
|
||||||
|
tipValue: typeof tipValue === 'number' ? tipValue : 0
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
resolve(post)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
const _incrementPost = ({ postID, page, orderAmount }) =>
|
||||||
|
new Promise((resolve, reject) => {
|
||||||
|
const parsedAmount = parseFloat(orderAmount)
|
||||||
|
|
||||||
|
if (typeof parsedAmount !== 'number') {
|
||||||
|
reject(new Error('Invalid order amount specified'))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
Logger.info('[POST TIP] Getting Post Tip Values...')
|
||||||
|
|
||||||
|
return _getPostTipInfo({ postID, page })
|
||||||
|
.then(({ tipValue, tipCounter }) => {
|
||||||
|
const updatedTip = {
|
||||||
|
tipCounter: tipCounter + 1,
|
||||||
|
tipValue: tipValue + parsedAmount
|
||||||
|
}
|
||||||
|
|
||||||
|
getUser()
|
||||||
|
.get(Key.WALL)
|
||||||
|
.get(Key.PAGES)
|
||||||
|
.get(page)
|
||||||
|
.get(Key.POSTS)
|
||||||
|
.get(postID)
|
||||||
|
.put(updatedTip, () => {
|
||||||
|
Logger.info('[POST TIP] Successfully updated Post tip info')
|
||||||
|
resolve(updatedTip)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.catch(err => {
|
||||||
|
Logger.error(err)
|
||||||
|
reject(err)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
const _updateTipData = (invoiceHash, data) =>
|
||||||
|
new Promise((resolve, reject) => {
|
||||||
|
try {
|
||||||
|
getUser()
|
||||||
|
.get(Key.TIPS_PAYMENT_STATUS)
|
||||||
|
.get(invoiceHash)
|
||||||
|
.put(data, tip => {
|
||||||
|
if (tip === undefined) {
|
||||||
|
reject(new Error('Tip update failed'))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(tip)
|
||||||
|
|
||||||
|
resolve(tip)
|
||||||
|
})
|
||||||
|
} catch (err) {
|
||||||
|
Logger.error('An error has occurred while updating tip^data')
|
||||||
|
throw err
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const _getTipData = invoiceHash =>
|
||||||
|
new Promise((resolve, reject) => {
|
||||||
|
getUser()
|
||||||
|
.get(Key.TIPS_PAYMENT_STATUS)
|
||||||
|
.get(invoiceHash)
|
||||||
|
.once(tip => {
|
||||||
|
if (tip === undefined) {
|
||||||
|
reject(new Error('Malformed data'))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
resolve(tip)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
const executeTipAction = (tip, invoice) => {
|
||||||
|
if (invoice.state !== INVOICE_STATE.SETTLED) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Execute actions once invoice is settled
|
||||||
|
Logger.info('Invoice settled!', invoice)
|
||||||
|
|
||||||
|
if (tip.targetType === 'post') {
|
||||||
|
_incrementPost({
|
||||||
|
postID: tip.postID,
|
||||||
|
page: tip.postPage,
|
||||||
|
orderAmount: invoice.amt_paid_sat
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const updateUnverifiedTips = () => {
|
||||||
|
getUser()
|
||||||
|
.get(Key.TIPS_PAYMENT_STATUS)
|
||||||
|
.map()
|
||||||
|
.once(async (tip, id) => {
|
||||||
|
try {
|
||||||
|
if (
|
||||||
|
!tip ||
|
||||||
|
tip.state !== INVOICE_STATE.OPEN ||
|
||||||
|
(tip._errorCount && tip._errorCount >= ERROR_TRIES_THRESHOLD)
|
||||||
|
) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
Logger.info('Unverified invoice found!', tip)
|
||||||
|
const invoice = await _lookupInvoice(tip.hash)
|
||||||
|
Logger.info('Invoice located:', invoice)
|
||||||
|
if (invoice.state !== tip.state) {
|
||||||
|
await _updateTipData(id, { state: invoice.state })
|
||||||
|
|
||||||
|
// Actions to be executed when the tip's state is updated
|
||||||
|
executeTipAction(tip, invoice)
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
Logger.error('[TIP] An error has occurred while updating invoice', err)
|
||||||
|
const errorCount = tip._errorCount ? tip._errorCount : 0
|
||||||
|
_updateTipData(id, {
|
||||||
|
_errorCount: errorCount + 1
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const startTipStatusJob = () => {
|
||||||
|
const { lightning } = LightningServices.services
|
||||||
|
const stream = lightning.subscribeInvoices({})
|
||||||
|
updateUnverifiedTips()
|
||||||
|
stream.on('data', async invoice => {
|
||||||
|
const hash = invoice.r_hash.toString('base64')
|
||||||
|
const tip = await _getTipData(hash)
|
||||||
|
if (tip.state !== invoice.state) {
|
||||||
|
await _updateTipData(hash, { state: invoice.state })
|
||||||
|
executeTipAction(tip, invoice)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
startTipStatusJob
|
||||||
|
}
|
||||||
|
|
@ -6016,10 +6016,9 @@ shellwords@^0.1.1:
|
||||||
resolved "https://registry.yarnpkg.com/shellwords/-/shellwords-0.1.1.tgz#d6b9181c1a48d397324c84871efbcfc73fc0654b"
|
resolved "https://registry.yarnpkg.com/shellwords/-/shellwords-0.1.1.tgz#d6b9181c1a48d397324c84871efbcfc73fc0654b"
|
||||||
integrity sha512-vFwSUfQvqybiICwZY5+DAWIPLKsWO31Q91JSKl3UYv+K5c2QRPzn0qzec6QPu1Qc9eHYItiP3NdJqNVqetYAww==
|
integrity sha512-vFwSUfQvqybiICwZY5+DAWIPLKsWO31Q91JSKl3UYv+K5c2QRPzn0qzec6QPu1Qc9eHYItiP3NdJqNVqetYAww==
|
||||||
|
|
||||||
shock-common@8.0.0:
|
shock-common@shocknet/shock-common#49aa269c723b2c2ee803662c98ba2ddd1f68f57e:
|
||||||
version "8.0.0"
|
version "10.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/shock-common/-/shock-common-8.0.0.tgz#4dbc8c917adfb221a00b6d1e815c4d26d205ce66"
|
resolved "https://codeload.github.com/shocknet/shock-common/tar.gz/49aa269c723b2c2ee803662c98ba2ddd1f68f57e"
|
||||||
integrity sha512-X9jkSxNUjQOcVdEAGBl6dlBgBxF9MpjV50Cih4hoqLqeGfrAYHK/iqgXgDyaHkLraHRxdP6FWJ2DoWOpuBgpDQ==
|
|
||||||
dependencies:
|
dependencies:
|
||||||
immer "^6.0.6"
|
immer "^6.0.6"
|
||||||
lodash "^4.17.19"
|
lodash "^4.17.19"
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue