Skip to content

Commit cdacae1

Browse files
committed
Merge branch 'main' into release
2 parents c2e7ce9 + 455c13e commit cdacae1

39 files changed

+938
-713
lines changed

.github/workflows/deploy.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ jobs:
4747
pnpm install -g "wrangler@${wrangler_version}"
4848
4949
# https://github.com/dorny/paths-filter/issues/232
50-
- uses: dorny/paths-filter@v3
50+
- uses: dorny/paths-filter@v4
5151
if: github.event_name != 'pull_request_review'
5252
id: changes
5353
with:

.nvmrc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
24.9.0
1+
24.14.0

README.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ Please read the [contribution guidelines](.github/contributing.md) before submit
2727
This is a monorepo containing several packages:
2828

2929
- **`api/`** - Hono-based API server running on Cloudflare Workers. Used by tools embedded on websites to fetch their config, handle payments, and manage probabilistic revenue sharing.
30-
- **`frontend/`** - Remix-based React frontend application. Provides the configuration interface where publishers customize their Web Monetization tools (banners, widgets, link tags).
30+
- **`frontend/`** - React Router 7 (framework mode) React frontend. Provides the configuration interface where publishers customize their Web Monetization tools (banners, widgets, link tags).
3131
- **`components/`** - Lit-based web components for publishers. Contains reusable web components that get embedded into publisher websites.
3232
- **`cdn/`** - Content delivery network package. Delivers the embeddable scripts and their related assets that publishers include on their websites to show monetization tools.
3333
- **`shared/`** - Shared utilities and types
@@ -36,7 +36,7 @@ This is a monorepo containing several packages:
3636
## Prerequisites
3737

