Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
13 changes: 11 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,16 @@ SRC_FILES := $(shell find src -name '*.ts')
lib: ${SRC_FILES} package.json tsconfig.json node_modules rollup.config.js
@./node_modules/.bin/rollup -c && touch lib

dev: ${SRC_FILES} package.json tsconfig.json node_modules rollup.config.js
test/public/bundle.js: ${SRC_FILES} package.json tsconfig.json node_modules test/rollup.config.js test/index.ts test/public/index.html
@./node_modules/.bin/rollup -c test/rollup.config.js

.PHONY: build-test
build-test: test/public/bundle.js

dev: node_modules
@./node_modules/.bin/vite

dev-rollup: ${SRC_FILES} package.json tsconfig.json node_modules rollup.config.js
@./node_modules/.bin/rollup -c test/rollup.config.js -w --host

.PHONY: test
Expand Down Expand Up @@ -55,7 +64,7 @@ publish: | distclean node_modules

.PHONY: clean
clean:
rm -rf lib/ coverage/ docs/
rm -rf lib/ coverage/ docs/ test/public/bundle.js test/public/bundle.js.map

.PHONY: distclean
distclean: clean
Expand Down
17 changes: 10 additions & 7 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@wharfkit/web-renderer",
"version": "1.4.3",
"version": "1.5.0-rc1",
"description": "",
"license": "BSD-3-Clause",
"main": "lib/web-renderer.js",
Expand Down Expand Up @@ -36,7 +36,7 @@
"crypto": false
},
"peerDependencies": {
"@wharfkit/session": "^1.4.0"
"@wharfkit/session": "^2.0.0-rc2"
},
"devDependencies": {
"@babel/core": "^7.20.12",
Expand All @@ -52,15 +52,16 @@
"@tsconfig/svelte": "^5.0.0",
"@typescript-eslint/eslint-plugin": "^5.61.0",
"@typescript-eslint/parser": "^5.61.0",
"@wharfkit/account-creation-plugin-anchor": "^1.3.1",
"@wharfkit/account-creation-plugin-anchor": "^1.4.0",
"@wharfkit/account-creation-plugin-jungle4": "^1.2.0",
"@wharfkit/session": "^1.4.0",
"@wharfkit/transact-plugin-autocorrect": "^1.1.0",
"@wharfkit/common": "^1.5.0",
"@wharfkit/session": "^1.8.0-rc1",
"@wharfkit/transact-plugin-autocorrect": "^1.4.0",
"@wharfkit/transact-plugin-cosigner": "^1.1.0",
"@wharfkit/transact-plugin-explorerlink": "^1.0.1",
"@wharfkit/transact-plugin-mock": "^1.1.0",
"@wharfkit/transact-plugin-resource-provider": "^1.1.0",
"@wharfkit/wallet-plugin-anchor": "^1.5.0-rc1",
"@wharfkit/wallet-plugin-anchor": "^1.6.1",
"@wharfkit/wallet-plugin-cleos": "^1.1.0",
"@wharfkit/wallet-plugin-cloudwallet": "^1.3.3",
"@wharfkit/wallet-plugin-metamask": "^1.0.0-rc3",
Expand Down Expand Up @@ -89,7 +90,9 @@
"tslib": "^2.6.0",
"typescript": "^5.0.0",
"vite": "^4.1.4",
"vite-plugin-mkcert": "^1.17.9",
"yarn-deduplicate": "^6.0.2"
},
"dependencies": {}
"dependencies": {},
"packageManager": "yarn@1.22.22+sha512.a6b2f7906b721bba3d67d4aff083df04dad64c399707841b7acf00f6b133b7ac24255f2652fa22ae3534329dc6180534e98d17432037ff6fd140556e2bb3137e"
}
179 changes: 178 additions & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,12 @@ import {
LoginContext,
PromptArgs,
PromptResponse,
SessionKeyConflictArgs,
SessionKeyConflictResponse,
SessionKeyConsentArgs,
SessionKeyMismatchArgs,
SessionKeyMismatchResponse,
SessionKeyRemoveArgs,
UserInterface,
UserInterfaceAccountCreationResponse,
UserInterfaceLoginResponse,
Expand All @@ -29,6 +35,14 @@ import {
props,
resetState,
router,
sessionKeyConflictData,
sessionKeyConflictPromise,
sessionKeyConsentData,
sessionKeyConsentPromise,
sessionKeyMismatchData,
sessionKeyMismatchPromise,
sessionKeyRemoveData,
sessionKeyRemovePromise,
settings,
} from './ui/state'
import {get} from 'svelte/store'
Expand All @@ -37,6 +51,7 @@ export interface WebRendererOptions {
id?: string
logging?: boolean
minimal?: boolean
colorMode?: 'light' | 'dark'
translations?: Record<string, Record<string, string>>
}

Expand Down Expand Up @@ -69,6 +84,7 @@ export class WebRenderer extends AbstractUserInterface implements UserInterface
public initialized = false
public logging = false
public minimal = false
public settings = settings

constructor(options: WebRendererOptions = defaultWebRendererOptions) {
super()
Expand All @@ -93,6 +109,22 @@ export class WebRenderer extends AbstractUserInterface implements UserInterface
this.i18n = makeLocalization()
let lang = getNavigatorLanguage()
this.minimal = options.minimal || false

// Apply color mode if specified
if (options.colorMode) {
const html = document.documentElement
if (options.colorMode === 'dark') {
html.setAttribute('data-color-mode', 'dark')
html.setAttribute('data-dark-theme', 'dark_dimmed')
} else {
html.setAttribute('data-color-mode', 'light')
html.removeAttribute('data-dark-theme')
}

// Update settings store to apply theme to web-renderer UI
settings.update((current) => ({...current, theme: options.colorMode}))
}

const settingsLanguage = get(settings).language
if (settingsLanguage) {
lang = settingsLanguage
Expand Down Expand Up @@ -143,7 +175,7 @@ export class WebRenderer extends AbstractUserInterface implements UserInterface

async login(context: LoginContext): Promise<UserInterfaceLoginResponse> {
this.log('login', context)
prompt.set(undefined)
prompt.reset()
router.push('login')
const promise = cancelable(
new Promise<UserInterfaceLoginResponse>((resolve, reject) =>
Expand Down Expand Up @@ -237,6 +269,15 @@ export class WebRenderer extends AbstractUserInterface implements UserInterface

async onLoginComplete() {
this.log('onLoginResult')

// Check if modal is still active (e.g., for session key consent)
// If so, don't close it - let the active flow complete
const currentRouter = get(router)
if (currentRouter.path.startsWith('sessionkey-')) {
this.log('onLoginComplete - skipping close, session key flow active')
return
}

// Close the dialog once the login completes
active.set(false)
// Reset all data in the state
Expand Down Expand Up @@ -351,6 +392,142 @@ export class WebRenderer extends AbstractUserInterface implements UserInterface
}
this.i18n.addTranslations(normalizedTranslations)
}

async onSessionKeyConsent(args: SessionKeyConsentArgs): Promise<boolean> {
this.log('onSessionKeyConsent', args)

// Clear any active prompt (e.g., from wallet QR code)
prompt.reset()

active.set(true)
props.set({title: 'Permission Request', subtitle: ''})
router.push('sessionkey-consent')

const promise = cancelable(
new Promise<boolean>((resolve, reject) =>
sessionKeyConsentPromise.set({
reject,
resolve,
})
)
)
this.addCancelablePromise(promise.cancel)
sessionKeyConsentData.set(args)

try {
const result = await promise
active.set(false)
resetState()
return result
} catch (error) {
active.set(false)
resetState()
return false
}
}

async onSessionKeyConflict(args: SessionKeyConflictArgs): Promise<SessionKeyConflictResponse> {
this.log('onSessionKeyConflict', args)
prompt.reset()
active.set(true)
props.set({title: 'Permission Request', subtitle: ''})
router.push('sessionkey-conflict')

const promise = cancelable(
new Promise<SessionKeyConflictResponse>((resolve, reject) =>
sessionKeyConflictPromise.set({
reject,
resolve,
})
)
)
this.addCancelablePromise(promise.cancel)
sessionKeyConflictData.set(args)

try {
const result = await promise
active.set(false)
resetState()
return result
} catch (error) {
active.set(false)
resetState()
return 'cancel'
}
}

async onSessionKeyMismatch(args: SessionKeyMismatchArgs): Promise<SessionKeyMismatchResponse> {
this.log('onSessionKeyMismatch', args)
prompt.reset()
active.set(true)
props.set({title: 'Permission Request', subtitle: ''})
router.push('sessionkey-mismatch')

const promise = cancelable(
new Promise<SessionKeyMismatchResponse>((resolve, reject) =>
sessionKeyMismatchPromise.set({
reject,
resolve,
})
)
)
this.addCancelablePromise(promise.cancel)
sessionKeyMismatchData.set(args)

try {
const result = await promise
active.set(false)
resetState()
return result
} catch (error) {
active.set(false)
resetState()
return 'dismiss'
}
}

getMinimal() {
return this.minimal
}

setMinimal(minimal: boolean) {
this.minimal = minimal
}

async onSessionKeyRemove(args: SessionKeyRemoveArgs): Promise<boolean> {
this.log('onSessionKeyRemove', args)
active.set(true)
props.set({title: 'Permission Request', subtitle: ''})
router.push('sessionkey-remove')
sessionKeyRemoveData.set(args)

const promise = cancelable(
new Promise<boolean>((resolve, reject) =>
sessionKeyRemovePromise.set({
reject,
resolve,
})
)
)
this.addCancelablePromise(promise.cancel)

try {
const result = await promise
if (result) {
// User confirmed - don't close UI yet, transact will take over
sessionKeyRemovePromise.set(undefined)
} else {
// User cancelled - close UI
active.set(false)
resetState()
}
return result
} catch (error) {
active.set(false)
resetState()
return false
}
}
}

export default WebRenderer
42 changes: 42 additions & 0 deletions src/lib/translations/en/common.json
Original file line number Diff line number Diff line change
Expand Up @@ -57,5 +57,47 @@
"author": "An open source SDK for Antelope-based blockchains created by Greymass and made possible through funding by the Antelope Coalition (EOS, Telos, UX, and WAX).",
"link": "Read more about Wharf"
}
},
"sessionkey": {
"consent": {
"description": "wants to perform actions on your behalf, so you won't need wallet approval each time.",
"section-label": "If approved, {{appName}} can perform these actions without wallet approval:",
"approve": "Allow",
"deny": "Not Now",
"revoke-note": "You can turn this off anytime.",
"wallet-notice": "Your wallet will ask you to confirm this setup.",
"decline-explanation": "This is optional. {{appName}} works without it - you'll just approve each action individually.",
"summary": "{{count}} permission(s) on {{contracts}} contract(s)",
"view-details": "View details",
"hide-details": "Hide details",
"boundary": "Any other action will still require wallet approval.",
"all-actions": "Full access - includes future actions",
"all-actions-with-contract": "Full access to {{contract}} - includes future actions"
},
"conflict": {
"description": "already has permissions on",
"add": "Add this device",
"add-description": "All devices will continue to work",
"replace": "Only use this device",
"replace-description": "Other devices will stop working",
"note": "This only affects {{appName}}. Your wallet still works everywhere.",
"cancel": "Cancel",
"continue": "Continue"
},
"mismatch": {
"wants-updated-access": "needs updated permissions.",
"new-permissions": "New permissions:",
"removed-permissions": "Permissions no longer needed:",
"later": "Not Now",
"update": "Update",
"revoke-note": "You can turn this off anytime."
},
"remove": {
"title": "Also remove session key?",
"description": "has active permissions on this device.",
"remove": "Remove and Log Out",
"force": "Log Out Only",
"note": "Your wallet will ask you to sign a transaction to remove this permission."
}
}
}
Loading