npm.io
2.2.0 • Published 2 weeks ago

@startbahn/startrail-sdk-js

Licence
UNLICENSED
Version
2.2.0
Deps
7
Size
2.0 MB
Vulns
0
Weekly
0

@startbahn/startrail-sdk-js

npm version

Front-end (browser) JavaScript/TypeScript SDK for the Startrail platform.

It authenticates a user's Ethereum wallet — Startrail (social / email login powered by Torus) or MetaMask — and signs Startrail meta-transactions on their behalf: minting Startrail Records (SRRs), managing collections, transferring ownership with provenance, and reading royalties. Ships with full TypeScript types.

  • One entry point: the Startrail class.
  • Lifecycle: new Startrail(config)await sdk.login() → call an action.
  • Browser only — it opens wallet popups and expects a DOM (not for Node runtimes).

For AI coding tools: a machine-readable API reference lives in llms.txt, and a short agent how-to in AGENTS.md.


Install

pnpm add @startbahn/startrail-sdk-js
# or
npm i @startbahn/startrail-sdk-js
# or
yarn add @startbahn/startrail-sdk-js

Or via a script tag (UMD build exposes a global Startrail):

<!-- jsDelivr -->
<script src="https://cdn.jsdelivr.net/npm/@startbahn/startrail-sdk-js"></script>
<!-- unpkg -->
<script src="https://unpkg.com/@startbahn/startrail-sdk-js"></script>

Quick start

import { Startrail } from '@startbahn/startrail-sdk-js'

// No config needed to target the Startrail production endpoint with the default Torus wallet.
const sdk = new Startrail({ env: 'staging', wallet: 'startrail', lang: 'en' })

// 1) Authenticate (opens the wallet login flow)
const eoas = await sdk.login()
if (!eoas) throw new Error('login was cancelled by the user')

// 2) Read who logged in
const user = await sdk.getUserInfo()

// 3) Act — e.g. mint a Startrail Record
const srr = await sdk.createSRR({
  isPrimaryIssuer: true,
  metadata: { name: 'Artwork #1' },
  artistAddress: '0xArtist…',
  lockExternalTransfer: false,
  startrailLUWContractAddress: '0xLUW…',
})
The | false return convention

Every action method resolves to its result on success, or to false when the call is skipped because a wallet popup is already open or the user cancelled/closed the popup. false is not an error and not the data — always branch on it:

const res = await sdk.createSRR(args)
if (res === false) {
  // user cancelled the popup — nothing happened on-chain
} else {
  console.log(res.tx.tokenId)
}

Unexpected failures (API / validation / RPC) throw one of the exported error classes.


Configuration

new Startrail(config?: StartrailSDKInitConfig) — every field is optional.

Field Type Default Description
env 'production' | 'staging' | 'lrc' | 'local' 'production' Target environment / network (see Environments).
wallet 'startrail' | 'metamask' 'startrail' Wallet backend. startrail = social/email login via Torus.
apiPath string production URL Startrail API base URL the SDK calls.
rpcEndpoint string per env Custom RPC endpoint the wallet connects to.
chainId number per env Custom EVM chain id.
lang 'en' | 'ja' 'en' UI language.
loginProvider LoginProvider[] Allowed providers, e.g. ['email_password'], ['google'], ['email_passwordless'].
authAction { login: boolean; signup: boolean } Restrict the email popup to a single tab and adjust wording.
auth0TorusConfigKey string Auth0Torus config key (provided by Torus) used to initialise the network.
customUi CustomUi UI customisation (logos, service name, wording) — see Custom UI.
callbackUrl string URL the signup verification email redirects back to.
withModal boolean false Show the Torus login-provider selection modal.
loginHint string User's email when known. With a single email_passwordless provider, login goes straight through and skips the modal.
debug boolean false Verbose SDK logging to the console.
mfaLevel 'none' | 'mandatory' | 'optional' Deprecated — no effect since torus-embed v6.
torusBuildEnv StartrailEnv Deprecated — alias for env; use env.

LoginProvider'google' \| 'email_password' \| 'email_passwordless' \| 'facebook' \| 'twitter' \| 'line' \| 'apple'.


API

All methods are async. Most write actions trigger login() automatically (a wallet popup) if the user isn't authenticated yet. startrailLUWContractAddress is the Licensed User Wallet (LUW) contract the meta-transaction is proxied through, and is required by most write actions. Addresses are checksummed hex; royalties are in basis points (1000 = 10%).

Auth & session
Method Returns
login(overwriteConfig?: OverwriteStartrailSDKConfig) Promise<EOA[] | false> — authenticated addresses, or false if cancelled.
logout() Promise<void | false>
getUserInfo() Promise<UserInfo | false>{ email, name, profileImage, … }.
signMessage(message: string, disableCustomPrefix?: boolean) Promise<MessageSignature | false> — set disableCustomPrefix = true to use personal_sign (preferred).
switchLanguage(lang: Language) Promise<void | false>'en' or 'ja'.

OverwriteStartrailSDKConfig (per-call overrides for login): { authAction?, lang?, loginProvider?, loginHint? }.

// Email known in advance + single passwordless provider → no modal shown
const eoas = await sdk.login({ loginProvider: ['email_passwordless'], loginHint: 'user@example.com' })
Collections
// Deploy a new collection (ERC-721) contract
await sdk.createCollection({
  name: 'My Collection',
  symbol: 'MYC',
  startrailLUWContractAddress: '0xLUW…',
}) // -> { txReceiptId, tx: { contractAddress, salt } } | false

