npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@w3art/profile-manager

v2.0.2

Published

Chrome user data directory manager for EOA-specific persistent profiles

Readme

@web3/profile-manager

🎯 Chrome 用户目录准备器 v2.0

为 EOA 地址准备持久化的 Chrome userDataDir,实现浏览器身份长期有状态管理。


✨ 核心功能

  • 自动分片目录管理{base}/{前2位}/{中2位}/{后36位}
  • 母版模板复制:新兵首次使用时从 {templateBase}/{walletPin} 复制初始化
  • 老兵直接复用:已存在的目录直接使用,保留历史状态
  • 多磁盘智能选择:按优先级自动选择可用的存储卷
  • 完全类型安全:TypeScript 严格模式,零 any

📦 安装

pnpm add @web3/profile-manager

🚀 快速开始

基础用法

import { prepareUserDataDir } from '@web3/profile-manager';

// 设置环境变量
process.env.EOA_ADDRESS = '0xabcdef1234567890abcdef1234567890abcdef12';
process.env.WALLET_PIN_ID = '41';

// 准备用户目录
const result = await prepareUserDataDir();

console.log(result.userDataDir);
// 输出: /M4-4t/ab/cd/ef1234567890abcdef1234567890abcdef12

console.log(result.initialized);
// 输出: true (新兵) 或 false (老兵)

在 Playwright Runner 中使用

import { chromium } from 'playwright';
import { prepareUserDataDir, DEFAULT_CHROME_LAUNCH_ARGS } from '@web3/profile-manager';

// 准备用户目录
const { userDataDir, initialized } = await prepareUserDataDir();

if (initialized) {
  console.log('🎖️ 新兵首次初始化完成');
} else {
  console.log('♻️ 老兵复用现有目录');
}

// 启动 Chrome
const context = await chromium.launchPersistentContext(userDataDir, {
  headless: false,
  args: DEFAULT_CHROME_LAUNCH_ARGS,
});

🔧 环境变量配置

必需环境变量

| 变量 | 说明 | 示例 | | --------------- | ---------------------- | ------------- | | EOA_ADDRESS | EOA 地址(0x开头40位) | 0xabcdef... | | WALLET_PIN_ID | 钱包模板编号 | 41 |

可选环境变量

| 变量 | 说明 | 默认值 | | ------------------------------- | -------------------------- | ------------------------------------------------------------------------------------- | | PROFILES_SEARCH_PATHS | 用户数据卷路径(逗号分隔) | /M4-4t,/sandiskpro-4t,/UDISK_15G | | MASTER_TEMPLATES_SEARCH_PATHS | 母版模板路径(逗号分隔) | /master_templates_m4-4t,/master_templates_sandiskpro-4t,/master_templates_udisk-15g |


📂 目录结构

用户数据目录(分片存储)

/M4-4t/
├── ab/                     # 前2位
│   ├── cd/                 # 中2位
│   │   └── ef12...34/      # 后36位(完整 userDataDir)
│   │       ├── Default/
│   │       ├── Extensions/
│   │       └── ...

母版模板目录(按 walletPin)

/master_templates_m4-4t/
├── 41/                     # walletPin=41 的模板
│   ├── Default/
│   ├── Extensions/
│   └── ...
├── 42/                     # walletPin=42 的模板
└── ...

🎨 导出的常量

import {
  CHROME_VERSION, // '140.0.7339.185' (与 .versions.env 保持一致)
  CHROME_EXECUTABLE_PATH, // '/usr/bin/google-chrome'
  DEFAULT_CHROME_LAUNCH_ARGS, // Chrome 启动参数数组
  DEFAULT_PROFILES_SEARCH_PATHS, // ['/M4-4t', '/sandiskpro-4t', '/UDISK_15G']
  DEFAULT_TEMPLATES_SEARCH_PATHS, // ['/master_templates_m4-4t', ...]
  SKIP_COPY_PATTERNS, // 跳过复制的目录正则
} from '@web3/profile-manager';

📋 API 参考

prepareUserDataDir()

准备 Chrome 用户数据目录。

返回Promise<PrepareResult>

interface PrepareResult {
  userDataDir: string; // 目标目录路径
  initialized: boolean; // 是否为本次初始化
  templateSource?: string; // 使用的模板路径(仅初始化时)
}

异常

  • Error('EOA_ADDRESS is required') - 缺少 EOA 地址
  • Error('WALLET_PIN_ID is required') - 缺少钱包编号
  • Error('Invalid EOA address format') - EOA 格式错误
  • Error('No accessible profiles base path') - 无可用存储卷
  • Error('Master template not found') - 母版模板不存在

🔍 工具函数

normalizeEoaAddress(eoa: string): string

标准化 EOA 地址为 40 位小写十六进制(去除 0x 前缀)。

import { normalizeEoaAddress } from '@web3/profile-manager';

normalizeEoaAddress('0xAbCd...');
// 返回: 'abcd...'

buildShardedUserPath(base: string, normalizedHex40: string): string

构建分片路径。

import { buildShardedUserPath } from '@web3/profile-manager';

buildShardedUserPath('/M4-4t', 'abcdef1234567890...');
// 返回: '/M4-4t/ab/cd/ef1234567890...'

findFirstExistingBasePath(paths: string[], description: string): Promise<string>

查找第一个存在的路径。

getEnvList(envKey: string, fallbackCommaList: string): string[]

从环境变量读取逗号分隔的路径列表。


🎯 设计原则

1. 极致的身份隔离

每个 EOA 拥有独立的 userDataDir,完全隔离 Cookies、LocalStorage、扩展状态等。

2. 长期有状态管理

"老兵"复用现有目录,保留完整的浏览器历史和身份状态。

3. 防女巫优化

  • 固定 Chrome 版本(140.0.7339.185,与 Playwright Runner Docker 一致)
  • 唯一指纹绑定
  • 持久化身份特征

4. 性能优化

  • 跳过缓存目录复制(CacheGPUCache 等)
  • 分片存储避免单目录文件过多
  • 多磁盘智能负载均衡

📊 包信息

  • 版本:2.0.0
  • 文件数:3 个源文件
  • 代码量:~330 行
  • 依赖:仅 Node.js 内置模块
  • 构建产物:ESM + TypeScript 声明文件

🔄 从 v1.0 迁移

v2.0 大幅简化,删除了冗余的 OOP 包装层:

// ❌ v1.0 (已废弃)
import { ProfileManager } from '@web3/profile-manager';
const manager = ProfileManager.getInstance();
await manager.createWorkspace(eoaAddress);

// ✅ v2.0 (推荐)
import { prepareUserDataDir } from '@web3/profile-manager';
const result = await prepareUserDataDir();

📄 许可证

MIT


🤝 贡献

欢迎提交 Issue 和 Pull Request!