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

@multiplatform.one/platform

v7.34.4

Published

Platform detection flags and utilities for multiplatform.one

Readme

@multiplatform.one/platform

Platform detection flags and small cross-platform utilities for multiplatform.one — one import to answer "where is this code running?" on web, native, desktop, and extension surfaces.

Install

pnpm add @multiplatform.one/platform

What it owns

  • Detection flags — isWeb, isNative, isIos, isAndroid, isServer, isClient, isGnome, isTauri, isDesktop, isExpo, isNext, isStorybook, isChrome, isFirefox, isWebExtension, isChromeExtension, isFirefoxExtension, isIframe, isTouchable, isWebTouchable, isWindowDefined, … plus the full platform object (platform.preciseName)
  • Env config — the config reader used across packages
  • Utilities — cookies, clipboard, downloadFile, openUrl, lifecycle helpers

What it must not do

  • No UI, no theming, no data fetching — packages above it (theme, core, logger, …) build on these flags, so this package stays dependency-light

Usage

import { isGnome, isNative, isServer, isTauri } from "@multiplatform.one/platform";

export function saveFile(contents: string) {
  if (isServer) return;
  if (isTauri) {
    // webview desktop path (see @multiplatform.one/desktop)
    return;
  }
  if (isGnome) {
    // GTK desktop path (see @multiplatform.one/desktop)
    return;
  }
  if (isNative) {
    // share sheet / expo-file-system path
    return;
  }
  // browser download path
}

Flags are evaluated once at module load and are safe to use in render logic and module scope.

Save bytes to a file

Import the opt-in subpath from a user action:

import { FileSaveError, saveFile } from "@multiplatform.one/platform/file";

try {
  const result = await saveFile({
    bytes: new TextEncoder().encode("café\n"),
    filename: "example.txt",
    mimeType: "text/plain; charset=utf-8",
  });
  // Render the returned status, not a blanket success message.
} catch (error) {
  if (error instanceof FileSaveError) {
    console.error(error.code, error.cause, error.cleanupError);
  }
}

| Result | What it establishes | | --- | --- | | written | Native byte writing completed at uri, with byteLength and requestedFilename. The actual filename is optional. Cloud synchronization is not confirmed. | | download-requested | A browser download was activated. Browser completion or cancellation is unknown. | | not-saved, reason cancelled-or-refused | The native picker reported cancellation or refused directory access. No file was created. iOS reports these with the same code. |

WrittenFile.requestedFilename always records the supplied filename. The optional filename reports the actual name only for an iOS file URI. Android content URIs omit it: Expo 55.0.26 derives File.name from the URI, which can contain an opaque document ID instead of a provider display name. Consumers must distinguish the requested name from an actual name and use uri for the saved destination.

Errors reject with FileSaveError: invalid-input, unavailable, busy, picker-failed or write-failed. The original failure is in cause. cleanupError records a second failure removing a partially written new file. Only ERR_PICKER_CANCELLED and ERR_FILE_PICKING_CANCELLED are classified as not-saved; other picker errors remain observable.

Native iOS/Android requires expo-file-system (~55.0.26, tested against 55.0.26) in the app and its native binary. Install it explicitly in the native host. JavaScript or an OTA update cannot add a missing native module. The module loads only when saveFile is invoked, and isn't exported through the platform root. Other hosts require browser download support or return unavailable.

Native opens the system directory picker and creates a new child through the selected provider. It doesn't request overwrite. A provider can refuse an existing name or choose a suffix. requestedFilename doesn't confirm which name the provider chose; filename is omitted when that metadata isn't established. Successful files belong to the user and are never automatically deleted. On write failure, cleanup attempts to delete only the newly created child. No shared cache file or share sheet is involved.

Pass a Uint8Array, a nonempty single filename without separators, dot/dot-dot or control characters, and a MIME type. Unicode filenames and empty files are valid. Bytes are copied before awaiting the directory picker, including the exact range of a sliced view. Native creation uses the MIME type without parameters; the browser Blob retains the supplied type.

The existing root downloadFile and downloadBlob remain synchronous void helpers. Blob URLs are released after 60 seconds; this delay manages resources and does not indicate that a download completed.

Platform/FileSave is a generic Storybook specimen for parent browser/native checks. Unit tests model native boundaries. Packed ESM/CJS and Metro checks are package preflight, not real-device save evidence or registry publication.

License

Apache-2.0