Skip to content

Commit 1451078

Browse files
committed
Merge branch 'main' into release
2 parents 867326d + 423ebb6 commit 1451078

File tree

100 files changed

+4291
-1327
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

100 files changed

+4291
-1327
lines changed

.github/workflows/pr-checks.yml

Lines changed: 8 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -14,32 +14,23 @@ concurrency:
1414
cancel-in-progress: true
1515

1616
jobs:
17-
typecheck:
18-
name: Typecheck
17+
lint:
18+
name: Lint and Typecheck
1919
runs-on: ubuntu-latest
2020
steps:
2121
- uses: actions/checkout@v6
2222
- uses: ./.github/workflows/setup
23+
- run: pnpm format:check
24+
- run: pnpm lint:check
2325
- run: pnpm typecheck
2426

25-
lint:
26-
name: Lint
27-
runs-on: ubuntu-latest
28-
steps:
29-
- name: Checkout code
30-
uses: actions/checkout@v6
31-
- name: Environment setup
32-
uses: ./.github/workflows/setup
33-
- name: Check lint
34-
run: pnpm lint:check
35-
36-
format:
37-
name: Format
27+
test:
28+
name: Test
3829
runs-on: ubuntu-latest
3930
steps:
4031
- name: Checkout code
4132
uses: actions/checkout@v6
4233
- name: Environment setup
4334
uses: ./.github/workflows/setup
44-
- name: Check format
45-
run: pnpm format:check
35+
- name: Run tests
36+
run: pnpm test

api/src/routes/get-profile.ts

