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 🙏

© 2025 – Pkg Stats / Ryan Hefner

y-prosemirror-awork

v1.3.5-awork.5

Published

Prosemirror bindings for Yjs with string/integer attribute compatibility - Awork fork

Downloads

7,711

Readme

y-prosemirror-awork

🎉 Shoutout

This fork was created to solve real-world interoperability challenges between JavaScript and .NET CRDT implementations. Special thanks to the original y-prosemirror team for creating such a solid foundation that made this enhancement possible!


This is a fork of y-prosemirror with enhanced string/integer attribute compatibility for better interoperability with YDotNet and other CRDT implementations.

Why this fork?

The original y-prosemirror expects attributes to maintain their JavaScript types (e.g., level: 1 as a number). However, some CRDT implementations like YDotNet only support string attributes. This creates type mismatches when:

  • YDotNet stores level: "1" (string)
  • y-prosemirror expects level: 1 (number)

This fork adds intelligent type conversion and comparison to handle these mismatches gracefully.

What's Changed

  1. Loose Equality Comparison: Attributes are compared using type coercion for common cases:

    • "1" equals 1 (string/number)
    • "true" equals true (string/boolean)
  2. Automatic Type Conversion: When creating ProseMirror nodes from Yjs data, attributes are automatically converted to match the schema's expected types based on default values.

  3. No Unnecessary Updates: Prevents redundant syncing when only the type differs but the value is equivalent.

Installation

npm install y-prosemirror-awork

Usage

Use exactly like the original y-prosemirror:

import { ySyncPlugin, yCursorPlugin, yUndoPlugin, undo, redo } from 'y-prosemirror-awork'

// Same API as original y-prosemirror
const provider = new WebrtcProvider(/* ... */)
const type = ydoc.getXmlFragment('prosemirror')

const plugins = [
  ySyncPlugin(type),
  yCursorPlugin(provider.awareness),
  yUndoPlugin(),
  keymap({
    'Mod-z': undo,
    'Mod-y': redo,
    'Mod-Shift-z': redo
  })
]

Detailed Modifications

1. looseEquals() Function (sync-plugin.js, lines 955-1000)

Added a new function that performs type-coerced equality comparison:

// Returns true if values are equal after type coercion
// Examples: 1 equals "1", true equals "true", [279] equals "279"
function looseEquals(a, b) {
  if (a === b) return true
  
  // Handle array/string comparison for colwidth
  if (Array.isArray(a) && typeof b === 'string') {
    const num = Number(b)
    if (!isNaN(num) && a.length === 1 && a[0] === num) {
      return true
    }
  }
  if (typeof a === 'string' && Array.isArray(b)) {
    const num = Number(a)
    if (!isNaN(num) && b.length === 1 && b[0] === num) {
      return true
    }
  }
  
  // Handle number/string comparison
  if (typeof a === 'number' && typeof b === 'string') {
    return a === Number(b)
  }
  if (typeof a === 'string' && typeof b === 'number') {
    return Number(a) === b
  }
  
  // Handle boolean/string comparison
  if (typeof a === 'boolean' && typeof b === 'string') {
    return a === (b === 'true')
  }
  if (typeof a === 'string' && typeof b === 'boolean') {
    return (a === 'true') === b
  }
  
  // Fallback to string comparison
  return String(a) === String(b)
}

2. Type Conversion in createNodeFromYElement() (sync-plugin.js, lines 808-848)

Automatically converts string attributes to match ProseMirror schema expectations:

  • Converts "1"1 when schema expects a number
  • Converts "true"true when schema expects a boolean
  • Special handling for colwidth attribute:
    • Single value: "279"[279]
    • Multiple values: "100,200,300"[100, 200, 300]
    • Matches TipTap's TableCell parseHTML behavior
  • Uses schema default values to determine expected types

3. Modified equalAttrs() (sync-plugin.js, line 991)

Changed from strict equality to use looseEquals():

eq = key === 'ychange' || looseEquals(l, r) || // AWORK CUSTOM

4. Modified updateYFragment() (sync-plugin.js, line 1231)

Uses looseEquals() when comparing attributes to prevent unnecessary updates:

if (!looseEquals(yDomAttrs[key], pAttrs[key]) && key !== 'ychange') {

All modifications are marked with // AWORK CUSTOM comments for easy identification.

Compatibility

This fork maintains full API compatibility with y-prosemirror v1.3.5. You can use it as a drop-in replacement.

Publishing a New Version

To publish a new version of y-prosemirror-awork:

1. Prepare the Package

# Run the publish preparation script
./publish-awork.sh

This script will:

  • Copy package-awork.json to package.json
  • Copy README-awork.md to README.md
  • Install dependencies with npm install
  • Build the package with npm run dist
  • Run tests with npm test

2. Test Locally

Before publishing, test the package locally:

# Create a local package
npm pack

# In your test project, install the local package
npm install path/to/y-prosemirror-awork-1.3.5-awork.X.tgz

3. Update Version

Update the version in package-awork.json:

"version": "1.3.5-awork.X"  // Increment X for each release

4. Publish to npm

# Login to npm (if not already logged in)
npm login

# Publish the package
npm publish

5. Create GitHub Release (Optional)

  1. Push code to GitHub repository: https://github.com/awork/y-prosemirror-awork
  2. Create a new release with the version tag
  3. Document the changes in the release notes

License

MIT (same as original y-prosemirror)

Credits

Original y-prosemirror by Kevin Jahns and the Yjs team. Fork modifications for Awork by the Awork team.