dmonad / lib0 Goto Github PK
View Code? Open in Web Editor NEWMonorepo of isomorphic utility functions
License: MIT License
Monorepo of isomorphic utility functions
License: MIT License
class ObservableV2<EVENTS extends {
[key: string]: (...arg0: any[]) => void;
}> {}
rejects interfaces because interfaces don't have an index signature.
would it be possible to do this instead?
class ObservableV2<EVENTS extends {
[key in EVENT_TYPES]: (...arg0: any[]) => void;
}, EVENT_TYPES extends keyof EVENTS = keyof EVENTS> {}
Describe the bug
A clear and concise description of what the bug is.
Observable.once
creates a wrapper around the function, so calling Observable.off
does not prevent it from being called.
let fn = ()=>{};
item.once('update', fn);
item.off('update', fn);
fn
, will still be invoked under this scenario.
This seems to by design, so it should be documented that off
will not prevent once
from being called.
Just in case somebody needs a starting point for decode/encoder in Swift here is some code. Since the variable encoding of integers is one of the trickiest parts of it, these are examples of this functionality. The rest should be pretty straight forward. Maybe there is some place for it somewhere...
import Foundation
func readVarInt(bytes: [UInt8], pos: Int = 0) -> Int {
var bytesPos = pos
var r = bytes[bytesPos]
var num: Int = Int(r & 0b00111111)
var mult: Int = 64
let sign = (r & 0b01000000) > 0 ? -1 : 1
// print("r=\(r) num=\(num) c=\(Int(r & 0b1)) sign=\(sign)")
if Int(r & 0b10000000) == 0 {
return sign * num
}
while true {
bytesPos += 1
r = bytes[bytesPos]
num = num + Int(r & 0b01111111) * mult
mult *= 128
if r < 0b10000000 {
return sign * num
}
}
}
func readVarUInt(bytes: [UInt8], pos: Int = 0) -> UInt {
var bytesPos = pos
var num: UInt = 0
var mult: UInt = 1
while true {
let r = bytes[bytesPos]
bytesPos += 1
num = num + UInt(r & 0b01111111) * mult
mult *= 128
if r < 0b10000000 {
return num
}
}
}
/// Just the same, but with Data as argument
func readVarUInt(data: Data, pos: Int = 0) -> UInt {
var bytesPos = pos
var num: UInt = 0
var mult: UInt = 1
while true {
let r = data[bytesPos]
bytesPos += 1
num = num + UInt(r & 0b01111111) * mult
mult *= 128
if r < 0b10000000 {
return num
}
}
}
func writeVarUInt(_ value: UInt) -> Data {
var bytes = Data()
var num = value
while num > 0b01111111 {
bytes.append(0b10000000 | (0b01111111 & UInt8(truncatingIfNeeded: num)))
num = num / 128
}
bytes.append(UInt8(0b01111111 & num))
return bytes
}
This is a unit test:
import XCTest
extension Data {
func hexEncodedString() -> String {
return map { String(format: "%02hhx", $0) }.joined()
}
}
class Lib0Test: XCTestCase {
func testReadVarInt() throws {
XCTAssertEqual(10, readVarInt(bytes: [10]))
XCTAssertEqual(128, readVarInt(bytes: [0x80, 0x02]))
XCTAssertEqual(-1, readVarInt(bytes: [0x41]))
XCTAssertEqual(-691529286, readVarInt(bytes: [0xc6, 0x99, 0xbf, 0x93, 0x05]))
XCTAssertEqual(691529286, readVarInt(bytes: [0x86, 0x99, 0xbf, 0x93, 0x05]))
}
func testReadVarUInt() throws {
XCTAssertEqual(10, readVarUInt(bytes: [10]))
XCTAssertEqual(127, readVarUInt(bytes: [0x7f]))
XCTAssertEqual(256, readVarUInt(bytes: [0x80, 0x02]))
XCTAssertEqual(691529286, readVarUInt(bytes: [0xc6, 0xcc, 0xdf, 0xc9, 0x02]))
}
func testReadVarUIntWithData() throws {
XCTAssertEqual(10, readVarUInt(data: Data([10])))
XCTAssertEqual(127, readVarUInt(data: Data([0x7f])))
XCTAssertEqual(256, readVarUInt(data: Data([0x80, 0x02])))
XCTAssertEqual(691529286, readVarUInt(data: Data([0xc6, 0xcc, 0xdf, 0xc9, 0x02])))
}
func testWriteVarUInt() throws {
print("Data \(writeVarUInt(10).hexEncodedString())")
XCTAssertEqual(writeVarUInt(10).hexEncodedString(), "0a")
XCTAssertEqual(writeVarUInt(127).hexEncodedString(), "7f")
XCTAssertEqual(writeVarUInt(256).hexEncodedString(), "8002")
XCTAssertEqual(writeVarUInt(691529286).hexEncodedString(), "c6ccdfc902")
}
}
Describe the bug
Super small issue, but I noticed a typo here:
Line 295 in fe162f4
--repitition-time
should be --repetition-time
(s/i/e)
Additional context
I considered opening a pull request to fix this, but it looks like it's used from a few dependent libraries that you have r/w access to, so it might be quicker to clean up centrally. Glad to help if I can though!
Describe the bug
After writing the content to IntDiffOptRleEncoder
(also UintOptRleEncoder
, IncUintOptRleEncoder
), when reading the content with toUint8Array()
, the content is different each time due to flush.
Expected behavior
Since toUint8Array()
is obviously a function for reading values, its contents should not change with each call.
To fix
IntDiffOptRleEncoder
should have a flag like mutated. In that case, the implementation would be as follows
export class IntDiffOptRleEncoder {
constructor () {
this.encoder = new Encoder()
/**
* @type {number}
*/
this.s = 0
this.count = 0
this.diff = 0
this.mutated = false
}
/**
* @param {number} v
*/
write (v) {
this.mutated = true
if (this.diff === v - this.s) {
this.s = v
this.count++
} else {
flushIntDiffOptRleEncoder(this)
this.count = 1
this.diff = v - this.s
this.s = v
}
}
toUint8Array () {
if (this.mutated) {
flushIntDiffOptRleEncoder(this)
this.mutated = false
}
return toUint8Array(this.encoder)
}
}
Appendices
In yjs, there is no part of IntDiffOptRleEncoder
that calls toUint8Array()
twice.
I also confirmed that IntDiffOptRleEncoder
with this modification passes all tests in yjs.
(I am personally working on yjs for Swift yswift. I discovered this in debugging).
Describe the bug
The following code loops forever due to r
being undefined inside readVarUint()
.
import { createDecoder, readVarUint } from 'lib0/decoding';
// Create a Blob (not an actual Blob, since they aren't a thing in Node, but
// let's pretend we have one like you get in the Browser)
const blob = { size: 20, type: '' };
const decoder = createDecoder(blob);
readVarUint(decoder);
Expected behavior
createDecoder() should throw if passed an unexpected value (such as a Blob)
... or something, anything, other than locking up the CPU/browser/system for all eternity. :-)
Describe the bug
A clear and concise description of what the bug is.
To Reproduce
Steps to reproduce the behavior:
Expected behavior
A clear and concise description of what you expected to happen.
Screenshots
If applicable, add screenshots to help explain your problem. Tip: you can drag-drop images into this textarea.
Additional context
Add any other context about the problem here.
Is your feature request related to a problem? Please describe.
When using an isometric library I prefer them to use functionality from the platform where possible. This uses fromCharCode to convert from binary to base64 when FileReader.readAsDataURL() ought to work.
Describe the solution you'd like
Wrapping FileReader.readAsDataURL would be preferable, because instead of looping through each byte in JS, a native method does the whole thing.
https://developer.mozilla.org/en-US/docs/Web/API/FileReader/readAsDataURL
Describe alternatives you've considered
I considered using platform functionality everywhere if it would work, however, FileReader.readAsDataURL is not available on Node. Uint8Array is on Node. So they still need separate ways to work.
Additional context
buffer.toBase64
is used in y-webrtc I was thinking of using it for saving Y Docs to localStorage but may end up using IndexedDB. My code already uses localStorage and IndexedDB isn't supported on Firefox Private Browsing sessions so that's why I may keep using localStorage for the time being.
Describe the bug
When running tests using jest and jest-environment-jsdom, version 0.2.86 of this package causes a failure:
FAIL ./test.js
โ Test suite failed to run
Jest encountered an unexpected token
Jest failed to parse a file. This happens e.g. when your code or its dependencies use non-standard JavaScript syntax, or when Jest is not configured to support such syntax.
Out of the box Jest supports Babel, which will be used to transform your files into valid JS based on your Babel configuration.
By default "node_modules" folder is ignored by transformers.
Here's what you can do:
โข If you are trying to use ECMAScript Modules, see https://jestjs.io/docs/ecmascript-modules for how to enable it.
โข If you are trying to use TypeScript, see https://jestjs.io/docs/getting-started#using-typescript
โข To have some of your "node_modules" files transformed, you can specify a custom "transformIgnorePatterns" in your config.
โข If you need a custom transformation specify a "transform" option in your config.
โข If you simply want to mock your non-JS modules (e.g. binary assets) you can stub them out with the "moduleNameMapper" config option.
You'll find more details and examples of these config options in the docs:
https://jestjs.io/docs/configuration
For information about custom transformations, see:
https://jestjs.io/docs/code-transformation
Details:
/tmp/test/node_modules/lib0/webcrypto.js:3
export const subtle = crypto.subtle
^^^^^^
SyntaxError: Unexpected token 'export'
3 | */
4 |
> 5 | const random = require( 'lib0/random' );
| ^
6 |
7 | test( 'it works', () => {
8 | const element = document.createElement('div');
at Runtime.createScriptFromCode (node_modules/jest-runtime/build/index.js:1505:14)
at Object.<anonymous> (node_modules/lib0/dist/random.cjs:7:17)
at Object.require (test.js:5:16)
Test Suites: 1 failed, 1 total
Tests: 0 total
Snapshots: 0 total
Time: 0.325 s
It worked with 0.2.85.
To Reproduce
Steps to reproduce the behavior:
npm add jest jest-environment-jsdom lib0
test.js
:
/**
* @jest-environment jsdom
*/
const random = require( 'lib0/random' );
test( 'it works', () => {
const element = document.createElement('div');
expect( element ).not.toBeNull();
} );
npm exec jest test.js
Expected behavior
Test passes, along the lines of
PASS ./test.js
โ it works (2 ms)
Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: 0.379 s
Environment Information
Additional context
The cause is 4b4faaa. With jest-environment-jsdom the conditions available are "browser", "require" (not "import"), and "default", but that commit assumes "browser" always comes with "import".
A detailed analysis of a similar problem in another package, along with potential workarounds, may be found at microsoft/accessibility-insights-web#5421 (comment).
Checklist
Is your feature request related to a problem? Please describe.
When calling idb
functions, it is possible that the page is forced to refresh in rtop
when onblocked
triggers:
Lines 19 to 28 in 8af099f
Perhaps there is something causing the db to be blocked in my specific case that I can investigate. Currently it is preventing me from calling clearData
in y-indexeddb
.
However, I'm concerned with the low-level behavior here. The risk of a forced page refresh in a production app is pretty bad. I can't think of a case where this would be a positive user experience.
Describe the solution you'd like
The app should be able to handle the blocked event with its own logic, at least by opting in, if not by default. This would allow one to ignore the blocked idb request, retry the request, show a message to the user, etc.
I would recommend rejecting with a custom Error
type that can be caught and detected higher up.
Describe alternatives you've considered
location.reload
cannot be monkey patched, so there is very little that can be down currently to stop it.
I'm happy to help with a PR if this is a valid request.
Describe the bug
When we attempt to call map.setIfUndefined(A, 'key', () => new B)
where class B extends the class used in Map A, we get the following:
Argument of type 'Map<string, A>' is not assignable to parameter of type 'Map<string, B>'.
Type 'A' is missing the following properties from type 'B': ... ts(2345)
This seems to be related to its definition:
* @function
* @template V,K
* @template {Map<K,V>} MAP
* @param {MAP} map
* @param {K} key
* @param {function():V} createT
* @return {V}
We have worked around the issue by copying the logic inline instead of using map.setifUndefined
, but it would be great to be able to use it with inherited classes.
To Reproduce
Steps to reproduce the behavior:
Use the following JS, and attempt to generate types with tsc
:
import * as map from 'lib0/map'
class A {
constructor() {
this.property1 = 1
}
}
class B extends A {
constructor() {
super()
this.property2 = 2
}
}
/**
* @type {Map<string, A>}
*/
const set = new Map()
const item = map.setIfUndefined(set, 'key', () => new B)
Expected behavior
We can call map.setIfUndefined(A, 'key', () => new B)
where class B extends the class used in Map A, and the function adds a new instance of B to the map without errors.
Screenshots
If applicable, add screenshots to help explain your problem. Tip: you can drag-drop images into this textarea.
Environment Information
Additional context
Add any other context about the problem here.
Hi,
I thought I'd just raise an issue for this as I was unsure of a good workaround.
I ran into an issue when using Yjs with Angular. Namely, since it is still run under a node environment, the lib0 library attempts to use node's crypto instead of browser crypto. (see this line
Line 11 in 17d4bee
However, Angular did not like this since it doesn't want to expose core node modules in this way to the frontend (understandable) - it would give an error saying it could not resolve requiring crypto.
My workaround, in this case, was just to remove this line altogether and modify the rest of the file such that it only uses browser crypto.
I just thought I'd make you, and anyone else that got as far as figuring this out, aware of the issue.
Maybe perhaps there is a better way of determining the environment?
Describe the bug
I was running yjs code through rollup and got the following error:
(!) Circular dependencies
node_modules/lib0/encoding.js -> node_modules/lib0/buffer.js -> node_modules/lib0/encoding.js
node_modules/lib0/buffer.js -> node_modules/lib0/decoding.js -> node_modules/lib0/buffer.js
Not sure of the best way to go about fixing these since I'm not familiar with the codebase, but thought I'd make you aware of it if you weren't already. :)
Describe the bug
ObservableV2
does not accept A
as a generic parameter if A
is not a @typedef
.
Related to:
To Reproduce
import { ObservableV2 } from 'lib0/observable';
class A {
/** @type {() => void} */ a;
}
/** @type {ObservableV2<A>} */
const what = /** @type {any} */ ({});
See this TypeScript playground link.
(Note that the implementation of lib0/observable
has been copied into the link - the TS playground seems to have problems importing its type definitons from npm)
Expected behavior
No type errors
See this TypeScript playground link for a demo of a potential solution.
Screenshots
N/A
Environment Information
Additional context
this is a potential solution:
/**
* @template {{[key in keyof EVENTS]: function(...any):void}} EVENTS
*/
it is implemented in the link in the "expected behavior" section above
it isn't valid JSDoc syntax though, so it may not be an option if you're planning on generating docs from the source.
I'm getting the following type error when compiling a project that depends on lib0
:
node_modules/lib0/tree.d.ts(54,22): error TS2315: Type 'N' is not generic.
This line seems to cause the error:
Line 297 in 73006db
The N
class does not have a @template
line in its doc comment.
(Also, thanks for the fantastic work you've done on Yjs and all of the supporting libraries.)
Follow-up on yjs/yjs#511, this issue tracker is probably a better place for it.
I'm not sure if this is a parcel bug or a problem with this library, but after release 0.2.70 projects that are using parcel 2 don't build anymore. I created a minimal example, just import
ing yjs, and it fails right away on building.
The repository is https://github.com/JanMisker/yjs-test
Please advise whether this should be resolved in Parcel or within this library...
I am interested in exploring the use yjs in react-native and expo, using valitio-yjs and y-websocket. I've started by porting the valtio-yjs-demo to react-native. Here is a an expo snack for the purpose of developing and testing the implementation.
Unfortunately, there are some issues with importing yjs in react-native, specifically related to lib0 as dependency.
The snack fails to resolve yjs as a dependency due to lib0:
Failed to resolve dependency 'yjs@^13.5.24' (export 'Observable' (imported as 'Observable') was not found in 'lib0/observable' (module has no exports)
If you download the example and run it locally, the metro.config.js file, when configured to resolve .mjs and .cjs files, successfully imports and runs in the web browser. But runs into some errors when trying to run it in the iOS simulator:
While trying to resolve module `isomorphic.js` from file `~/valtio-yjs-expo/node_modules/lib0/dist/random.cjs`, the package `~/valtio-yjs-expo/node_modules/isomorphic.js/package.json` was successfully found. However, this package itself specifies a `main` module field that could not be resolved (`~/valtio-yjs-expo/node_modules/isomorphic.js/browser.mjs`. Indeed, none of these files exist:
This issue is also referenced upstream at dai-shi/valtio-yjs/issues/20 and yjs/yjs/issues/381.
Steps to reproduce the issue:
yarn
yarn web
- successyarn ios
- failExpected behavior
A clear and concise description of what you expected to happen.
Environment Information
"yjs": "^13.5.24",
"lib0": "^0.2.43",
"valtio": "^1.2.9",
"valtio-yjs": "^0.3.0",
"y-websocket": "^1.3.18"
Describe the bug
I am unable to import and use the generated types because this is an es module, so I can import the cjs files fine from dist
but then I don't get the types. Is there a way to use the typescript d.ts
files at all?
To Reproduce
import { createEncoder } from 'lib0/encoding';
const encoder = createEncoder();
console.log(encoder);
Save as index.ts.
tsc index.ts
node dist/index.ts
internal/modules/cjs/loader.js:1092
throw new ERR_REQUIRE_ESM(filename, parentPath, packageJsonPath);
^
Error [ERR_REQUIRE_ESM]: Must use import to load ES Module: /Users/robindiddams/work/lib0test/node_modules/lib0/encoding.js
require() of ES modules is not supported.
according to this post on discuss.yjs.dev im supposed to do it like this:
const { createEncoder } = require('lib0/dist/encoding.cjs');
but then I lose my type definitions ๐ข .
Expected behavior
I expect to be able to use the types declarations in a typescript nodejs app.
Screenshots
I've made a repo with the code if you want to look more https://github.com/Robindiddams/lib0test
Environment Information
v14.9.0
4.1.3
Additional context
Using in a nodejs server, so not running in the background
Trying to compile lib0 with a recent typescript (4.63), I get:
iterator.js(15,29): error TS8024: JSDoc '@param' tag has name 'f', but there is no parameter with that name.
Describe the bug
When running tests for Yjs with react-scripts test
, import of lib0/webcrypto
inside lib0/dist/random.cjs
causes test failure with "SyntaxError: Unexpected token 'export'".
FAIL src/yjs.test.js
โ Test suite failed to run
Jest encountered an unexpected token
Jest failed to parse a file. This happens e.g. when your code or its dependencies use non-standard JavaScript syntax, or when Jest is not configured to support such syntax.
Out of the box Jest supports Babel, which will be used to transform your files into valid JS based on your Babel configuration.
By default "node_modules" folder is ignored by transformers.
Here's what you can do:
โข If you are trying to use ECMAScript Modules, see https://jestjs.io/docs/ecmascript-modules for how to enable it.
โข If you are trying to use TypeScript, see https://jestjs.io/docs/getting-started#using-typescript
โข To have some of your "node_modules" files transformed, you can specify a custom "transformIgnorePatterns" in your config.
โข If you need a custom transformation specify a "transform" option in your config.
โข If you simply want to mock your non-JS modules (e.g. binary assets) you can stub them out with the "moduleNameMapper" config option.
You'll find more details and examples of these config options in the docs:
https://jestjs.io/docs/configuration
For information about custom transformations, see:
https://jestjs.io/docs/code-transformation
Details:
/workspaces/lib0-webcrypto-jest-fail/node_modules/lib0/webcrypto.js:3
export const subtle = crypto.subtle
^^^^^^
SyntaxError: Unexpected token 'export'
> 1 | const yjs = require('yjs');
| ^
2 |
3 | describe('yjs', () => {
4 | it('fails', () => {
at Runtime.createScriptFromCode (node_modules/jest-runtime/build/index.js:1728:14)
at Object.<anonymous> (src/yjs.test.js:1:13)
Test Suites: 1 failed, 1 passed, 2 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: 1.395 s
To Reproduce
Steps to reproduce the behavior:
npx create-react-app example-app
npm add [email protected]
src/yjs.test.js
with the content:const yjs = require('yjs');
describe('yjs', () => {
it('fails', () => {
expect(yjs).toBeDefined();
});
});
npm run test -- --watchAll=false
Expected behavior
The test should not fail.
Environment Information
[email protected]
, [email protected]
Additional context
I created public repository for reproducing the issue in https://github.com/krotovic/lib0-webcrypto-jest-fail
typescript uses nodejs types when calling setTimes() => NodeJS.Timeout
. Sadly, the default setTimeout
function is not isomorphic as it depends on node types that are not available in some environments.
Is your feature request related to a problem? Please describe.
I see in random.d.ts
that uuidv4
has type any
, but should it not be string
?
I'm seeing channel.bc.close is not a function
when attempting to disconnect a broadcast channel. This is showing up on my CI server when attempting to upgrade lib0 beyond 0.2.58. I believe this was introduced in this commit which added a call to channel.bc.close
.
I assume my CI server is using LocalStoragePolyfill
which doesn't respond to close
. Should that method be added?
I can provide further details on this if needed.
I found that the statement data instanceof Array
in encoding.js is incorrect when checking arrays across iframe, which expected to be true.
Maybe Array.isArray
is preferred?
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/isArray#instanceof_vs_isarray
โข requestAnimationFrame
โข setTimeout
โข setIterval
โข event queue
Reproduction steps:
websocket.send(new Uint8Array([0, 1, 2, 3]).buffer)
Cause:
Lines 128 to 132 in 1c3bc44
it would also be nice to be able to disable ping
/pong
(since ping and pong frames are already built into the protocol)
Hi! ๐
Firstly, thanks for your work on this project! ๐
Today I used patch-package to patch [email protected]
for the project I'm working on.
After I updated to node@18 and jest@28 I found out jest reports some of my tests leak.
Jest has detected the following 1 open handle potentially keeping Jest from exiting:
โ MESSAGEPORT
at node_modules/lib0/broadcastchannel.js:66:16
at Object.setIfUndefined (node_modules/lib0/map.js:49:24)
at map.setIfUndefined (node_modules/lib0/broadcastchannel.js:64:3)
at Object.subscribe (node_modules/lib0/broadcastchannel.js:83:39)
at WebsocketProvider.bc.subscribe [as connectBc] (node_modules/y-websocket/src/y-websocket.js:345:7)
at WebsocketProvider.connect (node_modules/y-websocket/src/y-websocket.js:394:12)
at new WebsocketProvider (node_modules/y-websocket/src/y-websocket.js:305:12)
I found out that broadcastchannel module keeps BroadcastChannel alive for every room even with zero subscribers.
Here is the diff that solved my problem:
diff --git a/node_modules/lib0/dist/broadcastchannel-7655b66f.cjs b/node_modules/lib0/dist/broadcastchannel-7655b66f.cjs
index 12a6f51..fc82374 100644
--- a/node_modules/lib0/dist/broadcastchannel-7655b66f.cjs
+++ b/node_modules/lib0/dist/broadcastchannel-7655b66f.cjs
@@ -74,7 +74,17 @@ const subscribe = (room, f) => getChannel(room).subs.add(f);
* @param {string} room
* @param {function(any, any):any} f
*/
-const unsubscribe = (room, f) => getChannel(room).subs.delete(f);
+const unsubscribe = (room, f) => {
+ const channel = getChannel(room);
+ const unsubscribed = channel.subs.delete(f);
+ if (unsubscribed) {
+ if (channel.subs.size === 0) {
+ channel.bc.close();
+ channels.delete(room);
+ }
+ }
+ return unsubscribed;
+}
/**
* Publish data to all subscribers (including subscribers on this tab)
This issue body was partially generated by patch-package.
Hi there!
I am starting to use yjs, and ran into an issue with this library not being correctly used/transpiled by the bundling I'm using. The app is a next.js application, which uses webpack etc to bundle everything. I am trying to run the yjs function applyUpdate
, which seems to have a dep somewhere on the binary lib in lib0.
This is the error I get:
TypeError: contentRefs[(info & lib0_binary_js__WEBPACK_IMPORTED_MODULE_17__.BITS5)] is not a function
Also when I have tried to import other libraries from lib0, I get similar errors.
Thanks so much!
Describe the bug
Remix recently moved their development libs to depend on @jspm/core. Unfortunately this package will polyfill window.process
to make it look the like node, so that the following line returns true in the browser:
Lines 15 to 16 in bd69ab4
I realise this is not strictly a bug in lib0, but maybe the isNode
detection could be tweaked to work in browser environments patched with @jspm/core?
To Reproduce
Load y-js into any project with running via @remix-run/[email protected]
and the browser logic thinks it's running in node.
Expected behavior
Be able to detect the browser environment despite process
being patched by @jspm/core.
Environment Information
I'm running yjs
(13.2.0) in es-dev-server
(1.54.1).
I get this error in the Chrome console (85.0.4167.0):
Uncaught SyntaxError: The requested module '../isomorphic.js/iso-browser.js' does not provide an export named 'default'
The error is triggered by this import
Line 8 in 9e527d9
dmonad/isomorphic.js@0bee192 seems to have indeed removed the default export.
Not importing the default export solves the error:
import * as iso from 'isomorphic.js'
There is currently a use of the unload
event in indexeddb:
Line 52 in 2625702
This event handler is being deprecated by Chrome. Its use is also warned against on MDN as it is unreliable and it disables bfcache.
See Chrome's suggested alternatives, including the pagehide
event.
I ported some parts of lib0 to my open source lib zeed, because I needed some special changes for my usecase. The code is here: https://github.com/holtwick/zeed/tree/master/src/common/bin
While doing this, I noticed that there are some parts in the code, that will not be tree-shaken. Mainly global variables. Since the package.json states, that sideEffects: false
I thought this might be of interest.
I collected some learning during the process, which might help: https://github.com/holtwick/zeed/tree/master/demos/sideeffects#readme
Anyway, the binary encoder you wrote is just great! ๐
Describe the bug
When I am running on node 16.14.2 on Ubuntu I am getting this error:
/var/www/ps-article-storage/dev/.pm2/logs/ps-article-storage-error.log last 15 lines:
0|ps-artic | at Object. (/var/www/storage/dev/public_html/node_modules/lib0/dist/webcrypto.node.cjs:5:19)
0|ps-artic | at Module._compile (internal/modules/cjs/loader.js:1063:30)
0|ps-artic | at Object.Module._extensions..js (internal/modules/cjs/loader.js:1092:10)
0|ps-artic | at Module.load (internal/modules/cjs/loader.js:928:32)
0|ps-artic | at Function.Module._load (internal/modules/cjs/loader.js:769:14)
0|ps-artic | at Module.require (internal/modules/cjs/loader.js:952:19) {
0|ps-artic | code: 'MODULE_NOT_FOUND',
0|ps-artic | requireStack: [
0|ps-artic | '/var/www/storage/dev/public_html/node_modules/lib0/dist/webcrypto.node.cjs',
0|ps-artic | '/var/www/storage/dev/public_html/node_modules/lib0/dist/random.cjs',
0|ps-artic | '/var/www/storage/dev/public_html/node_modules/yjs/dist/yjs.cjs',
0|ps-artic | '/var/www/storage/dev/public_html/utils.js',
0|ps-artic | '/var/www/storage/dev/public_html/server.js'
0|ps-artic | ]
0|ps-artic | }
On Mac same node version this issue is not reproduced.
To Reproduce
using server from y-websocket/bin/utils:
node server
Expected behavior
should start the server
Is your feature request related to a problem? Please describe.
Install size for lib0 seems to be around 2.2MB. What causes the bloat is inclusion of the compiled test suite:
Describe the solution you'd like
These files could be added to .npmignore or other means of excluding them.
Describe the bug
The url
module is not exported from the index.js
file. Perhaps it is intentional?
Describe the bug
There is a circular dependency between encoding.js and buffer.js. Not sure why this is necessary as encodeAny
in buffer.js is the cause of this and it can easily be moved to buffer.js. That said, depending on if anyone is using this it might be a breaking change unfortunately, requiring a major release.
This isn't a big deal but does cause issues in some workflows (ie rollup).
Describe the bug
The jwt logic assumes exp
is in ms timestamp format (time.getUnixTime is just Date.now), but the JWT RFC (https://www.rfc-editor.org/rfc/rfc7519#section-4.1.4) states it should be seconds since epoch, not ms. This means that if something is using lib0 to validate a JWT token, but that JWT token was generated to the RFC, the expiration check will fail.
To Reproduce
Steps to reproduce the behavior:
Expected behavior
Expect epoch seconds for exp
claims.
Possibly add logic to support both since the bug was out there.
Relevant code:
Line 50 in e8bb155
Describe the bug
The ObservableV2
class allows the specification of a type which defines the set of events and callbacks, but the template is overly permissive. Namely, the EVENT
parameter can constrain the callbacks such that every callback must return a value. This possibility makes it very difficult to write well-typed abstractions over ObservableV2
(they must handle the case where EVENTS
has been instantiated this way).
To Reproduce
Here's a small example of this in typescript:
function foo() {
let x = new ObservableV2<{"hi": () => number}>();
x.on('hi', () => {}); // ERROR HERE
}
Which results in the error:
Argument of type '() => void' is not assignable to parameter of type '() => number'.
Type 'void' is not assignable to type 'number'.ts(2345)
Expected behavior
ObservableV2
should always allow callbacks that return void
.
Additional context
I ran into this problem while trying to write a utility function called waitUntil
that runs a test on all emitted events and resolves a promise when it successfully passes the test. The untyped form is basically:
const waitUntil = (observable, event, test) => Promise.new(resolve => {
function cb(..args) {
if (test(...args)) {
observable.off(event, cb);
resolve(args);
}
}
observable.on(event, cb);
});
This lets me write nice little functions like:
const waitUntilConnected = (client) =>
waitUntil(client, "update", status => (status === "connected"));
Unfortunately it's impossible (or at least beyond me) to make the function cb
inside waitUntil
typecheck because the observable could require that callbacks for this event return a value.
Currently, decoding 53bit integers fail because the binary operations don't work above the 32bit range. See y-crdt/ypy#30
Describe the bug
lib0/webcrypto
has been broken for browser contexts since [email protected]
due to remapping exports (2617ed3).
To Reproduce
# cargo install deno
git clone https://github.com/spence/lib0-webcrypto.git
cd lib0-webcrypto
deno task start
# open http://localhost:8080 and show console
Expected Behavior
Via pinning lib0/[email protected]
:
Actual Behavior
Environment Information
Additional context
You can see the published source of each version via source maps.
0.2.72
(works)
curl -sS https://esm.sh/v132/[email protected]/es2022/webcrypto.js.map | jq
{
"mappings": ";AAEO,IAAMA,EAAS,OAAO,OAChBC,EAAkB,OAAO,gBAAgB,KAAK,MAAM",
"names": [
"subtle",
"getRandomValues"
],
"sourceRoot": "/",
"sources": [
"../esmd/npm/[email protected]/node_modules/.pnpm/[email protected]/node_modules/lib0/webcrypto.browser.js"
],
"sourcesContent": [
"/* eslint-env browser */\n\nexport const subtle = crypto.subtle\nexport const getRandomValues = crypto.getRandomValues.bind(crypto)\n"
],
"version": 3
}
0.2.73
(broken)
curl -sS https://esm.sh/v132/[email protected]/es2022/webcrypto.js.map | jq
{
"mappings": ";AACA,OAAS,aAAAA,MAAiB,8DAEnB,IAAMC,EAA6BD,EAAW,OACxCE,EAAsCF,EAAW,gBAAgB,KAAKA,CAAS",
"names": [
"webcrypto",
"subtle",
"getRandomValues"
],
"sourceRoot": "/",
"sources": [
"../esmd/npm/[email protected]/node_modules/.pnpm/[email protected]/node_modules/lib0/webcrypto.node.js"
],
"sourcesContent": [
"\nimport { webcrypto } from 'node:crypto'\n\nexport const subtle = /** @type {any} */ (webcrypto).subtle\nexport const getRandomValues = /** @type {any} */ (webcrypto).getRandomValues.bind(webcrypto)\n"
],
"version": 3
}
Related:
Line 55 in 3fd7d6a
lib0 seems to require node >= 13:
npm WARN notsup Unsupported engine for [email protected]: wanted: {"node":">=13"} (current: {"node":"12.14.1","npm":"6.13.4"})
While node 12 is the current stable version I think you might want to consider changing to node >= 12 if it does not have any side effects.
Circular module dependencies are present in:
Version:
Note: this was reported while using solid-start
build tool:
Circular dependency: node_modules/.pnpm/[email protected]/node_modules/lib0/encoding.js -> node_modules/.pnpm/[email protected]/node_modules/lib0/buffer.js -> node_modules/.pnpm/[email protected]/node_modules/lib0/encoding.js
Circular dependency: node_modules/.pnpm/[email protected]/node_modules/lib0/buffer.js -> node_modules/.pnpm/[email protected]/node_modules/lib0/decoding.js -> node_modules/.pnpm/[email protected]/node_modules/lib0/buffer.js
Describe the bug
TextEncoder.encodeInto
usage is not always supported, which causes errors when calling writeVarString
:
.utf8TextEncoder.encodeInto is not a function.
More info:
y-protocols
API encodeAwarenessUpdate
on iOS โค 14.4.v0.2.52
by commit 672bcde
.TextEncoder.encodeInto
browser support: https://caniuse.com/mdn-api_textencoder_encodeintoIs your feature request related to a problem? Please describe.
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
NO_COLOR is de-facto standard and it frustrates me when some libs, tools wahtever don't support it
Describe the solution you'd like
A clear and concise description of what you want to happen.
honor NO_COLOR=true
Describe alternatives you've considered
A clear and concise description of any alternative solutions or features you've considered.
none
see also https://no-color.org/
I couldn't reopen the other issue, so I created a new one.
I stumbled upon this issue, because I had encountered some strange issues using rollup in watch mode. I temporarily fixed the issue and it seems to be the cause. My fix was rather simple, I simply inlined all the occurences of "createUint8ArrayViewFromArrayBuffer()" to "new Uint8Array()" and dropped the buffer.js import from encoding.js and decoding.js.
Could you please fix this somehow? It's possible that this is a rollup issue, but it seems to be easily solvable.
Originally posted by @szilu in #19 (comment)
Describe the bug
The jsdoc types added to the is
functions in 0.2.75 export typescript definitions which do not typecheck
To Reproduce
npm run clean && npm run types && npm run lint
yields the following errors
function.d.ts:12:62 - error TS2344: Type 'TYPE' does not satisfy the constraint 'abstract new (...args: any) => any'.
12 export function is<TYPE>(n: any, T: TYPE): n is InstanceType<TYPE>;
~~~~
function.d.ts:12:20
12 export function is<TYPE>(n: any, T: TYPE): n is InstanceType<TYPE>;
~~~~
This type parameter might need an `extends abstract new (...args: any) => any` constraint.
function.d.ts:13:74 - error TS2344: Type 'TYPE' does not satisfy the constraint 'abstract new (...args: any) => any'.
13 export function isTemplate<TYPE>(T: TYPE): (n: any) => n is InstanceType<TYPE>;
~~~~
function.d.ts:13:28
13 export function isTemplate<TYPE>(T: TYPE): (n: any) => n is InstanceType<TYPE>;
~~~~
This type parameter might need an `extends abstract new (...args: any) => any` constraint.
isomorphic.d.ts:1:10 - error TS2303: Circular definition of import alias 'performance'.
1 export { performance, cryptoRandomBuffer } from "isomorphic.js";
~~~~~~~~~~~
isomorphic.d.ts:1:23 - error TS2303: Circular definition of import alias 'cryptoRandomBuffer'.
1 export { performance, cryptoRandomBuffer } from "isomorphic.js";
~~~~~~~~~~~~~~~~~~
Expected behavior
Lints pass
Environment Information
Additional Information
you may want to add the linting as a prepublish script
Describe the bug
Short Background: I am evaluating at the moment, wether we should switch to yjs from automerge in our software
Looking at the mutex code
let token = true
return (f, g) => {
if (token) {
token = false
try {
f()
} finally {
token = true
}
} else if (g !== undefined) {
g()
}
}
}```
I am wondering, what that code should accomplish and what it actually does.
The mutex functionality only works, if the mutex is called within the mutex. Something like that:
const mutex = createMutex()
mutex(() => mutex(() => console.log('test')))
Here the mutex prevents the inner code from being executed. But it will not execute the inner function at all and does not inform about it (that is what the `g` function is for i guess, but that is not how I expect a mutex to work and that is also not how it was implemented in yjs). As javascript is single threaded (from a developer point of view) it is not even possible to enter this mutex without nesting a mutex call as shown above.
**Expected behavior**
What i think it should solve: if `f` being an async function, the mutex should not allow other async functions to execute until the running function has ended. See https://github.com/DirtyHairy/async-mutex
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.