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

dsh-allowed-workspace-roots

v1.0.0

Published

DSH Desktop plugin: allow selected non-NTFS roots (e.g. an rclone/WinFsp SFTP mount) as workspaces, and repair fs.realpath on such volumes.

Readme

dsh-allowed-workspace-roots

Плагин для DSH Desktop: разрешает использовать как рабочие области папки на томах, которые штатная политика считает неподходящими, и чинит realpath на таких томах.

Эталонный случай — корпоративный диск, смонтированный rclone через WinFsp (например SFTP-сервер): Windows показывает его как обычный фиксированный диск, но имя файловой системы у него не NTFS/ReFS, и нативный realpath на нём не работает.

Что именно чинится

WinFsp не поддерживает GetFinalPathNameByHandleW при монтировании буквой диска:

GetFinalPathNameByHandleW('<том>\каталог')  →  GetLastError = 1005
                                               (ERROR_NO_UNICODE_TRANSLATION)
                                               в Node это код UNKNOWN
GetFinalPathNameByHandleW('C:\Users')       →  OK

При этом stat, opendir и синхронный fs.realpathSync (JS-реализация, без libuv) на том же томе работают. Ломается только нативный вариант.

DSH канонизирует пути через realpath в нескольких независимых местах, и без плагина отказ выглядит как последовательность ошибок:

| Что делает пользователь | Что происходит без плагина | | --- | --- | | добавляет папку на томе как рабочую область | FUSE-RCLONE cannot safely host a DSH Desktop workspace | | повторяет после обхода проверки тома | workspace/invalid-path: ... UNKNOWN: unknown error, realpath | | отправляет первый запрос в сессии | UNKNOWN: unknown error, realpath из слоя файлов | | перезапускает DSH | сессия исчезает из списка |

Как устроено

Три независимых патча. Все три нужны при любой политике файлов — они не про песочницу.

1. Клиентская половина (lib/client.js). Штатная проверка тома живёт в клиентской половине Desktop-плагина и на каждом вызове читает функцию из window.__DSH_DESKTOP_VALIDATE_DIRECTORY__. Плагин подменяет это свойство аксессором: get возвращает обёртку, которая для путей из allow-list отвечает «разрешено» сразу, а для всех остальных вызывает настоящий валидатор DSH; set перехватывает настоящий валидатор, когда Desktop-плагин его устанавливает, поэтому порядок загрузки не важен.

2. Реестр рабочих областей (lib/registry-patch.mjs). Оборачивает create, resolveByPath, indexHeader и attachSession, подменяя канонизацию на JS-реализацию realpathSync — только для путей из allow-list. create дальше идёт ровно как в оригинале, минуя realpath. attachSession живёт на сущности рабочей области, поэтому патчится её прототип.

Отдельно: реестр индексирует заголовки сохранённых сессий при своём старте, то есть раньше, чем плагин получит управление. На «сломанном» томе сессии помечаются недействительными и после перезапуска пропадают из списка, хотя во время работы видны. Поэтому сразу после установки патча индексация прогоняется заново.

3. Слой файлов (lib/fs-patch.mjs). dsh-fs-local канонизирует цель через realpath и пробрасывает UNKNOWN наружу, потому что обрабатывает только ENOTDIR и ENOENT. Канонизация там вызывается ровно в двух местах, поэтому хватает двух методов: resolve — единственная точка входа для путей, и резолв детей при листинге каталога. Все остальные методы (stat, readText, writeText, editText) принимают уже готовую цель, где targetKey и есть путь для ввода-вывода.

resolve обязан переживать ещё не существующий файл — иначе создание файла падает с ENOENT. Для этого канонизируется ближайший существующий предок, а недостающий хвост приклеивается обратно.

Почему не подмена модуля node:fs/promises

