cleanup (subfolder removed, npm packages removed, etc.); added y-websocket-server code

This commit is contained in:
User
2026-03-16 02:26:57 +01:00
committed by Jannik Luboeinski
parent 78d5352a48
commit c89c6f95a6
1060 changed files with 610 additions and 101426 deletions

1
.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
node_modules/

View File

@@ -1,7 +1,28 @@
# P2P Poll App
## Setup
mkdir yjs-poll
cd yjs-poll
## Install npm packages
```
npm init -y
npm install y-websocket ws
npm install
```
Note: the frontend obtains the packages `yjs` and `y-websocket` dynamically.
## Run backend
```
node backend.js
```
### Note on Yjs suggestion
Note that the following server setup is suggested in the Yjs docs (https://docs.yjs.dev/ecosystem/connection-provider/y-websocket):
```
npm install y-websocket-server
HOST=localhost PORT=1000 npx y-websocket
```
However, across a range of npm versions, this does not work.
Nevertheless, the essential code from the `y-websocket-server` package is used here as provided in `utils.js`.
## Run frontend
Open "frontend.html" in browser.

View File

@@ -1,28 +1,31 @@
import { WebSocketServer } from 'ws';
// Create a WebSocket server
const WS_PORT = 8080;
const wss = new WebSocketServer({ port: WS_PORT });
console.log('WebSocket server is running on ws://localhost:' + String(WS_PORT));
// Connection event handler
wss.on('connection', (ws) => {
console.log('Client connected');
// Message event handler
ws.on('message', (message) => {
let msg_str = String(message);
console.log("Received: " + msg_str);
// If this is a text or state message (no Yjs logic) - echo the message back to the client
if (msg_str.startsWith("TEXT_MESSAGE") | msg_str.startsWith("STATE_MESSAGE")) {
ws.send(msg_str);
}
});
// Close event handler
ws.on('close', () => {
console.log('Client disconnected');
});
});
import { WebSocketServer } from 'ws';
import { setupWSConnection } from './utils.js'
// Create a WebSocket server
const WS_PORT = 8080;
const wss = new WebSocketServer({ port: WS_PORT });
console.log('WebSocket server is running on ws://localhost:' + String(WS_PORT));
// Connection event handler
wss.on('connection', setupWSConnection);
/*
wss.on('connection', (ws) => {
console.log('Client connected');
// Message event handler
ws.on('message', (message) => {
let msg_str = String(message);
console.log("Received: " + msg_str);
// If this is a text or state message (no Yjs logic) - echo the message back to the client
if (msg_str.startsWith("TEXT_MESSAGE") | msg_str.startsWith("STATE_MESSAGE")) {
ws.send(msg_str);
}
});
// Close event handler
ws.on('close', () => {
console.log('Client disconnected');
});
});*/

View File

@@ -1,191 +1,196 @@
<!DOCTYPE html>
<html>
<head>
<title>Poll Client</title>
<style>
body {
font-family: Arial, sans-serif;
max-width: 600px;
margin: 0 auto;
padding: 20px;
}
#messages {
height: 300px;
border: 1px solid #ccc;
overflow-y: auto;
padding: 10px;
margin-bottom: 10px;
}
.message { margin: 5px 0; }
</style>
</head>
<body>
<h1>Poll Client</h1>
<div id="status">Connecting to server...</div>
<div id="status2">Connecting to server...</div>
<div id="messages"></div>
<div>
<input type="text" id="messageInput" placeholder="Type your message">
<!--button onclick="sendMessage()">Send</button-->
<button id="sendBtn">Send</button>
<input id="optionInput" placeholder="Add option">
<button id="addBtn">Add</button>
<ul id="options"></ul>
</div>
<script type="module">
import * as Y from "https://esm.sh/yjs"
import { WebsocketProvider } from "https://esm.sh/y-websocket"
const WS_PORT = 8080;
const ydoc = new Y.Doc();
const status = document.getElementById('status');
const status2 = document.getElementById('status2');
const messages = document.getElementById('messages');
const messageInput = document.getElementById('messageInput');
// Connect to the backend (WebSocket server) via Yjs WebsocketProvider
const wsp = new WebsocketProvider(
'ws://localhost:' + String(WS_PORT), 'poll-room',
ydoc
)
wsp.on('status', event => {
//console.log("event.status =", event.status)
if (event.status == "connected") {
status.textContent = 'Yjs connected to WebSocket server';
status.style.color = 'green';
}
else {
status.textContent = 'Yjs disonnected from WebSocket server';
status.style.color = 'red';
}
})
wsp.onopen = () => {
console.log('connected to y-websocket server');
};
ydoc.on('update', () => {
console.log('Yjs document updated');
});
wsp.on('sync', isSynced => {
console.log("isSynced =", isSynced)
})
// Connect to the backend (WebSocket server) via common WebSocket (only for informative messages)
const ws = new WebSocket('ws://localhost:' + String(WS_PORT));
ws.onopen = () => {
status2.textContent = 'WebSocket client connected to WebSocket server';
status2.style.color = 'green';
};
ws.onmessage = (event) => {
const message = document.createElement('div');
message.className = 'message';
message.textContent = event.data;
messages.appendChild(message);
messages.scrollTop = messages.scrollHeight;
};
ws.onerror = (error) => {
status2.textContent = 'Error: ' + error.message;
status2.style.color = 'red';
};
ws.onclose = () => {
status2.textContent = 'WebSocket client disconnected from WebSocket server';
status2.style.color = 'red';
};
// Function to send a message
function sendMessage(command, payload) {
let message = "";
if (command === "TEXT_MESSAGE") {
message = command + ":" + messageInput.value.trim();
messageInput.value = "";
}
else if (command.startsWith("STATE_MESSAGE--")) {
message = command + ":" + payload;
}
else {
console.log("Error: unknown command '" + command + "'")
}
if (message) {
ws.send(message);
}
}
// Send message on button click
document.getElementById("sendBtn").onclick = () => {
sendMessage("TEXT_MESSAGE", "");
};
// Send message on Enter key
messageInput.addEventListener('keypress', (e) => {
if (e.key === 'Enter') {
sendMessage("TEXT_MESSAGE", "");
}
});
// Actual poll logic
const optionsMap = ydoc.getMap("options");
const optionsList = document.getElementById("options");
const input = document.getElementById("optionInput");
function render() {
optionsList.innerHTML = ""
optionsMap.forEach((vote, name) => {
// List element for this option
const li = document.createElement("li")
// Label for this option
const label = document.createElement("span")
label.textContent = name + " — " + vote + " "
// "Vote"/"Unvote" button
const voteBtn = document.createElement("button")
if (vote == false) {
voteBtn.textContent = "Vote"
}
else {
voteBtn.textContent = "Unvote"
}
voteBtn.onclick = () => {
vote = !vote;
optionsMap.set(name, vote);
sendMessage("STATE_MESSAGE--" + (vote ? "VOTE" : "UNVOTE"), name);
}
// "Remove" button
const removeBtn = document.createElement("button")
removeBtn.textContent = "Remove"
removeBtn.onclick = () => {
optionsMap.delete(name);
sendMessage("STATE_MESSAGE--REMOVE", name);
}
li.appendChild(label)
li.appendChild(voteBtn)
li.appendChild(removeBtn)
optionsList.appendChild(li)
})
};
document.getElementById("addBtn").onclick = () => {
const name = input.value.trim()
if (!name) return
if (!optionsMap.has(name)) {
optionsMap.set(name, false);
sendMessage("STATE_MESSAGE--ADD_OPTION", name);
}
input.value = ""
};
optionsMap.observe(render);
render();
</script>
</body>
</html>
<!DOCTYPE html>
<html>
<head>
<title>Poll Client</title>
<style>
body {
font-family: Arial, sans-serif;
max-width: 600px;
margin: 0 auto;
padding: 20px;
}
#messages {
height: 300px;
border: 1px solid #ccc;
overflow-y: auto;
padding: 10px;
margin-bottom: 10px;
}
.message { margin: 5px 0; }
</style>
</head>
<body>
<h1>Poll Client</h1>
<div id="status">Connecting to server...</div>
<div id="status2">Connecting to server...</div>
<div id="messages"></div>
<div>
<input type="text" id="messageInput" placeholder="Type your message">
<!--button onclick="sendMessage()">Send</button-->
<button id="sendBtn">Send</button>
<input id="optionInput" placeholder="Add option">
<button id="addBtn">Add</button>
<ul id="options"></ul>
</div>
<script type="module">
import * as Y from "https://esm.sh/yjs"
import { WebsocketProvider } from "https://esm.sh/y-websocket"
const WS_PORT = 8080;
const ydoc = new Y.Doc();
const status = document.getElementById('status');
const status2 = document.getElementById('status2');
const messages = document.getElementById('messages');
const messageInput = document.getElementById('messageInput');
// Connect to the backend (WebSocket server) via Yjs WebsocketProvider
const wsp = new WebsocketProvider(
'ws://localhost:' + String(WS_PORT), 'poll-room',
ydoc
)
wsp.on('status', event => {
//console.log("event.status =", event.status)
if (event.status == "connected") {
status.textContent = 'Yjs connected to WebSocket server';
status.style.color = 'green';
}
else {
status.textContent = 'Yjs disonnected from WebSocket server';
status.style.color = 'red';
}
})
wsp.onopen = () => {
console.log('connected to y-websocket server');
};
ydoc.on('update', () => {
console.log('Yjs document updated locally');
});
wsp.on('sync', isSynced => {
console.log("isSynced =", isSynced)
})
// Connect to the backend (WebSocket server) via common WebSocket (only for informative messages)
const ws = new WebSocket('ws://localhost:' + String(WS_PORT));
ws.onopen = () => {
status2.textContent = 'WebSocket client connected to WebSocket server';
status2.style.color = 'green';
};
ws.onmessage = (event) => {
const message = document.createElement('div');
message.className = 'message';
message.textContent = event.data;
messages.appendChild(message);
messages.scrollTop = messages.scrollHeight;
};
ws.onerror = (error) => {
status2.textContent = 'Error: ' + error.message;
status2.style.color = 'red';
};
ws.onclose = () => {
status2.textContent = 'WebSocket client disconnected from WebSocket server';
status2.style.color = 'red';
};
// Function to send a message
function sendMessage(command, payload) {
let message = "";
if (command === "TEXT_MESSAGE") {
message = command + ":" + messageInput.value.trim();
messageInput.value = "";
}
else if (command.startsWith("STATE_MESSAGE--")) {
message = command + ":" + payload;
}
else {
console.log("Error: unknown command '" + command + "'")
}
if (message) {
/* To make compatible with y-websocket-server API:
const encoder = encoding.createEncoder()
encoding.writeVarUint(encoder, messageTextMessage)
syncProtocol.writeUpdate(encoder, update)
enc_message = encoding.toUint8Array(encoder)*/
ws.send(message);
}
}
// Send message on button click
document.getElementById("sendBtn").onclick = () => {
sendMessage("TEXT_MESSAGE", "");
};
// Send message on Enter key
messageInput.addEventListener('keypress', (e) => {
if (e.key === 'Enter') {
sendMessage("TEXT_MESSAGE", "");
}
});
// Actual poll logic
const optionsMap = ydoc.getMap("options");
const optionsList = document.getElementById("options");
const input = document.getElementById("optionInput");
function render() {
optionsList.innerHTML = ""
optionsMap.forEach((vote, name) => {
// List element for this option
const li = document.createElement("li")
// Label for this option
const label = document.createElement("span")
label.textContent = name + " — " + vote + " "
// "Vote"/"Unvote" button
const voteBtn = document.createElement("button")
if (vote == false) {
voteBtn.textContent = "Vote"
}
else {
voteBtn.textContent = "Unvote"
}
voteBtn.onclick = () => {
vote = !vote;
optionsMap.set(name, vote);
sendMessage("STATE_MESSAGE--" + (vote ? "VOTE" : "UNVOTE"), name);
}
// "Remove" button
const removeBtn = document.createElement("button")
removeBtn.textContent = "Remove"
removeBtn.onclick = () => {
optionsMap.delete(name);
sendMessage("STATE_MESSAGE--REMOVE", name);
}
li.appendChild(label)
li.appendChild(voteBtn)
li.appendChild(removeBtn)
optionsList.appendChild(li)
})
};
document.getElementById("addBtn").onclick = () => {
const name = input.value.trim()
if (!name) return
if (!optionsMap.has(name)) {
optionsMap.set(name, false);
sendMessage("STATE_MESSAGE--ADD_OPTION", name);
}
input.value = ""
};
optionsMap.observe(render);
render();
</script>
</body>
</html>

View File

@@ -9,8 +9,66 @@
"version": "1.0.0",
"license": "ISC",
"dependencies": {
"@y/protocols": "^1.0.6-1",
"lib0": "^0.2.102",
"ws": "^8.19.0",
"y-websocket": "^3.0.0"
"yjs": "^14.0.0-7"
}
},
"node_modules/@y/protocols": {
"version": "1.0.6-rc.1",
"resolved": "https://registry.npmjs.org/@y/protocols/-/protocols-1.0.6-rc.1.tgz",
"integrity": "sha512-e/qs7hXcLk/SeNitxMXv2ymozyWFTULwbJEi7cAf/K/iXw9nGwGXHrR5TNluQ/bMwOX1cwuUT0hjEojkfH0gsA==",
"license": "MIT",
"dependencies": {
"lib0": "^1.0.0-rc.1"
},
"engines": {
"node": ">=16.0.0",
"npm": ">=8.0.0"
},
"funding": {
"type": "GitHub Sponsors ❤",
"url": "https://github.com/sponsors/dmonad"
},
"peerDependencies": {
"@y/y": "*"
}
},
"node_modules/@y/protocols/node_modules/lib0": {
"version": "1.0.0-rc.4",
"resolved": "https://registry.npmjs.org/lib0/-/lib0-1.0.0-rc.4.tgz",
"integrity": "sha512-mESL4089ji2HbS19DwAsYJRrtxZDjzMjEzjNR5kpzFBqlhvV0b7F9+SlA2SHOQU1Puu2A9xejKXtElK77swxLA==",
"license": "MIT",
"bin": {
"0ecdsa-generate-keypair": "src/bin/0ecdsa-generate-keypair.js",
"0gentesthtml": "src/bin/gentesthtml.js",
"0serve": "src/bin/0serve.js"
},
"engines": {
"node": ">=16"
},
"funding": {
"type": "GitHub Sponsors ❤",
"url": "https://github.com/sponsors/dmonad"
}
},
"node_modules/@y/y": {
"version": "14.0.0-16",
"resolved": "https://registry.npmjs.org/@y/y/-/y-14.0.0-16.tgz",
"integrity": "sha512-4zwbLnLannzUiEdJn9r3IS2FCVdHqADZHLqAivzAuKeoCGZ55JUFebp/YUtrYuTE2ZaBgctxpzulqAAHaahtIA==",
"license": "MIT",
"peer": true,
"dependencies": {
"lib0": "^0.2.115-6"
},
"engines": {
"node": ">=16.0.0",
"npm": ">=8.0.0"
},
"funding": {
"type": "GitHub Sponsors ❤",
"url": "https://github.com/sponsors/dmonad"
}
},
"node_modules/isomorphic.js": {
@@ -65,54 +123,13 @@
}
}
},
"node_modules/y-protocols": {
"version": "1.0.7",
"resolved": "https://registry.npmjs.org/y-protocols/-/y-protocols-1.0.7.tgz",
"integrity": "sha512-YSVsLoXxO67J6eE/nV4AtFtT3QEotZf5sK5BHxFBXso7VDUT3Tx07IfA6hsu5Q5OmBdMkQVmFZ9QOA7fikWvnw==",
"license": "MIT",
"dependencies": {
"lib0": "^0.2.85"
},
"engines": {
"node": ">=16.0.0",
"npm": ">=8.0.0"
},
"funding": {
"type": "GitHub Sponsors ❤",
"url": "https://github.com/sponsors/dmonad"
},
"peerDependencies": {
"yjs": "^13.0.0"
}
},
"node_modules/y-websocket": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/y-websocket/-/y-websocket-3.0.0.tgz",
"integrity": "sha512-mUHy7AzkOZ834T/7piqtlA8Yk6AchqKqcrCXjKW8J1w2lPtRDjz8W5/CvXz9higKAHgKRKqpI3T33YkRFLkPtg==",
"dependencies": {
"lib0": "^0.2.102",
"y-protocols": "^1.0.5"
},
"engines": {
"node": ">=16.0.0",
"npm": ">=8.0.0"
},
"funding": {
"type": "GitHub Sponsors ❤",
"url": "https://github.com/sponsors/dmonad"
},
"peerDependencies": {
"yjs": "^13.5.6"
}
},
"node_modules/yjs": {
"version": "13.6.29",
"resolved": "https://registry.npmjs.org/yjs/-/yjs-13.6.29.tgz",
"integrity": "sha512-kHqDPdltoXH+X4w1lVmMtddE3Oeqq48nM40FD5ojTd8xYhQpzIDcfE2keMSU5bAgRPJBe225WTUdyUgj1DtbiQ==",
"version": "14.0.0-16",
"resolved": "https://registry.npmjs.org/yjs/-/yjs-14.0.0-16.tgz",
"integrity": "sha512-n7jMrQz4pgU/NFnf4qY53K2adR/fu6ViQ79qVIw6Og+BtuDs1hx3DjOi3iREVnA6tsxQXXVG3gvG0I2kpmAwoQ==",
"license": "MIT",
"peer": true,
"dependencies": {
"lib0": "^0.2.99"
"lib0": "^0.2.115-6"
},
"engines": {
"node": ">=16.0.0",

View File

@@ -13,6 +13,8 @@
"description": "",
"dependencies": {
"ws": "^8.19.0",
"y-websocket": "^3.0.0"
"@y/protocols": "^1.0.6-1",
"lib0": "^0.2.102",
"yjs": "^14.0.0-7"
}
}

291
utils.js Normal file
View File

@@ -0,0 +1,291 @@
/* Adapted from https://github.com/yjs/y-websocket-server/blob/main/src/server.js, version of 2025-04-02
(author: dmonad/Kevin Jahns, MIT license) */
import * as Y from 'yjs'
import * as syncProtocol from '@y/protocols/sync'
import * as awarenessProtocol from '@y/protocols/awareness'
import * as encoding from 'lib0/encoding'
import * as decoding from 'lib0/decoding'
import * as map from 'lib0/map'
import * as eventloop from 'lib0/eventloop'
/*import { callbackHandler, isCallbackSet } from './callback.js'
const CALLBACK_DEBOUNCE_WAIT = parseInt(process.env.CALLBACK_DEBOUNCE_WAIT || '2000')
const CALLBACK_DEBOUNCE_MAXWAIT = parseInt(process.env.CALLBACK_DEBOUNCE_MAXWAIT || '10000')
const debouncer = eventloop.createDebouncer(CALLBACK_DEBOUNCE_WAIT, CALLBACK_DEBOUNCE_MAXWAIT)*/
const wsReadyStateConnecting = 0
const wsReadyStateOpen = 1
const wsReadyStateClosing = 2 // eslint-disable-line
const wsReadyStateClosed = 3 // eslint-disable-line
// disable gc when using snapshots!
const gcEnabled = process.env.GC !== 'false' && process.env.GC !== '0'
// const persistenceDir = process.env.YPERSISTENCE
/**
* @type {{bindState: function(string,WSSharedDoc):void, writeState:function(string,WSSharedDoc):Promise<any>, provider: any}|null}
*/
let persistence = null
/**
* @param {{bindState: function(string,WSSharedDoc):void,
* writeState:function(string,WSSharedDoc):Promise<any>,provider:any}|null} persistence_
*/
export const setPersistence = persistence_ => {
persistence = persistence_
}
/**
* @return {null|{bindState: function(string,WSSharedDoc):void,
* writeState:function(string,WSSharedDoc):Promise<any>}|null} used persistence layer
*/
export const getPersistence = () => persistence
/**
* @type {Map<string,WSSharedDoc>}
*/
export const docs = new Map()
const messageSync = 0
const messageAwareness = 1
// const messageAuth = 2
//const messageTextMessage = 3
//const messageStateMessage = 4
/**
* @param {Uint8Array} update
* @param {any} _origin
* @param {WSSharedDoc} doc
* @param {any} _tr
*/
const updateHandler = (update, _origin, doc, _tr) => {
const encoder = encoding.createEncoder()
encoding.writeVarUint(encoder, messageSync)
syncProtocol.writeUpdate(encoder, update)
const message = encoding.toUint8Array(encoder)
doc.conns.forEach((_, conn) => send(doc, conn, message))
}
/**
* @type {(ydoc: Y.Doc) => Promise<void>}
*/
let contentInitializor = _ydoc => Promise.resolve()
/**
* This function is called once every time a Yjs document is created. You can
* use it to pull data from an external source or initialize content.
*
* @param {(ydoc: Y.Doc) => Promise<void>} f
*/
export const setContentInitializor = (f) => {
contentInitializor = f
}
export class WSSharedDoc extends Y.Doc {
/**
* @param {string} name
*/
constructor (name) {
super({ gc: gcEnabled })
this.name = name
/**
* Maps from conn to set of controlled user ids. Delete all user ids from awareness when this conn is closed
* @type {Map<Object, Set<number>>}
*/
this.conns = new Map()
/**
* @type {awarenessProtocol.Awareness}
*/
this.awareness = new awarenessProtocol.Awareness(this)
this.awareness.setLocalState(null)
/**
* @param {{ added: Array<number>, updated: Array<number>, removed: Array<number> }} changes
* @param {Object | null} conn Origin is the connection that made the change
*/
const awarenessChangeHandler = ({ added, updated, removed }, conn) => {
const changedClients = added.concat(updated, removed)
if (conn !== null) {
const connControlledIDs = /** @type {Set<number>} */ (this.conns.get(conn))
if (connControlledIDs !== undefined) {
added.forEach(clientID => { connControlledIDs.add(clientID) })
removed.forEach(clientID => { connControlledIDs.delete(clientID) })
}
}
// broadcast awareness update
const encoder = encoding.createEncoder()
encoding.writeVarUint(encoder, messageAwareness)
encoding.writeVarUint8Array(encoder, awarenessProtocol.encodeAwarenessUpdate(this.awareness, changedClients))
const buff = encoding.toUint8Array(encoder)
this.conns.forEach((_, c) => {
send(this, c, buff)
})
}
this.awareness.on('update', awarenessChangeHandler)
this.on('update', /** @type {any} */ (updateHandler))
//if (isCallbackSet) {
// this.on('update', (_update, _origin, doc) => {
// debouncer(() => callbackHandler(/** @type {WSSharedDoc} */ (doc)))
// })
//}
this.whenInitialized = contentInitializor(this)
}
}
/**
* Gets a Y.Doc by name, whether in memory or on disk
*
* @param {string} docname - the name of the Y.Doc to find or create
* @param {boolean} gc - whether to allow gc on the doc (applies only when created)
* @return {WSSharedDoc}
*/
export const getYDoc = (docname, gc = true) => map.setIfUndefined(docs, docname, () => {
const doc = new WSSharedDoc(docname)
doc.gc = gc
if (persistence !== null) {
persistence.bindState(docname, doc)
}
docs.set(docname, doc)
return doc
})
/**
* @param {any} conn
* @param {WSSharedDoc} doc
* @param {Uint8Array} message
*/
const messageListener = (conn, doc, message) => {
try {
const encoder = encoding.createEncoder()
const decoder = decoding.createDecoder(new Uint8Array(message))
const messageType = decoding.readVarUint(decoder)
switch (messageType) {
case messageSync:
encoding.writeVarUint(encoder, messageSync)
syncProtocol.readSyncMessage(decoder, encoder, doc, conn)
// If the `encoder` only contains the type of reply message and no
// message, there is no need to send the message. When `encoder` only
// contains the type of reply, its length is 1.
if (encoding.length(encoder) > 1) {
send(doc, conn, encoding.toUint8Array(encoder))
}
break
case messageAwareness: {
awarenessProtocol.applyAwarenessUpdate(doc.awareness, decoding.readVarUint8Array(decoder), conn)
break
}
// If this is a text or a message (no Yjs logic) - echo the message back to the client
default: {
conn.send(String(message))
console.log(String(message))
break
}
}
} catch (err) {
console.error(err)
// @ts-ignore
doc.emit('error', [err])
}
}
/**
* @param {WSSharedDoc} doc
* @param {any} conn
*/
const closeConn = (doc, conn) => {
if (doc.conns.has(conn)) {
/**
* @type {Set<number>}
*/
// @ts-ignore
const controlledIds = doc.conns.get(conn)
doc.conns.delete(conn)
awarenessProtocol.removeAwarenessStates(doc.awareness, Array.from(controlledIds), null)
if (doc.conns.size === 0 && persistence !== null) {
// if persisted, we store state and destroy ydocument
persistence.writeState(doc.name, doc).then(() => {
doc.destroy()
})
docs.delete(doc.name)
}
}
conn.close()
}
/**
* @param {WSSharedDoc} doc
* @param {import('ws').WebSocket} conn
* @param {Uint8Array} m
*/
const send = (doc, conn, m) => {
if (conn.readyState !== wsReadyStateConnecting && conn.readyState !== wsReadyStateOpen) {
closeConn(doc, conn)
}
try {
conn.send(m, {}, err => { err != null && closeConn(doc, conn) })
} catch (e) {
closeConn(doc, conn)
}
}
const pingTimeout = 30000
/**
* @param {import('ws').WebSocket} conn
* @param {import('http').IncomingMessage} req
* @param {any} opts
*/
export const setupWSConnection = (conn, req, { docName = (req.url || '').slice(1).split('?')[0], gc = true } = {}) => {
conn.binaryType = 'arraybuffer'
// get doc, initialize if it does not exist yet
const doc = getYDoc(docName, gc)
doc.conns.set(conn, new Set())
// listen and reply to events
conn.on('message', /** @param {ArrayBuffer} message */ message => messageListener(conn, doc, message))
// Check if connection is still alive
let pongReceived = true
const pingInterval = setInterval(() => {
if (!pongReceived) {
if (doc.conns.has(conn)) {
closeConn(doc, conn)
}
clearInterval(pingInterval)
} else if (doc.conns.has(conn)) {
pongReceived = false
try {
conn.ping()
} catch (e) {
closeConn(doc, conn)
clearInterval(pingInterval)
}
}
}, pingTimeout)
conn.on('close', () => {
closeConn(doc, conn)
clearInterval(pingInterval)
})
conn.on('pong', () => {
pongReceived = true
})
// put the following in a variables in a block so the interval handlers don't keep in in
// scope
{
// send sync step 1
const encoder = encoding.createEncoder()
encoding.writeVarUint(encoder, messageSync)
syncProtocol.writeSyncStep1(encoder, doc)
send(doc, conn, encoding.toUint8Array(encoder))
const awarenessStates = doc.awareness.getStates()
if (awarenessStates.size > 0) {
const encoder = encoding.createEncoder()
encoding.writeVarUint(encoder, messageAwareness)
encoding.writeVarUint8Array(encoder, awarenessProtocol.encodeAwarenessUpdate(doc.awareness, Array.from(awarenessStates.keys())))
send(doc, conn, encoding.toUint8Array(encoder))
}
}
}

View File

@@ -1,16 +0,0 @@
#!/bin/sh
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
case `uname` in
*CYGWIN*|*MINGW*|*MSYS*)
if command -v cygpath > /dev/null 2>&1; then
basedir=`cygpath -w "$basedir"`
fi
;;
esac
if [ -x "$basedir/node" ]; then
exec "$basedir/node" "$basedir/../lib0/bin/0ecdsa-generate-keypair.js" "$@"
else
exec node "$basedir/../lib0/bin/0ecdsa-generate-keypair.js" "$@"
fi