Lines changed: 84 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,23 @@
11
import { HTTPException } from 'hono/http-exception'
22
import z from 'zod'
33
import { zValidator } from '@hono/zod-validator'
4-
import { ConfigStorageService } from '@shared/config-storage-service'
4+
import {
5+
ConfigStorageService,
6+
ConfigStorageServiceError,
7+
} from '@shared/config-storage-service'
58
import { AWS_PREFIX } from '@shared/defines'
6-
import { PROFILE_IDS, TOOLS } from '@shared/types'
9+
import {
10+
numberToBannerFontSize,
11+
numberToWidgetFontSize,
12+
PROFILE_IDS,
13+
TOOLS,
14+
} from '@shared/types'
715
import type {
8-
BannerConfig,
16+
BaseToolProfile,
917
ConfigVersions,
1018
ElementConfigType,
1119
Tool,
1220
ToolProfile,
13-
WidgetConfig,
1421
} from '@shared/types'
1522
import { app } from '../app.js'
1623
import { createHTTPException } from '../utils/utils.js'
@@ -43,12 +50,17 @@ app.get(
4350
return json<ToolProfile<typeof tool>>(profile)
4451
} catch (error) {
4552
if (error instanceof HTTPException) throw error
46-
if (error instanceof Error) {
47-
if (error.message.includes('404')) {
53+
if (error instanceof ConfigStorageServiceError) {
54+
if (error.code === 'not-found') {
4855
const msg = 'No saved profile found for given wallet address'
4956
throw createHTTPException(404, msg, {
50-
message: 'Not found', // can include the S3 key here perhaps
57+
message: 'Not found',
5158
code: '404',
59+
cause: {
60+
statusCode: error.statusCode,
61+
code: error.code,
62+
message: error.message,
63+
},
5264
})
5365
}
5466
}
@@ -62,6 +74,10 @@ function convertToProfile<T extends Tool>(
6274
config: ElementConfigType,
6375
tool: T,
6476
): ToolProfile<T> {
77+
if (tool === 'offerwall') {
78+
return config.offerwall as ToolProfile<T>
79+
}
80+
6581
return {
6682
$version: '0.0.1',
6783
$name: config.versionName,
@@ -70,30 +86,68 @@ function convertToProfile<T extends Tool>(
7086
} as ToolProfile<T>
7187
}
7288

89+
/** @legacy */
7390
function getToolProfile(profile: ElementConfigType, tool: Tool) {
74-
switch (tool) {
75-
case 'widget':
76-
return extract<WidgetConfig>(
77-
profile,
78-
(key) => key.startsWith('widget') || key.includes('Widget'),
79-
)
80-
case 'banner':
81-
return extract<BannerConfig>(
82-
profile,
83-
(key) => key.startsWith('banner') || key.includes('Banner'),
84-
)
91+
if (tool === 'banner') {
92+
return {
93+
title: {
94+
text: profile.bannerTitleText,
95+
},
96+
description: {
97+
text: profile.bannerDescriptionText,
98+
isVisible: profile.bannerDescriptionVisible,
99+
},
100+
font: {
101+
name: profile.bannerFontName,
102+
size: numberToBannerFontSize(profile.bannerFontSize),
103+
},
104+
animation: {
105+
type: profile.bannerSlideAnimation,
106+
},
107+
position: profile.bannerPosition,
108+
border: {
109+
type: profile.bannerBorder,
110+
},
111+
color: {
112+
text: profile.bannerTextColor,
113+
background: profile.bannerBackgroundColor,
114+
},
115+
thumbnail: {
116+
value: profile.bannerThumbnail,
117+
},
118+
} satisfies Omit<ToolProfile<'banner'>, keyof BaseToolProfile>
85119
}
86-
}
87-
88-
function extract<R, T = ElementConfigType, K = keyof T>(
89-
obj: T,
90-
filter: (key: K) => boolean,
91-
): R {
92-
const entries = Object.entries(obj as Record<string, unknown>).filter(
93-
([key]) => filter(key as K),
94-
)
95-
if (!entries.length) {
96-
throw new Error('No matching profile found')
120+
if (tool === 'widget') {
121+
return {
122+
title: {
123+
text: profile.widgetTitleText,
124+
},
125+
description: {
126+
text: profile.widgetDescriptionText,
127+
isVisible: profile.widgetDescriptionVisible,
128+
},
129+
font: {
130+
name: profile.widgetFontName,
131+
size: numberToWidgetFontSize(profile.widgetFontSize),
132+
},
133+
position: profile.widgetPosition,
134+
border: {
135+
type: profile.widgetButtonBorder,
136+
},
137+
color: {
138+
text: profile.widgetTextColor,
139+
background: profile.widgetBackgroundColor,
140+
theme: profile.widgetButtonBackgroundColor,
141+
},
142+
ctaPayButton: {
143+
text: profile.widgetButtonText,
144+
},
145+
icon: {
146+
value: '',
147+
color: profile.widgetTriggerBackgroundColor,
148+
},
149+
} satisfies Omit<ToolProfile<'widget'>, keyof BaseToolProfile>
97150
}
98-
return Object.fromEntries(entries) as R
151+
152+
throw new Error(`Unsupported tool type: ${tool}`)
99153
}

cdn/build.js

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,14 @@ function rawPlugin() {
6060
const namespace = 'raw-loader'
6161
const filter = /\?raw$/
6262
build.onResolve({ filter }, (args) => {
63-
const resolvedPath = path.join(args.resolveDir, args.path)
63+
let resolvedPath = path.join(args.resolveDir, args.path)
64+
// resolve TypeScript aliases
65+
if (args.path.includes('@c/')) {
66+
const filepath = args.path.split('@c/')[1]
67+
const root = path.join(process.cwd(), '..')
68+
const components = path.join(root, 'components')
69+
resolvedPath = path.join(components, 'src', filepath)
70+
}
6471
return { path: resolvedPath, namespace }
6572
})
6673
build.onLoad({ filter, namespace }, async (args) => {

cdn/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
"@fontsource/titillium-web": "^5.2.8",
1919
"@shared/defines": "workspace:^",
2020
"@shared/types": "workspace:^",
21+
"@shared/utils": "workspace:^",
2122
"@tools/components": "workspace:*",
2223
"directory-tree": "^3.5.2",
2324
"esbuild": "0.27.0",

cdn/src/banner.ts

Lines changed: 3 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -34,29 +34,12 @@ function drawBanner(profile: BannerProfile) {
3434
}
3535

3636
const bannerElement = document.createElement('wm-banner')
37-
const config = profile
38-
39-
const bannerConfig = {
37+
bannerElement.config = {
38+
...profile,
4039
cdnUrl: params.cdnUrl,
41-
bannerTitleText: config.bannerTitleText,
42-
bannerDescriptionText: config.bannerDescriptionText,
43-
isBannerDescriptionVisible: config.bannerDescriptionVisible,
44-
bannerBorderRadius: config.bannerBorder,
45-
bannerPosition: config.bannerPosition,
46-
bannerSlideAnimation: config.bannerSlideAnimation,
47-
bannerThumbnail: config.bannerThumbnail,
48-
theme: {
49-
backgroundColor: config.bannerBackgroundColor,
50-
textColor: config.bannerTextColor,
51-
fontFamily: config.bannerFontName,
52-
fontSize: config.bannerFontSize,
53-
},
5440
}
55-
bannerElement.config = bannerConfig
5641

57-
const position = config.bannerPosition
58-
? config.bannerPosition.toLowerCase()
59-
: 'bottom'
42+
const position = profile.position ? profile.position.toLowerCase() : 'bottom'
6043

6144
bannerElement.style.position = 'fixed'
6245
bannerElement.style.left = '0'

cdn/src/offerwall.ts

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
import { API_URL } from '@shared/defines'
2+
import { OfferwallModal } from '@tools/components'
3+
import { appendPaymentPointer, fetchProfile, getScriptParams } from './utils'
4+
import {
5+
WebMonetizationCustomOfferwallChoice,
6+
type OfferwallChoiceConstructorParams,
7+
type GoogleOfcExtendedWindow,
8+
} from './utils/offerwall'
9+
10+
const NAME = 'wm-offerwall'
11+
customElements.define(NAME, OfferwallModal)
12+
13+
const params = getScriptParams('offerwall')
14+
const linkElem = appendPaymentPointer(params.walletAddress)
15+
16+
const STORAGE_KEY_PREFIX = 'wmt.offerwall.'
17+
const toStorageKey = (key: string) => `${STORAGE_KEY_PREFIX}${key}`
18+
const storage: OfferwallChoiceConstructorParams['storage'] = {
19+
get: (key) => localStorage.getItem(toStorageKey(key)),
20+
set: (key, value) => localStorage.setItem(toStorageKey(key), value),
21+
delete: (key) => localStorage.removeItem(toStorageKey(key)),
22+
}
23+
24+
const offerwallConstructorParams: OfferwallChoiceConstructorParams = {
25+
elementName: NAME,
26+
linkElem,
27+
storage,
28+
params,
29+
fetchConfig: (params) => fetchProfile(API_URL, 'offerwall', params),
30+
}
31+
32+
// Register the custom choice with the Offerwall.
33+
const win = window as unknown as GoogleOfcExtendedWindow
34+
// @ts-expect-error defined by external script
35+
win.googlefc ||= {}
36+
// @ts-expect-error defined by external script
37+
win.googlefc.offerwall ||= {}
38+
// @ts-expect-error defined by external script
39+
win.googlefc.offerwall.customchoice ||= {}
40+
win.googlefc.offerwall.customchoice.registry =
41+
new WebMonetizationCustomOfferwallChoice(offerwallConstructorParams)
42+
43+
win.googletag ||= { cmd: [] }
44+
win.googletag?.cmd?.push(() => {
45+
win.googletag?.enableServices?.()
46+
})
47+
48+
// Uncomment following to show regardless of initialization status
49+
// win.googlefc.offerwall.customchoice.registry.show()

cdn/src/utils/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,4 +63,5 @@ export function appendPaymentPointer(walletAddressUrl: string) {
6363
monetizationElement.rel = 'monetization'
6464
monetizationElement.href = walletAddressUrl
6565
document.head.appendChild(monetizationElement)
66+
return monetizationElement
6667
}

0 commit comments

Comments
 (0)