@unlink-xyz/node 0.1.3-canary.a96530d → 0.1.3-canary.b0ad588
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +9 -10
- package/dist/index.d.ts +9 -10
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/init.ts","../src/errors.ts","../src/confirmation.ts","../src/events.ts","../src/storage/sqlite.ts"],"sourcesContent":["// Init\nexport { initWallet } from \"./init.js\";\n\n// Confirmation\nexport { waitForConfirmation, pollRelayStatus } from \"./confirmation.js\";\n\n// Events\nexport { createWalletEmitter } from \"./events.js\";\n\n// Storage\nexport {\n createSqliteStorage,\n type SqliteStorageOptions,\n} from \"./storage/sqlite.js\";\n\n// Errors\nexport {\n TimeoutError,\n TransactionFailedError,\n TERMINAL_TX_STATES,\n FAILED_TX_STATES,\n DEFAULT_TIMEOUT_MS,\n DEFAULT_POLL_INTERVAL_MS,\n} from \"./errors.js\";\n\n// Types\nexport type {\n NodeWalletConfig,\n TxStatus,\n WaitOptions,\n PollOptions,\n} from \"./types.js\";\n\n// Re-export commonly needed core types so consumers don't need @unlink-xyz/core\nexport { UnlinkWallet, createMemoryStorage } from \"@unlink-xyz/core\";\n\nexport type {\n Account,\n AccountInfo,\n AccountView,\n DepositRelayResult,\n Environment,\n HistoryEntry,\n NoteRecord,\n RelayState,\n RelayStatusResponse,\n Storage,\n TransactRelayResult,\n TransferPlanResult,\n TransferResult,\n WalletSDKEvent,\n WithdrawPlanResult,\n WithdrawResult,\n} from \"@unlink-xyz/core\";\n","import crypto from \"node:crypto\";\nimport { createMemoryStorage, UnlinkWallet } from \"@unlink-xyz/core\";\n\nimport type { NodeWalletConfig } from \"./types.js\";\n\nconst nodeRng = (n: number): Uint8Array =>\n new Uint8Array(crypto.randomBytes(n));\n\n/**\n * Initialize an Unlink wallet with Node.js-friendly defaults.\n *\n * Compared to `UnlinkWallet.create()`, this:\n * - Defaults storage to in-memory (no IndexedDB required)\n * - Defaults RNG to `node:crypto`\n * - Defaults autoSync to `false`\n * - Optionally creates seed + first account automatically\n * - Optionally syncs notes from blockchain\n *\n * @example\n * ```ts\n * // Minimal — ready to use in one call:\n * const wallet = await initWallet({\n * chainId: 11155111,\n * environment: \"testnet\",\n * });\n *\n * // Skip auto-setup (e.g., to import an existing mnemonic):\n * const wallet = await initWallet({\n * chainId: 11155111,\n * environment: \"testnet\",\n * setup: false,\n * sync: false,\n * });\n * await wallet.seed.importMnemonic(\"your mnemonic ...\");\n * await wallet.accounts.create();\n * await wallet.sync();\n * ```\n */\nexport async function initWallet(\n config: NodeWalletConfig,\n): Promise<UnlinkWallet> {\n // Strip node-specific fields before passing to core\n const { setup, sync, ...coreConfig } = config;\n void setup;\n void sync;\n\n const wallet = await UnlinkWallet.create({\n ...coreConfig,\n storage: config.storage ?? createMemoryStorage(),\n rng: config.rng ?? nodeRng,\n autoSync: config.autoSync ?? false,\n fetch: config.fetch ?? globalThis.fetch,\n });\n\n if (config.setup !== false) {\n const hasSeed = await wallet.seed.exists();\n if (!hasSeed) {\n await wallet.seed.create();\n }\n\n const accounts = await wallet.accounts.list();\n if (accounts.length === 0) {\n await wallet.accounts.create();\n }\n }\n\n if (config.sync !== false) {\n await wallet.sync();\n }\n\n return wallet;\n}\n","import type { RelayState } from \"@unlink-xyz/core\";\n\n/** Terminal relay states — the transaction has finished processing. */\nexport const TERMINAL_TX_STATES: readonly RelayState[] = [\n \"succeeded\",\n \"reverted\",\n \"failed\",\n \"dead\",\n] as const;\n\n/** Failed relay states — the transaction did not succeed. */\nexport const FAILED_TX_STATES: readonly RelayState[] = [\n \"reverted\",\n \"failed\",\n \"dead\",\n] as const;\n\n/** Default timeout for `waitForConfirmation` (5 minutes). */\nexport const DEFAULT_TIMEOUT_MS = 5 * 60 * 1000;\n\n/** Default initial poll interval (2 seconds). */\nexport const DEFAULT_POLL_INTERVAL_MS = 2_000;\n\n/** Maximum poll interval after backoff (30 seconds). */\nexport const MAX_POLL_INTERVAL_MS = 30_000;\n\n/** Backoff multiplier for exponential polling. */\nexport const BACKOFF_FACTOR = 1.5;\n\n/** Thrown when relay polling exceeds the configured timeout. */\nexport class TimeoutError extends Error {\n readonly txId: string;\n readonly timeout: number;\n\n constructor(txId: string, timeout: number) {\n super(`Transaction ${txId} did not confirm within ${timeout}ms`);\n this.name = \"TimeoutError\";\n this.txId = txId;\n this.timeout = timeout;\n }\n}\n\n/** Thrown when a transaction reaches a failed terminal state. */\nexport class TransactionFailedError extends Error {\n readonly txId: string;\n readonly state: RelayState;\n readonly reason?: string;\n\n constructor(txId: string, state: RelayState, reason?: string) {\n super(\n `Transaction ${txId} failed with state: ${state}${reason ? ` — ${reason}` : \"\"}`,\n );\n this.name = \"TransactionFailedError\";\n this.txId = txId;\n this.state = state;\n this.reason = reason;\n }\n}\n","import type { UnlinkWallet } from \"@unlink-xyz/core\";\n\nimport {\n BACKOFF_FACTOR,\n DEFAULT_POLL_INTERVAL_MS,\n DEFAULT_TIMEOUT_MS,\n FAILED_TX_STATES,\n MAX_POLL_INTERVAL_MS,\n TERMINAL_TX_STATES,\n TimeoutError,\n TransactionFailedError,\n} from \"./errors.js\";\nimport type { PollOptions, TxStatus, WaitOptions } from \"./types.js\";\n\nfunction toTxStatus(\n txId: string,\n raw: Awaited<ReturnType<UnlinkWallet[\"getTxStatus\"]>>,\n): TxStatus {\n return {\n txId,\n state: raw.state,\n txHash: raw.txHash ?? undefined,\n blockNumber: raw.receipt?.blockNumber ?? undefined,\n error: raw.error ?? undefined,\n };\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\n/**\n * Poll relay status until the transaction reaches a terminal state.\n *\n * Resolves with `TxStatus` on success (`\"succeeded\"`).\n * Throws `TransactionFailedError` on failure (`\"reverted\"`, `\"failed\"`, `\"dead\"`).\n * Throws `TimeoutError` if the timeout is exceeded.\n *\n * Uses exponential backoff: 2s → 3s → 4.5s → ... capped at 30s.\n *\n * @example\n * ```ts\n * const result = await wallet.transfer({ transfers: [{ token, recipient, amount }] });\n * const status = await waitForConfirmation(wallet, result.relayId);\n * console.log(status.state); // \"succeeded\"\n * ```\n */\nexport async function waitForConfirmation(\n wallet: UnlinkWallet,\n txId: string,\n opts?: WaitOptions,\n): Promise<TxStatus> {\n const timeout = opts?.timeout ?? DEFAULT_TIMEOUT_MS;\n let interval = opts?.pollInterval ?? DEFAULT_POLL_INTERVAL_MS;\n const deadline = Date.now() + timeout;\n\n while (Date.now() < deadline) {\n const raw = await wallet.getTxStatus(txId);\n const status = toTxStatus(txId, raw);\n\n if (status.state === \"succeeded\") {\n return status;\n }\n\n if (FAILED_TX_STATES.includes(status.state)) {\n throw new TransactionFailedError(txId, status.state, status.error);\n }\n\n const remaining = deadline - Date.now();\n if (remaining <= 0) break;\n\n await sleep(Math.min(interval, remaining));\n interval = Math.min(interval * BACKOFF_FACTOR, MAX_POLL_INTERVAL_MS);\n }\n\n throw new TimeoutError(txId, timeout);\n}\n\n/**\n * Async generator that yields `TxStatus` on each poll until a terminal state.\n *\n * Useful for streaming status updates (e.g., logging, progress bars).\n *\n * @example\n * ```ts\n * for await (const status of pollRelayStatus(wallet, relayId)) {\n * console.log(status.state); // \"pending\" → \"broadcasting\" → \"submitted\" → \"succeeded\"\n * }\n * ```\n */\nexport async function* pollRelayStatus(\n wallet: UnlinkWallet,\n txId: string,\n opts?: PollOptions,\n): AsyncGenerator<TxStatus, void, unknown> {\n const timeout = opts?.timeout ?? DEFAULT_TIMEOUT_MS;\n let interval = opts?.pollInterval ?? DEFAULT_POLL_INTERVAL_MS;\n const deadline = Date.now() + timeout;\n\n while (Date.now() < deadline) {\n const raw = await wallet.getTxStatus(txId);\n const status = toTxStatus(txId, raw);\n\n yield status;\n\n if (TERMINAL_TX_STATES.includes(status.state)) {\n return;\n }\n\n const remaining = deadline - Date.now();\n if (remaining <= 0) return;\n\n await sleep(Math.min(interval, remaining));\n interval = Math.min(interval * BACKOFF_FACTOR, MAX_POLL_INTERVAL_MS);\n }\n}\n","import { EventEmitter } from \"node:events\";\nimport type { UnlinkWallet, WalletSDKEvent } from \"@unlink-xyz/core\";\n\n/**\n * Wrap an UnlinkWallet's event system with a Node.js `EventEmitter`.\n *\n * Events are emitted by their `type` field (e.g., `\"notes-updated\"`,\n * `\"tx-status-changed\"`). A wildcard `\"*\"` event is also emitted for\n * every event.\n *\n * @returns An `EventEmitter` and an `unsubscribe` function to detach from the wallet.\n *\n * @example\n * ```ts\n * const { emitter, unsubscribe } = createWalletEmitter(wallet);\n *\n * emitter.on(\"notes-updated\", (event) => {\n * console.log(\"Notes updated on chain\", event.chainId);\n * });\n *\n * emitter.on(\"tx-status-changed\", (event) => {\n * console.log(`TX ${event.txId}: ${event.state}`);\n * });\n *\n * // Listen to all events\n * emitter.on(\"*\", (event) => console.log(event));\n *\n * // Cleanup when done\n * unsubscribe();\n * ```\n */\nexport function createWalletEmitter(wallet: UnlinkWallet): {\n emitter: EventEmitter;\n unsubscribe: () => void;\n} {\n const emitter = new EventEmitter();\n\n const unsubscribe = wallet.on((event: WalletSDKEvent) => {\n emitter.emit(event.type, event);\n emitter.emit(\"*\", event);\n });\n\n return { emitter, unsubscribe };\n}\n","import fs from \"node:fs\";\nimport path from \"node:path\";\nimport type {\n BatchOp,\n Bytes,\n IterOptions,\n KvPair,\n Storage,\n} from \"@unlink-xyz/core\";\nimport { validateKey } from \"@unlink-xyz/core\";\nimport Database from \"better-sqlite3\";\n\nexport type SqliteStorageOptions = {\n /** Full path to the .db file */\n path: string;\n};\n\nexport function createSqliteStorage(opts: SqliteStorageOptions): Storage {\n let db: Database.Database | null = null;\n let stmtGet: Database.Statement;\n let stmtPut: Database.Statement;\n let stmtDel: Database.Statement;\n let stmtGetSchema: Database.Statement;\n let stmtUpsertSchema: Database.Statement;\n\n return {\n async open() {\n const dir = path.dirname(opts.path);\n fs.mkdirSync(dir, { recursive: true });\n\n db = new Database(opts.path);\n db.pragma(\"journal_mode = WAL\");\n db.pragma(\"busy_timeout = 5000\");\n db.exec(`\n CREATE TABLE IF NOT EXISTS kv (key TEXT PRIMARY KEY, value BLOB NOT NULL);\n CREATE TABLE IF NOT EXISTS meta (key TEXT PRIMARY KEY, value INTEGER NOT NULL);\n `);\n\n stmtGet = db.prepare(\"SELECT value FROM kv WHERE key = ?\");\n stmtPut = db.prepare(\n \"INSERT OR REPLACE INTO kv (key, value) VALUES (?, ?)\",\n );\n stmtDel = db.prepare(\"DELETE FROM kv WHERE key = ?\");\n stmtGetSchema = db.prepare(\n \"SELECT value FROM meta WHERE key = 'schema_version'\",\n );\n stmtUpsertSchema = db.prepare(\n \"INSERT OR REPLACE INTO meta (key, value) VALUES ('schema_version', ?)\",\n );\n },\n\n async get(key: string): Promise<Bytes | null> {\n validateKey(key);\n const row = stmtGet.get(key) as { value: Buffer } | undefined;\n return row ? new Uint8Array(row.value) : null;\n },\n\n async put(key: string, value: Bytes): Promise<void> {\n validateKey(key);\n stmtPut.run(key, Buffer.from(value));\n },\n\n async delete(key: string): Promise<void> {\n validateKey(key);\n stmtDel.run(key);\n },\n\n async batch(ops: BatchOp[]): Promise<void> {\n const runBatch = db!.transaction(() => {\n for (const op of ops) {\n if (op.put) {\n const [k, v] = op.put;\n validateKey(k);\n stmtPut.run(k, Buffer.from(v));\n }\n if (op.del) {\n validateKey(op.del);\n stmtDel.run(op.del);\n }\n }\n });\n runBatch();\n },\n\n async iter(o: IterOptions = {}): Promise<KvPair[]> {\n if (o.start && o.end && o.start > o.end) {\n throw new Error(\"iter start bound must not exceed end bound\");\n }\n\n const conditions: string[] = [];\n const params: (string | number)[] = [];\n\n if (o.prefix) {\n // Escape SQL LIKE wildcards in the prefix\n const escaped = o.prefix.replace(/[%_\\\\]/g, \"\\\\$&\");\n conditions.push(\"key LIKE ? ESCAPE '\\\\'\");\n params.push(escaped + \"%\");\n }\n if (o.start) {\n conditions.push(\"key >= ?\");\n params.push(o.start);\n }\n if (o.end) {\n conditions.push(\"key <= ?\");\n params.push(o.end);\n }\n\n let sql = \"SELECT key, value FROM kv\";\n if (conditions.length > 0) {\n sql += \" WHERE \" + conditions.join(\" AND \");\n }\n sql += o.reverse ? \" ORDER BY key DESC\" : \" ORDER BY key ASC\";\n if (o.limit != null) {\n sql += \" LIMIT ?\";\n params.push(o.limit);\n }\n\n const rows = db!.prepare(sql).all(...params) as Array<{\n key: string;\n value: Buffer;\n }>;\n\n return rows.map((row) => ({\n key: row.key,\n value: new Uint8Array(row.value),\n }));\n },\n\n async count(prefix?: string): Promise<number> {\n let sql = \"SELECT COUNT(*) as cnt FROM kv\";\n const params: string[] = [];\n if (prefix) {\n const escaped = prefix.replace(/[%_\\\\]/g, \"\\\\$&\");\n sql += \" WHERE key LIKE ? ESCAPE '\\\\'\";\n params.push(escaped + \"%\");\n }\n const row = db!.prepare(sql).get(...params) as { cnt: number };\n return row.cnt;\n },\n\n async getSchemaVersion(): Promise<number> {\n const row = stmtGetSchema.get() as { value: number } | undefined;\n return row?.value ?? 0;\n },\n\n async setSchemaVersion(v: number): Promise<void> {\n stmtUpsertSchema.run(v);\n },\n };\n}\n"],"mappings":"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","names":["crypto","import_core","path","fs","Database","import_core"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/init.ts","../src/errors.ts","../src/confirmation.ts","../src/events.ts","../src/storage/sqlite.ts"],"sourcesContent":["// Init\nexport { initWallet } from \"./init.js\";\n\n// Confirmation\nexport { waitForConfirmation, pollRelayStatus } from \"./confirmation.js\";\n\n// Events\nexport { createWalletEmitter } from \"./events.js\";\n\n// Storage\nexport {\n createSqliteStorage,\n type SqliteStorageOptions,\n} from \"./storage/sqlite.js\";\n\n// Errors\nexport {\n TimeoutError,\n TransactionFailedError,\n TERMINAL_TX_STATES,\n FAILED_TX_STATES,\n DEFAULT_TIMEOUT_MS,\n DEFAULT_POLL_INTERVAL_MS,\n} from \"./errors.js\";\n\n// Types\nexport type {\n NodeWalletConfig,\n TxStatus,\n WaitOptions,\n PollOptions,\n} from \"./types.js\";\n\n// Re-export commonly needed core types so consumers don't need @unlink-xyz/core\nexport { UnlinkWallet, createMemoryStorage } from \"@unlink-xyz/core\";\n\nexport type {\n Account,\n AccountInfo,\n AccountView,\n ChainConfig,\n DepositRelayResult,\n HistoryEntry,\n NoteRecord,\n RelayState,\n RelayStatusResponse,\n Storage,\n SupportedChain,\n TransactRelayResult,\n TransferPlanResult,\n TransferResult,\n WalletSDKEvent,\n WithdrawPlanResult,\n WithdrawResult,\n} from \"@unlink-xyz/core\";\n","import crypto from \"node:crypto\";\nimport { createMemoryStorage, UnlinkWallet } from \"@unlink-xyz/core\";\n\nimport type { NodeWalletConfig } from \"./types.js\";\n\nconst nodeRng = (n: number): Uint8Array =>\n new Uint8Array(crypto.randomBytes(n));\n\n/**\n * Initialize an Unlink wallet with Node.js-friendly defaults.\n *\n * Compared to `UnlinkWallet.create()`, this:\n * - Defaults storage to in-memory (no IndexedDB required)\n * - Defaults RNG to `node:crypto`\n * - Defaults autoSync to `false`\n * - Optionally creates seed + first account automatically\n * - Optionally syncs notes from blockchain\n *\n * @example\n * ```ts\n * // Minimal — ready to use in one call:\n * const wallet = await initWallet({\n * chain: \"monad-testnet\",\n * });\n *\n * // Skip auto-setup (e.g., to import an existing mnemonic):\n * const wallet = await initWallet({\n * chain: \"monad-testnet\",\n * setup: false,\n * sync: false,\n * });\n * await wallet.seed.importMnemonic(\"your mnemonic ...\");\n * await wallet.accounts.create();\n * await wallet.sync();\n * ```\n */\nexport async function initWallet(\n config: NodeWalletConfig,\n): Promise<UnlinkWallet> {\n // Strip node-specific fields before passing to core\n const { setup, sync, ...coreConfig } = config;\n void setup;\n void sync;\n\n const wallet = await UnlinkWallet.create({\n ...coreConfig,\n storage: config.storage ?? createMemoryStorage(),\n rng: config.rng ?? nodeRng,\n autoSync: config.autoSync ?? false,\n fetch: config.fetch ?? globalThis.fetch,\n });\n\n if (config.setup !== false) {\n const hasSeed = await wallet.seed.exists();\n if (!hasSeed) {\n await wallet.seed.create();\n }\n\n const accounts = await wallet.accounts.list();\n if (accounts.length === 0) {\n await wallet.accounts.create();\n }\n }\n\n if (config.sync !== false) {\n await wallet.sync();\n }\n\n return wallet;\n}\n","import type { RelayState } from \"@unlink-xyz/core\";\n\n/** Terminal relay states — the transaction has finished processing. */\nexport const TERMINAL_TX_STATES: readonly RelayState[] = [\n \"succeeded\",\n \"reverted\",\n \"failed\",\n \"dead\",\n] as const;\n\n/** Failed relay states — the transaction did not succeed. */\nexport const FAILED_TX_STATES: readonly RelayState[] = [\n \"reverted\",\n \"failed\",\n \"dead\",\n] as const;\n\n/** Default timeout for `waitForConfirmation` (5 minutes). */\nexport const DEFAULT_TIMEOUT_MS = 5 * 60 * 1000;\n\n/** Default initial poll interval (2 seconds). */\nexport const DEFAULT_POLL_INTERVAL_MS = 2_000;\n\n/** Maximum poll interval after backoff (30 seconds). */\nexport const MAX_POLL_INTERVAL_MS = 30_000;\n\n/** Backoff multiplier for exponential polling. */\nexport const BACKOFF_FACTOR = 1.5;\n\n/** Thrown when relay polling exceeds the configured timeout. */\nexport class TimeoutError extends Error {\n readonly txId: string;\n readonly timeout: number;\n\n constructor(txId: string, timeout: number) {\n super(`Transaction ${txId} did not confirm within ${timeout}ms`);\n this.name = \"TimeoutError\";\n this.txId = txId;\n this.timeout = timeout;\n }\n}\n\n/** Thrown when a transaction reaches a failed terminal state. */\nexport class TransactionFailedError extends Error {\n readonly txId: string;\n readonly state: RelayState;\n readonly reason?: string;\n\n constructor(txId: string, state: RelayState, reason?: string) {\n super(\n `Transaction ${txId} failed with state: ${state}${reason ? ` — ${reason}` : \"\"}`,\n );\n this.name = \"TransactionFailedError\";\n this.txId = txId;\n this.state = state;\n this.reason = reason;\n }\n}\n","import type { UnlinkWallet } from \"@unlink-xyz/core\";\n\nimport {\n BACKOFF_FACTOR,\n DEFAULT_POLL_INTERVAL_MS,\n DEFAULT_TIMEOUT_MS,\n FAILED_TX_STATES,\n MAX_POLL_INTERVAL_MS,\n TERMINAL_TX_STATES,\n TimeoutError,\n TransactionFailedError,\n} from \"./errors.js\";\nimport type { PollOptions, TxStatus, WaitOptions } from \"./types.js\";\n\nfunction toTxStatus(\n txId: string,\n raw: Awaited<ReturnType<UnlinkWallet[\"getTxStatus\"]>>,\n): TxStatus {\n return {\n txId,\n state: raw.state,\n txHash: raw.txHash ?? undefined,\n blockNumber: raw.receipt?.blockNumber ?? undefined,\n error: raw.error ?? undefined,\n };\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\n/**\n * Poll relay status until the transaction reaches a terminal state.\n *\n * Resolves with `TxStatus` on success (`\"succeeded\"`).\n * Throws `TransactionFailedError` on failure (`\"reverted\"`, `\"failed\"`, `\"dead\"`).\n * Throws `TimeoutError` if the timeout is exceeded.\n *\n * Uses exponential backoff: 2s → 3s → 4.5s → ... capped at 30s.\n *\n * @example\n * ```ts\n * const result = await wallet.transfer({ transfers: [{ token, recipient, amount }] });\n * const status = await waitForConfirmation(wallet, result.relayId);\n * console.log(status.state); // \"succeeded\"\n * ```\n */\nexport async function waitForConfirmation(\n wallet: UnlinkWallet,\n txId: string,\n opts?: WaitOptions,\n): Promise<TxStatus> {\n const timeout = opts?.timeout ?? DEFAULT_TIMEOUT_MS;\n let interval = opts?.pollInterval ?? DEFAULT_POLL_INTERVAL_MS;\n const deadline = Date.now() + timeout;\n\n while (Date.now() < deadline) {\n const raw = await wallet.getTxStatus(txId);\n const status = toTxStatus(txId, raw);\n\n if (status.state === \"succeeded\") {\n return status;\n }\n\n if (FAILED_TX_STATES.includes(status.state)) {\n throw new TransactionFailedError(txId, status.state, status.error);\n }\n\n const remaining = deadline - Date.now();\n if (remaining <= 0) break;\n\n await sleep(Math.min(interval, remaining));\n interval = Math.min(interval * BACKOFF_FACTOR, MAX_POLL_INTERVAL_MS);\n }\n\n throw new TimeoutError(txId, timeout);\n}\n\n/**\n * Async generator that yields `TxStatus` on each poll until a terminal state.\n *\n * Useful for streaming status updates (e.g., logging, progress bars).\n *\n * @example\n * ```ts\n * for await (const status of pollRelayStatus(wallet, relayId)) {\n * console.log(status.state); // \"pending\" → \"broadcasting\" → \"submitted\" → \"succeeded\"\n * }\n * ```\n */\nexport async function* pollRelayStatus(\n wallet: UnlinkWallet,\n txId: string,\n opts?: PollOptions,\n): AsyncGenerator<TxStatus, void, unknown> {\n const timeout = opts?.timeout ?? DEFAULT_TIMEOUT_MS;\n let interval = opts?.pollInterval ?? DEFAULT_POLL_INTERVAL_MS;\n const deadline = Date.now() + timeout;\n\n while (Date.now() < deadline) {\n const raw = await wallet.getTxStatus(txId);\n const status = toTxStatus(txId, raw);\n\n yield status;\n\n if (TERMINAL_TX_STATES.includes(status.state)) {\n return;\n }\n\n const remaining = deadline - Date.now();\n if (remaining <= 0) return;\n\n await sleep(Math.min(interval, remaining));\n interval = Math.min(interval * BACKOFF_FACTOR, MAX_POLL_INTERVAL_MS);\n }\n}\n","import { EventEmitter } from \"node:events\";\nimport type { UnlinkWallet, WalletSDKEvent } from \"@unlink-xyz/core\";\n\n/**\n * Wrap an UnlinkWallet's event system with a Node.js `EventEmitter`.\n *\n * Events are emitted by their `type` field (e.g., `\"notes-updated\"`,\n * `\"tx-status-changed\"`). A wildcard `\"*\"` event is also emitted for\n * every event.\n *\n * @returns An `EventEmitter` and an `unsubscribe` function to detach from the wallet.\n *\n * @example\n * ```ts\n * const { emitter, unsubscribe } = createWalletEmitter(wallet);\n *\n * emitter.on(\"notes-updated\", (event) => {\n * console.log(\"Notes updated on chain\", event.chainId);\n * });\n *\n * emitter.on(\"tx-status-changed\", (event) => {\n * console.log(`TX ${event.txId}: ${event.state}`);\n * });\n *\n * // Listen to all events\n * emitter.on(\"*\", (event) => console.log(event));\n *\n * // Cleanup when done\n * unsubscribe();\n * ```\n */\nexport function createWalletEmitter(wallet: UnlinkWallet): {\n emitter: EventEmitter;\n unsubscribe: () => void;\n} {\n const emitter = new EventEmitter();\n\n const unsubscribe = wallet.on((event: WalletSDKEvent) => {\n emitter.emit(event.type, event);\n emitter.emit(\"*\", event);\n });\n\n return { emitter, unsubscribe };\n}\n","import fs from \"node:fs\";\nimport path from \"node:path\";\nimport type {\n BatchOp,\n Bytes,\n IterOptions,\n KvPair,\n Storage,\n} from \"@unlink-xyz/core\";\nimport { validateKey } from \"@unlink-xyz/core\";\nimport Database from \"better-sqlite3\";\n\nexport type SqliteStorageOptions = {\n /** Full path to the .db file */\n path: string;\n};\n\nexport function createSqliteStorage(opts: SqliteStorageOptions): Storage {\n let db: Database.Database | null = null;\n let stmtGet: Database.Statement;\n let stmtPut: Database.Statement;\n let stmtDel: Database.Statement;\n let stmtGetSchema: Database.Statement;\n let stmtUpsertSchema: Database.Statement;\n\n return {\n async open() {\n const dir = path.dirname(opts.path);\n fs.mkdirSync(dir, { recursive: true });\n\n db = new Database(opts.path);\n db.pragma(\"journal_mode = WAL\");\n db.pragma(\"busy_timeout = 5000\");\n db.exec(`\n CREATE TABLE IF NOT EXISTS kv (key TEXT PRIMARY KEY, value BLOB NOT NULL);\n CREATE TABLE IF NOT EXISTS meta (key TEXT PRIMARY KEY, value INTEGER NOT NULL);\n `);\n\n stmtGet = db.prepare(\"SELECT value FROM kv WHERE key = ?\");\n stmtPut = db.prepare(\n \"INSERT OR REPLACE INTO kv (key, value) VALUES (?, ?)\",\n );\n stmtDel = db.prepare(\"DELETE FROM kv WHERE key = ?\");\n stmtGetSchema = db.prepare(\n \"SELECT value FROM meta WHERE key = 'schema_version'\",\n );\n stmtUpsertSchema = db.prepare(\n \"INSERT OR REPLACE INTO meta (key, value) VALUES ('schema_version', ?)\",\n );\n },\n\n async get(key: string): Promise<Bytes | null> {\n validateKey(key);\n const row = stmtGet.get(key) as { value: Buffer } | undefined;\n return row ? new Uint8Array(row.value) : null;\n },\n\n async put(key: string, value: Bytes): Promise<void> {\n validateKey(key);\n stmtPut.run(key, Buffer.from(value));\n },\n\n async delete(key: string): Promise<void> {\n validateKey(key);\n stmtDel.run(key);\n },\n\n async batch(ops: BatchOp[]): Promise<void> {\n const runBatch = db!.transaction(() => {\n for (const op of ops) {\n if (op.put) {\n const [k, v] = op.put;\n validateKey(k);\n stmtPut.run(k, Buffer.from(v));\n }\n if (op.del) {\n validateKey(op.del);\n stmtDel.run(op.del);\n }\n }\n });\n runBatch();\n },\n\n async iter(o: IterOptions = {}): Promise<KvPair[]> {\n if (o.start && o.end && o.start > o.end) {\n throw new Error(\"iter start bound must not exceed end bound\");\n }\n\n const conditions: string[] = [];\n const params: (string | number)[] = [];\n\n if (o.prefix) {\n // Escape SQL LIKE wildcards in the prefix\n const escaped = o.prefix.replace(/[%_\\\\]/g, \"\\\\$&\");\n conditions.push(\"key LIKE ? ESCAPE '\\\\'\");\n params.push(escaped + \"%\");\n }\n if (o.start) {\n conditions.push(\"key >= ?\");\n params.push(o.start);\n }\n if (o.end) {\n conditions.push(\"key <= ?\");\n params.push(o.end);\n }\n\n let sql = \"SELECT key, value FROM kv\";\n if (conditions.length > 0) {\n sql += \" WHERE \" + conditions.join(\" AND \");\n }\n sql += o.reverse ? \" ORDER BY key DESC\" : \" ORDER BY key ASC\";\n if (o.limit != null) {\n sql += \" LIMIT ?\";\n params.push(o.limit);\n }\n\n const rows = db!.prepare(sql).all(...params) as Array<{\n key: string;\n value: Buffer;\n }>;\n\n return rows.map((row) => ({\n key: row.key,\n value: new Uint8Array(row.value),\n }));\n },\n\n async count(prefix?: string): Promise<number> {\n let sql = \"SELECT COUNT(*) as cnt FROM kv\";\n const params: string[] = [];\n if (prefix) {\n const escaped = prefix.replace(/[%_\\\\]/g, \"\\\\$&\");\n sql += \" WHERE key LIKE ? ESCAPE '\\\\'\";\n params.push(escaped + \"%\");\n }\n const row = db!.prepare(sql).get(...params) as { cnt: number };\n return row.cnt;\n },\n\n async getSchemaVersion(): Promise<number> {\n const row = stmtGetSchema.get() as { value: number } | undefined;\n return row?.value ?? 0;\n },\n\n async setSchemaVersion(v: number): Promise<void> {\n stmtUpsertSchema.run(v);\n },\n };\n}\n"],"mappings":"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","names":["crypto","import_core","path","fs","Database","import_core"]}
|
package/dist/index.d.cts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { Storage,
|
|
2
|
-
export { Account, AccountInfo, AccountView,
|
|
1
|
+
import { Storage, SupportedChain, RelayState, UnlinkWallet } from '@unlink-xyz/core';
|
|
2
|
+
export { Account, AccountInfo, AccountView, ChainConfig, DepositRelayResult, HistoryEntry, NoteRecord, RelayState, RelayStatusResponse, Storage, SupportedChain, TransactRelayResult, TransferPlanResult, TransferResult, UnlinkWallet, WalletSDKEvent, WithdrawPlanResult, WithdrawResult, createMemoryStorage } from '@unlink-xyz/core';
|
|
3
3
|
import { EventEmitter } from 'node:events';
|
|
4
4
|
|
|
5
5
|
/**
|
|
@@ -11,7 +11,6 @@ import { EventEmitter } from 'node:events';
|
|
|
11
11
|
* - `autoSync` defaults to `false`
|
|
12
12
|
*/
|
|
13
13
|
type NodeWalletConfig = {
|
|
14
|
-
chainId: number;
|
|
15
14
|
/** Storage backend. Defaults to `createMemoryStorage()`. */
|
|
16
15
|
storage?: Storage;
|
|
17
16
|
/** Random number generator. Defaults to `node:crypto.randomBytes`. */
|
|
@@ -41,11 +40,13 @@ type NodeWalletConfig = {
|
|
|
41
40
|
*/
|
|
42
41
|
sync?: boolean;
|
|
43
42
|
} & ({
|
|
44
|
-
/**
|
|
45
|
-
|
|
46
|
-
/** Override pool address (defaults to
|
|
43
|
+
/** Supported chain name — resolves chainId, gateway, pool, artifacts. */
|
|
44
|
+
chain: SupportedChain;
|
|
45
|
+
/** Override pool address (defaults to chain config). */
|
|
47
46
|
poolAddress?: string;
|
|
48
47
|
} | {
|
|
48
|
+
/** Chain ID for the target blockchain. */
|
|
49
|
+
chainId: number;
|
|
49
50
|
/** Explicit gateway URL. */
|
|
50
51
|
gatewayUrl: string;
|
|
51
52
|
/** Pool contract address (required with explicit gatewayUrl). */
|
|
@@ -88,14 +89,12 @@ type PollOptions = {
|
|
|
88
89
|
* ```ts
|
|
89
90
|
* // Minimal — ready to use in one call:
|
|
90
91
|
* const wallet = await initWallet({
|
|
91
|
-
*
|
|
92
|
-
* environment: "testnet",
|
|
92
|
+
* chain: "monad-testnet",
|
|
93
93
|
* });
|
|
94
94
|
*
|
|
95
95
|
* // Skip auto-setup (e.g., to import an existing mnemonic):
|
|
96
96
|
* const wallet = await initWallet({
|
|
97
|
-
*
|
|
98
|
-
* environment: "testnet",
|
|
97
|
+
* chain: "monad-testnet",
|
|
99
98
|
* setup: false,
|
|
100
99
|
* sync: false,
|
|
101
100
|
* });
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { Storage,
|
|
2
|
-
export { Account, AccountInfo, AccountView,
|
|
1
|
+
import { Storage, SupportedChain, RelayState, UnlinkWallet } from '@unlink-xyz/core';
|
|
2
|
+
export { Account, AccountInfo, AccountView, ChainConfig, DepositRelayResult, HistoryEntry, NoteRecord, RelayState, RelayStatusResponse, Storage, SupportedChain, TransactRelayResult, TransferPlanResult, TransferResult, UnlinkWallet, WalletSDKEvent, WithdrawPlanResult, WithdrawResult, createMemoryStorage } from '@unlink-xyz/core';
|
|
3
3
|
import { EventEmitter } from 'node:events';
|
|
4
4
|
|
|
5
5
|
/**
|
|
@@ -11,7 +11,6 @@ import { EventEmitter } from 'node:events';
|
|
|
11
11
|
* - `autoSync` defaults to `false`
|
|
12
12
|
*/
|
|
13
13
|
type NodeWalletConfig = {
|
|
14
|
-
chainId: number;
|
|
15
14
|
/** Storage backend. Defaults to `createMemoryStorage()`. */
|
|
16
15
|
storage?: Storage;
|
|
17
16
|
/** Random number generator. Defaults to `node:crypto.randomBytes`. */
|
|
@@ -41,11 +40,13 @@ type NodeWalletConfig = {
|
|
|
41
40
|
*/
|
|
42
41
|
sync?: boolean;
|
|
43
42
|
} & ({
|
|
44
|
-
/**
|
|
45
|
-
|
|
46
|
-
/** Override pool address (defaults to
|
|
43
|
+
/** Supported chain name — resolves chainId, gateway, pool, artifacts. */
|
|
44
|
+
chain: SupportedChain;
|
|
45
|
+
/** Override pool address (defaults to chain config). */
|
|
47
46
|
poolAddress?: string;
|
|
48
47
|
} | {
|
|
48
|
+
/** Chain ID for the target blockchain. */
|
|
49
|
+
chainId: number;
|
|
49
50
|
/** Explicit gateway URL. */
|
|
50
51
|
gatewayUrl: string;
|
|
51
52
|
/** Pool contract address (required with explicit gatewayUrl). */
|
|
@@ -88,14 +89,12 @@ type PollOptions = {
|
|
|
88
89
|
* ```ts
|
|
89
90
|
* // Minimal — ready to use in one call:
|
|
90
91
|
* const wallet = await initWallet({
|
|
91
|
-
*
|
|
92
|
-
* environment: "testnet",
|
|
92
|
+
* chain: "monad-testnet",
|
|
93
93
|
* });
|
|
94
94
|
*
|
|
95
95
|
* // Skip auto-setup (e.g., to import an existing mnemonic):
|
|
96
96
|
* const wallet = await initWallet({
|
|
97
|
-
*
|
|
98
|
-
* environment: "testnet",
|
|
97
|
+
* chain: "monad-testnet",
|
|
99
98
|
* setup: false,
|
|
100
99
|
* sync: false,
|
|
101
100
|
* });
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/init.ts","../src/errors.ts","../src/confirmation.ts","../src/events.ts","../src/storage/sqlite.ts","../src/index.ts"],"sourcesContent":["import crypto from \"node:crypto\";\nimport { createMemoryStorage, UnlinkWallet } from \"@unlink-xyz/core\";\n\nimport type { NodeWalletConfig } from \"./types.js\";\n\nconst nodeRng = (n: number): Uint8Array =>\n new Uint8Array(crypto.randomBytes(n));\n\n/**\n * Initialize an Unlink wallet with Node.js-friendly defaults.\n *\n * Compared to `UnlinkWallet.create()`, this:\n * - Defaults storage to in-memory (no IndexedDB required)\n * - Defaults RNG to `node:crypto`\n * - Defaults autoSync to `false`\n * - Optionally creates seed + first account automatically\n * - Optionally syncs notes from blockchain\n *\n * @example\n * ```ts\n * // Minimal — ready to use in one call:\n * const wallet = await initWallet({\n * chainId: 11155111,\n * environment: \"testnet\",\n * });\n *\n * // Skip auto-setup (e.g., to import an existing mnemonic):\n * const wallet = await initWallet({\n * chainId: 11155111,\n * environment: \"testnet\",\n * setup: false,\n * sync: false,\n * });\n * await wallet.seed.importMnemonic(\"your mnemonic ...\");\n * await wallet.accounts.create();\n * await wallet.sync();\n * ```\n */\nexport async function initWallet(\n config: NodeWalletConfig,\n): Promise<UnlinkWallet> {\n // Strip node-specific fields before passing to core\n const { setup, sync, ...coreConfig } = config;\n void setup;\n void sync;\n\n const wallet = await UnlinkWallet.create({\n ...coreConfig,\n storage: config.storage ?? createMemoryStorage(),\n rng: config.rng ?? nodeRng,\n autoSync: config.autoSync ?? false,\n fetch: config.fetch ?? globalThis.fetch,\n });\n\n if (config.setup !== false) {\n const hasSeed = await wallet.seed.exists();\n if (!hasSeed) {\n await wallet.seed.create();\n }\n\n const accounts = await wallet.accounts.list();\n if (accounts.length === 0) {\n await wallet.accounts.create();\n }\n }\n\n if (config.sync !== false) {\n await wallet.sync();\n }\n\n return wallet;\n}\n","import type { RelayState } from \"@unlink-xyz/core\";\n\n/** Terminal relay states — the transaction has finished processing. */\nexport const TERMINAL_TX_STATES: readonly RelayState[] = [\n \"succeeded\",\n \"reverted\",\n \"failed\",\n \"dead\",\n] as const;\n\n/** Failed relay states — the transaction did not succeed. */\nexport const FAILED_TX_STATES: readonly RelayState[] = [\n \"reverted\",\n \"failed\",\n \"dead\",\n] as const;\n\n/** Default timeout for `waitForConfirmation` (5 minutes). */\nexport const DEFAULT_TIMEOUT_MS = 5 * 60 * 1000;\n\n/** Default initial poll interval (2 seconds). */\nexport const DEFAULT_POLL_INTERVAL_MS = 2_000;\n\n/** Maximum poll interval after backoff (30 seconds). */\nexport const MAX_POLL_INTERVAL_MS = 30_000;\n\n/** Backoff multiplier for exponential polling. */\nexport const BACKOFF_FACTOR = 1.5;\n\n/** Thrown when relay polling exceeds the configured timeout. */\nexport class TimeoutError extends Error {\n readonly txId: string;\n readonly timeout: number;\n\n constructor(txId: string, timeout: number) {\n super(`Transaction ${txId} did not confirm within ${timeout}ms`);\n this.name = \"TimeoutError\";\n this.txId = txId;\n this.timeout = timeout;\n }\n}\n\n/** Thrown when a transaction reaches a failed terminal state. */\nexport class TransactionFailedError extends Error {\n readonly txId: string;\n readonly state: RelayState;\n readonly reason?: string;\n\n constructor(txId: string, state: RelayState, reason?: string) {\n super(\n `Transaction ${txId} failed with state: ${state}${reason ? ` — ${reason}` : \"\"}`,\n );\n this.name = \"TransactionFailedError\";\n this.txId = txId;\n this.state = state;\n this.reason = reason;\n }\n}\n","import type { UnlinkWallet } from \"@unlink-xyz/core\";\n\nimport {\n BACKOFF_FACTOR,\n DEFAULT_POLL_INTERVAL_MS,\n DEFAULT_TIMEOUT_MS,\n FAILED_TX_STATES,\n MAX_POLL_INTERVAL_MS,\n TERMINAL_TX_STATES,\n TimeoutError,\n TransactionFailedError,\n} from \"./errors.js\";\nimport type { PollOptions, TxStatus, WaitOptions } from \"./types.js\";\n\nfunction toTxStatus(\n txId: string,\n raw: Awaited<ReturnType<UnlinkWallet[\"getTxStatus\"]>>,\n): TxStatus {\n return {\n txId,\n state: raw.state,\n txHash: raw.txHash ?? undefined,\n blockNumber: raw.receipt?.blockNumber ?? undefined,\n error: raw.error ?? undefined,\n };\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\n/**\n * Poll relay status until the transaction reaches a terminal state.\n *\n * Resolves with `TxStatus` on success (`\"succeeded\"`).\n * Throws `TransactionFailedError` on failure (`\"reverted\"`, `\"failed\"`, `\"dead\"`).\n * Throws `TimeoutError` if the timeout is exceeded.\n *\n * Uses exponential backoff: 2s → 3s → 4.5s → ... capped at 30s.\n *\n * @example\n * ```ts\n * const result = await wallet.transfer({ transfers: [{ token, recipient, amount }] });\n * const status = await waitForConfirmation(wallet, result.relayId);\n * console.log(status.state); // \"succeeded\"\n * ```\n */\nexport async function waitForConfirmation(\n wallet: UnlinkWallet,\n txId: string,\n opts?: WaitOptions,\n): Promise<TxStatus> {\n const timeout = opts?.timeout ?? DEFAULT_TIMEOUT_MS;\n let interval = opts?.pollInterval ?? DEFAULT_POLL_INTERVAL_MS;\n const deadline = Date.now() + timeout;\n\n while (Date.now() < deadline) {\n const raw = await wallet.getTxStatus(txId);\n const status = toTxStatus(txId, raw);\n\n if (status.state === \"succeeded\") {\n return status;\n }\n\n if (FAILED_TX_STATES.includes(status.state)) {\n throw new TransactionFailedError(txId, status.state, status.error);\n }\n\n const remaining = deadline - Date.now();\n if (remaining <= 0) break;\n\n await sleep(Math.min(interval, remaining));\n interval = Math.min(interval * BACKOFF_FACTOR, MAX_POLL_INTERVAL_MS);\n }\n\n throw new TimeoutError(txId, timeout);\n}\n\n/**\n * Async generator that yields `TxStatus` on each poll until a terminal state.\n *\n * Useful for streaming status updates (e.g., logging, progress bars).\n *\n * @example\n * ```ts\n * for await (const status of pollRelayStatus(wallet, relayId)) {\n * console.log(status.state); // \"pending\" → \"broadcasting\" → \"submitted\" → \"succeeded\"\n * }\n * ```\n */\nexport async function* pollRelayStatus(\n wallet: UnlinkWallet,\n txId: string,\n opts?: PollOptions,\n): AsyncGenerator<TxStatus, void, unknown> {\n const timeout = opts?.timeout ?? DEFAULT_TIMEOUT_MS;\n let interval = opts?.pollInterval ?? DEFAULT_POLL_INTERVAL_MS;\n const deadline = Date.now() + timeout;\n\n while (Date.now() < deadline) {\n const raw = await wallet.getTxStatus(txId);\n const status = toTxStatus(txId, raw);\n\n yield status;\n\n if (TERMINAL_TX_STATES.includes(status.state)) {\n return;\n }\n\n const remaining = deadline - Date.now();\n if (remaining <= 0) return;\n\n await sleep(Math.min(interval, remaining));\n interval = Math.min(interval * BACKOFF_FACTOR, MAX_POLL_INTERVAL_MS);\n }\n}\n","import { EventEmitter } from \"node:events\";\nimport type { UnlinkWallet, WalletSDKEvent } from \"@unlink-xyz/core\";\n\n/**\n * Wrap an UnlinkWallet's event system with a Node.js `EventEmitter`.\n *\n * Events are emitted by their `type` field (e.g., `\"notes-updated\"`,\n * `\"tx-status-changed\"`). A wildcard `\"*\"` event is also emitted for\n * every event.\n *\n * @returns An `EventEmitter` and an `unsubscribe` function to detach from the wallet.\n *\n * @example\n * ```ts\n * const { emitter, unsubscribe } = createWalletEmitter(wallet);\n *\n * emitter.on(\"notes-updated\", (event) => {\n * console.log(\"Notes updated on chain\", event.chainId);\n * });\n *\n * emitter.on(\"tx-status-changed\", (event) => {\n * console.log(`TX ${event.txId}: ${event.state}`);\n * });\n *\n * // Listen to all events\n * emitter.on(\"*\", (event) => console.log(event));\n *\n * // Cleanup when done\n * unsubscribe();\n * ```\n */\nexport function createWalletEmitter(wallet: UnlinkWallet): {\n emitter: EventEmitter;\n unsubscribe: () => void;\n} {\n const emitter = new EventEmitter();\n\n const unsubscribe = wallet.on((event: WalletSDKEvent) => {\n emitter.emit(event.type, event);\n emitter.emit(\"*\", event);\n });\n\n return { emitter, unsubscribe };\n}\n","import fs from \"node:fs\";\nimport path from \"node:path\";\nimport type {\n BatchOp,\n Bytes,\n IterOptions,\n KvPair,\n Storage,\n} from \"@unlink-xyz/core\";\nimport { validateKey } from \"@unlink-xyz/core\";\nimport Database from \"better-sqlite3\";\n\nexport type SqliteStorageOptions = {\n /** Full path to the .db file */\n path: string;\n};\n\nexport function createSqliteStorage(opts: SqliteStorageOptions): Storage {\n let db: Database.Database | null = null;\n let stmtGet: Database.Statement;\n let stmtPut: Database.Statement;\n let stmtDel: Database.Statement;\n let stmtGetSchema: Database.Statement;\n let stmtUpsertSchema: Database.Statement;\n\n return {\n async open() {\n const dir = path.dirname(opts.path);\n fs.mkdirSync(dir, { recursive: true });\n\n db = new Database(opts.path);\n db.pragma(\"journal_mode = WAL\");\n db.pragma(\"busy_timeout = 5000\");\n db.exec(`\n CREATE TABLE IF NOT EXISTS kv (key TEXT PRIMARY KEY, value BLOB NOT NULL);\n CREATE TABLE IF NOT EXISTS meta (key TEXT PRIMARY KEY, value INTEGER NOT NULL);\n `);\n\n stmtGet = db.prepare(\"SELECT value FROM kv WHERE key = ?\");\n stmtPut = db.prepare(\n \"INSERT OR REPLACE INTO kv (key, value) VALUES (?, ?)\",\n );\n stmtDel = db.prepare(\"DELETE FROM kv WHERE key = ?\");\n stmtGetSchema = db.prepare(\n \"SELECT value FROM meta WHERE key = 'schema_version'\",\n );\n stmtUpsertSchema = db.prepare(\n \"INSERT OR REPLACE INTO meta (key, value) VALUES ('schema_version', ?)\",\n );\n },\n\n async get(key: string): Promise<Bytes | null> {\n validateKey(key);\n const row = stmtGet.get(key) as { value: Buffer } | undefined;\n return row ? new Uint8Array(row.value) : null;\n },\n\n async put(key: string, value: Bytes): Promise<void> {\n validateKey(key);\n stmtPut.run(key, Buffer.from(value));\n },\n\n async delete(key: string): Promise<void> {\n validateKey(key);\n stmtDel.run(key);\n },\n\n async batch(ops: BatchOp[]): Promise<void> {\n const runBatch = db!.transaction(() => {\n for (const op of ops) {\n if (op.put) {\n const [k, v] = op.put;\n validateKey(k);\n stmtPut.run(k, Buffer.from(v));\n }\n if (op.del) {\n validateKey(op.del);\n stmtDel.run(op.del);\n }\n }\n });\n runBatch();\n },\n\n async iter(o: IterOptions = {}): Promise<KvPair[]> {\n if (o.start && o.end && o.start > o.end) {\n throw new Error(\"iter start bound must not exceed end bound\");\n }\n\n const conditions: string[] = [];\n const params: (string | number)[] = [];\n\n if (o.prefix) {\n // Escape SQL LIKE wildcards in the prefix\n const escaped = o.prefix.replace(/[%_\\\\]/g, \"\\\\$&\");\n conditions.push(\"key LIKE ? ESCAPE '\\\\'\");\n params.push(escaped + \"%\");\n }\n if (o.start) {\n conditions.push(\"key >= ?\");\n params.push(o.start);\n }\n if (o.end) {\n conditions.push(\"key <= ?\");\n params.push(o.end);\n }\n\n let sql = \"SELECT key, value FROM kv\";\n if (conditions.length > 0) {\n sql += \" WHERE \" + conditions.join(\" AND \");\n }\n sql += o.reverse ? \" ORDER BY key DESC\" : \" ORDER BY key ASC\";\n if (o.limit != null) {\n sql += \" LIMIT ?\";\n params.push(o.limit);\n }\n\n const rows = db!.prepare(sql).all(...params) as Array<{\n key: string;\n value: Buffer;\n }>;\n\n return rows.map((row) => ({\n key: row.key,\n value: new Uint8Array(row.value),\n }));\n },\n\n async count(prefix?: string): Promise<number> {\n let sql = \"SELECT COUNT(*) as cnt FROM kv\";\n const params: string[] = [];\n if (prefix) {\n const escaped = prefix.replace(/[%_\\\\]/g, \"\\\\$&\");\n sql += \" WHERE key LIKE ? ESCAPE '\\\\'\";\n params.push(escaped + \"%\");\n }\n const row = db!.prepare(sql).get(...params) as { cnt: number };\n return row.cnt;\n },\n\n async getSchemaVersion(): Promise<number> {\n const row = stmtGetSchema.get() as { value: number } | undefined;\n return row?.value ?? 0;\n },\n\n async setSchemaVersion(v: number): Promise<void> {\n stmtUpsertSchema.run(v);\n },\n };\n}\n","// Init\nexport { initWallet } from \"./init.js\";\n\n// Confirmation\nexport { waitForConfirmation, pollRelayStatus } from \"./confirmation.js\";\n\n// Events\nexport { createWalletEmitter } from \"./events.js\";\n\n// Storage\nexport {\n createSqliteStorage,\n type SqliteStorageOptions,\n} from \"./storage/sqlite.js\";\n\n// Errors\nexport {\n TimeoutError,\n TransactionFailedError,\n TERMINAL_TX_STATES,\n FAILED_TX_STATES,\n DEFAULT_TIMEOUT_MS,\n DEFAULT_POLL_INTERVAL_MS,\n} from \"./errors.js\";\n\n// Types\nexport type {\n NodeWalletConfig,\n TxStatus,\n WaitOptions,\n PollOptions,\n} from \"./types.js\";\n\n// Re-export commonly needed core types so consumers don't need @unlink-xyz/core\nexport { UnlinkWallet, createMemoryStorage } from \"@unlink-xyz/core\";\n\nexport type {\n Account,\n AccountInfo,\n AccountView,\n DepositRelayResult,\n Environment,\n HistoryEntry,\n NoteRecord,\n RelayState,\n RelayStatusResponse,\n Storage,\n TransactRelayResult,\n TransferPlanResult,\n TransferResult,\n WalletSDKEvent,\n WithdrawPlanResult,\n WithdrawResult,\n} from \"@unlink-xyz/core\";\n"],"mappings":"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","names":["UnlinkWallet","createMemoryStorage"]}
|
|
1
|
+
{"version":3,"sources":["../src/init.ts","../src/errors.ts","../src/confirmation.ts","../src/events.ts","../src/storage/sqlite.ts","../src/index.ts"],"sourcesContent":["import crypto from \"node:crypto\";\nimport { createMemoryStorage, UnlinkWallet } from \"@unlink-xyz/core\";\n\nimport type { NodeWalletConfig } from \"./types.js\";\n\nconst nodeRng = (n: number): Uint8Array =>\n new Uint8Array(crypto.randomBytes(n));\n\n/**\n * Initialize an Unlink wallet with Node.js-friendly defaults.\n *\n * Compared to `UnlinkWallet.create()`, this:\n * - Defaults storage to in-memory (no IndexedDB required)\n * - Defaults RNG to `node:crypto`\n * - Defaults autoSync to `false`\n * - Optionally creates seed + first account automatically\n * - Optionally syncs notes from blockchain\n *\n * @example\n * ```ts\n * // Minimal — ready to use in one call:\n * const wallet = await initWallet({\n * chain: \"monad-testnet\",\n * });\n *\n * // Skip auto-setup (e.g., to import an existing mnemonic):\n * const wallet = await initWallet({\n * chain: \"monad-testnet\",\n * setup: false,\n * sync: false,\n * });\n * await wallet.seed.importMnemonic(\"your mnemonic ...\");\n * await wallet.accounts.create();\n * await wallet.sync();\n * ```\n */\nexport async function initWallet(\n config: NodeWalletConfig,\n): Promise<UnlinkWallet> {\n // Strip node-specific fields before passing to core\n const { setup, sync, ...coreConfig } = config;\n void setup;\n void sync;\n\n const wallet = await UnlinkWallet.create({\n ...coreConfig,\n storage: config.storage ?? createMemoryStorage(),\n rng: config.rng ?? nodeRng,\n autoSync: config.autoSync ?? false,\n fetch: config.fetch ?? globalThis.fetch,\n });\n\n if (config.setup !== false) {\n const hasSeed = await wallet.seed.exists();\n if (!hasSeed) {\n await wallet.seed.create();\n }\n\n const accounts = await wallet.accounts.list();\n if (accounts.length === 0) {\n await wallet.accounts.create();\n }\n }\n\n if (config.sync !== false) {\n await wallet.sync();\n }\n\n return wallet;\n}\n","import type { RelayState } from \"@unlink-xyz/core\";\n\n/** Terminal relay states — the transaction has finished processing. */\nexport const TERMINAL_TX_STATES: readonly RelayState[] = [\n \"succeeded\",\n \"reverted\",\n \"failed\",\n \"dead\",\n] as const;\n\n/** Failed relay states — the transaction did not succeed. */\nexport const FAILED_TX_STATES: readonly RelayState[] = [\n \"reverted\",\n \"failed\",\n \"dead\",\n] as const;\n\n/** Default timeout for `waitForConfirmation` (5 minutes). */\nexport const DEFAULT_TIMEOUT_MS = 5 * 60 * 1000;\n\n/** Default initial poll interval (2 seconds). */\nexport const DEFAULT_POLL_INTERVAL_MS = 2_000;\n\n/** Maximum poll interval after backoff (30 seconds). */\nexport const MAX_POLL_INTERVAL_MS = 30_000;\n\n/** Backoff multiplier for exponential polling. */\nexport const BACKOFF_FACTOR = 1.5;\n\n/** Thrown when relay polling exceeds the configured timeout. */\nexport class TimeoutError extends Error {\n readonly txId: string;\n readonly timeout: number;\n\n constructor(txId: string, timeout: number) {\n super(`Transaction ${txId} did not confirm within ${timeout}ms`);\n this.name = \"TimeoutError\";\n this.txId = txId;\n this.timeout = timeout;\n }\n}\n\n/** Thrown when a transaction reaches a failed terminal state. */\nexport class TransactionFailedError extends Error {\n readonly txId: string;\n readonly state: RelayState;\n readonly reason?: string;\n\n constructor(txId: string, state: RelayState, reason?: string) {\n super(\n `Transaction ${txId} failed with state: ${state}${reason ? ` — ${reason}` : \"\"}`,\n );\n this.name = \"TransactionFailedError\";\n this.txId = txId;\n this.state = state;\n this.reason = reason;\n }\n}\n","import type { UnlinkWallet } from \"@unlink-xyz/core\";\n\nimport {\n BACKOFF_FACTOR,\n DEFAULT_POLL_INTERVAL_MS,\n DEFAULT_TIMEOUT_MS,\n FAILED_TX_STATES,\n MAX_POLL_INTERVAL_MS,\n TERMINAL_TX_STATES,\n TimeoutError,\n TransactionFailedError,\n} from \"./errors.js\";\nimport type { PollOptions, TxStatus, WaitOptions } from \"./types.js\";\n\nfunction toTxStatus(\n txId: string,\n raw: Awaited<ReturnType<UnlinkWallet[\"getTxStatus\"]>>,\n): TxStatus {\n return {\n txId,\n state: raw.state,\n txHash: raw.txHash ?? undefined,\n blockNumber: raw.receipt?.blockNumber ?? undefined,\n error: raw.error ?? undefined,\n };\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\n/**\n * Poll relay status until the transaction reaches a terminal state.\n *\n * Resolves with `TxStatus` on success (`\"succeeded\"`).\n * Throws `TransactionFailedError` on failure (`\"reverted\"`, `\"failed\"`, `\"dead\"`).\n * Throws `TimeoutError` if the timeout is exceeded.\n *\n * Uses exponential backoff: 2s → 3s → 4.5s → ... capped at 30s.\n *\n * @example\n * ```ts\n * const result = await wallet.transfer({ transfers: [{ token, recipient, amount }] });\n * const status = await waitForConfirmation(wallet, result.relayId);\n * console.log(status.state); // \"succeeded\"\n * ```\n */\nexport async function waitForConfirmation(\n wallet: UnlinkWallet,\n txId: string,\n opts?: WaitOptions,\n): Promise<TxStatus> {\n const timeout = opts?.timeout ?? DEFAULT_TIMEOUT_MS;\n let interval = opts?.pollInterval ?? DEFAULT_POLL_INTERVAL_MS;\n const deadline = Date.now() + timeout;\n\n while (Date.now() < deadline) {\n const raw = await wallet.getTxStatus(txId);\n const status = toTxStatus(txId, raw);\n\n if (status.state === \"succeeded\") {\n return status;\n }\n\n if (FAILED_TX_STATES.includes(status.state)) {\n throw new TransactionFailedError(txId, status.state, status.error);\n }\n\n const remaining = deadline - Date.now();\n if (remaining <= 0) break;\n\n await sleep(Math.min(interval, remaining));\n interval = Math.min(interval * BACKOFF_FACTOR, MAX_POLL_INTERVAL_MS);\n }\n\n throw new TimeoutError(txId, timeout);\n}\n\n/**\n * Async generator that yields `TxStatus` on each poll until a terminal state.\n *\n * Useful for streaming status updates (e.g., logging, progress bars).\n *\n * @example\n * ```ts\n * for await (const status of pollRelayStatus(wallet, relayId)) {\n * console.log(status.state); // \"pending\" → \"broadcasting\" → \"submitted\" → \"succeeded\"\n * }\n * ```\n */\nexport async function* pollRelayStatus(\n wallet: UnlinkWallet,\n txId: string,\n opts?: PollOptions,\n): AsyncGenerator<TxStatus, void, unknown> {\n const timeout = opts?.timeout ?? DEFAULT_TIMEOUT_MS;\n let interval = opts?.pollInterval ?? DEFAULT_POLL_INTERVAL_MS;\n const deadline = Date.now() + timeout;\n\n while (Date.now() < deadline) {\n const raw = await wallet.getTxStatus(txId);\n const status = toTxStatus(txId, raw);\n\n yield status;\n\n if (TERMINAL_TX_STATES.includes(status.state)) {\n return;\n }\n\n const remaining = deadline - Date.now();\n if (remaining <= 0) return;\n\n await sleep(Math.min(interval, remaining));\n interval = Math.min(interval * BACKOFF_FACTOR, MAX_POLL_INTERVAL_MS);\n }\n}\n","import { EventEmitter } from \"node:events\";\nimport type { UnlinkWallet, WalletSDKEvent } from \"@unlink-xyz/core\";\n\n/**\n * Wrap an UnlinkWallet's event system with a Node.js `EventEmitter`.\n *\n * Events are emitted by their `type` field (e.g., `\"notes-updated\"`,\n * `\"tx-status-changed\"`). A wildcard `\"*\"` event is also emitted for\n * every event.\n *\n * @returns An `EventEmitter` and an `unsubscribe` function to detach from the wallet.\n *\n * @example\n * ```ts\n * const { emitter, unsubscribe } = createWalletEmitter(wallet);\n *\n * emitter.on(\"notes-updated\", (event) => {\n * console.log(\"Notes updated on chain\", event.chainId);\n * });\n *\n * emitter.on(\"tx-status-changed\", (event) => {\n * console.log(`TX ${event.txId}: ${event.state}`);\n * });\n *\n * // Listen to all events\n * emitter.on(\"*\", (event) => console.log(event));\n *\n * // Cleanup when done\n * unsubscribe();\n * ```\n */\nexport function createWalletEmitter(wallet: UnlinkWallet): {\n emitter: EventEmitter;\n unsubscribe: () => void;\n} {\n const emitter = new EventEmitter();\n\n const unsubscribe = wallet.on((event: WalletSDKEvent) => {\n emitter.emit(event.type, event);\n emitter.emit(\"*\", event);\n });\n\n return { emitter, unsubscribe };\n}\n","import fs from \"node:fs\";\nimport path from \"node:path\";\nimport type {\n BatchOp,\n Bytes,\n IterOptions,\n KvPair,\n Storage,\n} from \"@unlink-xyz/core\";\nimport { validateKey } from \"@unlink-xyz/core\";\nimport Database from \"better-sqlite3\";\n\nexport type SqliteStorageOptions = {\n /** Full path to the .db file */\n path: string;\n};\n\nexport function createSqliteStorage(opts: SqliteStorageOptions): Storage {\n let db: Database.Database | null = null;\n let stmtGet: Database.Statement;\n let stmtPut: Database.Statement;\n let stmtDel: Database.Statement;\n let stmtGetSchema: Database.Statement;\n let stmtUpsertSchema: Database.Statement;\n\n return {\n async open() {\n const dir = path.dirname(opts.path);\n fs.mkdirSync(dir, { recursive: true });\n\n db = new Database(opts.path);\n db.pragma(\"journal_mode = WAL\");\n db.pragma(\"busy_timeout = 5000\");\n db.exec(`\n CREATE TABLE IF NOT EXISTS kv (key TEXT PRIMARY KEY, value BLOB NOT NULL);\n CREATE TABLE IF NOT EXISTS meta (key TEXT PRIMARY KEY, value INTEGER NOT NULL);\n `);\n\n stmtGet = db.prepare(\"SELECT value FROM kv WHERE key = ?\");\n stmtPut = db.prepare(\n \"INSERT OR REPLACE INTO kv (key, value) VALUES (?, ?)\",\n );\n stmtDel = db.prepare(\"DELETE FROM kv WHERE key = ?\");\n stmtGetSchema = db.prepare(\n \"SELECT value FROM meta WHERE key = 'schema_version'\",\n );\n stmtUpsertSchema = db.prepare(\n \"INSERT OR REPLACE INTO meta (key, value) VALUES ('schema_version', ?)\",\n );\n },\n\n async get(key: string): Promise<Bytes | null> {\n validateKey(key);\n const row = stmtGet.get(key) as { value: Buffer } | undefined;\n return row ? new Uint8Array(row.value) : null;\n },\n\n async put(key: string, value: Bytes): Promise<void> {\n validateKey(key);\n stmtPut.run(key, Buffer.from(value));\n },\n\n async delete(key: string): Promise<void> {\n validateKey(key);\n stmtDel.run(key);\n },\n\n async batch(ops: BatchOp[]): Promise<void> {\n const runBatch = db!.transaction(() => {\n for (const op of ops) {\n if (op.put) {\n const [k, v] = op.put;\n validateKey(k);\n stmtPut.run(k, Buffer.from(v));\n }\n if (op.del) {\n validateKey(op.del);\n stmtDel.run(op.del);\n }\n }\n });\n runBatch();\n },\n\n async iter(o: IterOptions = {}): Promise<KvPair[]> {\n if (o.start && o.end && o.start > o.end) {\n throw new Error(\"iter start bound must not exceed end bound\");\n }\n\n const conditions: string[] = [];\n const params: (string | number)[] = [];\n\n if (o.prefix) {\n // Escape SQL LIKE wildcards in the prefix\n const escaped = o.prefix.replace(/[%_\\\\]/g, \"\\\\$&\");\n conditions.push(\"key LIKE ? ESCAPE '\\\\'\");\n params.push(escaped + \"%\");\n }\n if (o.start) {\n conditions.push(\"key >= ?\");\n params.push(o.start);\n }\n if (o.end) {\n conditions.push(\"key <= ?\");\n params.push(o.end);\n }\n\n let sql = \"SELECT key, value FROM kv\";\n if (conditions.length > 0) {\n sql += \" WHERE \" + conditions.join(\" AND \");\n }\n sql += o.reverse ? \" ORDER BY key DESC\" : \" ORDER BY key ASC\";\n if (o.limit != null) {\n sql += \" LIMIT ?\";\n params.push(o.limit);\n }\n\n const rows = db!.prepare(sql).all(...params) as Array<{\n key: string;\n value: Buffer;\n }>;\n\n return rows.map((row) => ({\n key: row.key,\n value: new Uint8Array(row.value),\n }));\n },\n\n async count(prefix?: string): Promise<number> {\n let sql = \"SELECT COUNT(*) as cnt FROM kv\";\n const params: string[] = [];\n if (prefix) {\n const escaped = prefix.replace(/[%_\\\\]/g, \"\\\\$&\");\n sql += \" WHERE key LIKE ? ESCAPE '\\\\'\";\n params.push(escaped + \"%\");\n }\n const row = db!.prepare(sql).get(...params) as { cnt: number };\n return row.cnt;\n },\n\n async getSchemaVersion(): Promise<number> {\n const row = stmtGetSchema.get() as { value: number } | undefined;\n return row?.value ?? 0;\n },\n\n async setSchemaVersion(v: number): Promise<void> {\n stmtUpsertSchema.run(v);\n },\n };\n}\n","// Init\nexport { initWallet } from \"./init.js\";\n\n// Confirmation\nexport { waitForConfirmation, pollRelayStatus } from \"./confirmation.js\";\n\n// Events\nexport { createWalletEmitter } from \"./events.js\";\n\n// Storage\nexport {\n createSqliteStorage,\n type SqliteStorageOptions,\n} from \"./storage/sqlite.js\";\n\n// Errors\nexport {\n TimeoutError,\n TransactionFailedError,\n TERMINAL_TX_STATES,\n FAILED_TX_STATES,\n DEFAULT_TIMEOUT_MS,\n DEFAULT_POLL_INTERVAL_MS,\n} from \"./errors.js\";\n\n// Types\nexport type {\n NodeWalletConfig,\n TxStatus,\n WaitOptions,\n PollOptions,\n} from \"./types.js\";\n\n// Re-export commonly needed core types so consumers don't need @unlink-xyz/core\nexport { UnlinkWallet, createMemoryStorage } from \"@unlink-xyz/core\";\n\nexport type {\n Account,\n AccountInfo,\n AccountView,\n ChainConfig,\n DepositRelayResult,\n HistoryEntry,\n NoteRecord,\n RelayState,\n RelayStatusResponse,\n Storage,\n SupportedChain,\n TransactRelayResult,\n TransferPlanResult,\n TransferResult,\n WalletSDKEvent,\n WithdrawPlanResult,\n WithdrawResult,\n} from \"@unlink-xyz/core\";\n"],"mappings":"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","names":["UnlinkWallet","createMemoryStorage"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@unlink-xyz/node",
|
|
3
|
-
"version": "0.1.3-canary.
|
|
3
|
+
"version": "0.1.3-canary.b0ad588",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "dist/index.cjs",
|
|
6
6
|
"module": "dist/index.js",
|
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
"test:coverage": "vitest run --coverage"
|
|
36
36
|
},
|
|
37
37
|
"dependencies": {
|
|
38
|
-
"@unlink-xyz/core": "0.1.3-canary.
|
|
38
|
+
"@unlink-xyz/core": "0.1.3-canary.b0ad588",
|
|
39
39
|
"better-sqlite3": "^11.10.0"
|
|
40
40
|
},
|
|
41
41
|
"devDependencies": {
|