View File

@@ -1,17 +0,0 @@
@ECHO off
GOTO start
:find_dp0
SET dp0=%~dp0
EXIT /b
:start
SETLOCAL
CALL :find_dp0
IF EXIST "%dp0%\node.exe" (
SET "_prog=%dp0%\node.exe"
) ELSE (
SET "_prog=node"
SET PATHEXT=%PATHEXT:;.JS;=;%
)
endLocal & goto #_undefined_# 2>NUL || title %COMSPEC% & "%_prog%" "%dp0%\..\lib0\bin\0ecdsa-generate-keypair.js" %*

View File

@@ -1,28 +0,0 @@
#!/usr/bin/env pwsh
$basedir=Split-Path $MyInvocation.MyCommand.Definition -Parent
$exe=""
if ($PSVersionTable.PSVersion -lt "6.0" -or $IsWindows) {
# Fix case when both the Windows and Linux builds of Node
# are installed in the same directory
$exe=".exe"
}
$ret=0
if (Test-Path "$basedir/node$exe") {
# Support pipeline input
if ($MyInvocation.ExpectingInput) {
$input | & "$basedir/node$exe" "$basedir/../lib0/bin/0ecdsa-generate-keypair.js" $args
} else {
& "$basedir/node$exe" "$basedir/../lib0/bin/0ecdsa-generate-keypair.js" $args
}
$ret=$LASTEXITCODE
} else {
# Support pipeline input
if ($MyInvocation.ExpectingInput) {
$input | & "node$exe" "$basedir/../lib0/bin/0ecdsa-generate-keypair.js" $args
} else {
& "node$exe" "$basedir/../lib0/bin/0ecdsa-generate-keypair.js" $args
}
$ret=$LASTEXITCODE
}
exit $ret

View File

@@ -1,16 +0,0 @@
#!/bin/sh
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
case `uname` in
*CYGWIN*|*MINGW*|*MSYS*)
if command -v cygpath > /dev/null 2>&1; then
basedir=`cygpath -w "$basedir"`
fi
;;
esac
if [ -x "$basedir/node" ]; then
exec "$basedir/node" "$basedir/../lib0/bin/gentesthtml.js" "$@"
else
exec node "$basedir/../lib0/bin/gentesthtml.js" "$@"
fi

View File

@@ -1,17 +0,0 @@
@ECHO off
GOTO start
:find_dp0
SET dp0=%~dp0
EXIT /b
:start
SETLOCAL
CALL :find_dp0
IF EXIST "%dp0%\node.exe" (
SET "_prog=%dp0%\node.exe"
) ELSE (
SET "_prog=node"
SET PATHEXT=%PATHEXT:;.JS;=;%
)
endLocal & goto #_undefined_# 2>NUL || title %COMSPEC% & "%_prog%" "%dp0%\..\lib0\bin\gentesthtml.js" %*

View File

@@ -1,28 +0,0 @@
#!/usr/bin/env pwsh
$basedir=Split-Path $MyInvocation.MyCommand.Definition -Parent
$exe=""
if ($PSVersionTable.PSVersion -lt "6.0" -or $IsWindows) {
# Fix case when both the Windows and Linux builds of Node
# are installed in the same directory
$exe=".exe"
}
$ret=0
if (Test-Path "$basedir/node$exe") {
# Support pipeline input
if ($MyInvocation.ExpectingInput) {
$input | & "$basedir/node$exe" "$basedir/../lib0/bin/gentesthtml.js" $args
} else {
& "$basedir/node$exe" "$basedir/../lib0/bin/gentesthtml.js" $args
}
$ret=$LASTEXITCODE
} else {
# Support pipeline input
if ($MyInvocation.ExpectingInput) {
$input | & "node$exe" "$basedir/../lib0/bin/gentesthtml.js" $args
} else {
& "node$exe" "$basedir/../lib0/bin/gentesthtml.js" $args
}
$ret=$LASTEXITCODE
}
exit $ret

16
yjs-poll/node_modules/.bin/0serve generated vendored
View File

@@ -1,16 +0,0 @@
#!/bin/sh
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
case `uname` in
*CYGWIN*|*MINGW*|*MSYS*)
if command -v cygpath > /dev/null 2>&1; then
basedir=`cygpath -w "$basedir"`
fi
;;
esac
if [ -x "$basedir/node" ]; then
exec "$basedir/node" "$basedir/../lib0/bin/0serve.js" "$@"
else
exec node "$basedir/../lib0/bin/0serve.js" "$@"
fi

View File

@@ -1,17 +0,0 @@
@ECHO off
GOTO start
:find_dp0
SET dp0=%~dp0
EXIT /b
:start
SETLOCAL
CALL :find_dp0
IF EXIST "%dp0%\node.exe" (
SET "_prog=%dp0%\node.exe"
) ELSE (
SET "_prog=node"
SET PATHEXT=%PATHEXT:;.JS;=;%
)
endLocal & goto #_undefined_# 2>NUL || title %COMSPEC% & "%_prog%" "%dp0%\..\lib0\bin\0serve.js" %*

View File

@@ -1,28 +0,0 @@
#!/usr/bin/env pwsh
$basedir=Split-Path $MyInvocation.MyCommand.Definition -Parent
$exe=""
if ($PSVersionTable.PSVersion -lt "6.0" -or $IsWindows) {
# Fix case when both the Windows and Linux builds of Node
# are installed in the same directory
$exe=".exe"
}
$ret=0
if (Test-Path "$basedir/node$exe") {
# Support pipeline input
if ($MyInvocation.ExpectingInput) {
$input | & "$basedir/node$exe" "$basedir/../lib0/bin/0serve.js" $args
} else {
& "$basedir/node$exe" "$basedir/../lib0/bin/0serve.js" $args
}
$ret=$LASTEXITCODE
} else {
# Support pipeline input
if ($MyInvocation.ExpectingInput) {
$input | & "node$exe" "$basedir/../lib0/bin/0serve.js" $args
} else {
& "node$exe" "$basedir/../lib0/bin/0serve.js" $args
}
$ret=$LASTEXITCODE
}
exit $ret

View File

@@ -1,118 +0,0 @@
{
"name": "yjs-poll",
"version": "1.0.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"node_modules/isomorphic.js": {
"version": "0.2.5",
"resolved": "https://registry.npmjs.org/isomorphic.js/-/isomorphic.js-0.2.5.tgz",
"integrity": "sha512-PIeMbHqMt4DnUP3MA/Flc0HElYjMXArsw1qwJZcm9sqR8mq3l8NYizFMty0pWwE/tzIGH3EKK5+jes5mAr85yw==",
"license": "MIT",
"funding": {
"type": "GitHub Sponsors ❤",
"url": "https://github.com/sponsors/dmonad"
}
},
"node_modules/lib0": {
"version": "0.2.117",
"resolved": "https://registry.npmjs.org/lib0/-/lib0-0.2.117.tgz",
"integrity": "sha512-DeXj9X5xDCjgKLU/7RR+/HQEVzuuEUiwldwOGsHK/sfAfELGWEyTcf0x+uOvCvK3O2zPmZePXWL85vtia6GyZw==",
"license": "MIT",
"dependencies": {
"isomorphic.js": "^0.2.4"
},
"bin": {
"0ecdsa-generate-keypair": "bin/0ecdsa-generate-keypair.js",
"0gentesthtml": "bin/gentesthtml.js",
"0serve": "bin/0serve.js"
},
"engines": {
"node": ">=16"
},
"funding": {
"type": "GitHub Sponsors ❤",
"url": "https://github.com/sponsors/dmonad"
}
},
"node_modules/ws": {
"version": "8.19.0",
"resolved": "https://registry.npmjs.org/ws/-/ws-8.19.0.tgz",
"integrity": "sha512-blAT2mjOEIi0ZzruJfIhb3nps74PRWTCz1IjglWEEpQl5XS/UNama6u2/rjFkDDouqr4L67ry+1aGIALViWjDg==",
"license": "MIT",
"engines": {
"node": ">=10.0.0"
},
"peerDependencies": {
"bufferutil": "^4.0.1",
"utf-8-validate": ">=5.0.2"
},
"peerDependenciesMeta": {
"bufferutil": {
"optional": true
},
"utf-8-validate": {
"optional": true
}
}
},
"node_modules/y-protocols": {
"version": "1.0.7",
"resolved": "https://registry.npmjs.org/y-protocols/-/y-protocols-1.0.7.tgz",
"integrity": "sha512-YSVsLoXxO67J6eE/nV4AtFtT3QEotZf5sK5BHxFBXso7VDUT3Tx07IfA6hsu5Q5OmBdMkQVmFZ9QOA7fikWvnw==",
"license": "MIT",
"dependencies": {
"lib0": "^0.2.85"
},
"engines": {
"node": ">=16.0.0",
"npm": ">=8.0.0"
},
"funding": {
"type": "GitHub Sponsors ❤",
"url": "https://github.com/sponsors/dmonad"
},
"peerDependencies": {
"yjs": "^13.0.0"
}
},
"node_modules/y-websocket": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/y-websocket/-/y-websocket-3.0.0.tgz",
"integrity": "sha512-mUHy7AzkOZ834T/7piqtlA8Yk6AchqKqcrCXjKW8J1w2lPtRDjz8W5/CvXz9higKAHgKRKqpI3T33YkRFLkPtg==",
"dependencies": {
"lib0": "^0.2.102",
"y-protocols": "^1.0.5"
},
"engines": {
"node": ">=16.0.0",
"npm": ">=8.0.0"
},
"funding": {
"type": "GitHub Sponsors ❤",
"url": "https://github.com/sponsors/dmonad"
},
"peerDependencies": {
"yjs": "^13.5.6"
}
},
"node_modules/yjs": {
"version": "13.6.29",
"resolved": "https://registry.npmjs.org/yjs/-/yjs-13.6.29.tgz",
"integrity": "sha512-kHqDPdltoXH+X4w1lVmMtddE3Oeqq48nM40FD5ojTd8xYhQpzIDcfE2keMSU5bAgRPJBe225WTUdyUgj1DtbiQ==",
"license": "MIT",
"peer": true,
"dependencies": {
"lib0": "^0.2.99"
},
"engines": {
"node": ">=16.0.0",
"npm": ">=8.0.0"
},
"funding": {
"type": "GitHub Sponsors ❤",
"url": "https://github.com/sponsors/dmonad"
}
}
}
}

View File

@@ -1,21 +0,0 @@
The MIT License (MIT)
Copyright (c) 2020 Kevin Jahns <kevin.jahns@protonmail.com>.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@@ -1,3 +0,0 @@
# Isomorphic.js
This module provides platform-specific features as a common API. This module is mainly about providing crypto features to node, browser, and non-supported platforms using a polyfill.

View File

@@ -1,28 +0,0 @@
/* eslint-env browser */
const perf = typeof performance === 'undefined' ? null : performance
const isoCrypto = typeof crypto === 'undefined' ? null : crypto
/**
* @type {function(number):ArrayBuffer}
*/
const cryptoRandomBuffer = isoCrypto !== null
? len => {
// browser
const buf = new ArrayBuffer(len)
const arr = new Uint8Array(buf)
isoCrypto.getRandomValues(arr)
return buf
}
: len => {
// polyfill
const buf = new ArrayBuffer(len)
const arr = new Uint8Array(buf)
for (let i = 0; i < len; i++) {
arr[i] = Math.ceil((Math.random() * 0xFFFFFFFF) >>> 0)
}
return buf
}
exports.performance = perf
exports.cryptoRandomBuffer = cryptoRandomBuffer

View File

@@ -1,25 +0,0 @@
/* eslint-env browser */
export const performance = typeof window === 'undefined' ? null : (typeof window.performance !== 'undefined' && window.performance) || null
const isoCrypto = typeof crypto === 'undefined' ? null : crypto
/**
* @type {function(number):ArrayBuffer}
*/
export const cryptoRandomBuffer = isoCrypto !== null
? len => {
// browser
const buf = new ArrayBuffer(len)
const arr = new Uint8Array(buf)
isoCrypto.getRandomValues(arr)
return buf
}
: len => {
// polyfill
const buf = new ArrayBuffer(len)
const arr = new Uint8Array(buf)
for (let i = 0; i < len; i++) {
arr[i] = Math.ceil((Math.random() * 0xFFFFFFFF) >>> 0)
}
return buf
}

View File

@@ -1,18 +0,0 @@
const isNode = typeof process !== 'undefined' && process.release && /node|io\.js/.test(process.release.name)
const isoBrowser = require('./browser.js')
const perf = isNode ? require('perf_hooks').performance : isoBrowser.performance
const nodeCrypto = isNode ? require('crypto') : null
/**
* @type {function(number):ArrayBuffer}
*/
const cryptoRandomBuffer = nodeCrypto
// node
? len => nodeCrypto.randomBytes(len).buffer
: isoBrowser.cryptoRandomBuffer
exports.performance = perf
exports.cryptoRandomBuffer = cryptoRandomBuffer

View File

@@ -1,5 +0,0 @@
import perfHooks from 'perf_hooks'
import crypto from 'crypto'
export const performance = perfHooks.performance
export const cryptoRandomBuffer = len => crypto.randomBytes(len).buffer

View File

@@ -1,66 +0,0 @@
{
"name": "isomorphic.js",
"version": "0.2.5",
"description": "Isomorphic JavaScript helper functions (performance, crpyto, ..)",
"sideEffects": false,
"main": "./iso.js",
"browser": "./browser.mjs",
"unpkg": "./browser.mjs",
"module": "./browser.mjs",
"exports": {
".": {
"node": {
"import": "./node.mjs",
"require": "./iso.js"
},
"browser": {
"import": "./browser.mjs",
"require": "./browser.js"
},
"default": {
"import": "./browser.mjs",
"require": "./iso.js"
}
},
"./package.json": "./package.json"
},
"dependencies": {},
"funding": {
"type": "GitHub Sponsors ❤",
"url": "https://github.com/sponsors/dmonad"
},
"devDependencies": {
"@types/node": "^13.13.9",
"standard": "^14.3.4",
"typescript": "^3.9.3"
},
"scripts": {
"test": "npm run lint",
"lint": "standard && tsc",
"preversion": "npm run test"
},
"files": [
"browser.js",
"browser.mjs",
"iso.js",
"node.js",
"node.mjs"
],
"repository": {
"type": "git",
"url": "git+https://github.com/dmonad/isomorphic.js.git"
},
"author": "Kevin Jahns <kevin.jahns@protonmail.com>",
"license": "MIT",
"bugs": {
"url": "https://github.com/dmonad/isomorphic.js/issues"
},
"homepage": "https://github.com/dmonad/isomorphic.js#readme",
"standard": {
"ignore": [
"/dist",
"/node_modules",
"/docs"
]
}
}

View File

@@ -1,24 +0,0 @@
# This workflow will do a clean install of node dependencies, build the source code and run tests across different versions of node
# For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions
name: Testing Lib0
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [16.x, 18.x]
steps:
- uses: actions/checkout@v3
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v3
with:
node-version: ${{ matrix.node-version }}
- run: npm ci
- run: npm test

View File

@@ -1,18 +0,0 @@
{
"plugins": [
"plugins/markdown",
"jsdoc-plugin-typescript"
],
"recurseDepth": 10,
"source": {
"excludePattern": "/\\.test\\.js/"
},
"sourceType": "module",
"tags": {
"allowUnknownTags": true,
"dictionaries": ["jsdoc", "closure"]
},
"typescript": {
"moduleRoot": "./"
}
}

View File

@@ -1,17 +0,0 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"type": "node",
"request": "launch",
"name": "Gen Docs",
"program": "${workspaceFolder}/bin/gendocs.js",
"skipFiles": [
"<node_internals>/**"
],
}
]
}

21
yjs-poll/node_modules/lib0/LICENSE generated vendored
View File

@@ -1,21 +0,0 @@
The MIT License (MIT)
Copyright (c) 2019 Kevin Jahns <kevin.jahns@protonmail.com>.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

1414
yjs-poll/node_modules/lib0/README.md generated vendored

File diff suppressed because it is too large Load Diff

View File

@@ -1,30 +0,0 @@
export function last<L>(arr: ArrayLike<L>): L;
export function create<C>(): Array<C>;
export function copy<D>(a: Array<D>): Array<D>;
export function appendTo<M>(dest: Array<M>, src: Array<M>): void;
/**
* Transforms something array-like to an actual Array.
*
* @function
* @template T
* @param {ArrayLike<T>|Iterable<T>} arraylike
* @return {T}
*/
export const from: {
<T_1>(arrayLike: ArrayLike<T_1>): T_1[];
<T_1, U>(arrayLike: ArrayLike<T_1>, mapfn: (v: T_1, k: number) => U, thisArg?: any): U[];
<T_1>(iterable: Iterable<T_1> | ArrayLike<T_1>): T_1[];
<T_1, U>(iterable: Iterable<T_1> | ArrayLike<T_1>, mapfn: (v: T_1, k: number) => U, thisArg?: any): U[];
};
export function every<ARR extends ArrayLike<any>>(arr: ARR, f: ARR extends ArrayLike<infer S> ? ((value: S, index: number, arr: ARR) => boolean) : any): boolean;
export function some<ARR extends ArrayLike<any>>(arr: ARR, f: ARR extends ArrayLike<infer S> ? ((value: S, index: number, arr: ARR) => boolean) : never): boolean;
export function equalFlat<ELEM>(a: ArrayLike<ELEM>, b: ArrayLike<ELEM>): boolean;
export function flatten<ELEM>(arr: Array<Array<ELEM>>): Array<ELEM>;
export function unfold<T_1>(len: number, f: (arg0: number, arg1: Array<T_1>) => T_1): Array<T_1>;
export function fold<T_1, RESULT>(arr: Array<T_1>, seed: RESULT, folder: (arg0: RESULT, arg1: T_1, arg2: number) => RESULT): RESULT;
export const isArray: (arg: any) => arg is any[];
export function unique<T_1>(arr: Array<T_1>): Array<T_1>;
export function uniqueBy<T_1, M>(arr: ArrayLike<T_1>, mapper: (arg0: T_1) => M): Array<T_1>;
export function map<ARR extends ArrayLike<any>, MAPPER extends (arg0: ARR extends ArrayLike<infer T_1> ? T_1 : never, arg1: number, arg2: ARR) => any>(arr: ARR, mapper: MAPPER): Array<MAPPER extends (...args: any[]) => infer M ? M : never>;
export function bubblesortItem<T_1>(arr: Array<T_1>, i: number, compareFn: (a: T_1, b: T_1) => number): number;
//# sourceMappingURL=array.d.ts.map