3838
- [Node.js](https://nodejs.org/) 24+
39-
- [pnpm](https://pnpm.io/) 9.15.9+
39+
- [pnpm](https://pnpm.io/) 10.33+
4040

4141
## Installation
4242

@@ -122,8 +122,8 @@ This will trigger the deploy workflow and create preview environments for the PR
122122

123123
- **Runtime**: Cloudflare workers
124124
- **Development**: Node.js
125-
- **Package Manager**: pnpm 9.15.9
126-
- **Frontend**: React 19 with Remix framework
125+
- **Package Manager**: pnpm 10.33+
126+
- **Frontend**: React Router 7
127127
- **API**: Hono framework on Cloudflare Workers
128128
- **Components**: Lit web components
129129
- **Styling**: TailwindCSS

api/package.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,12 @@
1717
"@hono/zod-validator": "^0.7.6",
1818
"@interledger/open-payments": "^7.1.3",
1919
"@noble/ed25519": "^3.0.0",
20-
"@paralleldrive/cuid2": "^2.3.1",
20+
"@paralleldrive/cuid2": "^3.3.0",
2121
"@shared/config-storage-service": "workspace:^",
22-
"@shared/probabilistic-revenue-share": "workspace:^",
2322
"@shared/default-data": "workspace:^",
23+
"@shared/probabilistic-revenue-share": "workspace:^",
2424
"@shared/utils": "workspace:^",
25-
"hono": "^4.11.3",
25+
"hono": "^4.12.7",
2626
"http-message-signatures": "^1.0.4",
2727
"httpbis-digest-headers": "^1.0.0",
2828
"zod": "^4.1.13"

api/src/routes/payment.ts

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { zValidator } from '@hono/zod-validator'
22
import { APP_URL } from '@shared/defines'
3-
import { KV_PAYMENTS_PREFIX } from '@shared/types'
3+
import { KV_PAYMENTS_PREFIX, PAYMENT_ERROR } from '@shared/types'
44
import { app } from '../app.js'
55
import {
66
PaymentQuoteSchema,
@@ -9,7 +9,10 @@ import {
99
PaymentStatusParamSchema,
1010
} from '../schemas/payment.js'
1111
import type { PaymentStatus } from '../types'
12-
import { OpenPaymentsService } from '../utils/open-payments.js'
12+
import {
13+
OpenPaymentsService,
14+
isNonPositiveAmountError,
15+
} from '../utils/open-payments.js'
1316
import { createHTTPException, waitWithAbort } from '../utils/utils'
1417

1518
app.post(
@@ -30,6 +33,15 @@ app.post(
3033

3134
return json(result)
3235
} catch (error) {
36+
if (isNonPositiveAmountError(error)) {
37+
return json(
38+
{
39+
error: PAYMENT_ERROR.NON_POSITIVE_AMOUNT,
40+
minSendAmount: error.details?.minSendAmount,
41+
},
42+
400,
43+
)
44+
}
3345
throw createHTTPException(500, 'Payment quote creation error: ', error)
3446
}
3547
},

api/src/utils/open-payments.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import {
2+
OpenPaymentsClientError,
23
type PendingGrant,
34
type WalletAddress,
45
type AuthenticatedClient,
@@ -9,6 +10,7 @@ import {
910
isPendingGrant,
1011
createAuthenticatedClient,
1112
} from '@interledger/open-payments'
13+
import type { components as RSComponents } from '@interledger/open-payments/dist/openapi/generated/resource-server-types'
1214
import { createId } from '@paralleldrive/cuid2'
1315
import { getWalletAddress, urlWithParams } from '@shared/utils'
1416
import { createHeaders, sleep, createHTTPException } from './utils.js'
@@ -21,6 +23,7 @@ export interface Amount {
2123
}
2224

2325
export type CreatePayment = { quote: Quote; incomingPaymentGrant: Grant }
26+
type AmountType = RSComponents['schemas']['amount']
2427

2528
type CreateIncomingPaymentParams = {
2629
accessToken: string
@@ -308,6 +311,7 @@ export class OpenPaymentsService {
308311
},
309312
)
310313
} catch (error) {
314+
if (isOpenPaymentsClientError(error)) throw error
311315
throw createHTTPException(
312316
500,
313317
`Could not create payment quote for receiver ${args.walletAddress.id}.`,
@@ -492,3 +496,19 @@ export class OpenPaymentsService {
492496
return { success: true }
493497
}
494498
}
499+
500+
const isOpenPaymentsClientError = (error: unknown) =>
501+
error instanceof OpenPaymentsClientError
502+
503+
// happens during quoting only
504+
export const isNonPositiveAmountError = (
505+
error: unknown,
506+
): error is OpenPaymentsClientError & {
507+
details?: { minSendAmount?: AmountType }
508+
} => {
509+
if (!isOpenPaymentsClientError(error)) return false
510+
return (
511+
error.status === 400 &&
512+
error.description?.toLowerCase()?.includes('non-positive receive amount')
513+
)
514+
}

cdn/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,14 +13,14 @@
1313
},
1414
"devDependencies": {
1515
"@fontsource-variable/open-sans": "^5.2.7",
16-
"@fontsource-variable/roboto": "^5.2.9",
16+
"@fontsource-variable/roboto": "^5.2.10",
1717
"@fontsource/cookie": "^5.2.7",
1818
"@fontsource/titillium-web": "^5.2.8",
1919
"@shared/defines": "workspace:^",
2020
"@shared/types": "workspace:^",
2121
"@shared/utils": "workspace:^",
2222
"@tools/components": "workspace:*",
23-
"directory-tree": "^3.5.2",
23+
"directory-tree": "^3.6.0",
2424
"esbuild": "0.27.0",
2525
"esbuild-plugin-copy": "^2.1.1",
2626
"typescript": "^5.9.3",

cdn/src/utils/offerwall/WebMonetizationCustomOfferwallChoice.ts

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import type { OfferwallModal } from '@c/offerwall'
2-
import type { Controller } from '@c/offerwall/controller'
2+
import type { Actions } from '@c/offerwall/controller'
33
import { applyFontFamily } from '@c/utils'
44
import {
55
BORDER_RADIUS,
@@ -95,7 +95,9 @@ export class WebMonetizationCustomOfferwallChoice implements OfferwallCustomChoi
9595

9696
const abortController = new AbortController()
9797
const onDoneResolver = withResolvers<boolean>()
98-
const controller: Controller = {
98+
99+
const owElem = document.createElement(elementName) as OfferwallModal
100+
const actions = owElem.setController({
99101
onExtensionLinkClick() {
100102
// can start tracking
101103
},
@@ -106,10 +108,7 @@ export class WebMonetizationCustomOfferwallChoice implements OfferwallCustomChoi
106108
onDone() {
107109
onDoneResolver.resolve(true)
108110
},
109-
}
110-
111-
const owElem = document.createElement(elementName) as OfferwallModal
112-
owElem.setController(controller)
111+
})
113112

114113
// in case initialize() wasn't called
115114
this.#configPromise ??= fetchConfig(params)
@@ -119,7 +118,7 @@ export class WebMonetizationCustomOfferwallChoice implements OfferwallCustomChoi
119118
document.body.appendChild(owElem)
120119

121120
try {
122-
await this.#runBusinessLogic(owElem, abortController.signal)
121+
await this.#runBusinessLogic(actions, abortController.signal)
123122
onDoneResolver.resolve(true)
124123
} catch (error) {
125124
console.error(error)
@@ -157,7 +156,7 @@ export class WebMonetizationCustomOfferwallChoice implements OfferwallCustomChoi
157156
* to give access.
158157
* - If either of above was within allowed time, give access.
159158
*/
160-
#runBusinessLogic = async (elem: OfferwallModal, signal: AbortSignal) => {
159+
#runBusinessLogic = async (actions: Actions, signal: AbortSignal) => {
161160
const { linkElem } = this.#deps
162161
const wasExtensionInstalledAtStart = isExtensionInstalled()
163162

@@ -167,11 +166,11 @@ export class WebMonetizationCustomOfferwallChoice implements OfferwallCustomChoi
167166
this.#isWithinAllowedTime(lastEvent.timestamp) &&
168167
isExtensionInstalled()
169168
) {
170-
return elem.setScreen('all-set')
169+
return actions.setScreen('all-set')
171170
}
172171

173172
if (wasExtensionInstalledAtStart) {
174-
elem.setScreen('contribution-required')
173+
actions.setScreen('contribution-required')
175174
while (true) {
176175
if (!this.#monetizationEventResolver) {
177176
// if not initialized
@@ -189,7 +188,7 @@ export class WebMonetizationCustomOfferwallChoice implements OfferwallCustomChoi
189188
this.#isForSameWalletAddress(event.paymentPointer) &&
190189
(await isValidPayment(event.incomingPayment))
191190
) {
192-
elem.setScreen('all-set')
191+
actions.setScreen('all-set')
193192
this.#setLastEvent({
194193
type: 'monetization',
195194
timestamp: Date.now(),
@@ -211,7 +210,7 @@ export class WebMonetizationCustomOfferwallChoice implements OfferwallCustomChoi
211210
}
212211
} else {
213212
await this.#waitForExtensionInstall(signal)
214-
elem.setScreen('all-set')
213+
actions.setScreen('all-set')
215214
this.#setLastEvent({ type: 'install', timestamp: Date.now() })
216215
}
217216
}

components/src/assets/wm_close_button.svg

Lines changed: 0 additions & 1 deletion
This file was deleted.

0 commit comments

Comments
 (0)