
Security News
Socket Releases Free Certified Patches for Critical vm2 Sandbox Escape
A critical vm2 sandbox escape can allow untrusted JavaScript to break isolation and execute commands on the host Node.js process.
@lukso/core
Advanced tools
Core utilities, services, and mixins for LUKSO web components and applications
Core utilities, services, and mixins for LUKSO web components and applications.
pnpm add @lukso/core
# or
npm install @lukso/core
# or
yarn add @lukso/core
This package requires lit as a peer dependency (for the Lit mixins):
pnpm add lit
If you're using chain definitions with viem types, you'll also need:
pnpm add viem
Package contains some basic elements:
Detect device type, OS, and browser:
import { deviceService } from '@lukso/core/services/device'
const device = deviceService()
if (device.isMobile) {
console.log('Mobile device detected')
}
console.log({
os: device.isMacOS ? 'macOS' : device.isWindows ? 'Windows' : 'Unknown',
browser: device.isSafari ? 'Safari' : device.isChrome ? 'Chrome' : 'Unknown',
})
Format messages, numbers, and dates:
import { createIntlService, setIntlService } from '@lukso/core/services/intl'
const intl = createIntlService({
locale: 'en-US',
messages: {
'app.welcome': 'Welcome',
'app.hello': 'Hello, {name}!',
},
})
setIntlService(intl)
console.log(intl.formatMessage('app.welcome')) // 'Welcome'
console.log(intl.formatMessage('app.hello', { name: 'John' })) // 'Hello, John!'
console.log(intl.formatNumber(1234.56)) // '1,234.56'
// Enable warnings for missing translations (useful for debugging)
const intlWithWarnings = createIntlService({
locale: 'en-US',
messages: {
'app.welcome': 'Welcome',
},
onError: (err) => {
console.error('Translation error:', err)
},
})
Note: By default, missing translation warnings are suppressed since translations are optional. To enable warnings during development, pass a custom
onErrorhandler.
Detect browser type and get browser-specific metadata (name, icon, store link):
import { browserInfo, type BrowserInfo } from '@lukso/core/utils'
import { deviceService } from '@lukso/core/services'
const device = deviceService()
const browser: BrowserInfo = browserInfo(device)
console.log(browser.id) // 'chrome', 'firefox', 'safari', 'edge', 'brave', 'opera'
console.log(browser.name) // 'Chrome', 'Firefox', 'Safari', etc.
console.log(browser.icon) // 'logo-chrome', 'logo-firefox', etc.
console.log(browser.storeLink) // URL to browser's extension store for Universal Profile
The browserInfo function is useful for:
Check if an asset is the native LYX token:
import { isLyx } from '@lukso/core/utils'
isLyx({ isNativeToken: true }) // true
isLyx({ standard: 'LSP7DigitalAsset' }) // false
Check if an asset is a fungible token (including native LYX):
import { isToken } from '@lukso/core/utils'
isToken({ isNativeToken: true }) // true (LYX)
isToken({ standard: 'LSP7DigitalAsset', tokenType: 0 }) // true (Token)
isToken({ standard: 'LSP7DigitalAsset', tokenType: 1 }) // false (NFT)
isToken({ standard: 'LSP8IdentifiableDigitalAsset', tokenType: 0 }) // false
Check if an asset is a collectible (NFT or collection) based on its LSP standard and token type:
import { isCollectible } from '@lukso/core/utils'
isCollectible({ standard: 'LSP7DigitalAsset', tokenType: 1 }) // true (NFT)
isCollectible({ standard: 'LSP8IdentifiableDigitalAsset', tokenType: 2 }) // true (Collection)
isCollectible({ standard: 'LSP7DigitalAsset', tokenType: 0 }) // false (Token)
Convert text to slug format (lowercase with hyphens):
import { slug } from '@lukso/core/utils'
console.log(slug('Hello World')) // 'hello-world'
console.log(slug('TEST')) // 'test'
console.log(slug('some-text')) // 'some-text'
console.log(slug('')) // ''
The slug function is useful for:
Create and verify signed QR codes for Universal Profile check-ins. This is useful for proving ownership of a Universal Profile without on-chain transactions.
URI Format: ethereum:<address>@<chainId>?ts=<unixTimestamp>&sig=<signature>
import {
createSignedQR,
verifySignedQR,
parseSignedQR,
isSignedQRFormat,
getControllerAddress,
getEIP1271Data,
EIP1271_MAGIC_VALUE,
} from '@lukso/core/utils'
Creating a signed QR code:
// Using a private key directly
const uri = await createSignedQR(
'0x1234...', // controller private key
'0xabcd...', // profile address
42, // LUKSO mainnet (or 4201 for testnet)
{ generationOffsetSeconds: 2 } // optional: account for QR display latency
)
// Returns: ethereum:0xabcd...@42?ts=1706345678&sig=0x...
// Using a custom signer (WalletConnect, hardware wallet, etc.)
const uri = await createSignedQR(
null, // not needed when signer is provided
'0xabcd...', // profile address
42,
{
signer: async (message) => await wallet.signMessage(message)
}
)
Verifying a signed QR code:
const result = await verifySignedQR(uri, {
maxAgeSeconds: 60, // default: 60 seconds
})
if (result.isValid) {
console.log('Profile:', result.profileAddress)
console.log('Chain ID:', result.chainId)
console.log('Signed by:', result.recoveredAddress)
console.log('Timestamp:', result.timestamp)
console.log('Is expired:', result.isExpired)
}
EIP-1271 verification (for smart contract wallets):
import { createPublicClient, http } from 'viem'
import { lukso } from 'viem/chains'
const result = await verifySignedQR(uri)
const { hash, signature } = getEIP1271Data(uri, result)
// Call isValidSignature on the Universal Profile contract
const client = createPublicClient({ chain: lukso, transport: http() })
const magicValue = await client.readContract({
address: result.profileAddress,
abi: [{
name: 'isValidSignature',
type: 'function',
stateMutability: 'view',
inputs: [
{ name: 'dataHash', type: 'bytes32' },
{ name: 'signature', type: 'bytes' },
],
outputs: [{ name: '', type: 'bytes4' }],
}],
functionName: 'isValidSignature',
args: [hash, signature],
})
const isAuthorizedController = magicValue === EIP1271_MAGIC_VALUE
Quick format check:
if (isSignedQRFormat(uri)) {
// Valid format, proceed with verification
const parsed = parseSignedQR(uri)
console.log(parsed?.profileAddress, parsed?.chainId)
}
Get controller address from private key:
const controllerAddress = getControllerAddress('0x1234...')
console.log('Will sign as:', controllerAddress)
The signed QR code functionality is useful for:
Add device detection to your component:
import { LitElement, html } from 'lit'
import { customElement } from 'lit/decorators.js'
import { withDeviceService } from '@lukso/core/mixins'
@customElement('my-component')
export class MyComponent extends withDeviceService(LitElement) {
render() {
return html`
<div>
Is mobile: ${this.device?.isMobile}
Is Safari: ${this.device?.isSafari}
</div>
`
}
}
Add internationalization to your component:
import { LitElement, html } from 'lit'
import { customElement } from 'lit/decorators.js'
import { withIntlService } from '@lukso/core/mixins'
@customElement('my-component')
export class MyComponent extends withIntlService(LitElement) {
render() {
return html`
<h1>${this.formatMessage('app.title')}</h1>
<p>${this.formatMessage('app.welcome')}</p>
`
}
}
Add theme management with automatic dark mode support:
import { LitElement, html } from 'lit'
import { customElement } from 'lit/decorators.js'
import { withTheme } from '@lukso/core/mixins'
@customElement('my-component')
export class MyComponent extends withTheme(LitElement) {
render() {
return html`
<div class="bg-neutral-100 dark:bg-neutral-10">
<h1 class="text-neutral-10 dark:text-neutral-100">
Hello World
</h1>
<p>Current theme: ${this.theme}</p>
<p>Is dark mode: ${this.isDark}</p>
</div>
`
}
}
Features:
'light', 'dark', or 'auto''auto'data-theme-root attributedark class for Tailwind's dark mode utilitiesAPI:
theme ('light' | 'dark' | 'auto'): The theme mode (reflects to attribute)isDark (boolean): Read-only computed state indicating if dark mode is activeHTML Structure:
<!-- Light mode -->
<my-component theme="light">
#shadow-root
<div data-theme-root>
<!-- Your component's rendered content -->
</div>
</my-component>
<!-- Dark mode -->
<my-component theme="dark">
#shadow-root
<div data-theme-root class="dark">
<!-- Your component's rendered content -->
</div>
</my-component>
Extended chain configurations for LUKSO networks with custom contracts and metadata.
import { luksoMainnet, luksoTestnet } from '@lukso/core/chains'
Package contain some basic types.
import type { ChainExtended, NetworkSlug, Address } from '@lukso/core'
Package provides some basic constants.
import { SUPPORTED_NETWORK_IDS, GRAPHQL_ENDPOINT_MAINNET, GRAPHQL_ENDPOINT_TESTNET } from '@lukso/core/config'
If you need to use @lukso/core in environments without a bundler (e.g., plain HTML, WordPress, static sites), you can use import maps to resolve bare module specifiers.
Since this package uses Lit as a peer dependency and marks it as external, it outputs bare imports like import { html } from 'lit'. Browsers can't resolve these without help.
<!DOCTYPE html>
<html>
<head>
<script type="importmap">
{
"imports": {
"lit": "https://cdn.jsdelivr.net/npm/lit@3.3/+esm",
"lit/": "https://cdn.jsdelivr.net/npm/lit@3.3/",
"@lit/reactive-element": "https://cdn.jsdelivr.net/npm/@lit/reactive-element@2/+esm",
"@lit/reactive-element/": "https://cdn.jsdelivr.net/npm/@lit/reactive-element@2/",
"@preact/signals-core": "https://cdn.jsdelivr.net/npm/@preact/signals-core@1/+esm",
"@lukso/core": "https://cdn.jsdelivr.net/npm/@lukso/core/+esm",
"@lukso/core/": "https://cdn.jsdelivr.net/npm/@lukso/core/"
}
}
</script>
</head>
<body>
<script type="module">
import { deviceService } from '@lukso/core/services/device'
import { luksoMainnet } from '@lukso/core/chains'
const device = deviceService()
console.log('Is mobile:', device.isMobile)
console.log('Chain ID:', luksoMainnet.id)
</script>
</body>
</html>
<script type="importmap"> must appear before any <script type="module">"@lukso/core/" to map subpath imports like @lukso/core/servicesMIT
FAQs
Core utilities, services, and mixins for LUKSO web components and applications
The npm package @lukso/core receives a total of 210 weekly downloads. As such, @lukso/core popularity was classified as not popular.
We found that @lukso/core demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago.Ā It has 2 open source maintainers collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
A critical vm2 sandbox escape can allow untrusted JavaScript to break isolation and execute commands on the host Node.js process.

Research
Five malicious NuGet packages impersonate Chinese .NET libraries to deploy a stealer targeting browser credentials, crypto wallets, SSH keys, and local files.

Security News
pnpm 11 turns on a 1-day Minimum Release Age and blocks exotic subdeps by default, adding safeguards against fast-moving supply chain attacks.