View File

@@ -1 +0,0 @@
{"version":3,"file":"array.d.ts","sourceRoot":"","sources":["array.js"],"names":[],"mappings":"AAeO,qBAJM,CAAC,OACH,SAAS,CAAC,CAAC,CAAC,GACX,CAAC,CAEiC;AAMvC,uBAHM,CAAC,KACF,KAAK,CAAC,CAAC,CAAC,CAEoC;AAOjD,qBAJM,CAAC,KACH,KAAK,CAAC,CAAC,CAAC,GACP,KAAK,CAAC,CAAC,CAAC,CAEwC;AASrD,yBAJM,CAAC,QACH,KAAK,CAAC,CAAC,CAAC,OACR,KAAK,CAAC,CAAC,CAAC,QAMlB;AAED;;;;;;;GAOG;AACH;;;;;EAA8B;AAYvB,sBANuB,GAAG,SAAnB,SAAS,CAAC,GAAG,CAAE,OAElB,GAAG,KACH,GAAG,SAAS,SAAS,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,EAAC,CAAC,EAAE,KAAK,EAAC,MAAM,EAAE,GAAG,EAAC,GAAG,KAAK,OAAO,CAAC,GAAG,GAAG,GACnF,OAAO,CASlB;AAYM,qBANuB,GAAG,SAAnB,SAAS,CAAC,GAAG,CAAE,OAElB,GAAG,KACH,GAAG,SAAS,SAAS,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,EAAC,CAAC,EAAE,KAAK,EAAC,MAAM,EAAE,GAAG,EAAC,GAAG,KAAK,OAAO,CAAC,GAAG,KAAK,GACrF,OAAO,CASlB;AASM,0BANM,IAAI,KAEN,SAAS,CAAC,IAAI,CAAC,KACf,SAAS,CAAC,IAAI,CAAC,GACd,OAAO,CAEqF;AAOjG,wBAJM,IAAI,OACN,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,GACjB,KAAK,CAAC,IAAI,CAAC,CAEgF;AAQhG,iCAJI,MAAM,KACN,CAAS,IAAM,EAAN,MAAM,EAAE,IAAQ,EAAR,KAAK,CAAC,GAAC,CAAC,KAAE,GAAC,GAC3B,KAAK,CAAC,GAAC,CAAC,CAQnB;AASM,0BALM,MAAM,OACR,KAAK,CAAC,GAAC,CAAC,QACR,MAAM,UACN,CAAS,IAAM,EAAN,MAAM,EAAE,IAAC,EAAD,GAAC,EAAE,IAAM,EAAN,MAAM,KAAE,MAAM,UAEsB;AAEnE,iDAAoC;AAO7B,iCAHI,KAAK,CAAC,GAAC,CAAC,GACP,KAAK,CAAC,GAAC,CAAC,CAE4B;AASzC,8BALM,CAAC,OACH,SAAS,CAAC,GAAC,CAAC,UACZ,CAAS,IAAC,EAAD,GAAC,KAAE,CAAC,GACZ,KAAK,CAAC,GAAC,CAAC,CAoBnB;AASM,oBANuB,GAAG,SAAnB,SAAS,CAAC,GAAG,CAAE,EACwD,MAAM,SAA9E,CAAU,IAA0C,EAA1C,GAAG,SAAS,SAAS,CAAC,MAAM,GAAC,CAAC,GAAG,GAAC,GAAG,KAAK,EAAE,IAAM,EAAN,MAAM,EAAE,IAAG,EAAH,GAAG,KAAE,GAAI,OACzE,GAAG,UACH,MAAM,GACL,KAAK,CAAC,MAAM,SAAS,IAAS,IAAM,EAAH,GAAG,EAAA,KAAG,MAAM,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC,CAWtE;AAoBM,yCAJI,KAAK,CAAC,GAAC,CAAC,KACR,MAAM,aACN,CAAC,CAAC,EAAC,GAAC,EAAC,CAAC,EAAC,GAAC,KAAK,MAAM,UAkB7B"}

219
yjs-poll/node_modules/lib0/array.js generated vendored
View File

@@ -1,219 +0,0 @@
/**
* Utility module to work with Arrays.
*
* @module array
*/
import * as set from './set.js'
/**
* Return the last element of an array. The element must exist
*
* @template L
* @param {ArrayLike<L>} arr
* @return {L}
*/
export const last = arr => arr[arr.length - 1]
/**
* @template C
* @return {Array<C>}
*/
export const create = () => /** @type {Array<C>} */ ([])
/**
* @template D
* @param {Array<D>} a
* @return {Array<D>}
*/
export const copy = a => /** @type {Array<D>} */ (a.slice())
/**
* Append elements from src to dest
*
* @template M
* @param {Array<M>} dest
* @param {Array<M>} src
*/
export const appendTo = (dest, src) => {
for (let i = 0; i < src.length; i++) {
dest.push(src[i])
}
}
/**
* Transforms something array-like to an actual Array.
*
* @function
* @template T
* @param {ArrayLike<T>|Iterable<T>} arraylike
* @return {T}
*/
export const from = Array.from
/**
* True iff condition holds on every element in the Array.
*
* @function
* @template {ArrayLike<any>} ARR
*
* @param {ARR} arr
* @param {ARR extends ArrayLike<infer S> ? ((value:S, index:number, arr:ARR) => boolean) : any} f
* @return {boolean}
*/
export const every = (arr, f) => {
for (let i = 0; i < arr.length; i++) {
if (!f(arr[i], i, arr)) {
return false
}
}
return true
}
/**
* True iff condition holds on some element in the Array.
*
* @function
* @template {ArrayLike<any>} ARR
*
* @param {ARR} arr
* @param {ARR extends ArrayLike<infer S> ? ((value:S, index:number, arr:ARR) => boolean) : never} f
* @return {boolean}
*/
export const some = (arr, f) => {
for (let i = 0; i < arr.length; i++) {
if (f(arr[i], i, arr)) {
return true
}
}
return false
}
/**
* @template ELEM
*
* @param {ArrayLike<ELEM>} a
* @param {ArrayLike<ELEM>} b
* @return {boolean}
*/
export const equalFlat = (a, b) => a.length === b.length && every(a, (item, index) => item === b[index])
/**
* @template ELEM
* @param {Array<Array<ELEM>>} arr
* @return {Array<ELEM>}
*/
export const flatten = arr => fold(arr, /** @type {Array<ELEM>} */ ([]), (acc, val) => acc.concat(val))
/**
* @template T
* @param {number} len
* @param {function(number, Array<T>):T} f
* @return {Array<T>}
*/
export const unfold = (len, f) => {
const array = new Array(len)
for (let i = 0; i < len; i++) {
array[i] = f(i, array)
}
return array
}
/**
* @template T
* @template RESULT
* @param {Array<T>} arr
* @param {RESULT} seed
* @param {function(RESULT, T, number):RESULT} folder
*/
export const fold = (arr, seed, folder) => arr.reduce(folder, seed)
export const isArray = Array.isArray
/**
* @template T
* @param {Array<T>} arr
* @return {Array<T>}
*/
export const unique = arr => from(set.from(arr))
/**
* @template T
* @template M
* @param {ArrayLike<T>} arr
* @param {function(T):M} mapper
* @return {Array<T>}
*/
export const uniqueBy = (arr, mapper) => {
/**
* @type {Set<M>}
*/
const happened = set.create()
/**
* @type {Array<T>}
*/
const result = []
for (let i = 0; i < arr.length; i++) {
const el = arr[i]
const mapped = mapper(el)
if (!happened.has(mapped)) {
happened.add(mapped)
result.push(el)
}
}
return result
}
/**
* @template {ArrayLike<any>} ARR
* @template {function(ARR extends ArrayLike<infer T> ? T : never, number, ARR):any} MAPPER
* @param {ARR} arr
* @param {MAPPER} mapper
* @return {Array<MAPPER extends function(...any): infer M ? M : never>}
*/
export const map = (arr, mapper) => {
/**
* @type {Array<any>}
*/
const res = Array(arr.length)
for (let i = 0; i < arr.length; i++) {
res[i] = mapper(/** @type {any} */ (arr[i]), i, /** @type {any} */ (arr))
}
return /** @type {any} */ (res)
}
/**
* This function bubble-sorts a single item to the correct position. The sort happens in-place and
* might be useful to ensure that a single item is at the correct position in an otherwise sorted
* array.
*
* @example
* const arr = [3, 2, 5]
* arr.sort((a, b) => a - b)
* arr // => [2, 3, 5]
* arr.splice(1, 0, 7)
* array.bubbleSortItem(arr, 1, (a, b) => a - b)
* arr // => [2, 3, 5, 7]
*
* @template T
* @param {Array<T>} arr
* @param {number} i
* @param {(a:T,b:T) => number} compareFn
*/
export const bubblesortItem = (arr, i, compareFn) => {
const n = arr[i]
let j = i
// try to sort to the right
while (j + 1 < arr.length && compareFn(n, arr[j + 1]) > 0) {
arr[j] = arr[j + 1]
arr[++j] = n
}
if (i === j && j > 0) { // no change yet
// sort to the left
while (j > 0 && compareFn(arr[j - 1], n) > 0) {
arr[j] = arr[j - 1]
arr[--j] = n
}
}
return j
}

View File

@@ -1,13 +0,0 @@
export function testIsarrayPerformance(_tc: t.TestCase): void;
export function testAppend(_tc: t.TestCase): void;
export function testBasic(_tc: t.TestCase): void;
export function testflatten(_tc: t.TestCase): void;
export function testFolding(_tc: t.TestCase): void;
export function testEvery(_tc: t.TestCase): void;
export function testIsArray(_tc: t.TestCase): void;
export function testUnique(_tc: t.TestCase): void;
export function testBubblesortItemEdgeCases(tc: t.TestCase): void;
export function testRepeatBubblesortItem(tc: t.TestCase): void;
export function testRepeatBubblesort(tc: t.TestCase): void;
import * as t from './testing.js';
//# sourceMappingURL=array.test.d.ts.map

View File

@@ -1 +0,0 @@
{"version":3,"file":"array.test.d.ts","sourceRoot":"","sources":["array.test.js"],"names":[],"mappings":"AAOO,4CAFI,CAAC,CAAC,QAAQ,QAkCpB;AAKM,gCAFI,CAAC,CAAC,QAAQ,QAMpB;AAKM,+BAFI,CAAC,CAAC,QAAQ,QAMpB;AAKM,iCAFI,CAAC,CAAC,QAAQ,QAKpB;AAKM,iCAFI,CAAC,CAAC,QAAQ,QAkBpB;AAKM,+BAFI,CAAC,CAAC,QAAQ,QAQpB;AAKM,iCAFI,CAAC,CAAC,QAAQ,QASpB;AAKM,gCAFI,CAAC,CAAC,QAAQ,QAOpB;AAKM,gDAFI,CAAC,CAAC,QAAQ,QAOpB;AAKM,6CAFI,CAAC,CAAC,QAAQ,QAWpB;AAKM,yCAFI,CAAC,CAAC,QAAQ,QASpB;mBA1JkB,cAAc"}

View File

@@ -1,3 +0,0 @@
#!/usr/bin/env node
export {};
//# sourceMappingURL=0ecdsa-generate-keypair.d.ts.map

View File

@@ -1 +0,0 @@
{"version":3,"file":"0ecdsa-generate-keypair.d.ts","sourceRoot":"","sources":["0ecdsa-generate-keypair.js"],"names":[],"mappings":""}

View File

@@ -1,15 +0,0 @@
#!/usr/bin/env node
import * as ecdsa from 'lib0/crypto/ecdsa'
import * as json from 'lib0/json'
import * as env from 'lib0/environment'
const prefix = env.getConf('name')
const keypair = await ecdsa.generateKeyPair({ extractable: true })
const privateJwk = json.stringify(await ecdsa.exportKeyJwk(keypair.privateKey))
const publicJwk = json.stringify(await ecdsa.exportKeyJwk(keypair.publicKey))
console.log(`
${prefix ? prefix.toUpperCase() + '_' : ''}PUBLIC_KEY=${publicJwk}
${prefix ? prefix.toUpperCase() + '_' : ''}PRIVATE_KEY=${privateJwk}
`)

View File

@@ -1,3 +0,0 @@
#!/usr/bin/env node
export {};
//# sourceMappingURL=0serve.d.ts.map

View File

@@ -1 +0,0 @@
{"version":3,"file":"0serve.d.ts","sourceRoot":"","sources":["0serve.js"],"names":[],"mappings":""}

View File

@@ -1,97 +0,0 @@
#!/usr/bin/env node
/**
* Simple http server implementation.
* Optionally, you may set `DEBUG_BROWSER` environment variable to use a different browser to debug
* web apps.
*/
import * as http from 'http'
import * as path from 'path'
import * as fs from 'fs'
import * as env from '../environment.js'
import * as number from '../number.js'
import * as logging from 'lib0/logging'
const host = env.getParam('--host', 'localhost')
const port = number.parseInt(env.getParam('--port', '8000'))
const paramOpenFile = env.getParam('-o', '')
const debugBrowser = env.getConf('DEBUG_BROWSER')
/**
* @type {Object<string,string>}
*/
const types = {
html: 'text/html',
css: 'text/css',
js: 'application/javascript',
mjs: 'application/javascript',
png: 'image/png',
jpg: 'image/jpeg',
jpeg: 'image/jpeg',
gif: 'image/gif',
json: 'application/json',
xml: 'application/xml',
wasm: 'application/wasm'
}
const root = path.normalize(path.resolve('./'))
const server = http.createServer((req, res) => {
const url = (req.url || '/index.html').split('?')[0]
logging.print(logging.ORANGE, logging.BOLD, req.method || '', ' ', logging.GREY, logging.UNBOLD, url)
const extension = path.extname(url).slice(1)
/**
* @type {string}
*/
const type = (extension && types[extension]) || types.html
const supportedExtension = Boolean(type)
if (!supportedExtension) {
res.writeHead(404, { 'Content-Type': 'text/html' })
res.end('404: File not found')
return
}
let fileName = url
if (url === '/') fileName = 'index.html'
else if (!extension) {
try {
fs.accessSync(path.join(root, url + '.html'), fs.constants.F_OK)
fileName = url + '.html'
} catch (e) {
fileName = path.join(url, 'index.html')
}
}
const filePath = path.join(root, fileName)
const isPathUnderRoot = path
.normalize(path.resolve(filePath))
.startsWith(root)
if (!isPathUnderRoot) {
res.writeHead(404, { 'Content-Type': 'text/html' })
res.end('404: File not found')
logging.print(logging.RED, logging.BOLD, 'Not Found: ', logging.GREY, logging.UNBOLD, url)
return
}
fs.readFile(filePath, (err, data) => {
if (err) {
logging.print(logging.RED, logging.BOLD, 'Cannot read file: ', logging.GREY, logging.UNBOLD, url)
res.writeHead(404, { 'Content-Type': 'text/html' })
res.end('404: File not found')
} else {
res.writeHead(200, { 'Content-Type': type })
res.end(data)
}
})
})
server.listen(port, host, () => {
logging.print(logging.BOLD, logging.ORANGE, `Server is running on http://${host}:${port}`)
if (paramOpenFile) {
const start = debugBrowser || (process.platform === 'darwin' ? 'open' : process.platform === 'win32' ? 'start' : 'xdg-open')
import('child_process').then(cp => {
cp.exec(`${start} http://${host}:${port}/${paramOpenFile}`)
})
}
})

View File

@@ -1,3 +0,0 @@
#!/usr/bin/env node
export {};
//# sourceMappingURL=gendocs.d.ts.map

View File

@@ -1 +0,0 @@
{"version":3,"file":"gendocs.d.ts","sourceRoot":"","sources":["gendocs.js"],"names":[],"mappings":""}

View File

@@ -1,117 +0,0 @@
#!/usr/bin/env node
// @ts-ignore
import jsdoc from 'jsdoc-api'
import * as fs from 'fs'
const firstTagContentRegex = /<\w>([^<]+)<\/\w>([^]*)/
const jsdocReturnRegex = /\* @return {(.*)}/
const jsdocTypeRegex = /\* @type {(.*)}/
const files = fs.readdirSync('./').filter(file => /(?<!(test|config))\.js$/.test(file))
const _ltregex = /</g
const _rtregex = />/g
/**
* @param {string} s
*/
const toSafeHtml = s => s.replace(_ltregex, '&lt;').replace(_rtregex, '&gt;')
const READMEcontent = fs.readFileSync('./README.md', 'utf8')
jsdoc.explain({
files,
configure: '.jsdoc.json'
}).then(/** @param {Array<any>} json */ json => {
const strBuilder = []
/**
* @type {Object<string, { items: Array<any>, name: string, description: string }>}
*/
const modules = {}
json.forEach(item => {
if (item.meta && item.meta.filename) {
const mod = modules[item.meta.filename] || (modules[item.meta.filename] = { items: [], name: item.meta.filename.slice(0, -3), description: '' })
if (item.kind === 'module') {
mod.name = item.name
mod.description = item.description || ''
} else {
mod.items.push(item)
}
}
})
/**
* @type {Object<string,string>}
*/
const classDescriptions = {}
for (const fileName in modules) {
const mod = modules[fileName]
const items = mod.items
const desc = firstTagContentRegex.exec(mod.description)
const descHead = desc ? desc[1] : ''
const descRest = desc ? desc[2] : ''
strBuilder.push(`<details><summary><b>[lib0/${mod.name}]</b> ${descHead}</summary>`)
strBuilder.push(`<pre>import * as ${mod.name} from 'lib0/${fileName.slice(0, -3)}'</pre>`)
if (descRest.length > 0) {
strBuilder.push(descRest)
}
strBuilder.push('<dl>')
for (let i = 0; i < items.length; i++) {
const item = items[i]
if (!item.ignore && item.scope !== 'inner' && item.name[0] !== '_' && item.longname.indexOf('~') < 0) {
// strBuilder.push(JSON.stringify(item)) // output json for debugging
switch (item.kind) {
case 'class': {
if (item.params == null) {
classDescriptions[item.longname] = item.classdesc
break
}
}
// eslint-disable-next-line
case 'constant': {
if (item.params == null && item.returns == null) {
const typeEval = jsdocTypeRegex.exec(item.comment)
strBuilder.push(`<b><code>${item.longname.slice(7)}${typeEval ? (': ' + toSafeHtml(typeEval[1])) : ''}</code></b><br>`)
if (item.description) {
strBuilder.push(`<dd>${item.description}</dd>`)
}
break
}
}
// eslint-disable-next-line
case 'function': {
/**
* @param {string} name
*/
const getOriginalParamTypeDecl = name => {
const regval = new RegExp('@param {(.*)} \\[?' + name + '\\]?[^\\w]*').exec(item.comment)
return regval ? regval[1] : null
}
if (item.params == null && item.returns == null) {
break
}
const paramVal = (item.params || []).map(/** @param {any} ret */ ret => `${ret.name}: ${getOriginalParamTypeDecl(ret.name) || ret.type.names.join('|')}`).join(', ')
const evalReturnRegex = jsdocReturnRegex.exec(item.comment)
const returnVal = evalReturnRegex ? `: ${evalReturnRegex[1]}` : (item.returns ? item.returns.map(/** @param {any} r */ r => r.type.names.join('|')).join('|') : '')
strBuilder.push(`<b><code>${item.kind === 'class' ? 'new ' : ''}${item.longname.slice(7)}(${toSafeHtml(paramVal)})${toSafeHtml(returnVal)}</code></b><br>`)
const desc = item.description || item.classdesc || classDescriptions[item.longname] || null
if (desc) {
strBuilder.push(`<dd>${desc}</dd>`)
}
break
}
case 'member': {
if (item.type) {
strBuilder.push(`<b><code>${item.longname.slice(7)}: ${toSafeHtml(/** @type {RegExpExecArray} */ (jsdocTypeRegex.exec(item.comment))[1])}</code></b><br>`)
if (item.description) {
strBuilder.push(`<dd>${item.description}</dd>`)
}
}
}
}
}
}
strBuilder.push('</dl>')
strBuilder.push('</details>')
}
const replaceReadme = READMEcontent.replace(/<details>[^]*<\/details>/, strBuilder.join('\n'))
fs.writeFileSync('./README.md', replaceReadme)
})

View File

@@ -1,3 +0,0 @@
#!/usr/bin/env node
export {};
//# sourceMappingURL=gentesthtml.d.ts.map

View File

@@ -1 +0,0 @@
{"version":3,"file":"gentesthtml.d.ts","sourceRoot":"","sources":["gentesthtml.js"],"names":[],"mappings":""}

View File

@@ -1,89 +0,0 @@
#!/usr/bin/env node
import * as fs from 'fs'
import * as object from '../object.js'
import * as env from '../environment.js'
const script = env.getParam('--script', './test.js')
const includeDeps = env.getParam('--include-dependencies', '').split(',').filter(d => d.length)
const customImportsPath = env.getParam('--custom-imports', '')
/**
* @type {Object<string,string>}
*/
const exports = {}
/**
* @type {Object<string,Object<string,string>>}
*/
const scopes = {}
/**
* @param {any} v
* @param {string} k
* @param {string} pkgName
* @param {string} pathPrefix
* @param {Object<string,string>} importMap
*/
const extractModMap = (v, k, pkgName, pathPrefix, importMap) => {
if (k[0] !== '.') return
if (typeof v === 'object') {
extractModMap(v.browser || v.import || v.module || v.default, k, pkgName, pathPrefix, importMap)
} else if (v && v[0] === '.') {
importMap[pkgName + k.slice(1)] = pathPrefix + v.slice(1)
}
}
/**
* @param {string} s
*/
const _maybeAddRelPrefix = s => (s[0] !== '.' ? './' : '') + s
/**
* @param {any} pkgJson
* @param {string} pathPrefix
* @param {Object<string,string>} importMap
*/
const readPkg = (pkgJson, pathPrefix, importMap) => {
if (pkgJson.exports == null && pkgJson.main != null) {
importMap[pkgJson.name] = pathPrefix + _maybeAddRelPrefix(pkgJson.main).slice(1)
}
object.forEach(pkgJson.exports, (v, k) => extractModMap(v, k, pkgJson.name, pathPrefix, importMap))
object.forEach(pkgJson.dependencies, (_v, depName) => {
const nextImportMap = pathPrefix === '.' ? exports : (scopes[pathPrefix + '/'] || (scopes[pathPrefix + '/'] = {}))
const prefix = `./node_modules/${depName}`
const depPkgJson = JSON.parse(fs.readFileSync(prefix + '/package.json', { encoding: 'utf8' }))
readPkg(depPkgJson, prefix, nextImportMap)
})
}
const rootPkgJson = JSON.parse(fs.readFileSync('./package.json', { encoding: 'utf8' }))
readPkg(rootPkgJson, '.', exports)
includeDeps.forEach(depName => {
const prefix = `./node_modules/${depName}`
const depPkgJson = JSON.parse(fs.readFileSync(`${prefix}/package.json`, { encoding: 'utf8' }))
readPkg(depPkgJson, prefix, exports)
})
const customImports = {}
if (customImportsPath !== '') {
object.assign(customImports, JSON.parse(fs.readFileSync(customImportsPath, { encoding: 'utf8' })))
}
const testHtml = `
<!DOCTYPE html>
<html>
<head>
<title>Testing ${rootPkgJson.name}</title>
<script type="importmap">
{
"imports": ${JSON.stringify(object.assign({}, exports, customImports), null, 2)},
"scopes": ${JSON.stringify(scopes, null, 2)}
}
</script>
</head>
<body>
<script type="module" src="${script}"></script>
</body>
</html>
`
console.log(testHtml)

