Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: carousel integration with history navigation #1601

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
78 commits
Select commit Hold shift + click to select a range
8745e4a
feat: carousel integration with history navigation
aegroto Nov 18, 2024
4239f9a
Merge branch 'master' of github.com:stackernews/stacker.news into enh…
aegroto Nov 21, 2024
ec2ab58
Merge branch 'master' into enhancement-backward-carousel-images
huumn Nov 21, 2024
c691259
Merge branch 'master' of github.com:stackernews/stacker.news into enh…
aegroto Nov 21, 2024
a7a16e4
Merge branch 'enhancement-backward-carousel-images' of github.com:aeg…
aegroto Nov 21, 2024
3be1418
fix: navigation-based carousel close action
aegroto Nov 22, 2024
3d2063a
Use invoice.cancelledAt to determine if invoice expired or was cancel…
ekzyis Nov 22, 2024
7d0eb60
add in error message how high are estimated fees when too high (#1634)
riccardobl Nov 22, 2024
b8dd4c4
fix LNC attachment and docs (#1639)
riccardobl Nov 23, 2024
6b44b14
Remove unused function usePayment (#1641)
ekzyis Nov 23, 2024
0039700
refactor: Check darkmode in useWallets (#1640)
ekzyis Nov 23, 2024
4aba93f
Only fetch logs when we need them (#1638)
ekzyis Nov 24, 2024
ad4644f
Create useWalletStatus and useWalletSupport (#1646)
ekzyis Nov 24, 2024
2bed712
Fix inconsistent actionArgs on retry (#1651)
ekzyis Nov 26, 2024
971b510
direct receives and send paid action (#1650)
huumn Nov 27, 2024
57a30a4
Wallet filters (#1627)
ekzyis Nov 27, 2024
5c3ca67
use flexbox for wallet card header and make logos more consistent (#1…
riccardobl Nov 27, 2024
b7fd9e2
Improve LNC realiability by being nicer (#1658)
riccardobl Nov 27, 2024
e30185e
fix: cannot add images above text (#1659)
Soxasora Nov 27, 2024
3a7e1d9
Remove unused useWallet from QR code component (#1660)
ekzyis Nov 27, 2024
6f1dabb
Fix deposit push notifications (#1662)
ekzyis Nov 28, 2024
acdfdb2
Fix comment
ekzyis Nov 24, 2024
d42dc91
sender fallbacks
ekzyis Nov 25, 2024
2b20cfa
Fix SenderError name
ekzyis Nov 26, 2024
4b39e98
Fix TypeError
ekzyis Nov 26, 2024
8976b30
Fix old invoice passed to QR code
ekzyis Nov 26, 2024
0911ec3
Remove unnecessary sort
ekzyis Nov 26, 2024
b860a57
Fix payments if recv-only wallet enabled
ekzyis Nov 26, 2024
1ddc4fa
Refactor wallet error handling with inheritance
ekzyis Nov 26, 2024
c49b6f8
Abort payment on unexpected errors
ekzyis Nov 26, 2024
6b4dbed
Add comment when err.newInvoice is not set
ekzyis Nov 26, 2024
b562412
Ignore wallet configuration errors in QR code
ekzyis Nov 26, 2024
2f1833c
Fix last wallet not returning new invoice
ekzyis Nov 26, 2024
2bd928d
Allow retries of pessimistic actions
ekzyis Nov 26, 2024
f011bbc
Fix payment method returned by retries
ekzyis Nov 26, 2024
748cc22
Show aggregated wallet errors in QR code
ekzyis Nov 26, 2024
250b64b
Return last attempted invoice in canceled state
ekzyis Nov 27, 2024
16a28c9
Fix filter for wallets that can send
ekzyis Nov 27, 2024
2b64fef
Fix invoice retry even if no payment was attempted
ekzyis Nov 27, 2024
85ece35
Fix missing item invoice update for optimistic actions
ekzyis Nov 27, 2024
f4426bb
Remove unnecessary error handling in LNC
ekzyis Nov 27, 2024
744602f
Return latest state of paid or failed invoice
ekzyis Nov 27, 2024
e24e118
Create wrapped invoices on p2p zap retries
ekzyis Nov 27, 2024
b1f064d
Only retry same receiver if forward did not fail
ekzyis Nov 27, 2024
f2e1806
refactor out array of hooks
huumn Nov 27, 2024
ded2096
Fix wallet save
ekzyis Nov 28, 2024
de598c1
Fix [undefined] in logs
ekzyis Nov 28, 2024
bb9fc60
readability improvements
huumn Nov 28, 2024
9574cd2
Fix missing item invoice update on failure
ekzyis Nov 28, 2024
fda130a
make logger use full wallet
huumn Nov 28, 2024
4f05a9e
usesendwallets
huumn Nov 28, 2024
9ea9352
fix zap fallback retries in notifications
huumn Nov 28, 2024
0abbc6b
make fallback retry cache updates a special case
huumn Nov 28, 2024
0774b67
function for merging data after retry
huumn Nov 28, 2024
f5ea386
fix cache update option name on qr
huumn Nov 28, 2024
91aa1f6
feat: recent unpaid bounties selection (#1589)
aegroto Nov 29, 2024
fc9b8f0
Fix Territories selector updates without hard-reload (#1619)
aegroto Nov 30, 2024
d63f466
Introduce SubPopover (#1620)
felipebueno Nov 30, 2024
d890ab7
Fix missing authentication check for invite revocation (#1666)
ekzyis Nov 30, 2024
7ef6fd2
Fix: progress bar shown on back navigation through pathname check (#1…
aegroto Dec 1, 2024
aff5f8d
fix: top boosts shows others' unpaid boosts (#1647)
Soxasora Dec 1, 2024
6c86b39
fix can't upload from iOS camera/mov files (#1667)
Soxasora Dec 1, 2024
6abe6ea
Custom invite code and note (#1649)
riccardobl Dec 1, 2024
42da56e
stop probable source of 504 toasts
huumn Dec 1, 2024
107aefd
Dockerfile update
aegroto Dec 2, 2024
977d4dd
fix: fixed dockerfile
aegroto Dec 3, 2024
e50caa2
chore: removed commented dockerfile
aegroto Dec 3, 2024
edd83a1
feat: bundle action scaffolding
aegroto Dec 3, 2024
c953638
fix: added environment set-up on bundle action
aegroto Dec 3, 2024
42a25e0
chore: printing environment in action
aegroto Dec 3, 2024
a74ea83
fix: changed base CI image and fixed environment creation
aegroto Dec 3, 2024
8f0db77
chore: restore base ubuntu image
aegroto Dec 3, 2024
c7b4054
fix: test VAPID keys with the right bytes count
aegroto Dec 3, 2024
7eaed29
fix: using actually generated VAPID keys
aegroto Dec 3, 2024
f5a67ac
chore: temporarily disabled compare steps
aegroto Dec 3, 2024
de3562f
Revert "chore: temporarily disabled compare steps"
aegroto Dec 3, 2024
999846b
Fix edit timer stuck at 00:00 (#1673)
ekzyis Dec 2, 2024
e2d5380
item referral threshold
huumn Dec 2, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
128 changes: 128 additions & 0 deletions .github/workflows/nextjs_bundle_analysis.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
# Copyright (c) HashiCorp, Inc.
# SPDX-License-Identifier: MPL-2.0

name: 'Next.js Bundle Analysis'

on:
pull_request:
push:
branches:
- master # change this if your default branch is named differently
workflow_dispatch:

defaults:
run:
# change this if your nextjs app does not live at the root of the repo
working-directory: ./

permissions:
contents: read # for checkout repository
actions: read # for fetching base branch bundle stats
pull-requests: write # for comments

jobs:
analyze:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3

- name: Install Node.js
uses: actions/setup-node@v3
with:
node-version: 18

- name: Install dependencies
uses: bahmutov/npm-install@v1

- name: Restore next build
uses: actions/cache@v3
id: restore-build-cache
env:
cache-name: cache-next-build
with:
path: .next/cache
key: ${{ runner.os }}-build-${{ env.cache-name }}

- name: Create dotenv file
run: |
touch .env
cat .env.development >> .env
cat .env.production >> .env
echo "VAPID_MAILTO=mailto:[email protected]" >> .env
echo "NEXT_PUBLIC_VAPID_PUBKEY=BPxWyxu_wyLJKvK8YQIOz9Bu7lyck6PJVZE9DcZKuxMzii_AcS6J43N8xaed6Q4uBmeMuUvAHE6UQRGIJY1CCMo" >> .env
echo "VAPID_PRIVKEY=mqF8ZYR8DucADCoyux17QCy8T_kFocnfDWEOndPW-WE" >> .env
echo "Environment:"
cat .env

- name: Build next.js app
# change this if your site requires a custom build command
run: ./node_modules/.bin/next build

# Here's the first place where next-bundle-analysis' own script is used
# This step pulls the raw bundle stats for the current bundle
- name: Analyze bundle
run: npx -p nextjs-bundle-analysis report

- name: Upload bundle
uses: actions/upload-artifact@v3
with:
name: bundle
path: .next/analyze/__bundle_analysis.json

- name: Download base branch bundle stats
uses: dawidd6/action-download-artifact@v2
if: success() && github.event.number
with:
workflow: nextjs_bundle_analysis.yml
branch: ${{ github.event.pull_request.base.ref }}
path: .next/analyze/base

# And here's the second place - this runs after we have both the current and
# base branch bundle stats, and will compare them to determine what changed.
# There are two configurable arguments that come from package.json:
#
# - budget: optional, set a budget (bytes) against which size changes are measured
# it's set to 350kb here by default, as informed by the following piece:
# https://infrequently.org/2021/03/the-performance-inequality-gap/
#
# - red-status-percentage: sets the percent size increase where you get a red
# status indicator, defaults to 20%
#
# Either of these arguments can be changed or removed by editing the `nextBundleAnalysis`
# entry in your package.json file.
- name: Compare with base branch bundle
if: success() && github.event.number
run: ls -laR .next/analyze/base && npx -p nextjs-bundle-analysis compare

- name: Get Comment Body
id: get-comment-body
if: success() && github.event.number
# https://docs.github.com/en/actions/using-workflows/workflow-commands-for-github-actions#multiline-strings
run: |
echo "body<<EOF" >> $GITHUB_OUTPUT
echo "$(cat .next/analyze/__bundle_analysis_comment.txt)" >> $GITHUB_OUTPUT
echo EOF >> $GITHUB_OUTPUT

- name: Find Comment
uses: peter-evans/find-comment@v2
if: success() && github.event.number
id: fc
with:
issue-number: ${{ github.event.number }}
body-includes: '<!-- __NEXTJS_BUNDLE -->'

- name: Create Comment
uses: peter-evans/create-or-update-comment@v2
if: success() && github.event.number && steps.fc.outputs.comment-id == 0
with:
issue-number: ${{ github.event.number }}
body: ${{ steps.get-comment-body.outputs.body }}

- name: Update Comment
uses: peter-evans/create-or-update-comment@v2
if: success() && github.event.number && steps.fc.outputs.comment-id != 0
with:
issue-number: ${{ github.event.number }}
body: ${{ steps.get-comment-body.outputs.body }}
comment-id: ${{ steps.fc.outputs.comment-id }}
edit-mode: replace
13 changes: 3 additions & 10 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,11 @@

FROM node:18.20.4-bullseye

ENV NODE_ENV=development

ARG UID
ARG GID
RUN groupadd -fg "$GID" apprunner
RUN useradd -om -u "$UID" -g "$GID" apprunner
USER apprunner

WORKDIR /app

EXPOSE 3000

COPY package.json package-lock.json ./
COPY . .
RUN npm ci --legacy-peer-deps --loglevel verbose
CMD ["sh","-c","npm install --loglevel verbose --legacy-peer-deps && npx prisma migrate dev && npm run dev"]
RUN npm run build --verbose
CMD ["/bin/bash"]
28 changes: 22 additions & 6 deletions api/lnd/index.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import { cachedFetcher } from '@/lib/fetch'
import { toPositiveNumber } from '@/lib/validate'
import { toPositiveNumber } from '@/lib/format'
import { authenticatedLndGrpc } from '@/lib/lnd'
import { getIdentity, getHeight, getWalletInfo, getNode } from 'ln-service'
import { getIdentity, getHeight, getWalletInfo, getNode, getPayment } from 'ln-service'
import { datePivot } from '@/lib/time'
import { LND_PATHFINDING_TIMEOUT_MS } from '@/lib/constants'

const lnd = global.lnd || authenticatedLndGrpc({
cert: process.env.LND_CERT,
Expand Down Expand Up @@ -88,22 +90,22 @@ export function getPaymentFailureStatus (withdrawal) {
throw new Error('withdrawal is not failed')
}

if (withdrawal?.failed.is_insufficient_balance) {
if (withdrawal?.failed?.is_insufficient_balance) {
return {
status: 'INSUFFICIENT_BALANCE',
message: 'you didn\'t have enough sats'
}
} else if (withdrawal?.failed.is_invalid_payment) {
} else if (withdrawal?.failed?.is_invalid_payment) {
return {
status: 'INVALID_PAYMENT',
message: 'invalid payment'
}
} else if (withdrawal?.failed.is_pathfinding_timeout) {
} else if (withdrawal?.failed?.is_pathfinding_timeout) {
return {
status: 'PATHFINDING_TIMEOUT',
message: 'no route found'
}
} else if (withdrawal?.failed.is_route_not_found) {
} else if (withdrawal?.failed?.is_route_not_found) {
return {
status: 'ROUTE_NOT_FOUND',
message: 'no route found'
Expand Down Expand Up @@ -160,4 +162,18 @@ export const getNodeSockets = cachedFetcher(async function fetchNodeSockets ({ l
}
})

export async function getPaymentOrNotSent ({ id, lnd, createdAt }) {
try {
return await getPayment({ id, lnd })
} catch (err) {
if (err[1] === 'SentPaymentNotFound' &&
createdAt < datePivot(new Date(), { milliseconds: -LND_PATHFINDING_TIMEOUT_MS * 2 })) {
// if the payment is older than 2x timeout, but not found in LND, we can assume it errored before lnd stored it
return { notSent: true, is_failed: true }
} else {
throw err
}
}
}

export default lnd
107 changes: 91 additions & 16 deletions api/paidAction/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ import { datePivot } from '@/lib/time'
import { PAID_ACTION_PAYMENT_METHODS, USER_ID } from '@/lib/constants'
import { createHmac } from '@/api/resolvers/wallet'
import { Prisma } from '@prisma/client'
import { createWrappedInvoice } from '@/wallets/server'
import { assertBelowMaxPendingInvoices } from './lib/assert'
import { createWrappedInvoice, createInvoice as createUserInvoice } from '@/wallets/server'
import { assertBelowMaxPendingInvoices, assertBelowMaxPendingDirectPayments } from './lib/assert'

import * as ITEM_CREATE from './itemCreate'
import * as ITEM_UPDATE from './itemUpdate'
Expand Down Expand Up @@ -106,6 +106,17 @@ export default async function performPaidAction (actionType, args, incomingConte
}
} else if (paymentMethod === PAID_ACTION_PAYMENT_METHODS.OPTIMISTIC) {
return await performOptimisticAction(actionType, args, contextWithPaymentMethod)
} else if (paymentMethod === PAID_ACTION_PAYMENT_METHODS.DIRECT) {
try {
return await performDirectAction(actionType, args, contextWithPaymentMethod)
} catch (e) {
if (e instanceof NonInvoiceablePeerError) {
console.log('peer cannot be invoiced, skipping')
continue
}
console.error(`${paymentMethod} action failed`, e)
throw e
}
}
}
}
Expand Down Expand Up @@ -229,6 +240,55 @@ async function performP2PAction (actionType, args, incomingContext) {
: await beginPessimisticAction(actionType, args, context)
}

// we don't need to use the module for perform-ing outside actions
// because we can't track the state of outside invoices we aren't paid/paying
async function performDirectAction (actionType, args, incomingContext) {
const { models, lnd, cost } = incomingContext
const { comment, lud18Data, noteStr, description: actionDescription } = args

const userId = await paidActions[actionType]?.getInvoiceablePeer?.(args, incomingContext)
if (!userId) {
throw new NonInvoiceablePeerError()
}

let invoiceObject

try {
await assertBelowMaxPendingDirectPayments(userId, incomingContext)

const description = actionDescription ?? await paidActions[actionType].describe(args, incomingContext)
invoiceObject = await createUserInvoice(userId, {
msats: cost,
description,
expiry: INVOICE_EXPIRE_SECS
}, { models, lnd })
} catch (e) {
console.error('failed to create outside invoice', e)
throw new NonInvoiceablePeerError()
}

const { invoice, wallet } = invoiceObject
const hash = parsePaymentRequest({ request: invoice }).id

const payment = await models.directPayment.create({
data: {
comment,
lud18Data,
desc: noteStr,
bolt11: invoice,
msats: cost,
hash,
walletId: wallet.id,
receiverId: userId
}
})

return {
invoice: payment,
paymentMethod: 'DIRECT'
}
}

export async function retryPaidAction (actionType, args, incomingContext) {
const { models, me } = incomingContext
const { invoice: failedInvoice } = args
Expand All @@ -244,28 +304,43 @@ export async function retryPaidAction (actionType, args, incomingContext) {
throw new Error(`retryPaidAction - must be logged in ${actionType}`)
}

if (!action.paymentMethods.includes(PAID_ACTION_PAYMENT_METHODS.OPTIMISTIC)) {
throw new Error(`retryPaidAction - action does not support optimism ${actionType}`)
}

if (!action.retry) {
throw new Error(`retryPaidAction - action does not support retrying ${actionType}`)
}

if (!failedInvoice) {
throw new Error(`retryPaidAction - missing invoice ${actionType}`)
}

const { msatsRequested, actionId } = failedInvoice
const { msatsRequested, actionId, actionArgs, actionOptimistic } = failedInvoice
const retryContext = {
...incomingContext,
optimistic: true,
optimistic: actionOptimistic,
me: await models.user.findUnique({ where: { id: me.id } }),
cost: BigInt(msatsRequested),
actionId
}

const invoiceArgs = await createSNInvoice(actionType, args, retryContext)
let invoiceArgs
const invoiceForward = await models.invoiceForward.findUnique({
where: { invoiceId: failedInvoice.id },
include: {
wallet: true,
invoice: true,
withdrawl: true
}
})
// TODO: receiver fallbacks
// use next receiver wallet if forward failed (we currently immediately fallback to SN)
const failedForward = invoiceForward?.withdrawl && invoiceForward.withdrawl.actionState !== 'CONFIRMED'
if (invoiceForward && !failedForward) {
const { userId } = invoiceForward.wallet
const { invoice: bolt11, wrappedInvoice: wrappedBolt11, wallet, maxFee } = await createWrappedInvoice(userId, {
msats: failedInvoice.msatsRequested,
feePercent: await action.getSybilFeePercent?.(actionArgs, retryContext),
description: await action.describe?.(actionArgs, retryContext),
expiry: INVOICE_EXPIRE_SECS
}, retryContext)
invoiceArgs = { bolt11, wrappedBolt11, wallet, maxFee }
} else {
invoiceArgs = await createSNInvoice(actionType, actionArgs, retryContext)
}

return await models.$transaction(async tx => {
const context = { ...retryContext, tx, invoiceArgs }
Expand All @@ -282,12 +357,12 @@ export async function retryPaidAction (actionType, args, incomingContext) {
})

// create a new invoice
const invoice = await createDbInvoice(actionType, args, context)
const invoice = await createDbInvoice(actionType, actionArgs, context)

return {
result: await action.retry({ invoiceId: failedInvoice.id, newInvoiceId: invoice.id }, context),
result: await action.retry?.({ invoiceId: failedInvoice.id, newInvoiceId: invoice.id }, context),
invoice,
paymentMethod: 'OPTIMISTIC'
paymentMethod: actionOptimistic ? 'OPTIMISTIC' : 'PESSIMISTIC'
}
}, { isolationLevel: Prisma.TransactionIsolationLevel.ReadCommitted })
}
Expand Down
Loading
Loading