Естественный вопрос: почему бы просто не подменить realpath в node:fs/promises и не закрыть все вызовы разом? Пробовали, в этом окружении не работает:

  • правка объекта fs.promises не помогает — dsh-app-boot импортирует node:fs/promises задолго до плагинов, а ESM-фасад фиксирует нативную функцию в момент первого импорта;
  • хук загрузчика (module.registerHooks) помогает, но обязан встать раньше первого импорта, а плагин загружается позже — проверено счётчиком модулей: dsh-workspace среди них=false;
  • предзагрузка через NODE_OPTIONS успевает (среди них=true), но переменная окружения до процесса хоста не доходит: хост DSH — это utility-процесс внутри Electron-приложения, а не процесс, запускаемый через сгенерированный dsh.cmd. Правка самого dsh.cmd не переживает перезапуск: приложение сверяет содержимое генерации и создаёт новую.

Поэтому вместо одного общего шима — три точечных патча, которые работают независимо от порядка загрузки.

Установка

dsh plugin --profile desktop add dsh-allowed-workspace-roots

Или из скачанного архива:

dsh plugin --profile desktop add ./dsh-allowed-workspace-roots-1.0.0.tgz

После установки нужен полный перезапуск DSH Desktop: граф клиентских бандлов собирается при старте хоста.

Настройка

Список разрешённых корней задаётся в cordis.patch.yml пакета:

- insert:
    - id: allowed-workspace-roots
      name: 'dsh-allowed-workspace-roots'
      config:
        roots:
          - 'T:\'
          # - 'T:\Shared'   # пример сужения области

Сравнение идёт по границе сегмента пути: корень T:\Shared не пропустит T:\SharedOther. Регистр, прямые слэши и завершающий разделитель значения не имеют. После правки конфигурации нужен перезапуск DSH.

Для всего, что не входит в allow-list, поведение DSH не меняется: решение принимает штатный валидатор.

Ограничения

Нужен режим «Полный доступ» (danger-full-access). При workspace-write команда выполняется отдельным процессом — ACL-runner'ом песочницы, — а до него внутрипроцессные патчи не достают. При danger-full-access dsh-sandbox-local не вызывает confine() вовсе, runner не запускается, и этот слой исчезает.

Учтите цену: песочница ограничивает, куда агент может писать. При полном доступе он пишет всюду, куда может писать пользователь.

Патчи опираются на внутренности DSH. Проверено на DSH Desktop 2.0.9. После обновления DSH стоит пройти сценарий заново: добавить папку, создать сессию, отправить запрос. Отказ безопасен — пользователь просто увидит прежнюю ошибку.

Сам том остаётся сетевым. Плагин чинит канонизацию путей, но не меняет природу монтирования: при обрыве связи с сервером рабочая область виснет, блокировки и атомарные переименования ненадёжны, а VFS-кэш rclone делает обход больших каталогов заметно медленнее локального диска.

Не используйте --network-mode как альтернативу. Он действительно чинит realpath, но переводит монтирование в общее на машину пространство имён: имя шары видно через net use из чужого сеанса, и пользователи получают доступ к файлам друг друга. Изоляция букв диска этого не допускает.

Проверка

node test/verify.mjs

41 проверка: логика allow-list, клиентская половина в обоих порядках загрузки, патч реестра и патч слоя файлов. Часть проверок идёт по настоящему тому — подделка не воспроизведёт сломанный realpath. Корень задаётся переменной DSH_TEST_ROOT (по умолчанию T:\); если тома нет или он обычный NTFS, эти проверки пропускаются с пояснением.

Если Node нет, тесты запускаются встроенным в DSH Desktop:

$env:ELECTRON_RUN_AS_NODE='1'
& 'C:\Program Files\DSH Desktop\DSH Desktop.exe' test/verify.mjs

Внутри запущенного DSH есть и самопроверка хоста: переменная DSH_ALLOWED_ROOTS_PROBE=1 заставляет плагин сразу создать рабочую область, разрешить путь и перечислить каталог, записав результат в лог.

Состав

| Файл | Назначение | | --- | --- | | lib/client.js | патч 1: снятие проверки тома для путей из allow-list | | lib/registry-patch.mjs | патч 2: реестр рабочих областей | | lib/fs-patch.mjs | патч 3: слой файлов | | lib/roots.mjs | общая логика allow-list | | lib/index.js | host-половина: ставит патчи 2 и 3 | | cordis.patch.yml | строка плагина в дереве загрузчика + allow-list | | test/verify.mjs | автотесты |