View File

@@ -1,87 +0,0 @@
/**
* Binary data constants.
*
* @module binary
*/
/**
* n-th bit activated.
*
* @type {number}
*/
export const BIT1: number;
export const BIT2: 2;
export const BIT3: 4;
export const BIT4: 8;
export const BIT5: 16;
export const BIT6: 32;
export const BIT7: 64;
export const BIT8: 128;
export const BIT9: 256;
export const BIT10: 512;
export const BIT11: 1024;
export const BIT12: 2048;
export const BIT13: 4096;
export const BIT14: 8192;
export const BIT15: 16384;
export const BIT16: 32768;
export const BIT17: 65536;
export const BIT18: number;
export const BIT19: number;
export const BIT20: number;
export const BIT21: number;
export const BIT22: number;
export const BIT23: number;
export const BIT24: number;
export const BIT25: number;
export const BIT26: number;
export const BIT27: number;
export const BIT28: number;
export const BIT29: number;
export const BIT30: number;
export const BIT31: number;
export const BIT32: number;
/**
* First n bits activated.
*
* @type {number}
*/
export const BITS0: number;
export const BITS1: 1;
export const BITS2: 3;
export const BITS3: 7;
export const BITS4: 15;
export const BITS5: 31;
export const BITS6: 63;
export const BITS7: 127;
export const BITS8: 255;
export const BITS9: 511;
export const BITS10: 1023;
export const BITS11: 2047;
export const BITS12: 4095;
export const BITS13: 8191;
export const BITS14: 16383;
export const BITS15: 32767;
export const BITS16: 65535;
export const BITS17: number;
export const BITS18: number;
export const BITS19: number;
export const BITS20: number;
export const BITS21: number;
export const BITS22: number;
export const BITS23: number;
export const BITS24: number;
export const BITS25: number;
export const BITS26: number;
export const BITS27: number;
export const BITS28: number;
export const BITS29: number;
export const BITS30: number;
/**
* @type {number}
*/
export const BITS31: number;
/**
* @type {number}
*/
export const BITS32: number;
//# sourceMappingURL=binary.d.ts.map

View File

@@ -1 +0,0 @@
{"version":3,"file":"binary.d.ts","sourceRoot":"","sources":["binary.js"],"names":[],"mappings":"AAEA;;;;GAIG;AAEH;;;;GAIG;AACH,mBAFU,MAAM,CAEK;AACrB,mBAAoB,CAAC,CAAA;AACrB,mBAAoB,CAAC,CAAA;AACrB,mBAAoB,CAAC,CAAA;AACrB,mBAAoB,EAAE,CAAA;AACtB,mBAAoB,EAAE,CAAA;AACtB,mBAAoB,EAAE,CAAA;AACtB,mBAAoB,GAAG,CAAA;AACvB,mBAAoB,GAAG,CAAA;AACvB,oBAAqB,GAAG,CAAA;AACxB,oBAAqB,IAAI,CAAA;AACzB,oBAAqB,IAAI,CAAA;AACzB,oBAAqB,IAAI,CAAA;AACzB,oBAAqB,IAAI,CAAA;AACzB,oBAAqB,KAAK,CAAA;AAC1B,oBAAqB,KAAK,CAAA;AAC1B,oBAAqB,KAAK,CAAA;AAC1B,2BAA4B;AAC5B,2BAA4B;AAC5B,2BAA4B;AAC5B,2BAA4B;AAC5B,2BAA4B;AAC5B,2BAA4B;AAC5B,2BAA4B;AAC5B,2BAA4B;AAC5B,2BAA4B;AAC5B,2BAA4B;AAC5B,2BAA4B;AAC5B,2BAA4B;AAC5B,2BAA4B;AAC5B,2BAA4B;AAC5B,2BAA4B;AAE5B;;;;GAIG;AACH,oBAFU,MAAM,CAEM;AACtB,oBAAqB,CAAC,CAAA;AACtB,oBAAqB,CAAC,CAAA;AACtB,oBAAqB,CAAC,CAAA;AACtB,oBAAqB,EAAE,CAAA;AACvB,oBAAqB,EAAE,CAAA;AACvB,oBAAqB,EAAE,CAAA;AACvB,oBAAqB,GAAG,CAAA;AACxB,oBAAqB,GAAG,CAAA;AACxB,oBAAqB,GAAG,CAAA;AACxB,qBAAsB,IAAI,CAAA;AAC1B,qBAAsB,IAAI,CAAA;AAC1B,qBAAsB,IAAI,CAAA;AAC1B,qBAAsB,IAAI,CAAA;AAC1B,qBAAsB,KAAK,CAAA;AAC3B,qBAAsB,KAAK,CAAA;AAC3B,qBAAsB,KAAK,CAAA;AAC3B,4BAA+B;AAC/B,4BAA+B;AAC/B,4BAA+B;AAC/B,4BAA+B;AAC/B,4BAA+B;AAC/B,4BAA+B;AAC/B,4BAA+B;AAC/B,4BAA+B;AAC/B,4BAA+B;AAC/B,4BAA+B;AAC/B,4BAA+B;AAC/B,4BAA+B;AAC/B,4BAA+B;AAC/B,4BAA+B;AAC/B;;GAEG;AACH,qBAFU,MAAM,CAEgB;AAChC;;GAEG;AACH,qBAFU,MAAM,CAEgB"}

90
yjs-poll/node_modules/lib0/binary.js generated vendored
View File

@@ -1,90 +0,0 @@
/* eslint-env browser */
/**
* Binary data constants.
*
* @module binary
*/
/**
* n-th bit activated.
*
* @type {number}
*/
export const BIT1 = 1
export const BIT2 = 2
export const BIT3 = 4
export const BIT4 = 8
export const BIT5 = 16
export const BIT6 = 32
export const BIT7 = 64
export const BIT8 = 128
export const BIT9 = 256
export const BIT10 = 512
export const BIT11 = 1024
export const BIT12 = 2048
export const BIT13 = 4096
export const BIT14 = 8192
export const BIT15 = 16384
export const BIT16 = 32768
export const BIT17 = 65536
export const BIT18 = 1 << 17
export const BIT19 = 1 << 18
export const BIT20 = 1 << 19
export const BIT21 = 1 << 20
export const BIT22 = 1 << 21
export const BIT23 = 1 << 22
export const BIT24 = 1 << 23
export const BIT25 = 1 << 24
export const BIT26 = 1 << 25
export const BIT27 = 1 << 26
export const BIT28 = 1 << 27
export const BIT29 = 1 << 28
export const BIT30 = 1 << 29
export const BIT31 = 1 << 30
export const BIT32 = 1 << 31
/**
* First n bits activated.
*
* @type {number}
*/
export const BITS0 = 0
export const BITS1 = 1
export const BITS2 = 3
export const BITS3 = 7
export const BITS4 = 15
export const BITS5 = 31
export const BITS6 = 63
export const BITS7 = 127
export const BITS8 = 255
export const BITS9 = 511
export const BITS10 = 1023
export const BITS11 = 2047
export const BITS12 = 4095
export const BITS13 = 8191
export const BITS14 = 16383
export const BITS15 = 32767
export const BITS16 = 65535
export const BITS17 = BIT18 - 1
export const BITS18 = BIT19 - 1
export const BITS19 = BIT20 - 1
export const BITS20 = BIT21 - 1
export const BITS21 = BIT22 - 1
export const BITS22 = BIT23 - 1
export const BITS23 = BIT24 - 1
export const BITS24 = BIT25 - 1
export const BITS25 = BIT26 - 1
export const BITS26 = BIT27 - 1
export const BITS27 = BIT28 - 1
export const BITS28 = BIT29 - 1
export const BITS29 = BIT30 - 1
export const BITS30 = BIT31 - 1
/**
* @type {number}
*/
export const BITS31 = 0x7FFFFFFF
/**
* @type {number}
*/
export const BITS32 = 0xFFFFFFFF

View File

@@ -1,4 +0,0 @@
export function testBitx(tc: t.TestCase): void;
export function testBitsx(tc: t.TestCase): void;
import * as t from './testing.js';
//# sourceMappingURL=binary.test.d.ts.map

View File

@@ -1 +0,0 @@
{"version":3,"file":"binary.test.d.ts","sourceRoot":"","sources":["binary.test.js"],"names":[],"mappings":"AAMO,6BAFI,CAAC,CAAC,QAAQ,QAOpB;AAKM,8BAFI,CAAC,CAAC,QAAQ,QAWpB;mBAxBkB,cAAc"}

View File

@@ -1,8 +0,0 @@
export function subscribe(room: string, f: (arg0: any, arg1: any) => any): (arg0: any, arg1: any) => any;
export function unsubscribe(room: string, f: (arg0: any, arg1: any) => any): boolean;
export function publish(room: string, data: any, origin?: any): void;
export type Channel = {
subs: Set<(arg0: any, arg1: any) => any>;
bc: any;
};
//# sourceMappingURL=broadcastchannel.d.ts.map

View File

@@ -1 +0,0 @@
{"version":3,"file":"broadcastchannel.d.ts","sourceRoot":"","sources":["broadcastchannel.js"],"names":[],"mappings":"AA+FO,gCAHI,MAAM,KACN,CAAS,IAAG,EAAH,GAAG,EAAE,IAAG,EAAH,GAAG,KAAE,GAAG,UAAb,GAAG,QAAE,GAAG,KAAE,GAAG,CAKhC;AASM,kCAHI,MAAM,KACN,CAAS,IAAG,EAAH,GAAG,EAAE,IAAG,EAAH,GAAG,KAAE,GAAG,WAUhC;AAUM,8BAJI,MAAM,QACN,GAAG,WACH,GAAG,QAMb;;UAvGa,GAAG,CAAC,CAAS,IAAG,EAAH,GAAG,EAAE,IAAG,EAAH,GAAG,KAAE,GAAG,CAAC;QAC3B,GAAG"}

View File

@@ -1,130 +0,0 @@
/* eslint-env browser */
/**
* Helpers for cross-tab communication using broadcastchannel with LocalStorage fallback.
*
* ```js
* // In browser window A:
* broadcastchannel.subscribe('my events', data => console.log(data))
* broadcastchannel.publish('my events', 'Hello world!') // => A: 'Hello world!' fires synchronously in same tab
*
* // In browser window B:
* broadcastchannel.publish('my events', 'hello from tab B') // => A: 'hello from tab B'
* ```
*
* @module broadcastchannel
*/
// @todo before next major: use Uint8Array instead as buffer object
import * as map from './map.js'
import * as set from './set.js'
import * as buffer from './buffer.js'
import * as storage from './storage.js'
/**
* @typedef {Object} Channel
* @property {Set<function(any, any):any>} Channel.subs
* @property {any} Channel.bc
*/
/**
* @type {Map<string, Channel>}
*/
const channels = new Map()
/* c8 ignore start */
class LocalStoragePolyfill {
/**
* @param {string} room
*/
constructor (room) {
this.room = room
/**
* @type {null|function({data:Uint8Array}):void}
*/
this.onmessage = null
/**
* @param {any} e
*/
this._onChange = e => e.key === room && this.onmessage !== null && this.onmessage({ data: buffer.fromBase64(e.newValue || '') })
storage.onChange(this._onChange)
}
/**
* @param {ArrayBuffer} buf
*/
postMessage (buf) {
storage.varStorage.setItem(this.room, buffer.toBase64(buffer.createUint8ArrayFromArrayBuffer(buf)))
}
close () {
storage.offChange(this._onChange)
}
}
/* c8 ignore stop */
// Use BroadcastChannel or Polyfill
/* c8 ignore next */
const BC = typeof BroadcastChannel === 'undefined' ? LocalStoragePolyfill : BroadcastChannel
/**
* @param {string} room
* @return {Channel}
*/
const getChannel = room =>
map.setIfUndefined(channels, room, () => {
const subs = set.create()
const bc = new BC(room)
/**
* @param {{data:ArrayBuffer}} e
*/
/* c8 ignore next */
bc.onmessage = e => subs.forEach(sub => sub(e.data, 'broadcastchannel'))
return {
bc, subs
}
})
/**
* Subscribe to global `publish` events.
*
* @function
* @param {string} room
* @param {function(any, any):any} f
*/
export const subscribe = (room, f) => {
getChannel(room).subs.add(f)
return f
}
/**
* Unsubscribe from `publish` global events.
*
* @function
* @param {string} room
* @param {function(any, any):any} f
*/
export const unsubscribe = (room, f) => {
const channel = getChannel(room)
const unsubscribed = channel.subs.delete(f)
if (unsubscribed && channel.subs.size === 0) {
channel.bc.close()
channels.delete(room)
}
return unsubscribed
}
/**
* Publish data to all subscribers (including subscribers on this tab)
*
* @function
* @param {string} room
* @param {any} data
* @param {any} [origin]
*/
export const publish = (room, data, origin = null) => {
const c = getChannel(room)
c.bc.postMessage(data)
c.subs.forEach(sub => sub(data, origin))
}

View File

@@ -1,3 +0,0 @@
export function testBroadcastChannel(tc: t.TestCase): void;
import * as t from './testing.js';
//# sourceMappingURL=broadcastchannel.test.d.ts.map

View File

@@ -1 +0,0 @@
{"version":3,"file":"broadcastchannel.test.d.ts","sourceRoot":"","sources":["broadcastchannel.test.js"],"names":[],"mappings":"AAMO,yCAFI,CAAC,CAAC,QAAQ,QAkBpB;mBAtBkB,cAAc"}

View File

@@ -1,22 +0,0 @@
export function createUint8ArrayFromLen(len: number): Uint8Array<ArrayBuffer>;
export function createUint8ArrayViewFromArrayBuffer(buffer: ArrayBuffer, byteOffset: number, length: number): Uint8Array<ArrayBuffer>;
export function createUint8ArrayFromArrayBuffer(buffer: ArrayBuffer): Uint8Array<ArrayBuffer>;
/**
* @param {Uint8Array} bytes
* @return {string}
*/
export function toBase64(bytes: Uint8Array): string;
/**
* @param {string} s
* @return {Uint8Array<ArrayBuffer>}
*/
export function fromBase64(s: string): Uint8Array<ArrayBuffer>;
export function toBase64UrlEncoded(buf: Uint8Array): string;
export function fromBase64UrlEncoded(base64: string): Uint8Array<ArrayBuffer>;
export function toHexString(buf: Uint8Array): string;
export function fromHexString(hex: string): Uint8Array<ArrayBuffer>;
export function copyUint8Array(uint8Array: Uint8Array): Uint8Array;
export function encodeAny(data: any): Uint8Array;
export function decodeAny(buf: Uint8Array): any;
export function shiftNBitsLeft(bs: Uint8Array, N: number): Uint8Array<ArrayBufferLike>;
//# sourceMappingURL=buffer.d.ts.map

View File

@@ -1 +0,0 @@
{"version":3,"file":"buffer.d.ts","sourceRoot":"","sources":["buffer.js"],"names":[],"mappings":"AAgBO,6CAFI,MAAM,2BAEgD;AAS1D,4DAJI,WAAW,cACX,MAAM,UACN,MAAM,2BAE4G;AAOtH,wDAFI,WAAW,2BAEyD;AAG/E;;;GAGG;AACH,gCAHW,UAAU,GACT,MAAM,CASjB;AAUD;;;GAGG;AACH,8BAHW,MAAM,GACL,UAAU,CAAC,WAAW,CAAC,CAUlC;AAqBM,wCAFI,UAAU,UAE+F;AAK7G,6CAFI,MAAM,2BAEyF;AAOnG,iCAFI,UAAU,UAE0E;AAOxF,mCAFI,MAAM,2BAShB;AAQM,2CAHI,UAAU,GACT,UAAU,CAMrB;AASM,gCAHI,GAAG,GACF,UAAU,CAGwC;AAQvD,+BAHI,UAAU,GACT,GAAG,CAE8D;AAQtE,mCAHI,UAAU,KACV,MAAM,+BAWhB"}

163
yjs-poll/node_modules/lib0/buffer.js generated vendored
View File

@@ -1,163 +0,0 @@
/**
* Utility functions to work with buffers (Uint8Array).
*
* @module buffer
*/
import * as string from './string.js'
import * as env from './environment.js'
import * as array from './array.js'
import * as math from './math.js'
import * as encoding from './encoding.js'
import * as decoding from './decoding.js'
/**
* @param {number} len
*/
export const createUint8ArrayFromLen = len => new Uint8Array(len)
/**
* Create Uint8Array with initial content from buffer
*
* @param {ArrayBuffer} buffer
* @param {number} byteOffset
* @param {number} length
*/
export const createUint8ArrayViewFromArrayBuffer = (buffer, byteOffset, length) => new Uint8Array(buffer, byteOffset, length)
/**
* Create Uint8Array with initial content from buffer
*
* @param {ArrayBuffer} buffer
*/
export const createUint8ArrayFromArrayBuffer = buffer => new Uint8Array(buffer)
/* c8 ignore start */
/**
* @param {Uint8Array} bytes
* @return {string}
*/
const toBase64Browser = bytes => {
let s = ''
for (let i = 0; i < bytes.byteLength; i++) {
s += string.fromCharCode(bytes[i])
}
// eslint-disable-next-line no-undef
return btoa(s)
}
/* c8 ignore stop */
/**
* @param {Uint8Array} bytes
* @return {string}
*/
const toBase64Node = bytes => Buffer.from(bytes.buffer, bytes.byteOffset, bytes.byteLength).toString('base64')
/* c8 ignore start */
/**
* @param {string} s
* @return {Uint8Array<ArrayBuffer>}
*/
const fromBase64Browser = s => {
// eslint-disable-next-line no-undef
const a = atob(s)
const bytes = createUint8ArrayFromLen(a.length)
for (let i = 0; i < a.length; i++) {
bytes[i] = a.charCodeAt(i)
}
return bytes
}
/* c8 ignore stop */
/**
* @param {string} s
*/
const fromBase64Node = s => {
const buf = Buffer.from(s, 'base64')
return createUint8ArrayViewFromArrayBuffer(buf.buffer, buf.byteOffset, buf.byteLength)
}
/* c8 ignore next */
export const toBase64 = env.isBrowser ? toBase64Browser : toBase64Node
/* c8 ignore next */
export const fromBase64 = env.isBrowser ? fromBase64Browser : fromBase64Node
/**
* Implements base64url - see https://datatracker.ietf.org/doc/html/rfc4648#section-5
* @param {Uint8Array} buf
*/
export const toBase64UrlEncoded = buf => toBase64(buf).replaceAll('+', '-').replaceAll('/', '_').replaceAll('=', '')
/**
* @param {string} base64
*/
export const fromBase64UrlEncoded = base64 => fromBase64(base64.replaceAll('-', '+').replaceAll('_', '/'))
/**
* Base64 is always a more efficient choice. This exists for utility purposes only.
*
* @param {Uint8Array} buf
*/
export const toHexString = buf => array.map(buf, b => b.toString(16).padStart(2, '0')).join('')
/**
* Note: This function expects that the hex doesn't start with 0x..
*
* @param {string} hex
*/
export const fromHexString = hex => {
const hlen = hex.length
const buf = new Uint8Array(math.ceil(hlen / 2))
for (let i = 0; i < hlen; i += 2) {
buf[buf.length - i / 2 - 1] = Number.parseInt(hex.slice(hlen - i - 2, hlen - i), 16)
}
return buf
}
/**
* Copy the content of an Uint8Array view to a new ArrayBuffer.
*
* @param {Uint8Array} uint8Array
* @return {Uint8Array}
*/
export const copyUint8Array = uint8Array => {
const newBuf = createUint8ArrayFromLen(uint8Array.byteLength)
newBuf.set(uint8Array)
return newBuf
}
/**
* Encode anything as a UInt8Array. It's a pun on typescripts's `any` type.
* See encoding.writeAny for more information.
*
* @param {any} data
* @return {Uint8Array}
*/
export const encodeAny = data =>
encoding.encode(encoder => encoding.writeAny(encoder, data))
/**
* Decode an any-encoded value.
*
* @param {Uint8Array} buf
* @return {any}
*/
export const decodeAny = buf => decoding.readAny(decoding.createDecoder(buf))
/**
* Shift Byte Array {N} bits to the left. Does not expand byte array.
*
* @param {Uint8Array} bs
* @param {number} N should be in the range of [0-7]
*/
export const shiftNBitsLeft = (bs, N) => {
if (N === 0) return bs
bs = new Uint8Array(bs)
bs[0] <<= N
for (let i = 1; i < bs.length; i++) {
bs[i - 1] |= bs[i] >>> (8 - N)
bs[i] <<= N
}
return bs
}

View File

@@ -1,6 +0,0 @@
export function testRepeatBase64urlEncoding(tc: t.TestCase): void;
export function testRepeatBase64Encoding(tc: t.TestCase): void;
export function testRepeatHexEncoding(tc: t.TestCase): void;
export function testAnyEncoding(_tc: t.TestCase): void;
import * as t from './testing.js';
//# sourceMappingURL=buffer.test.d.ts.map

View File

@@ -1 +0,0 @@
{"version":3,"file":"buffer.test.d.ts","sourceRoot":"","sources":["buffer.test.js"],"names":[],"mappings":"AA2BO,gDAFI,CAAC,CAAC,QAAQ,QAIpB;AAKM,6CAFI,CAAC,CAAC,QAAQ,QAIpB;AAKM,0CAFI,CAAC,CAAC,QAAQ,QAIpB;AAKM,qCAFI,CAAC,CAAC,QAAQ,QAMpB;mBApDkB,cAAc"}

View File

@@ -1,52 +0,0 @@
/**
* @template K, V
*/
export class Cache<K, V> {
/**
* @param {number} timeout
*/
constructor(timeout: number);
timeout: number;
/**
* @type list.List<Entry<K, V>>
*/
_q: list.List<Entry<K, V>>;
/**
* @type {Map<K, Entry<K, V>>}
*/
_map: Map<K, Entry<K, V>>;
}
export function removeStale<K, V>(cache: Cache<K, V>): number;
export function set<K, V>(cache: Cache<K, V>, key: K, value: V): void;
export function get<K, V>(cache: Cache<K, V>, key: K): V | undefined;
export function refreshTimeout<K, V>(cache: Cache<K, V>, key: K): void;
export function getAsync<K, V>(cache: Cache<K, V>, key: K): V | Promise<V> | undefined;
export function remove<K, V>(cache: Cache<K, V>, key: K): NonNullable<V> | undefined;
export function setIfUndefined<K, V>(cache: Cache<K, V>, key: K, init: () => Promise<V>, removeNull?: boolean): Promise<V> | V;
export function create(timeout: number): Cache<any, any>;
import * as list from './list.js';
/**
* @template K, V
*
* @implements {list.ListNode}
*/
declare class Entry<K, V> implements list.ListNode {
/**
* @param {K} key
* @param {V | Promise<V>} val
*/
constructor(key: K, val: V | Promise<V>);
/**
* @type {this | null}
*/
prev: this | null;
/**
* @type {this | null}
*/
next: this | null;
created: number;
val: V | Promise<V>;
key: K;
}
export {};
//# sourceMappingURL=cache.d.ts.map