// Transfer collection ownership
await sdk.transferCollectionOwnership({
  contractAddress: '0xCollection…',
  newOwner: '0xNewOwner…',
  startrailLUWContractAddress: '0xLUW…',
}) // -> { txReceiptId, tx: { contractAddress } } | false
Startrail Records (SRRs)
// Mint
await sdk.createSRR({
  isPrimaryIssuer: true,
  metadata: { name: 'Artwork #1' },        // validated against the SRR schema
  artistAddress: '0xArtist…',
  lockExternalTransfer: false,             // true = Startrail-only transfers
  startrailLUWContractAddress: '0xLUW…',
}) // -> { txReceiptId, tx: { tokenId, metadataCID, contractAddress? } } | false

// Update metadata
await sdk.updateMetadata({ tokenId: '123', metadata: { name: 'New title' }, startrailLUWContractAddress: '0xLUW…' })

// Transfer to an Ethereum address with provenance
await sdk.transferSRRToEthereumAddress({
  to: '0xRecipient…',
  tokenId: '123',
  metadata: { transferType: 'sale' },      // HistoryMetadata
  startrailLUWContractAddress: '0xLUW…',
})

// Two-step transfer (step 1 — the new owner must reveal to finalise)
await sdk.approveSRRByCommitment({ tokenId: '123', metadata: { transferType: 'sale' }, startrailLUWContractAddress: '0xLUW…' })

// Associate custom histories
await sdk.addCustomHistoriesToSRRs({ tokenIds: ['123'], customHistoryIds: ['10'], startrailLUWContractAddress: '0xLUW…' })

// Convert metadata to the latest schema (offline — no popup, no tx)
await sdk.convertMetadata({ metadataBatch: [{ metadata: { name: 'legacy' }, tokenId: '123' }] })

// Read ERC-2981 royalty (read-only)
await sdk.checkERC2981Royalty({ tokenId: '123' }) // -> { royaltyReceiver, royaltyBasisPoints } | false
Batch
// Run several operations in one transaction
await sdk.bulk({
  isCompressEnabled: false,
  startrailLUWContractAddress: '0xLUW…',
  txs: [
    { functionType: 'createSRR', data: { /* CreateSRRForRequest */ } },
    // functionType ∈ 'createSRR' | 'approveSRRByCommitment' | 'transferFromWithProvenance'
  ],
}) // -> { batchId } | false

Success responses carry a txReceiptId (or batchId); the on-chain state change is asynchronous — poll the Startrail API with that id to confirm completion.

transferFromWithProvenance(args) is deprecated — use transferSRRToEthereumAddress(args).


Environments

Selected via env. Determines the blockchain network and the Torus/Auth0 accounts used.

env Network Notes
production Polygon (Matic) mainnet Production Torus + Startrail production API.
staging Amoy testnet Production Torus + Startrail staging API.
lrc Amoy testnet LRC Torus + Startrail QA API.
local http://localhost:8545 Local development.

Custom UI

customUi customises logos, names, and wording. words supplies per-language overrides for the modal, signPopup, emailAuthPopup, and embed strings.

const sdk = new Startrail({
  env: 'lrc',
  customUi: {
    logoUrl: 'https://sample.com/logo',
    logoWhiteUrl: 'https://sample.com/white-logo',   // white logo on dark backgrounds
    serviceName: 'Your service',
    contactUrl: 'contact@startrail.io',
    verificationEmailTitle: 'Your verification email title',
    words: {
      en: {
        modal: {
          // {verifier} is replaced with the chosen provider name if present
          continueLogin: 'Login with previous {verifier} account',
          termsConditions: 'Terms & Conditions',
          termsConditionsLinkUrl: 'https://…',
          privacyPolicyLinkUrl: 'https://…',
        },
        signPopup: { title: '…', requestFrom: '…', dataToSign: '…', confirm: 'Confirm', cancel: 'Cancel' },
        emailAuthPopup: { titleLogin: 'Log in', titleSignup: 'Sign up' },
      },
      ja: {
        modal: { continueLogin: '前回の{verifier}アカウントを使う' },
        emailAuthPopup: { titleLogin: 'ログイン', titleSignup: '新規登録' },
      },
    },
  },
})

Errors

Unexpected failures throw a subclass of a common Startrail error base, all exported from the package. Catch the specific class or inspect error.errorCode.

import { Startrail, METADATA_VALIDATION_FAILED } from '@startbahn/startrail-sdk-js'

try {
  const res = await sdk.createSRR(args)
  if (res === false) { /* user cancelled the popup */ }
} catch (e) {
  if (e instanceof METADATA_VALIDATION_FAILED) { /* fix the metadata */ }
  else throw e
}

Common classes: StartrailApiError, STARTRAIL_API_QUOTA_LIMIT_EXCEEDED, METADATA_VALIDATION_FAILED, Auth0VerifyEmail, WALLET_NOT_FOUND, WALLET_NOT_INITIALIZED, WALLET_EOA_NOT_MATCH, WALLET_USER_REJECT_WALLET_REQUEST, WALLET_RPC_CONNECTION_FAILURE, TORUS_FAILS_INIT, TORUS_THIRD_PARTY_COOKIES_UNSUPPORTED, JSON_RPC_ERROR, Others. See llms.txt for the full list and when each is thrown.


Tips

  • MetaMask: call sdk.login() before asking the user to sign or call the API, to fetch the currently active EOA and compare it in your app — the SDK can't prevent users from switching accounts (a mismatch surfaces as WALLET_EOA_NOT_MATCH).
  • Read-only methods (convertMetadata, checkERC2981Royalty) don't submit transactions.
  • TypeScript: types are bundled (types/startrail-sdk-js.d.ts) — hover any method or argument for inline docs.

Resources

Keywords