View File

@@ -1 +0,0 @@
{"version":3,"file":"cache.d.ts","sourceRoot":"","sources":["cache.js"],"names":[],"mappings":"AAqCA;;GAEG;AACH,mBAFa,CAAC,EAAE,CAAC;IAGf;;OAEG;IACH,qBAFW,MAAM,EAYhB;IATC,gBAAsB;IACtB;;OAEG;IACH,IAFS,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAER;IACvB;;OAEG;IACH,MAFU,GAAG,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAEL;CAE3B;AAQM,4BALM,CAAC,EAAE,CAAC,SAEN,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,GACV,MAAM,CAUjB;AASM,oBANM,CAAC,EAAE,CAAC,SAEN,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,OACX,CAAC,SACD,CAAC,QAgBX;AAwBM,oBANM,CAAC,EAAE,CAAC,SAEN,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,OACX,CAAC,GACA,CAAC,GAAG,SAAS,CAKxB;AAQM,+BALM,CAAC,EAAE,CAAC,SAEN,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,OACX,CAAC,QAWX;AAYM,yBANM,CAAC,EAAE,CAAC,SAEN,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,OACX,CAAC,GACA,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,GAAG,SAAS,CAKrC;AAQM,uBALM,CAAC,EAAE,CAAC,SAEN,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,OACX,CAAC,8BASX;AAWM,+BARM,CAAC,EAAE,CAAC,SAEN,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,OACX,CAAC,QACD,MAAW,OAAO,CAAC,CAAC,CAAC,eACrB,OAAO,GACN,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAuBzB;AAKM,gCAFI,MAAM,mBAEkC;sBArM7B,WAAW;AAIjC;;;;GAIG;AACH,oBAJa,CAAC,EAAE,CAAC,aAED,IAAI,CAAC,QAAQ;IAG3B;;;OAGG;IACH,iBAHW,CAAC,OACD,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,EAcxB;IAXC;;OAEG;IACH,MAFU,IAAI,GAAG,IAAI,CAEL;IAChB;;OAEG;IACH,MAFU,IAAI,GAAG,IAAI,CAEL;IAChB,gBAAiC;IACjC,oBAAc;IACd,OAAc;CAEjB"}

206
yjs-poll/node_modules/lib0/cache.js generated vendored
View File

@@ -1,206 +0,0 @@
/* eslint-env browser */
/**
* An implementation of a map which has keys that expire.
*
* @module cache
*/
import * as list from './list.js'
import * as map from './map.js'
import * as time from './time.js'
/**
* @template K, V
*
* @implements {list.ListNode}
*/
class Entry {
/**
* @param {K} key
* @param {V | Promise<V>} val
*/
constructor (key, val) {
/**
* @type {this | null}
*/
this.prev = null
/**
* @type {this | null}
*/
this.next = null
this.created = time.getUnixTime()
this.val = val
this.key = key
}
}
/**
* @template K, V
*/
export class Cache {
/**
* @param {number} timeout
*/
constructor (timeout) {
this.timeout = timeout
/**
* @type list.List<Entry<K, V>>
*/
this._q = list.create()
/**
* @type {Map<K, Entry<K, V>>}
*/
this._map = map.create()
}
}
/**
* @template K, V
*
* @param {Cache<K, V>} cache
* @return {number} Returns the current timestamp
*/
export const removeStale = cache => {
const now = time.getUnixTime()
const q = cache._q
while (q.start && now - q.start.created > cache.timeout) {
cache._map.delete(q.start.key)
list.popFront(q)
}
return now
}
/**
* @template K, V
*
* @param {Cache<K, V>} cache
* @param {K} key
* @param {V} value
*/
export const set = (cache, key, value) => {
const now = removeStale(cache)
const q = cache._q
const n = cache._map.get(key)
if (n) {
list.removeNode(q, n)
list.pushEnd(q, n)
n.created = now
n.val = value
} else {
const node = new Entry(key, value)
list.pushEnd(q, node)
cache._map.set(key, node)
}
}
/**
* @template K, V
*
* @param {Cache<K, V>} cache
* @param {K} key
* @return {Entry<K, V> | undefined}
*/
const getNode = (cache, key) => {
removeStale(cache)
const n = cache._map.get(key)
if (n) {
return n
}
}
/**
* @template K, V
*
* @param {Cache<K, V>} cache
* @param {K} key
* @return {V | undefined}
*/
export const get = (cache, key) => {
const n = getNode(cache, key)
return n && !(n.val instanceof Promise) ? n.val : undefined
}
/**
* @template K, V
*
* @param {Cache<K, V>} cache
* @param {K} key
*/
export const refreshTimeout = (cache, key) => {
const now = time.getUnixTime()
const q = cache._q
const n = cache._map.get(key)
if (n) {
list.removeNode(q, n)
list.pushEnd(q, n)
n.created = now
}
}
/**
* Works well in conjunktion with setIfUndefined which has an async init function.
* Using getAsync & setIfUndefined ensures that the init function is only called once.
*
* @template K, V
*
* @param {Cache<K, V>} cache
* @param {K} key
* @return {V | Promise<V> | undefined}
*/
export const getAsync = (cache, key) => {
const n = getNode(cache, key)
return n ? n.val : undefined
}
/**
* @template K, V
*
* @param {Cache<K, V>} cache
* @param {K} key
*/
export const remove = (cache, key) => {
const n = cache._map.get(key)
if (n) {
list.removeNode(cache._q, n)
cache._map.delete(key)
return n.val && !(n.val instanceof Promise) ? n.val : undefined
}
}
/**
* @template K, V
*
* @param {Cache<K, V>} cache
* @param {K} key
* @param {function():Promise<V>} init
* @param {boolean} removeNull Optional argument that automatically removes values that resolve to null/undefined from the cache.
* @return {Promise<V> | V}
*/
export const setIfUndefined = (cache, key, init, removeNull = false) => {
removeStale(cache)
const q = cache._q
const n = cache._map.get(key)
if (n) {
return n.val
} else {
const p = init()
const node = new Entry(key, p)
list.pushEnd(q, node)
cache._map.set(key, node)
p.then(v => {
if (p === node.val) {
node.val = v
}
if (removeNull && v == null) {
remove(cache, key)
}
})
return p
}
}
/**
* @param {number} timeout
*/
export const create = timeout => new Cache(timeout)

View File

@@ -1,3 +0,0 @@
export function testCache(tc: t.TestCase): Promise<void>;
import * as t from './testing.js';
//# sourceMappingURL=cache.test.d.ts.map

View File

@@ -1 +0,0 @@
{"version":3,"file":"cache.test.d.ts","sourceRoot":"","sources":["cache.test.js"],"names":[],"mappings":"AAOO,8BAFI,CAAC,CAAC,QAAQ,iBA6EpB;mBAlFkB,cAAc"}

View File

@@ -1,86 +0,0 @@
/**
* @type {CustomElementRegistry}
*/
export const registry: CustomElementRegistry;
export function define(name: string, constr: any, opts?: ElementDefinitionOptions): void;
export function whenDefined(name: string): Promise<CustomElementConstructor>;
/**
* @template S
*/
export class Lib0Component<S> extends HTMLElement {
/**
* @param {S} [state]
*/
constructor(state?: S);
/**
* @type {S|null}
*/
state: S | null;
/**
* @type {any}
*/
_internal: any;
/**
* @param {S} _state
* @param {boolean} [_forceStateUpdate] Force that the state is rerendered even if state didn't change
*/
setState(_state: S, _forceStateUpdate?: boolean): void;
/**
* @param {any} _stateUpdate
*/
updateState(_stateUpdate: any): void;
}
export function createComponent<T>(name: string, { template, style, state: defaultState, onStateChange, childStates, attrs, listeners, slots }: CONF<T>): typeof Lib0Component;
export function createComponentDefiner(definer: Function): () => any;
export function defineListComponent(): any;
export function defineLazyLoadingComponent(): any;
export type CONF<S> = {
/**
* Template for the shadow dom.
*/
template?: string | null | undefined;
/**
* shadow dom style. Is only used when
* `CONF.template` is defined
*/
style?: string | undefined;
/**
* Initial component state.
*/
state?: S | undefined;
/**
* Called when
* the state changes.
*/
onStateChange?: ((arg0: S, arg1: S | null, arg2: Lib0Component<S>) => void) | undefined;
/**
* maps from
* CSS-selector to transformer function. The first element that matches the
* CSS-selector receives state updates via the transformer function.
*/
childStates?: {
[x: string]: (arg0: any, arg1: any) => Object;
} | undefined;
/**
* attrs-keys and state-keys should be camelCase, but the DOM uses kebap-case. I.e.
* `attrs = { myAttr: 4 }` is represeted as `<my-elem my-attr="4" />` in the DOM
*/
attrs?: {
[x: string]: "string" | "number" | "json" | "bool";
} | undefined;
/**
* Maps from dom-event-name
* to event listener.
*/
listeners?: {
[x: string]: (arg0: CustomEvent, arg1: Lib0Component<any>) => boolean | void;
} | undefined;
/**
* Fill slots
* automatically when state changes. Maps from slot-name to slot-html.
*/
slots?: ((arg0: S, arg1: S, arg2: Lib0Component<S>) => {
[x: string]: string;
}) | undefined;
};
//# sourceMappingURL=component.d.ts.map

View File

@@ -1 +0,0 @@
{"version":3,"file":"component.d.ts","sourceRoot":"","sources":["component.js"],"names":[],"mappings":"AAiBA;;GAEG;AACH,uBAFU,qBAAqB,CAEO;AAO/B,6BAJI,MAAM,UACN,GAAG,SACH,wBAAwB,QAE8C;AAM1E,kCAHI,MAAM,GACL,OAAO,CAAC,wBAAwB,CAAC,CAEgB;AAM7D;;GAEG;AACH,2BAFa,CAAC;IAGZ;;OAEG;IACH,oBAFW,CAAC,EAYX;IARC;;OAEG;IACH,OAFU,CAAC,GAAC,IAAI,CAEuB;IACvC;;OAEG;IACH,WAFU,GAAG,CAEM;IAGrB;;;OAGG;IACH,iBAHW,CAAC,sBACD,OAAO,QAE4B;IAE9C;;QAEI;IACJ,0BAFY,GAAG,QAEe;CAC/B;AA6DM,gCALM,CAAC,QACH,MAAM,iGACN,IAAI,CAAC,CAAC,CAAC,GACN,OAAO,aAAa,CAuM/B;AAKM,qEAWN;AANQ,2CAKN;AALM,kDAKN;iBA9OU,CAAC;;;;;;;;;;;;;;;;;;4BAMS,CAAC,QAAC,CAAC,GAAC,IAAI,QAAC,aAAa,CAAC,CAAC,CAAC,KAAE,IAAI;;;;;;;4BAEjB,GAAG,QAAE,GAAG,KAAE,MAAM;;;;;;;;;;;;;;4BAMf,WAAW,QAAE,aAAa,CAAC,GAAG,CAAC,KAAE,OAAO,GAAC,IAAI;;;;;;oBAE5D,CAAC,QAAE,CAAC,QAAE,aAAa,CAAC,CAAC,CAAC"}

View File

@@ -1,414 +0,0 @@
/* eslint-env browser */
/**
* Web components.
*
* @module component
*/
import * as dom from './dom.js'
import * as diff from './diff.js'
import * as object from './object.js'
import * as json from './json.js'
import * as string from './string.js'
import * as array from './array.js'
import * as number from './number.js'
import * as func from './function.js'
/**
* @type {CustomElementRegistry}
*/
export const registry = customElements
/**
* @param {string} name
* @param {any} constr
* @param {ElementDefinitionOptions} [opts]
*/
export const define = (name, constr, opts) => registry.define(name, constr, opts)
/**
* @param {string} name
* @return {Promise<CustomElementConstructor>}
*/
export const whenDefined = name => registry.whenDefined(name)
const upgradedEventName = 'upgraded'
const connectedEventName = 'connected'
const disconnectedEventName = 'disconnected'
/**
* @template S
*/
export class Lib0Component extends HTMLElement {
/**
* @param {S} [state]
*/
constructor (state) {
super()
/**
* @type {S|null}
*/
this.state = /** @type {any} */ (state)
/**
* @type {any}
*/
this._internal = {}
}
/**
* @param {S} _state
* @param {boolean} [_forceStateUpdate] Force that the state is rerendered even if state didn't change
*/
setState (_state, _forceStateUpdate = true) {}
/**
* @param {any} _stateUpdate
*/
updateState (_stateUpdate) { }
}
/**
* @param {any} val
* @param {"json"|"string"|"number"} type
* @return {string}
*/
const encodeAttrVal = (val, type) => {
if (type === 'json') {
val = json.stringify(val)
}
return val + ''
}
/**
* @param {any} val
* @param {"json"|"string"|"number"|"bool"} type
* @return {any}
*/
const parseAttrVal = (val, type) => {
switch (type) {
case 'json':
return json.parse(val)
case 'number':
return Number.parseFloat(val)
case 'string':
return val
case 'bool':
return val != null
default:
return null
}
}
/**
* @template S
* @typedef {Object} CONF
* @property {string?} [CONF.template] Template for the shadow dom.
* @property {string} [CONF.style] shadow dom style. Is only used when
* `CONF.template` is defined
* @property {S} [CONF.state] Initial component state.
* @property {function(S,S|null,Lib0Component<S>):void} [CONF.onStateChange] Called when
* the state changes.
* @property {Object<string,function(any, any):Object>} [CONF.childStates] maps from
* CSS-selector to transformer function. The first element that matches the
* CSS-selector receives state updates via the transformer function.
* @property {Object<string,"json"|"number"|"string"|"bool">} [CONF.attrs]
* attrs-keys and state-keys should be camelCase, but the DOM uses kebap-case. I.e.
* `attrs = { myAttr: 4 }` is represeted as `<my-elem my-attr="4" />` in the DOM
* @property {Object<string, function(CustomEvent, Lib0Component<any>):boolean|void>} [CONF.listeners] Maps from dom-event-name
* to event listener.
* @property {function(S, S, Lib0Component<S>):Object<string,string>} [CONF.slots] Fill slots
* automatically when state changes. Maps from slot-name to slot-html.
*/
/**
* @template T
* @param {string} name
* @param {CONF<T>} cnf
* @return {typeof Lib0Component}
*/
export const createComponent = (name, { template, style = '', state: defaultState, onStateChange = () => {}, childStates = { }, attrs = {}, listeners = {}, slots = () => ({}) }) => {
/**
* Maps from camelCase attribute name to kebap-case attribute name.
* @type {Object<string,string>}
*/
const normalizedAttrs = {}
for (const key in attrs) {
normalizedAttrs[string.fromCamelCase(key, '-')] = key
}
const templateElement = template
? /** @type {HTMLTemplateElement} */ (dom.parseElement(`
<template>
<style>${style}</style>
${template}
</template>
`))
: null
class _Lib0Component extends HTMLElement {
/**
* @param {T} [state]
*/
constructor (state) {
super()
/**
* @type {Array<{d:Lib0Component<T>, s:function(any, any):Object}>}
*/
this._childStates = []
/**
* @type {Object<string,string>}
*/
this._slots = {}
this._init = false
/**
* @type {any}
*/
this._internal = {}
/**
* @type {any}
*/
this.state = state || null
this.connected = false
// init shadow dom
if (templateElement) {
const shadow = /** @type {ShadowRoot} */ (this.attachShadow({ mode: 'open' }))
shadow.appendChild(templateElement.content.cloneNode(true))
// fill child states
for (const key in childStates) {
this._childStates.push({
d: /** @type {Lib0Component<T>} */ (dom.querySelector(/** @type {any} */ (shadow), key)),
s: childStates[key]
})
}
}
dom.emitCustomEvent(this, upgradedEventName, { bubbles: true })
}
connectedCallback () {
this.connected = true
if (!this._init) {
this._init = true
const shadow = this.shadowRoot
if (shadow) {
dom.addEventListener(shadow, upgradedEventName, event => {
this.setState(this.state, true)
event.stopPropagation()
})
}
/**
* @type {Object<string, any>}
*/
const startState = this.state || object.assign({}, defaultState)
if (attrs) {
for (const key in attrs) {
const normalizedKey = string.fromCamelCase(key, '-')
const val = parseAttrVal(this.getAttribute(normalizedKey), attrs[key])
if (val) {
startState[key] = val
}
}
}
// add event listeners
for (const key in listeners) {
dom.addEventListener(shadow || this, key, event => {
if (listeners[key](/** @type {CustomEvent} */ (event), this) !== false) {
event.stopPropagation()
event.preventDefault()
return false
}
})
}
// first setState call
this.state = null
this.setState(startState)
}
dom.emitCustomEvent(/** @type {any} */ (this.shadowRoot || this), connectedEventName, { bubbles: true })
}
disconnectedCallback () {
this.connected = false
dom.emitCustomEvent(/** @type {any} */ (this.shadowRoot || this), disconnectedEventName, { bubbles: true })
this.setState(null)
}
static get observedAttributes () {
return object.keys(normalizedAttrs)
}
/**
* @param {string} name
* @param {string} oldVal
* @param {string} newVal
*
* @private
*/
attributeChangedCallback (name, oldVal, newVal) {
const curState = /** @type {any} */ (this.state)
const camelAttrName = normalizedAttrs[name]
const type = attrs[camelAttrName]
const parsedVal = parseAttrVal(newVal, type)
if (curState && (type !== 'json' || json.stringify(curState[camelAttrName]) !== newVal) && curState[camelAttrName] !== parsedVal && !number.isNaN(parsedVal)) {
this.updateState({ [camelAttrName]: parsedVal })
}
}
/**
* @param {any} stateUpdate
*/
updateState (stateUpdate) {
this.setState(object.assign({}, this.state, stateUpdate))
}
/**
* @param {any} state
*/
setState (state, forceStateUpdates = false) {
const prevState = this.state
this.state = state
if (this._init && (!func.equalityFlat(state, prevState) || forceStateUpdates)) {
// fill slots
if (state) {
const slotElems = slots(state, prevState, this)
for (const key in slotElems) {
const slotContent = slotElems[key]
if (this._slots[key] !== slotContent) {
this._slots[key] = slotContent
const currentSlots = /** @type {Array<any>} */ (key !== 'default' ? array.from(dom.querySelectorAll(this, `[slot="${key}"]`)) : array.from(this.childNodes).filter(/** @param {any} child */ child => !dom.checkNodeType(child, dom.ELEMENT_NODE) || !child.hasAttribute('slot')))
currentSlots.slice(1).map(dom.remove)
const nextSlot = dom.parseFragment(slotContent)
if (key !== 'default') {
array.from(nextSlot.children).forEach(c => c.setAttribute('slot', key))
}
if (currentSlots.length > 0) {
dom.replaceWith(currentSlots[0], nextSlot)
} else {
dom.appendChild(this, nextSlot)
}
}
}
}
onStateChange(state, prevState, this)
if (state != null) {
this._childStates.forEach(cnf => {
const d = cnf.d
if (d.updateState) {
d.updateState(cnf.s(state, this))
}
})
}
for (const key in attrs) {
const normalizedKey = string.fromCamelCase(key, '-')
if (state == null) {
this.removeAttribute(normalizedKey)
} else {
const stateVal = state[key]
const attrsType = attrs[key]
if (!prevState || prevState[key] !== stateVal) {
if (attrsType === 'bool') {
if (stateVal) {
this.setAttribute(normalizedKey, '')
} else {
this.removeAttribute(normalizedKey)
}
} else if (stateVal == null && (attrsType === 'string' || attrsType === 'number')) {
this.removeAttribute(normalizedKey)
} else {
this.setAttribute(normalizedKey, encodeAttrVal(stateVal, attrsType))
}
}
}
}
}
}
}
define(name, _Lib0Component)
// @ts-ignore
return _Lib0Component
}
/**
* @param {function} definer function that defines a component when executed
*/
export const createComponentDefiner = definer => {
/**
* @type {any}
*/
let defined = null
return () => {
if (!defined) {
defined = definer()
}
return defined
}
}
export const defineListComponent = createComponentDefiner(() => {
const ListItem = createComponent('lib0-list-item', {
template: '<slot name="content"></slot>',
slots: state => ({
content: `<div>${state}</div>`
})
})
return createComponent('lib0-list', {
state: { list: /** @type {Array<string>} */ ([]), Item: ListItem },
onStateChange: (state, prevState, component) => {
if (state == null) {
return
}
const { list = /** @type {Array<any>} */ ([]), Item = ListItem } = state
// @todo deep compare here by providing another parameter to simpleDiffArray
let { index, remove, insert } = diff.simpleDiffArray(prevState ? prevState.list : [], list, func.equalityFlat)
if (remove === 0 && insert.length === 0) {
return
}
let child = /** @type {Lib0Component<any>} */ (component.firstChild)
while (index-- > 0) {
child = /** @type {Lib0Component<any>} */ (child.nextElementSibling)
}
let insertStart = 0
while (insertStart < insert.length && remove-- > 0) {
// update existing state
child.setState(insert[insertStart++])
child = /** @type {Lib0Component<any>} */ (child.nextElementSibling)
}
while (remove-- > 0) {
// remove remaining
const prevChild = child
child = /** @type {Lib0Component<any>} */ (child.nextElementSibling)
component.removeChild(prevChild)
}
// insert remaining
component.insertBefore(dom.fragment(insert.slice(insertStart).map(/** @param {any} insState */ insState => {
const el = new Item()
el.setState(insState)
return el
})), child)
}
})
})
export const defineLazyLoadingComponent = createComponentDefiner(() => createComponent('lib0-lazy', {
state: /** @type {{component:null|String,import:null|function():Promise<any>,state:null|object}} */ ({
component: null, import: null, state: null
}),
attrs: {
component: 'string'
},
onStateChange: ({ component, state, import: getImport }, prevState, componentEl) => {
if (component !== null) {
if (getImport) {
getImport()
}
if (!prevState || component !== prevState.component) {
const el = /** @type {any} */ (dom.createElement(component))
componentEl.innerHTML = ''
componentEl.insertBefore(el, null)
}
const el = /** @type {any} */ (componentEl.firstElementChild)
// @todo generalize setting state and check if setState is defined
if (el.setState) {
el.setState(state)
}
}
}
}))

View File

@@ -1,2 +0,0 @@
export function undefinedToNull<T>(v: T | null | undefined): T | null;
//# sourceMappingURL=conditions.d.ts.map

View File

@@ -1 +0,0 @@
{"version":3,"file":"conditions.d.ts","sourceRoot":"","sources":["conditions.js"],"names":[],"mappings":"AAYO,gCALM,CAAC,KACH,CAAC,GAAC,IAAI,GAAC,SAAS,GACf,CAAC,GAAC,IAAI,CAG4C"}

View File

@@ -1,13 +0,0 @@
/**
* Often used conditions.
*
* @module conditions
*/
/**
* @template T
* @param {T|null|undefined} v
* @return {T|null}
*/
/* c8 ignore next */
export const undefinedToNull = v => v === undefined ? null : v

File diff suppressed because one or more lines are too long

View File

@@ -1,9 +0,0 @@
export function testJwt(_tc: t.TestCase): Promise<void>;
export function testEncryption(tc: t.TestCase): Promise<void>;
export function testReapeatEncryption(tc: t.TestCase): Promise<void>;
export function testImportExport(tc: t.TestCase): Promise<void>;
export function testEncryptionPerformance(tc: t.TestCase): Promise<void>;
export function testConsistentKeyGeneration(_tc: t.TestCase): Promise<void>;
export function testSigning(tc: t.TestCase): Promise<void>;
import * as t from './testing.js';
//# sourceMappingURL=crypto.test.d.ts.map

View File

@@ -1 +0,0 @@
{"version":3,"file":"crypto.test.d.ts","sourceRoot":"","sources":["crypto.test.js"],"names":[],"mappings":"AAYO,6BAFI,CAAC,CAAC,QAAQ,iBA8BpB;AAKM,mCAFI,CAAC,CAAC,QAAQ,iBAoCpB;AAKM,0CAFI,CAAC,CAAC,QAAQ,iBA8BpB;AAKM,qCAFI,CAAC,CAAC,QAAQ,iBAgDpB;AAKM,8CAFI,CAAC,CAAC,QAAQ,iBAwCpB;AAKM,iDAFI,CAAC,CAAC,QAAQ,iBA2EpB;AAKM,gCAFI,CAAC,CAAC,QAAQ,iBAapB;mBAvSkB,cAAc"}

View File

@@ -1,17 +0,0 @@
export function encrypt(key: CryptoKey, data: Uint8Array<ArrayBuffer>): Promise<Uint8Array<ArrayBuffer>>;
export function decrypt(key: CryptoKey, data: Uint8Array<ArrayBuffer>): PromiseLike<Uint8Array>;
export function importKeyJwk(jwk: any, { usages, extractable }?: {
usages?: Usages | undefined;
extractable?: boolean | undefined;
}): Promise<CryptoKey>;
export function importKeyRaw(raw: Uint8Array<ArrayBuffer>, { usages, extractable }?: {
usages?: Usages | undefined;
extractable?: boolean | undefined;
}): Promise<CryptoKey>;
export function deriveKey(secret: Uint8Array<ArrayBuffer> | string, salt: Uint8Array<ArrayBuffer> | string, { extractable, usages }?: {
extractable?: boolean | undefined;
usages?: Usages | undefined;
}): Promise<CryptoKey>;
export type Usages = Array<"encrypt" | "decrypt">;
export { exportKeyJwk, exportKeyRaw } from "./common.js";
//# sourceMappingURL=aes-gcm.d.ts.map

View File

@@ -1 +0,0 @@
{"version":3,"file":"aes-gcm.d.ts","sourceRoot":"","sources":["aes-gcm.js"],"names":[],"mappings":"AAuBO,6BAHI,SAAS,QACT,UAAU,CAAC,WAAW,CAAC,oCAkBjC;AAWM,6BAJI,SAAS,QACT,UAAU,CAAC,WAAW,CAAC,GACtB,WAAW,CAAC,UAAU,CAAC,CAclC;AAaM,kCALI,GAAG,4BAEX;IAAsB,MAAM;IACL,WAAW;CAAC,sBAQrC;AAUM,kCALI,UAAU,CAAC,WAAW,CAAC,4BAE/B;IAAsB,MAAM;IACL,WAAW;CAAC,sBAG0D;AAmBzF,kCANI,UAAU,CAAC,WAAW,CAAC,GAAC,MAAM,QAC9B,UAAU,CAAC,WAAW,CAAC,GAAC,MAAM,4BAEtC;IAAuB,WAAW;IACZ,MAAM;CAAC,sBAsB7B;qBAxHU,KAAK,CAAC,SAAS,GAAC,SAAS,CAAC"}

View File

@@ -1,132 +0,0 @@
/**
* AES-GCM is a symmetric key for encryption
*/
import * as encoding from '../encoding.js'
import * as decoding from '../decoding.js'
import * as webcrypto from 'lib0/webcrypto'
import * as string from '../string.js'
export { exportKeyJwk, exportKeyRaw } from './common.js'
/**
* @typedef {Array<'encrypt'|'decrypt'>} Usages
*/
/**
* @type {Usages}
*/
const defaultUsages = ['encrypt', 'decrypt']
/**
* @param {CryptoKey} key
* @param {Uint8Array<ArrayBuffer>} data
*/
export const encrypt = (key, data) => {
const iv = webcrypto.getRandomValues(new Uint8Array(16)) // 92bit is enough. 128bit is recommended if space is not an issue.
return webcrypto.subtle.encrypt(
{
name: 'AES-GCM',
iv
},
key,
data
).then(cipher => {
const encryptedDataEncoder = encoding.createEncoder()
// iv may be sent in the clear to the other peers
encoding.writeUint8Array(encryptedDataEncoder, iv)
encoding.writeVarUint8Array(encryptedDataEncoder, new Uint8Array(cipher))
return encoding.toUint8Array(encryptedDataEncoder)
})
}
/**
* @experimental The API is not final!
*
* Decrypt some data using AES-GCM method.
*
* @param {CryptoKey} key
* @param {Uint8Array<ArrayBuffer>} data
* @return {PromiseLike<Uint8Array>} decrypted buffer
*/
export const decrypt = (key, data) => {
const dataDecoder = decoding.createDecoder(data)
const iv = decoding.readUint8Array(dataDecoder, 16)
const cipher = decoding.readVarUint8Array(dataDecoder)
return webcrypto.subtle.decrypt(
{
name: 'AES-GCM',
iv
},
key,
cipher
).then(data => new Uint8Array(data))
}
const aesAlgDef = {
name: 'AES-GCM',
length: 256
}
/**
* @param {any} jwk
* @param {Object} opts
* @param {Usages} [opts.usages]
* @param {boolean} [opts.extractable]
*/
export const importKeyJwk = (jwk, { usages, extractable = false } = {}) => {
if (usages == null) {
/* c8 ignore next */
usages = jwk.key_ops || defaultUsages
}
return webcrypto.subtle.importKey('jwk', jwk, 'AES-GCM', extractable, /** @type {Usages} */ (usages))
}
/**
* Only suited for importing public keys.
*
* @param {Uint8Array<ArrayBuffer>} raw
* @param {Object} opts
* @param {Usages} [opts.usages]
* @param {boolean} [opts.extractable]
*/
export const importKeyRaw = (raw, { usages = defaultUsages, extractable = false } = {}) =>
webcrypto.subtle.importKey('raw', raw, aesAlgDef, extractable, /** @type {Usages} */ (usages))
/**
* @param {Uint8Array<ArrayBuffer> | string} data
*/
/* c8 ignore next */
const toBinary = data => typeof data === 'string' ? string.encodeUtf8(data) : data
/**
* @experimental The API is not final!
*
* Derive an symmetric key using the Password-Based-Key-Derivation-Function-2.
*
* @param {Uint8Array<ArrayBuffer>|string} secret
* @param {Uint8Array<ArrayBuffer>|string} salt
* @param {Object} opts
* @param {boolean} [opts.extractable]
* @param {Usages} [opts.usages]
*/
export const deriveKey = (secret, salt, { extractable = false, usages = defaultUsages } = {}) =>
webcrypto.subtle.importKey(
'raw',
toBinary(secret),
'PBKDF2',
false,
['deriveKey']
).then(keyMaterial =>
webcrypto.subtle.deriveKey(
{
name: 'PBKDF2',
salt: toBinary(salt), // NIST recommends at least 64 bits
iterations: 600000, // OWASP recommends 600k iterations
hash: 'SHA-256'
},
keyMaterial,
aesAlgDef,
extractable,
usages
)
)

View File

@@ -1,3 +0,0 @@
export function exportKeyJwk(key: CryptoKey): Promise<JsonWebKey>;
export function exportKeyRaw(key: CryptoKey): Promise<Uint8Array<ArrayBuffer>>;
//# sourceMappingURL=common.d.ts.map

View File

@@ -1 +0,0 @@
{"version":3,"file":"common.d.ts","sourceRoot":"","sources":["common.js"],"names":[],"mappings":"AAKO,kCAFI,SAAS,uBAMnB;AAQM,kCAHI,SAAS,GACR,OAAO,CAAC,UAAU,CAAC,WAAW,CAAC,CAAC,CAG6B"}

View File

@@ -1,19 +0,0 @@
import * as webcrypto from 'lib0/webcrypto'
/**
* @param {CryptoKey} key
*/
export const exportKeyJwk = async key => {
const jwk = await webcrypto.subtle.exportKey('jwk', key)
jwk.key_ops = key.usages
return jwk
}
/**
* Only suited for exporting public keys.
*
* @param {CryptoKey} key
* @return {Promise<Uint8Array<ArrayBuffer>>}
*/
export const exportKeyRaw = key =>
webcrypto.subtle.exportKey('raw', key).then(key => new Uint8Array(key))

View File

@@ -1,17 +0,0 @@
export function sign(key: CryptoKey, data: Uint8Array<ArrayBuffer>): PromiseLike<Uint8Array<ArrayBuffer>>;
export function verify(key: CryptoKey, signature: Uint8Array<ArrayBuffer>, data: Uint8Array<ArrayBuffer>): PromiseLike<boolean>;
export function generateKeyPair({ extractable, usages }?: {
extractable?: boolean | undefined;
usages?: Usages | undefined;
}): Promise<CryptoKeyPair>;
export function importKeyJwk(jwk: any, { extractable, usages }?: {
extractable?: boolean | undefined;
usages?: Usages | undefined;
}): Promise<CryptoKey>;
export function importKeyRaw(raw: any, { extractable, usages }?: {
extractable?: boolean | undefined;
usages?: Usages | undefined;
}): Promise<CryptoKey>;
export type Usages = Array<"sign" | "verify">;
export { exportKeyJwk, exportKeyRaw } from "./common.js";
//# sourceMappingURL=ecdsa.d.ts.map

View File

@@ -1 +0,0 @@
{"version":3,"file":"ecdsa.d.ts","sourceRoot":"","sources":["ecdsa.js"],"names":[],"mappings":"AA8BO,0BAJI,SAAS,QACT,UAAU,CAAC,WAAW,CAAC,GACtB,WAAW,CAAC,UAAU,CAAC,WAAW,CAAC,CAAC,CAOA;AAYzC,4BALI,SAAS,aACT,UAAU,CAAC,WAAW,CAAC,QACvB,UAAU,CAAC,WAAW,CAAC,GACtB,WAAW,CAAC,OAAO,CAAC,CAQ7B;AAaI,0DAHJ;IAAuB,WAAW;IACZ,MAAM;CAAC,0BAO7B;AAQI,kCALI,GAAG,4BAEX;IAAuB,WAAW;IACZ,MAAM;CAAC,sBAQ/B;AAUM,kCALI,GAAG,4BAEX;IAAuB,WAAW;IACZ,MAAM;CAAC,sBAGkD;qBAxFrE,KAAK,CAAC,MAAM,GAAC,QAAQ,CAAC"}

View File

@@ -1,97 +0,0 @@
/**
* ECDSA is an asymmetric key for signing
*/
import * as webcrypto from 'lib0/webcrypto'
export { exportKeyJwk, exportKeyRaw } from './common.js'
/**
* @typedef {Array<'sign'|'verify'>} Usages
*/
/**
* @type {Usages}
*/
const defaultUsages = ['sign', 'verify']
const defaultSignAlgorithm = {
name: 'ECDSA',
hash: 'SHA-384'
}
/**
* @experimental The API is not final!
*
* Sign a message
*
* @param {CryptoKey} key
* @param {Uint8Array<ArrayBuffer>} data
* @return {PromiseLike<Uint8Array<ArrayBuffer>>} signature
*/
export const sign = (key, data) =>
webcrypto.subtle.sign(
defaultSignAlgorithm,
key,
data
).then(signature => new Uint8Array(signature))
/**
* @experimental The API is not final!
*
* Sign a message
*
* @param {CryptoKey} key
* @param {Uint8Array<ArrayBuffer>} signature
* @param {Uint8Array<ArrayBuffer>} data
* @return {PromiseLike<boolean>} signature
*/
export const verify = (key, signature, data) =>
webcrypto.subtle.verify(
defaultSignAlgorithm,
key,
signature,
data
)
const defaultKeyAlgorithm = {
name: 'ECDSA',
namedCurve: 'P-384'
}
/* c8 ignore next */
/**
* @param {Object} opts
* @param {boolean} [opts.extractable]
* @param {Usages} [opts.usages]
*/
export const generateKeyPair = ({ extractable = false, usages = defaultUsages } = {}) =>
webcrypto.subtle.generateKey(
defaultKeyAlgorithm,
extractable,
usages
)
/**
* @param {any} jwk
* @param {Object} opts
* @param {boolean} [opts.extractable]
* @param {Usages} [opts.usages]
*/
export const importKeyJwk = (jwk, { extractable = false, usages } = {}) => {
if (usages == null) {
/* c8 ignore next 2 */
usages = jwk.key_ops || defaultUsages
}
return webcrypto.subtle.importKey('jwk', jwk, defaultKeyAlgorithm, extractable, /** @type {Usages} */ (usages))
}
/**
* Only suited for importing public keys.
*
* @param {any} raw
* @param {Object} opts
* @param {boolean} [opts.extractable]
* @param {Usages} [opts.usages]
*/
export const importKeyRaw = (raw, { extractable = false, usages = defaultUsages } = {}) =>
webcrypto.subtle.importKey('raw', raw, defaultKeyAlgorithm, extractable, usages)

View File

@@ -1,10 +0,0 @@
export function encodeJwt(privateKey: CryptoKey, payload: Object): PromiseLike<string>;
export function verifyJwt(publicKey: CryptoKey, jwt: string): Promise<{
header: any;
payload: any;
}>;
export function unsafeDecode(jwt: string): {
header: any;
payload: any;
};
//# sourceMappingURL=jwt.d.ts.map

View File

@@ -1 +0,0 @@
{"version":3,"file":"jwt.d.ts","sourceRoot":"","sources":["jwt.js"],"names":[],"mappings":"AAqBO,sCAHI,SAAS,WACT,MAAM,uBAgBhB;AAMM,qCAHI,SAAS,OACT,MAAM;;;GAiBhB;AAOM,kCAFI,MAAM;;;EAQhB"}

View File

@@ -1,70 +0,0 @@
import * as error from '../error.js'
import * as buffer from '../buffer.js'
import * as string from '../string.js'
import * as json from '../json.js'
import * as ecdsa from '../crypto/ecdsa.js'
import * as time from '../time.js'
/**
* @param {Object} data
*/
const _stringify = data => buffer.toBase64UrlEncoded(string.encodeUtf8(json.stringify(data)))
/**
* @param {string} base64url
*/
const _parse = base64url => json.parse(string.decodeUtf8(buffer.fromBase64UrlEncoded(base64url)))
/**
* @param {CryptoKey} privateKey
* @param {Object} payload
*/
export const encodeJwt = (privateKey, payload) => {
const { name: algName, namedCurve: algCurve } = /** @type {any} */ (privateKey.algorithm)
/* c8 ignore next 3 */
if (algName !== 'ECDSA' || algCurve !== 'P-384') {
error.unexpectedCase()
}
const header = {
alg: 'ES384',
typ: 'JWT'
}
const jwt = _stringify(header) + '.' + _stringify(payload)
return ecdsa.sign(privateKey, string.encodeUtf8(jwt)).then(signature =>
jwt + '.' + buffer.toBase64UrlEncoded(signature)
)
}
/**
* @param {CryptoKey} publicKey
* @param {string} jwt
*/
export const verifyJwt = async (publicKey, jwt) => {
const [headerBase64, payloadBase64, signatureBase64] = jwt.split('.')
const verified = await ecdsa.verify(publicKey, buffer.fromBase64UrlEncoded(signatureBase64), string.encodeUtf8(headerBase64 + '.' + payloadBase64))
/* c8 ignore next 3 */
if (!verified) {
throw new Error('Invalid JWT')
}
const payload = _parse(payloadBase64)
if (payload.exp != null && time.getUnixTime() > payload.exp) {
throw new Error('Expired JWT')
}
return {
header: _parse(headerBase64),
payload
}
}
/**
* Decode a jwt without verifying it. Probably a bad idea to use this. Only use if you know the jwt was already verified!
*
* @param {string} jwt
*/
export const unsafeDecode = jwt => {
const [headerBase64, payloadBase64] = jwt.split('.')
return {
header: _parse(headerBase64),
payload: _parse(payloadBase64)
}
}

View File

@@ -1,13 +0,0 @@
export { exportKeyJwk } from "./common.js";
export function encrypt(key: CryptoKey, data: Uint8Array<ArrayBuffer>): PromiseLike<Uint8Array<ArrayBuffer>>;
export function decrypt(key: CryptoKey, data: Uint8Array<ArrayBuffer>): PromiseLike<Uint8Array>;
export function generateKeyPair({ extractable, usages }?: {
extractable?: boolean | undefined;
usages?: Usages | undefined;
}): Promise<CryptoKeyPair>;
export function importKeyJwk(jwk: any, { extractable, usages }?: {
extractable?: boolean | undefined;
usages?: Usages | undefined;
}): Promise<CryptoKey>;
export type Usages = Array<"encrypt" | "decrypt">;
//# sourceMappingURL=rsa-oaep.d.ts.map

View File

@@ -1 +0,0 @@
{"version":3,"file":"rsa-oaep.d.ts","sourceRoot":"","sources":["rsa-oaep.js"],"names":[],"mappings":";AAuBO,6BAJI,SAAS,QACT,UAAU,CAAC,WAAW,CAAC,GACtB,WAAW,CAAC,UAAU,CAAC,WAAW,CAAC,CAAC,CASZ;AAW7B,6BAJI,SAAS,QACT,UAAU,CAAC,WAAW,CAAC,GACtB,WAAW,CAAC,UAAU,CAAC,CASG;AAQ/B,0DAJJ;IAAuB,WAAW;IACZ,MAAM;CAC5B,GAAS,OAAO,CAAC,aAAa,CAAC,CAY/B;AAQI,kCALI,GAAG,4BAEX;IAAuB,WAAW;IACZ,MAAM;CAAC,sBAQ/B;qBAxEY,KAAK,CAAC,SAAS,GAAC,SAAS,CAAC"}

View File

@@ -1,81 +0,0 @@
/**
* RSA-OAEP is an asymmetric keypair used for encryption
*/
import * as webcrypto from 'lib0/webcrypto'
export { exportKeyJwk } from './common.js'
/**
* @typedef {Array<'encrypt'|'decrypt'>} Usages
*/
/**
* @type {Usages}
*/
const defaultUsages = ['encrypt', 'decrypt']
/**
* Note that the max data size is limited by the size of the RSA key.
*
* @param {CryptoKey} key
* @param {Uint8Array<ArrayBuffer>} data
* @return {PromiseLike<Uint8Array<ArrayBuffer>>}
*/
export const encrypt = (key, data) =>
webcrypto.subtle.encrypt(
{
name: 'RSA-OAEP'
},
key,
data
).then(buf => new Uint8Array(buf))
/**
* @experimental The API is not final!
*
* Decrypt some data using AES-GCM method.
*
* @param {CryptoKey} key
* @param {Uint8Array<ArrayBuffer>} data
* @return {PromiseLike<Uint8Array>} decrypted buffer
*/
export const decrypt = (key, data) =>
webcrypto.subtle.decrypt(
{
name: 'RSA-OAEP'
},
key,
data
).then(data => new Uint8Array(data))
/**
* @param {Object} opts
* @param {boolean} [opts.extractable]
* @param {Usages} [opts.usages]
* @return {Promise<CryptoKeyPair>}
*/
export const generateKeyPair = ({ extractable = false, usages = defaultUsages } = {}) =>
webcrypto.subtle.generateKey(
{
name: 'RSA-OAEP',
modulusLength: 4096,
publicExponent: new Uint8Array([1, 0, 1]),
hash: 'SHA-256'
},
extractable,
usages
)
/**
* @param {any} jwk
* @param {Object} opts
* @param {boolean} [opts.extractable]
* @param {Usages} [opts.usages]
*/
export const importKeyJwk = (jwk, { extractable = false, usages } = {}) => {
if (usages == null) {
/* c8 ignore next */
usages = jwk.key_ops || defaultUsages
}
return webcrypto.subtle.importKey('jwk', jwk, { name: 'RSA-OAEP', hash: 'SHA-256' }, extractable, /** @type {Usages} */ (usages))
}

View File

@@ -1,165 +0,0 @@
/**
* A Decoder handles the decoding of an Uint8Array.
* @template {ArrayBufferLike} [Buf=ArrayBufferLike]
*/
export class Decoder<Buf extends ArrayBufferLike = ArrayBufferLike> {
/**
* @param {Uint8Array<Buf>} uint8Array Binary data to decode
*/
constructor(uint8Array: Uint8Array<Buf>);
/**
* Decoding target.
*
* @type {Uint8Array<Buf>}
*/
arr: Uint8Array<Buf>;
/**
* Current decoding position.
*
* @type {number}
*/
pos: number;
}
export function createDecoder<Buf extends ArrayBufferLike>(uint8Array: Uint8Array<Buf>): Decoder<Buf>;
export function hasContent(decoder: Decoder): boolean;
export function clone(decoder: Decoder, newPos?: number): Decoder;
export function readUint8Array<Buf extends ArrayBufferLike>(decoder: Decoder<Buf>, len: number): Uint8Array<Buf>;
export function readVarUint8Array<Buf extends ArrayBufferLike>(decoder: Decoder<Buf>): Uint8Array<Buf>;
export function readTailAsUint8Array(decoder: Decoder): Uint8Array;
export function skip8(decoder: Decoder): number;
export function readUint8(decoder: Decoder): number;
export function readUint16(decoder: Decoder): number;
export function readUint32(decoder: Decoder): number;
export function readUint32BigEndian(decoder: Decoder): number;
export function peekUint8(decoder: Decoder): number;
export function peekUint16(decoder: Decoder): number;
export function peekUint32(decoder: Decoder): number;
export function readVarUint(decoder: Decoder): number;
export function readVarInt(decoder: Decoder): number;
export function peekVarUint(decoder: Decoder): number;
export function peekVarInt(decoder: Decoder): number;
export function _readVarStringPolyfill(decoder: Decoder): string;
export function _readVarStringNative(decoder: Decoder): string;
export function readVarString(decoder: Decoder): string;
export function readTerminatedUint8Array(decoder: Decoder): Uint8Array;
export function readTerminatedString(decoder: Decoder): string;
export function peekVarString(decoder: Decoder): string;
export function readFromDataView(decoder: Decoder, len: number): DataView;
export function readFloat32(decoder: Decoder): number;
export function readFloat64(decoder: Decoder): number;
export function readBigInt64(decoder: Decoder): any;
export function readBigUint64(decoder: Decoder): any;
export function readAny(decoder: Decoder): any;
/**
* T must not be null.
*
* @template T
*/
export class RleDecoder<T> extends Decoder<ArrayBufferLike> {
/**
* @param {Uint8Array} uint8Array
* @param {function(Decoder):T} reader
*/
constructor(uint8Array: Uint8Array, reader: (arg0: Decoder) => T);
/**
* The reader
*/
reader: (arg0: Decoder) => T;
/**
* Current state
* @type {T|null}
*/
s: T | null;
count: number;
read(): T;
}
export class IntDiffDecoder extends Decoder<ArrayBufferLike> {
/**
* @param {Uint8Array} uint8Array
* @param {number} start
*/
constructor(uint8Array: Uint8Array, start: number);
/**
* Current state
* @type {number}
*/
s: number;
/**
* @return {number}
*/
read(): number;
}
export class RleIntDiffDecoder extends Decoder<ArrayBufferLike> {
/**
* @param {Uint8Array} uint8Array
* @param {number} start
*/
constructor(uint8Array: Uint8Array, start: number);
/**
* Current state
* @type {number}
*/
s: number;
count: number;
/**
* @return {number}
*/
read(): number;
}
export class UintOptRleDecoder extends Decoder<ArrayBufferLike> {
/**
* @param {Uint8Array} uint8Array
*/
constructor(uint8Array: Uint8Array);
/**
* @type {number}
*/
s: number;
count: number;
read(): number;
}
export class IncUintOptRleDecoder extends Decoder<ArrayBufferLike> {
/**
* @param {Uint8Array} uint8Array
*/
constructor(uint8Array: Uint8Array);
/**
* @type {number}
*/
s: number;
count: number;
read(): number;
}
export class IntDiffOptRleDecoder extends Decoder<ArrayBufferLike> {
/**
* @param {Uint8Array} uint8Array
*/
constructor(uint8Array: Uint8Array);
/**
* @type {number}
*/
s: number;
count: number;
diff: number;
/**
* @return {number}
*/
read(): number;
}
export class StringDecoder {
/**
* @param {Uint8Array} uint8Array
*/
constructor(uint8Array: Uint8Array);
decoder: UintOptRleDecoder;
str: string;
/**
* @type {number}
*/
spos: number;
/**
* @return {string}
*/
read(): string;
}
//# sourceMappingURL=decoding.d.ts.map

View File

@@ -1 +0,0 @@
{"version":3,"file":"decoding.d.ts","sourceRoot":"","sources":["decoding.js"],"names":[],"mappings":"AAsCA;;;GAGG;AACH,qBAFgC,GAAG,SAArB,eAAgB;IAG5B;;OAEG;IACH,wBAFW,UAAU,CAAC,GAAG,CAAC,EAezB;IAZC;;;;OAIG;IACH,KAFU,UAAU,CAAC,GAAG,CAAC,CAEJ;IACrB;;;;OAIG;IACH,KAFU,MAAM,CAEJ;CAEf;AAQM,8BAJwB,GAAG,SAApB,eAAgB,cACnB,UAAU,CAAC,GAAG,CAAC,GACd,OAAO,CAAC,GAAG,CAAC,CAE0C;AAO3D,oCAHI,OAAO,GACN,OAAO,CAEoD;AAWhE,+BAJI,OAAO,WACP,MAAM,GACL,OAAO,CAMlB;AAcM,+BALwB,GAAG,SAApB,eAAgB,WACnB,OAAO,CAAC,GAAG,CAAC,OACZ,MAAM,GACL,UAAU,CAAC,GAAG,CAAC,CAM1B;AAaM,kCAJwB,GAAG,SAApB,eAAgB,WACnB,OAAO,CAAC,GAAG,CAAC,GACX,UAAU,CAAC,GAAG,CAAC,CAE8D;AAQlF,8CAHI,OAAO,GACN,UAAU,CAEkF;AAQjG,+BAHI,OAAO,GACN,MAAM,CAE2B;AAQtC,mCAHI,OAAO,GACN,MAAM,CAE4C;AASvD,oCAHI,OAAO,GACN,MAAM,CAQjB;AASM,oCAHI,OAAO,GACN,MAAM,CAUjB;AAUM,6CAHI,OAAO,GACN,MAAM,CAUjB;AAUM,mCAHI,OAAO,GACN,MAAM,CAE0C;AAUrD,oCAHI,OAAO,GACN,MAAM,CAImB;AAU9B,oCAHI,OAAO,GACN,MAAM,CAOX;AAYA,qCAHI,OAAO,GACN,MAAM,CAqBjB;AAaM,oCAHI,OAAO,GACN,MAAM,CA2BjB;AASM,qCAHI,OAAO,GACN,MAAM,CAOjB;AASM,oCAHI,OAAO,GACN,MAAM,CAOjB;AAgBM,gDAJI,OAAO,UA2BjB;AAQM,8CAHI,OAAO,UAI4D;AAhCvE,uCAJI,OAAO,UA2BjB;AA2BM,kDAHI,OAAO,GACN,UAAU,CAerB;AAMM,8CAHI,OAAO,GACN,MAAM,CAEiF;AAS5F,uCAHI,OAAO,GACN,MAAM,CAOjB;AAOM,0CAJI,OAAO,OACP,MAAM,GACL,QAAQ,CAMnB;AAKM,qCAFI,OAAO,UAEqE;AAKhF,qCAFI,OAAO,UAEqE;AAKhF,sCAFI,OAAO,OAE4F;AAKvG,uCAFI,OAAO,OAE8F;AAyCzG,iCAFI,OAAO,OAEqE;AAEvF;;;;GAIG;AACH,wBAFa,CAAC;IAGZ;;;OAGG;IACH,wBAHW,UAAU,UACV,CAAS,IAAO,EAAP,OAAO,KAAE,CAAC,EAc7B;IAVC;;OAEG;IACH,eAPkB,OAAO,KAAE,CAAC,CAOR;IACpB;;;OAGG;IACH,GAFU,CAAC,GAAC,IAAI,CAEH;IACb,cAAc;IAGhB,QAUoB,CAAC,CACpB;CACF;AAED;IACE;;;OAGG;IACH,wBAHW,UAAU,SACV,MAAM,EAShB;IALC;;;OAGG;IACH,GAFU,MAAM,CAEF;IAGhB;;OAEG;IACH,QAFY,MAAM,CAKjB;CACF;AAED;IACE;;;OAGG;IACH,wBAHW,UAAU,SACV,MAAM,EAUhB;IANC;;;OAGG;IACH,GAFU,MAAM,CAEF;IACd,cAAc;IAGhB;;OAEG;IACH,QAFY,MAAM,CAajB;CACF;AAED;IACE;;OAEG;IACH,wBAFW,UAAU,EASpB;IALC;;OAEG;IACH,GAFU,MAAM,CAEN;IACV,cAAc;IAGhB,QAYoB,MAAM,CACzB;CACF;AAED;IACE;;OAEG;IACH,wBAFW,UAAU,EASpB;IALC;;OAEG;IACH,GAFU,MAAM,CAEN;IACV,cAAc;IAGhB,QAYoB,MAAM,CACzB;CACF;AAED;IACE;;OAEG;IACH,wBAFW,UAAU,EAUpB;IANC;;OAEG;IACH,GAFU,MAAM,CAEN;IACV,cAAc;IACd,aAAa;IAGf;;OAEG;IACH,QAFY,MAAM,CAgBjB;CACF;AAED;IACE;;OAEG;IACH,wBAFW,UAAU,EASpB;IANC,2BAAgD;IAChD,YAAsC;IACtC;;OAEG;IACH,MAFU,MAAM,CAEH;IAGf;;OAEG;IACH,QAFY,MAAM,CAOjB;CACF"}

View File

@@ -1,710 +0,0 @@
/**
* Efficient schema-less binary decoding with support for variable length encoding.
*
* Use [lib0/decoding] with [lib0/encoding]. Every encoding function has a corresponding decoding function.
*
* Encodes numbers in little-endian order (least to most significant byte order)
* and is compatible with Golang's binary encoding (https://golang.org/pkg/encoding/binary/)
* which is also used in Protocol Buffers.
*
* ```js
* // encoding step
* const encoder = encoding.createEncoder()
* encoding.writeVarUint(encoder, 256)
* encoding.writeVarString(encoder, 'Hello world!')
* const buf = encoding.toUint8Array(encoder)
* ```
*
* ```js
* // decoding step
* const decoder = decoding.createDecoder(buf)
* decoding.readVarUint(decoder) // => 256
* decoding.readVarString(decoder) // => 'Hello world!'
* decoding.hasContent(decoder) // => false - all data is read
* ```
*
* @module decoding
*/
import * as binary from './binary.js'
import * as math from './math.js'
import * as number from './number.js'
import * as string from './string.js'
import * as error from './error.js'
import * as encoding from './encoding.js'
const errorUnexpectedEndOfArray = error.create('Unexpected end of array')
const errorIntegerOutOfRange = error.create('Integer out of Range')
/**
* A Decoder handles the decoding of an Uint8Array.
* @template {ArrayBufferLike} [Buf=ArrayBufferLike]
*/
export class Decoder {
/**
* @param {Uint8Array<Buf>} uint8Array Binary data to decode
*/
constructor (uint8Array) {
/**
* Decoding target.
*
* @type {Uint8Array<Buf>}
*/
this.arr = uint8Array
/**
* Current decoding position.
*
* @type {number}
*/
this.pos = 0
}
}
/**
* @function
* @template {ArrayBufferLike} Buf
* @param {Uint8Array<Buf>} uint8Array
* @return {Decoder<Buf>}
*/
export const createDecoder = uint8Array => new Decoder(uint8Array)
/**
* @function
* @param {Decoder} decoder
* @return {boolean}
*/
export const hasContent = decoder => decoder.pos !== decoder.arr.length
/**
* Clone a decoder instance.
* Optionally set a new position parameter.
*
* @function
* @param {Decoder} decoder The decoder instance
* @param {number} [newPos] Defaults to current position
* @return {Decoder} A clone of `decoder`
*/
export const clone = (decoder, newPos = decoder.pos) => {
const _decoder = createDecoder(decoder.arr)
_decoder.pos = newPos
return _decoder
}
/**
* Create an Uint8Array view of the next `len` bytes and advance the position by `len`.
*
* Important: The Uint8Array still points to the underlying ArrayBuffer. Make sure to discard the result as soon as possible to prevent any memory leaks.
* Use `buffer.copyUint8Array` to copy the result into a new Uint8Array.
*
* @function
* @template {ArrayBufferLike} Buf
* @param {Decoder<Buf>} decoder The decoder instance
* @param {number} len The length of bytes to read
* @return {Uint8Array<Buf>}
*/
export const readUint8Array = (decoder, len) => {
const view = new Uint8Array(decoder.arr.buffer, decoder.pos + decoder.arr.byteOffset, len)
decoder.pos += len
return view
}
/**
* Read variable length Uint8Array.
*
* Important: The Uint8Array still points to the underlying ArrayBuffer. Make sure to discard the result as soon as possible to prevent any memory leaks.
* Use `buffer.copyUint8Array` to copy the result into a new Uint8Array.
*
* @function
* @template {ArrayBufferLike} Buf
* @param {Decoder<Buf>} decoder
* @return {Uint8Array<Buf>}
*/
export const readVarUint8Array = decoder => readUint8Array(decoder, readVarUint(decoder))
/**
* Read the rest of the content as an ArrayBuffer
* @function
* @param {Decoder} decoder
* @return {Uint8Array}
*/
export const readTailAsUint8Array = decoder => readUint8Array(decoder, decoder.arr.length - decoder.pos)
/**
* Skip one byte, jump to the next position.
* @function
* @param {Decoder} decoder The decoder instance
* @return {number} The next position
*/
export const skip8 = decoder => decoder.pos++
/**
* Read one byte as unsigned integer.
* @function
* @param {Decoder} decoder The decoder instance
* @return {number} Unsigned 8-bit integer
*/
export const readUint8 = decoder => decoder.arr[decoder.pos++]
/**
* Read 2 bytes as unsigned integer.
*
* @function
* @param {Decoder} decoder
* @return {number} An unsigned integer.
*/
export const readUint16 = decoder => {
const uint =
decoder.arr[decoder.pos] +
(decoder.arr[decoder.pos + 1] << 8)
decoder.pos += 2
return uint
}
/**
* Read 4 bytes as unsigned integer.
*
* @function
* @param {Decoder} decoder
* @return {number} An unsigned integer.
*/
export const readUint32 = decoder => {
const uint =
(decoder.arr[decoder.pos] +
(decoder.arr[decoder.pos + 1] << 8) +
(decoder.arr[decoder.pos + 2] << 16) +
(decoder.arr[decoder.pos + 3] << 24)) >>> 0
decoder.pos += 4
return uint
}
/**
* Read 4 bytes as unsigned integer in big endian order.
* (most significant byte first)
*
* @function
* @param {Decoder} decoder
* @return {number} An unsigned integer.
*/
export const readUint32BigEndian = decoder => {
const uint =
(decoder.arr[decoder.pos + 3] +
(decoder.arr[decoder.pos + 2] << 8) +
(decoder.arr[decoder.pos + 1] << 16) +
(decoder.arr[decoder.pos] << 24)) >>> 0
decoder.pos += 4
return uint
}
/**
* Look ahead without incrementing the position
* to the next byte and read it as unsigned integer.
*
* @function
* @param {Decoder} decoder
* @return {number} An unsigned integer.
*/
export const peekUint8 = decoder => decoder.arr[decoder.pos]
/**
* Look ahead without incrementing the position
* to the next byte and read it as unsigned integer.
*
* @function
* @param {Decoder} decoder
* @return {number} An unsigned integer.
*/
export const peekUint16 = decoder =>
decoder.arr[decoder.pos] +
(decoder.arr[decoder.pos + 1] << 8)
/**
* Look ahead without incrementing the position
* to the next byte and read it as unsigned integer.
*
* @function
* @param {Decoder} decoder
* @return {number} An unsigned integer.
*/
export const peekUint32 = decoder => (
decoder.arr[decoder.pos] +
(decoder.arr[decoder.pos + 1] << 8) +
(decoder.arr[decoder.pos + 2] << 16) +
(decoder.arr[decoder.pos + 3] << 24)
) >>> 0
/**
* Read unsigned integer (32bit) with variable length.
* 1/8th of the storage is used as encoding overhead.
* * numbers < 2^7 is stored in one bytlength
* * numbers < 2^14 is stored in two bylength
*
* @function
* @param {Decoder} decoder
* @return {number} An unsigned integer.length
*/
export const readVarUint = decoder => {
let num = 0
let mult = 1
const len = decoder.arr.length
while (decoder.pos < len) {
const r = decoder.arr[decoder.pos++]
// num = num | ((r & binary.BITS7) << len)
num = num + (r & binary.BITS7) * mult // shift $r << (7*#iterations) and add it to num
mult *= 128 // next iteration, shift 7 "more" to the left
if (r < binary.BIT8) {
return num
}
/* c8 ignore start */
if (num > number.MAX_SAFE_INTEGER) {
throw errorIntegerOutOfRange
}
/* c8 ignore stop */
}
throw errorUnexpectedEndOfArray
}
/**
* Read signed integer (32bit) with variable length.
* 1/8th of the storage is used as encoding overhead.
* * numbers < 2^7 is stored in one bytlength
* * numbers < 2^14 is stored in two bylength
* @todo This should probably create the inverse ~num if number is negative - but this would be a breaking change.
*
* @function
* @param {Decoder} decoder
* @return {number} An unsigned integer.length
*/
export const readVarInt = decoder => {
let r = decoder.arr[decoder.pos++]
let num = r & binary.BITS6
let mult = 64
const sign = (r & binary.BIT7) > 0 ? -1 : 1
if ((r & binary.BIT8) === 0) {
// don't continue reading
return sign * num
}
const len = decoder.arr.length
while (decoder.pos < len) {
r = decoder.arr[decoder.pos++]
// num = num | ((r & binary.BITS7) << len)
num = num + (r & binary.BITS7) * mult
mult *= 128
if (r < binary.BIT8) {
return sign * num
}
/* c8 ignore start */
if (num > number.MAX_SAFE_INTEGER) {
throw errorIntegerOutOfRange
}
/* c8 ignore stop */
}
throw errorUnexpectedEndOfArray
}
/**
* Look ahead and read varUint without incrementing position
*
* @function
* @param {Decoder} decoder
* @return {number}
*/
export const peekVarUint = decoder => {
const pos = decoder.pos
const s = readVarUint(decoder)
decoder.pos = pos
return s
}
/**
* Look ahead and read varUint without incrementing position
*
* @function
* @param {Decoder} decoder
* @return {number}
*/
export const peekVarInt = decoder => {
const pos = decoder.pos
const s = readVarInt(decoder)
decoder.pos = pos
return s
}
/**
* We don't test this function anymore as we use native decoding/encoding by default now.
* Better not modify this anymore..
*
* Transforming utf8 to a string is pretty expensive. The code performs 10x better
* when String.fromCodePoint is fed with all characters as arguments.
* But most environments have a maximum number of arguments per functions.
* For effiency reasons we apply a maximum of 10000 characters at once.
*
* @function
* @param {Decoder} decoder
* @return {String} The read String.
*/
/* c8 ignore start */
export const _readVarStringPolyfill = decoder => {
let remainingLen = readVarUint(decoder)
if (remainingLen === 0) {
return ''
} else {
let encodedString = String.fromCodePoint(readUint8(decoder)) // remember to decrease remainingLen
if (--remainingLen < 100) { // do not create a Uint8Array for small strings
while (remainingLen--) {
encodedString += String.fromCodePoint(readUint8(decoder))
}
} else {
while (remainingLen > 0) {
const nextLen = remainingLen < 10000 ? remainingLen : 10000
// this is dangerous, we create a fresh array view from the existing buffer
const bytes = decoder.arr.subarray(decoder.pos, decoder.pos + nextLen)
decoder.pos += nextLen
// Starting with ES5.1 we can supply a generic array-like object as arguments
encodedString += String.fromCodePoint.apply(null, /** @type {any} */ (bytes))
remainingLen -= nextLen
}
}
return decodeURIComponent(escape(encodedString))
}
}
/* c8 ignore stop */
/**
* @function
* @param {Decoder} decoder
* @return {String} The read String
*/
export const _readVarStringNative = decoder =>
/** @type any */ (string.utf8TextDecoder).decode(readVarUint8Array(decoder))
/**
* Read string of variable length
* * varUint is used to store the length of the string
*
* @function
* @param {Decoder} decoder
* @return {String} The read String
*
*/
/* c8 ignore next */
export const readVarString = string.utf8TextDecoder ? _readVarStringNative : _readVarStringPolyfill
/**
* @param {Decoder} decoder
* @return {Uint8Array}
*/
export const readTerminatedUint8Array = decoder => {
const encoder = encoding.createEncoder()
let b
while (true) {
b = readUint8(decoder)
if (b === 0) {
return encoding.toUint8Array(encoder)
}
if (b === 1) {
b = readUint8(decoder)
}
encoding.write(encoder, b)
}
}
/**
* @param {Decoder} decoder
* @return {string}
*/
export const readTerminatedString = decoder => string.decodeUtf8(readTerminatedUint8Array(decoder))
/**
* Look ahead and read varString without incrementing position
*
* @function
* @param {Decoder} decoder
* @return {string}
*/
export const peekVarString = decoder => {
const pos = decoder.pos
const s = readVarString(decoder)
decoder.pos = pos
return s
}
/**
* @param {Decoder} decoder
* @param {number} len
* @return {DataView}
*/
export const readFromDataView = (decoder, len) => {
const dv = new DataView(decoder.arr.buffer, decoder.arr.byteOffset + decoder.pos, len)
decoder.pos += len
return dv
}
/**
* @param {Decoder} decoder
*/
export const readFloat32 = decoder => readFromDataView(decoder, 4).getFloat32(0, false)
/**
* @param {Decoder} decoder
*/
export const readFloat64 = decoder => readFromDataView(decoder, 8).getFloat64(0, false)
/**
* @param {Decoder} decoder
*/
export const readBigInt64 = decoder => /** @type {any} */ (readFromDataView(decoder, 8)).getBigInt64(0, false)
/**
* @param {Decoder} decoder
*/
export const readBigUint64 = decoder => /** @type {any} */ (readFromDataView(decoder, 8)).getBigUint64(0, false)
/**
* @type {Array<function(Decoder):any>}
*/
const readAnyLookupTable = [
decoder => undefined, // CASE 127: undefined
decoder => null, // CASE 126: null
readVarInt, // CASE 125: integer
readFloat32, // CASE 124: float32
readFloat64, // CASE 123: float64
readBigInt64, // CASE 122: bigint
decoder => false, // CASE 121: boolean (false)
decoder => true, // CASE 120: boolean (true)
readVarString, // CASE 119: string
decoder => { // CASE 118: object<string,any>
const len = readVarUint(decoder)
/**
* @type {Object<string,any>}
*/
const obj = {}
for (let i = 0; i < len; i++) {
const key = readVarString(decoder)
obj[key] = readAny(decoder)
}
return obj
},
decoder => { // CASE 117: array<any>
const len = readVarUint(decoder)
const arr = []
for (let i = 0; i < len; i++) {
arr.push(readAny(decoder))
}
return arr
},
readVarUint8Array // CASE 116: Uint8Array
]
/**
* @param {Decoder} decoder
*/
export const readAny = decoder => readAnyLookupTable[127 - readUint8(decoder)](decoder)
/**
* T must not be null.
*
* @template T
*/
export class RleDecoder extends Decoder {
/**
* @param {Uint8Array} uint8Array
* @param {function(Decoder):T} reader
*/
constructor (uint8Array, reader) {
super(uint8Array)
/**
* The reader
*/
this.reader = reader
/**
* Current state
* @type {T|null}
*/
this.s = null
this.count = 0
}
read () {
if (this.count === 0) {
this.s = this.reader(this)
if (hasContent(this)) {
this.count = readVarUint(this) + 1 // see encoder implementation for the reason why this is incremented
} else {
this.count = -1 // read the current value forever
}
}
this.count--
return /** @type {T} */ (this.s)
}
}
export class IntDiffDecoder extends Decoder {
/**
* @param {Uint8Array} uint8Array
* @param {number} start
*/
constructor (uint8Array, start) {
super(uint8Array)
/**
* Current state
* @type {number}
*/
this.s = start
}
/**
* @return {number}
*/
read () {
this.s += readVarInt(this)
return this.s
}
}
export class RleIntDiffDecoder extends Decoder {
/**
* @param {Uint8Array} uint8Array
* @param {number} start
*/
constructor (uint8Array, start) {
super(uint8Array)
/**
* Current state
* @type {number}
*/
this.s = start
this.count = 0
}
/**
* @return {number}
*/
read () {
if (this.count === 0) {
this.s += readVarInt(this)
if (hasContent(this)) {
this.count = readVarUint(this) + 1 // see encoder implementation for the reason why this is incremented
} else {
this.count = -1 // read the current value forever
}
}
this.count--
return /** @type {number} */ (this.s)
}
}
export class UintOptRleDecoder extends Decoder {
/**
* @param {Uint8Array} uint8Array
*/
constructor (uint8Array) {
super(uint8Array)
/**
* @type {number}
*/
this.s = 0
this.count = 0
}
read () {
if (this.count === 0) {
this.s = readVarInt(this)
// if the sign is negative, we read the count too, otherwise count is 1
const isNegative = math.isNegativeZero(this.s)
this.count = 1
if (isNegative) {
this.s = -this.s
this.count = readVarUint(this) + 2
}
}
this.count--
return /** @type {number} */ (this.s)
}
}
export class IncUintOptRleDecoder extends Decoder {
/**
* @param {Uint8Array} uint8Array
*/
constructor (uint8Array) {
super(uint8Array)
/**
* @type {number}
*/
this.s = 0
this.count = 0
}
read () {
if (this.count === 0) {
this.s = readVarInt(this)
// if the sign is negative, we read the count too, otherwise count is 1
const isNegative = math.isNegativeZero(this.s)
this.count = 1
if (isNegative) {
this.s = -this.s
this.count = readVarUint(this) + 2
}
}
this.count--
return /** @type {number} */ (this.s++)
}
}
export class IntDiffOptRleDecoder extends Decoder {
/**
* @param {Uint8Array} uint8Array
*/
constructor (uint8Array) {
super(uint8Array)
/**
* @type {number}
*/
this.s = 0
this.count = 0
this.diff = 0
}
/**
* @return {number}
*/
read () {
if (this.count === 0) {
const diff = readVarInt(this)
// if the first bit is set, we read more data
const hasCount = diff & 1
this.diff = math.floor(diff / 2) // shift >> 1
this.count = 1
if (hasCount) {
this.count = readVarUint(this) + 2
}
}
this.s += this.diff
this.count--
return this.s
}
}
export class StringDecoder {
/**
* @param {Uint8Array} uint8Array
*/
constructor (uint8Array) {
this.decoder = new UintOptRleDecoder(uint8Array)
this.str = readVarString(this.decoder)
/**
* @type {number}
*/
this.spos = 0
}
/**
* @return {string}
*/
read () {
const end = this.spos + this.decoder.read()
const res = this.str.slice(this.spos, end)
this.spos = end
return res
}
}

View File

@@ -1,107 +0,0 @@
/**
* @template T
* @typedef {import('../schema.js').Schema<T>} Schema
*/
/**
* @template {delta.AbstractDelta} DeltaA
* @template {delta.AbstractDelta} DeltaB
*/
export class Binding<DeltaA extends delta.AbstractDelta, DeltaB extends delta.AbstractDelta> {
/**
* @param {RDT<DeltaA>} a
* @param {RDT<DeltaB>} b
* @param {dt.Template<any,DeltaA,DeltaB>} template
*/
constructor(a: RDT<DeltaA>, b: RDT<DeltaB>, template: dt.Template<any, DeltaA, DeltaB>);
/**
* @type {dt.Transformer<any,DeltaA,DeltaB>}
*/
t: dt.Transformer<any, DeltaA, DeltaB>;
a: RDT<DeltaA>;
b: RDT<DeltaB>;
_mux: mux.mutex;
_achanged: (delta: DeltaA) => void;
_bchanged: (delta: DeltaB) => void;
destroy: () => void;
}
export function bind<DeltaA extends delta.AbstractDelta, Transformer extends dt.Template<any, DeltaA, any>>(a: RDT<DeltaA>, b: RDT<Transformer extends dt.Template<any, DeltaA, infer DeltaB> ? DeltaB : never>, template: dt.Template<any, DeltaA, any>): Binding<DeltaA, Transformer extends dt.Template<any, DeltaA, infer DeltaB> ? DeltaB : never>;
export function deltaRDT<Delta extends delta.AbstractDelta>($delta: Schema<Delta>): DeltaRDT<Delta>;
export const $domDelta: any;
export function domRDT(dom: Element): DomRDT<delta.RecursiveNode<string, {
[key: string]: string;
}, never, true>>;
export type Schema<T> = import("../schema.js").Schema<T>;
/**
* Abstract Interface for a delta-based Replicated Data Type.
*/
export type RDT<Delta extends delta.AbstractDelta> = ObservableV2<{
"change": (delta: Delta) => void;
"destroy": (rdt: RDT<Delta>) => void;
}> & {
update: (delta: Delta) => any;
destroy: () => void;
};
export type DomDelta = delta.RecursiveNode<string, {
[key: string]: string;
}, never, true>;
import * as delta from './delta.js';
import * as dt from './t3.test.js';
import * as mux from '../mutex.js';
/**
* @template {delta.AbstractDelta} Delta
* @implements RDT<Delta>
* @extends {ObservableV2<{ change: (delta: Delta) => void, 'destroy': (rdt:DeltaRDT<Delta>)=>void }>}
*/
declare class DeltaRDT<Delta extends delta.AbstractDelta> extends ObservableV2<{
change: (delta: Delta) => void;
destroy: (rdt: DeltaRDT<Delta>) => void;
}> implements RDT<Delta> {
/**
* @param {Schema<Delta>} $delta
*/
constructor($delta: Schema<Delta>);
$delta: s.Schema<Delta>;
/**
* @type {Delta?}
*/
state: Delta | null;
_mux: mux.mutex;
/**
* @param {Delta} delta
*/
update: (delta: Delta) => any;
}
/**
* @typedef {delta.RecursiveNode<string, { [key:string]: string }, never, true>} DomDelta
*/
/**
* @template {DomDelta} [D=DomDelta]
* @implements RDT<D>
* @extends {ObservableV2<{ change: (delta: D)=>void, destroy: (rdt:DomRDT<D>)=>void }>}>}
*/
declare class DomRDT<D extends DomDelta = delta.RecursiveNode<string, {
[key: string]: string;
}, never, true>> extends ObservableV2<{
change: (delta: D) => void;
destroy: (rdt: DomRDT<D>) => void;
}> implements RDT<D> {
/**
* @param {Element} observedNode
*/
constructor(observedNode: Element);
observedNode: Element;
_mux: mux.mutex;
observer: MutationObserver;
/**
* @param {MutationRecord[]} mutations
*/
_mutationHandler: (mutations: MutationRecord[]) => any;
/**
* @param {D} delta
*/
update: (delta: D) => void;
}
import { ObservableV2 } from '../observable.js';
import * as s from '../schema.js';
export {};
//# sourceMappingURL=binding.d.ts.map

View File

@@ -1 +0,0 @@
{"version":3,"file":"binding.d.ts","sourceRoot":"","sources":["binding.js"],"names":[],"mappings":"AAeA;;;GAGG;AAEH;;;GAGG;AACH,qBAHmC,MAAM,SAA3B,KAAK,CAAC,aAAc,EACC,MAAM,SAA3B,KAAK,CAAC,aAAc;IAGhC;;;;OAIG;IACH,eAJW,GAAG,CAAC,MAAM,CAAC,KACX,GAAG,CAAC,MAAM,CAAC,YACX,EAAE,CAAC,QAAQ,CAAC,GAAG,EAAC,MAAM,EAAC,MAAM,CAAC,EA4BxC;IAzBC;;OAEG;IACH,GAFU,EAAE,CAAC,WAAW,CAAC,GAAG,EAAC,MAAM,EAAC,MAAM,CAAC,CAEnB;IACxB,eAAU;IACV,eAAU;IACV,gBAA6B;IAC7B,8BAgCoD,IAAI,CAxBrD;IACH,8BAuBoD,IAAI,CAfrD;IAGL,oBAKC;CACF;AAgBM,qBAN4B,MAAM,SAA3B,KAAK,CAAC,aAAc,EACS,WAAW,SAAxC,EAAE,CAAC,QAAQ,CAAC,GAAG,EAAC,MAAM,EAAC,GAAG,CAAE,KAC/B,GAAG,CAAC,MAAM,CAAC,KACX,GAAG,CAAC,WAAW,SAAS,EAAE,CAAC,QAAQ,CAAC,GAAG,EAAC,MAAM,EAAC,MAAM,MAAM,CAAC,GAAG,MAAM,GAAG,KAAK,CAAC,YAC9E,EAAE,CAAC,QAAQ,CAAC,GAAG,EAAC,MAAM,EAAC,GAAG,CAAC,sEAD0B,MAAM,oBAGH;AA2C5D,yBAH4B,KAAK,SAA1B,KAAK,CAAC,aAAc,UACvB,MAAM,CAAC,KAAK,CAAC,mBAE8B;AAkGtD,4BAA+H;AAsJxH,4BAFI,OAAO;;iBAE0B;mBAnW/B,CAAC,IACD,OAAO,cAAc,EAAE,MAAM,CAAC,CAAC,CAAC;;;;gBAoDV,KAAK,SAA1B,KAAK,CAAC,aAAc,IACrB,YAAY,CAAC;IAAE,QAAQ,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;IAAC,SAAS,EAAE,CAAC,GAAG,EAAC,GAAG,CAAC,KAAK,CAAC,KAAG,IAAI,CAAA;CAAE,CAAC,GAAG;IAAE,MAAM,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,GAAG,CAAC;IAAC,OAAO,EAAE,MAAM,IAAI,CAAA;CAAE;uBAkP9I,KAAK,CAAC,aAAa,CAAC,MAAM,EAAE;IAAE,CAAC,GAAG,EAAC,MAAM,GAAG,MAAM,CAAA;CAAE,EAAE,KAAK,EAAE,IAAI,CAAC;uBAnTxD,YAAY;oBACf,cAAc;qBAMb,aAAa;AAsElC;;;;GAIG;AACH,uBAJmC,KAAK,SAA1B,KAAK,CAAC,aAAc;YAEE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI;aAAa,CAAC,GAAG,EAAC,QAAQ,CAAC,KAAK,CAAC,KAAG,IAAI;cADnF,GAAG,CAAC,KAAK;IAItB;;OAEG;IACH,oBAFW,MAAM,CAAC,KAAK,CAAC,EAUvB;IANC,wBAAoB;IACpB;;OAEG;IACH,OAFU,KAAK,OAAC,CAEC;IACjB,gBAA6B;IAG/B;;OAEG;IACH,SAAS,OAFE,KAEG,SAOZ;CAMH;AAkMD;;GAEG;AAEH;;;;GAIG;AACH,qBAJyB,CAAC,SAAZ,QAAS;;;YAEa,CAAC,KAAK,EAAE,CAAC,KAAG,IAAI;aAAW,CAAC,GAAG,EAAC,MAAM,CAAC,CAAC,CAAC,KAAG,IAAI;cADrE,GAAG,CAAC,CAAC;IAIlB;;OAEG;IACH,0BAFW,OAAO,EAajB;IATC,sBAAgC;IAChC,gBAA6B;IAC7B,2BAA2D;IAS7D;;OAEG;IACH,mBAAmB,WAFR,cAAc,EAEG,SAGxB;IAEJ;;OAEG;IACH,SAAS,OAFE,CAEG,UAWb;CAOF;6BA1W4B,kBAAkB;mBAS5B,cAAc"}

View File

@@ -1,372 +0,0 @@
/* eslint-disable */
// @ts-nocheck
// @todo remove all @ts-nocheck and eslint-disable
/* global MutationObserver */
import { ObservableV2 } from '../observable.js'
import * as delta from './delta.js'
import * as dt from './t3.test.js' // eslint-disable-line
import * as dom from '../dom.js'
import * as set from '../set.js'
import * as map from '../map.js'
import * as error from '../error.js'
import * as math from '../math.js'
import * as mux from '../mutex.js'
import * as s from '../schema.js'
/**
* @template T
* @typedef {import('../schema.js').Schema<T>} Schema
*/
/**
* @template {delta.AbstractDelta} DeltaA
* @template {delta.AbstractDelta} DeltaB
*/
export class Binding {
/**
* @param {RDT<DeltaA>} a
* @param {RDT<DeltaB>} b
* @param {dt.Template<any,DeltaA,DeltaB>} template
*/
constructor (a, b, template) {
/**
* @type {dt.Transformer<any,DeltaA,DeltaB>}
*/
this.t = template.init()
this.a = a
this.b = b
this._mux = mux.createMutex()
this._achanged = this.a.on('change', d => this._mux(() => {
const tres = this.t.applyA(d)
if (tres.a) {
a.update(tres.a)
}
if (tres.b) {
b.update(tres.b)
}
}))
this._bchanged = this.b.on('change', d => this._mux(() => {
const tres = this.t.applyB(d)
if (tres.b) {
this.b.update(tres.b)
}
if (tres.a) {
a.update(tres.a)
}
}))
}
destroy = () => {
this.a.off('destroy', this.destroy)
this.b.off('destroy', this.destroy)
this.a.off('change', this._achanged)
this.b.off('change', this._bchanged)
}
}
/**
* Abstract Interface for a delta-based Replicated Data Type.
*
* @template {delta.AbstractDelta} Delta
* @typedef {ObservableV2<{ 'change': (delta: Delta) => void, 'destroy': (rdt:RDT<Delta>)=>void }> & { update: (delta: Delta) => any, destroy: () => void }} RDT
*/
/**
* @template {delta.AbstractDelta} DeltaA
* @template {dt.Template<any,DeltaA,any>} Transformer
* @param {RDT<DeltaA>} a
* @param {RDT<Transformer extends dt.Template<any,DeltaA,infer DeltaB> ? DeltaB : never>} b
* @param {dt.Template<any,DeltaA,any>} template
*/
export const bind = (a, b, template) => new Binding(a, b, template)
/**
* @template {delta.AbstractDelta} Delta
* @implements RDT<Delta>
* @extends {ObservableV2<{ change: (delta: Delta) => void, 'destroy': (rdt:DeltaRDT<Delta>)=>void }>}
*/
class DeltaRDT extends ObservableV2 {
/**
* @param {Schema<Delta>} $delta
*/
constructor ($delta) {
super()
this.$delta = $delta
/**
* @type {Delta?}
*/
this.state = null
this._mux = mux.createMutex()
}
/**
* @param {Delta} delta
*/
update = delta => delta.isEmpty() || this._mux(() => {
if (this.state != null) {
this.state.apply(delta)
} else {
this.state = delta
}
this.emit('change', [delta])
})
destroy () {
this.emit('destroy', [this])
super.destroy()
}
}
/**
* @template {delta.AbstractDelta} Delta
* @param {Schema<Delta>} $delta
*/
export const deltaRDT = $delta => new DeltaRDT($delta)
/**
* @param {Node} domNode
*/
const domToDelta = domNode => {
if (dom.$element.check(domNode)) {
const d = delta.node(domNode.nodeName.toLowerCase())
for (let i = 0; i < domNode.attributes.length; i++) {
const attr = /** @type {Attr} */ (domNode.attributes.item(i))
d.attributes.set(attr.nodeName, attr.value)
}
domNode.childNodes.forEach(child => {
d.children.insert(dom.$text.check(child) ? child.textContent : [domToDelta(child)])
})
return d
}
error.unexpectedCase()
}
/**
* @param {DomDelta} d
*/
const deltaToDom = d => {
if (delta.$nodeAny.check(d)) {
const n = dom.element(d.name)
d.attributes.forEach(change => {
if (delta.$insertOp.check(change)) {
n.setAttribute(change.key, change.value)
}
})
d.children.forEach(child => {
if (delta.$insertOp.check(child)) {
n.append(...child.insert.map(deltaToDom))
} else if (delta.$textOp.check(child)) {
n.append(dom.text(child.insert))
}
})
return n
}
error.unexpectedCase()
}
/**
* @param {Element} el
* @param {delta.Node<string,any,any,any>} d
*/
const applyDeltaToDom = (el, d) => {
d.attributes.forEach(change => {
if (delta.$deleteOp.check(change)) {
el.removeAttribute(change.key)
} else {
el.setAttribute(change.key, change.value)
}
})
let childIndex = 0
let childOffset = 0
d.children.forEach(change => {
let child = el.childNodes[childIndex] || null
if (delta.$deleteOp.check(change)) {
let len = change.length
while (len > 0) {
if (dom.$element.check(child)) {
child.remove()
len--
} else if (dom.$text.check(child)) {
const childLen = child.length
if (childOffset === 0 && childLen <= len) {
child.remove()
len -= childLen
} else {
const spliceLen = math.min(len, childLen - childOffset)
child.deleteData(childOffset, spliceLen)
if (child.length <= childOffset) {
childOffset = 0
childIndex++
}
}
}
}
} else if (delta.$insertOp.check(change)) {
if (childOffset > 0) {
const tchild = dom.$text.cast(child)
child = tchild.splitText(childOffset)
childIndex++
childOffset = 0
}
el.insertBefore(dom.fragment(change.insert.map(deltaToDom)), child)
} else if (delta.$modifyOp.check(change)) {
applyDeltaToDom(dom.$element.cast(child), change.modify)
} else if (delta.$textOp.check(change)) {
el.insertBefore(dom.text(change.insert), child)
} else {
error.unexpectedCase()
}
})
}
export const $domDelta = delta.$node(s.$string, s.$record(s.$string, s.$string), s.$never, { recursive: true, withText: true })
/**
* @param {Element} observedNode
* @param {MutationRecord[]} mutations
* @param {any} origin assign this origin to the generated delta
*/
const _mutationsToDelta = (observedNode, mutations, origin) => {
/**
* @typedef {{ removedBefore: Map<Node?,number>, added: Set<Node>, modified: number, d: delta.Node }} ChangedNodeInfo
*/
/**
* Compute all deltas without recursion.
*
* 1. mark all changed parents in parentsChanged
* 2. fill out necessary information for each changed parent ()
*/
//
/**
* @type {Map<Node,ChangedNodeInfo>}
*/
const changedNodes = map.create()
/**
* @param {Node} node
* @return {ChangedNodeInfo}
*/
const getChangedNodeInfo = node => map.setIfUndefined(changedNodes, node, () => ({ removedBefore: map.create(), added: set.create(), modified: 0, d: delta.node(node.nodeName.toLowerCase()) }))
const observedNodeInfo = getChangedNodeInfo(observedNode)
mutations.forEach(mutation => {
const target = /** @type {HTMLElement} */ (mutation.target)
const parent = target.parentNode
const attrName = /** @type {string} */ (mutation.attributeName)
const newVal = target.getAttribute(attrName)
const info = getChangedNodeInfo(target)
const d = info.d
// go up the tree and mark that a child has been modified
for (let changedParent = parent; changedParent != null && getChangedNodeInfo(changedParent).modified++ > 1 && changedParent !== observedNode; changedParent = changedParent.parentNode) {
// nop
}
switch (mutation.type) {
case 'attributes': {
const attrs = /** @type {delta.Node<any,any,any>} */ (d).attributes
if (newVal == null) {
attrs.delete(attrName)
} else {
attrs.set(/** @type {string} */ (attrName), newVal)
}
break
}
case 'characterData': {
error.methodUnimplemented()
break
}
case 'childList': {
const targetInfo = getChangedNodeInfo(target)
mutation.addedNodes.forEach(node => {
targetInfo.added.add(node)
})
const removed = mutation.removedNodes.length
if (removed > 0) {
// @todo this can't work because next can be null
targetInfo.removedBefore.set(mutation.nextSibling, removed)
}
break
}
}
})
changedNodes.forEach((info, node) => {
const numOfChildChanges = info.modified + info.removedBefore.size + info.added.size
const d = /** @type {delta.Node<any,any,any>} */ (info.d)
if (numOfChildChanges > 0) {
node.childNodes.forEach(nchild => {
if (info.removedBefore.has(nchild)) { // can happen separately
d.children.delete(/** @type {number} */ (info.removedBefore.get(nchild)))
}
if (info.added.has(nchild)) {
d.children.insert(dom.$text.check(nchild) ? nchild.textContent : [domToDelta(nchild)])
} else if (changedNodes.has(nchild)) {
d.children.modify(getChangedNodeInfo(nchild).d)
}
})
// remove items to the end, if necessary
d.children.delete(info.removedBefore.get(null) ?? 0)
}
d.done()
})
observedNodeInfo.d.origin = origin
return observedNodeInfo.d
}
/**
* @typedef {delta.RecursiveNode<string, { [key:string]: string }, never, true>} DomDelta
*/
/**
* @template {DomDelta} [D=DomDelta]
* @implements RDT<D>
* @extends {ObservableV2<{ change: (delta: D)=>void, destroy: (rdt:DomRDT<D>)=>void }>}>}
*/
class DomRDT extends ObservableV2 {
/**
* @param {Element} observedNode
*/
constructor (observedNode) {
super()
this.observedNode = observedNode
this._mux = mux.createMutex()
this.observer = new MutationObserver(this._mutationHandler)
this.observer.observe(observedNode, {
subtree: true,
childList: true,
attributes: true,
characterDataOldValue: true
})
}
/**
* @param {MutationRecord[]} mutations
*/
_mutationHandler = mutations =>
mutations.length > 0 && this._mux(() => {
this.emit('change', [/** @type {D} */(_mutationsToDelta(this.observedNode, mutations, this))])
})
/**
* @param {D} delta
*/
update = delta => {
if (delta.origin !== this) {
// @todo the retrieved changes must be transformed agains the updated changes. need a proper
// transaction system
this._mutationHandler(this.observer.takeRecords())
this._mux(() => {
applyDeltaToDom(this.observedNode, delta)
const mutations = this.observer.takeRecords()
this.emit('change', [/** @type {D} */(_mutationsToDelta(this.observedNode, mutations, delta.origin))])
})
}
}
destroy () {
this.emit('destroy', [this])
super.destroy()
this.observer.disconnect()
}
}
/**
* @param {Element} dom
*/
export const domRDT = dom => new DomRDT(dom)

View File

@@ -1,5 +0,0 @@
export function testBinding(): void;
export function testDomBindingBasics(): void;
export function testDomBindingBackAndForth(): void;
export function testDataToDom(): void;
//# sourceMappingURL=binding.test.d.ts.map

View File

@@ -1 +0,0 @@
{"version":3,"file":"binding.test.d.ts","sourceRoot":"","sources":["binding.test.js"],"names":[],"mappings":"AAUO,oCAcN;AAEM,6CAcN;AAEM,mDAkCN;AAEM,sCAiBN"}

View File

@@ -1,5 +0,0 @@
export function testDeltaBasics(_tc: t.TestCase): void;
export function testDeltaBasicSchema(_tc: t.TestCase): void;
export function testDeltaValues(_tc: t.TestCase): void;
import * as t from 'lib0/testing';
//# sourceMappingURL=delta-pitch.test.d.ts.map

View File

@@ -1 +0,0 @@
{"version":3,"file":"delta-pitch.test.d.ts","sourceRoot":"","sources":["delta-pitch.test.js"],"names":[],"mappings":"AAmCO,qCAFI,CAAC,CAAC,QAAQ,QAWpB;AAmBM,0CAFI,CAAC,CAAC,QAAQ,QAWpB;AAYM,qCAFI,CAAC,CAAC,QAAQ,QAwBpB;mBAzGkB,cAAc"}

Some files were not shown because too many files have changed in this diff Show More