fix: Collaboration debounce shared between docs (#3401)
* fix: Collaboration debounce shared between docs * Rename, Tracing -> Metrics * Add tracing * tsc * fix: Lock document row when loading document in collaboration service incase state needs writing * fix: Incorrect service name regression
This commit is contained in:
@@ -51,9 +51,9 @@
|
||||
"@dnd-kit/core": "^4.0.3",
|
||||
"@dnd-kit/modifiers": "^4.0.0",
|
||||
"@dnd-kit/sortable": "^5.1.0",
|
||||
"@getoutline/y-prosemirror": "^1.0.16",
|
||||
"@hocuspocus/provider": "^1.0.0-alpha.21",
|
||||
"@hocuspocus/server": "^1.0.0-alpha.78",
|
||||
"@getoutline/y-prosemirror": "^1.0.18",
|
||||
"@hocuspocus/provider": "^1.0.0-alpha.36",
|
||||
"@hocuspocus/server": "^1.0.0-alpha.102",
|
||||
"@outlinewiki/koa-passport": "^4.1.4",
|
||||
"@outlinewiki/passport-azure-ad-oauth2": "^0.1.0",
|
||||
"@renderlesskit/react": "^0.6.0",
|
||||
@@ -200,7 +200,7 @@
|
||||
"winston": "^3.3.3",
|
||||
"ws": "^7.5.3",
|
||||
"y-indexeddb": "^9.0.6",
|
||||
"yjs": "^13.5.12"
|
||||
"yjs": "^13.5.34"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/cli": "^7.10.5",
|
||||
|
||||
@@ -1,10 +1,14 @@
|
||||
import { onAuthenticatePayload } from "@hocuspocus/server";
|
||||
import { onAuthenticatePayload, Extension } from "@hocuspocus/server";
|
||||
import { APM } from "@server/logging/tracing";
|
||||
import Document from "@server/models/Document";
|
||||
import { can } from "@server/policies";
|
||||
import { getUserForJWT } from "@server/utils/jwt";
|
||||
import { AuthenticationError } from "../errors";
|
||||
|
||||
export default class Authentication {
|
||||
@APM.trace({
|
||||
spanName: "authentication",
|
||||
})
|
||||
export default class AuthenticationExtension implements Extension {
|
||||
async onAuthenticate({
|
||||
connection,
|
||||
token,
|
||||
@@ -2,13 +2,14 @@ import {
|
||||
onConnectPayload,
|
||||
onDisconnectPayload,
|
||||
onLoadDocumentPayload,
|
||||
Extension,
|
||||
} from "@hocuspocus/server";
|
||||
import Logger from "@server/logging/logger";
|
||||
|
||||
export default class CollaborationLogger {
|
||||
export default class LoggerExtension implements Extension {
|
||||
async onLoadDocument(data: onLoadDocumentPayload) {
|
||||
Logger.info("hocuspocus", `Loaded document "${data.documentName}"`, {
|
||||
userId: data.context.user.id,
|
||||
userId: data.context.user?.id,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -17,6 +18,8 @@ export default class CollaborationLogger {
|
||||
}
|
||||
|
||||
async onDisconnect(data: onDisconnectPayload) {
|
||||
Logger.info("hocuspocus", `Connection to "${data.documentName}" closed `);
|
||||
Logger.info("hocuspocus", `Closed connection to "${data.documentName}"`, {
|
||||
userId: data.context.user?.id,
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -3,11 +3,12 @@ import {
|
||||
onConnectPayload,
|
||||
onDisconnectPayload,
|
||||
onLoadDocumentPayload,
|
||||
Extension,
|
||||
} from "@hocuspocus/server";
|
||||
import Metrics from "@server/logging/metrics";
|
||||
|
||||
export default class Tracing {
|
||||
onLoadDocument({ documentName, instance }: onLoadDocumentPayload) {
|
||||
export default class MetricsExtension implements Extension {
|
||||
async onLoadDocument({ documentName, instance }: onLoadDocumentPayload) {
|
||||
Metrics.increment("collaboration.load_document", {
|
||||
documentName,
|
||||
});
|
||||
@@ -23,7 +24,7 @@ export default class Tracing {
|
||||
});
|
||||
}
|
||||
|
||||
onConnect({ documentName, instance }: onConnectPayload) {
|
||||
async onConnect({ documentName, instance }: onConnectPayload) {
|
||||
Metrics.increment("collaboration.connect", {
|
||||
documentName,
|
||||
});
|
||||
@@ -33,7 +34,7 @@ export default class Tracing {
|
||||
);
|
||||
}
|
||||
|
||||
onDisconnect({ documentName, instance }: onDisconnectPayload) {
|
||||
async onDisconnect({ documentName, instance }: onDisconnectPayload) {
|
||||
Metrics.increment("collaboration.disconnect", {
|
||||
documentName,
|
||||
});
|
||||
@@ -47,13 +48,13 @@ export default class Tracing {
|
||||
);
|
||||
}
|
||||
|
||||
onChange({ documentName }: onChangePayload) {
|
||||
async onStoreDocument({ documentName }: onChangePayload) {
|
||||
Metrics.increment("collaboration.change", {
|
||||
documentName,
|
||||
});
|
||||
}
|
||||
|
||||
onDestroy() {
|
||||
async onDestroy() {
|
||||
Metrics.gaugePerInstance("collaboration.connections_count", 0);
|
||||
Metrics.gaugePerInstance("collaboration.documents_count", 0);
|
||||
}
|
||||
86
server/collaboration/PersistenceExtension.ts
Normal file
86
server/collaboration/PersistenceExtension.ts
Normal file
@@ -0,0 +1,86 @@
|
||||
import {
|
||||
onStoreDocumentPayload,
|
||||
onLoadDocumentPayload,
|
||||
Extension,
|
||||
} from "@hocuspocus/server";
|
||||
import invariant from "invariant";
|
||||
import * as Y from "yjs";
|
||||
import { sequelize } from "@server/database/sequelize";
|
||||
import Logger from "@server/logging/logger";
|
||||
import { APM } from "@server/logging/tracing";
|
||||
import Document from "@server/models/Document";
|
||||
import documentUpdater from "../commands/documentUpdater";
|
||||
import markdownToYDoc from "./utils/markdownToYDoc";
|
||||
|
||||
@APM.trace({
|
||||
spanName: "persistence",
|
||||
})
|
||||
export default class PersistenceExtension implements Extension {
|
||||
async onLoadDocument({ documentName, ...data }: onLoadDocumentPayload) {
|
||||
const [, documentId] = documentName.split(".");
|
||||
const fieldName = "default";
|
||||
|
||||
// Check if the given field already exists in the given y-doc. This is import
|
||||
// so we don't import a document fresh if it exists already.
|
||||
if (!data.document.isEmpty(fieldName)) {
|
||||
return;
|
||||
}
|
||||
|
||||
return await sequelize.transaction(async (transaction) => {
|
||||
const document = await Document.scope("withState").findOne({
|
||||
transaction,
|
||||
lock: transaction.LOCK.UPDATE,
|
||||
where: {
|
||||
id: documentId,
|
||||
},
|
||||
});
|
||||
invariant(document, "Document not found");
|
||||
|
||||
if (document.state) {
|
||||
const ydoc = new Y.Doc();
|
||||
Logger.info("database", `Document ${documentId} is in database state`);
|
||||
Y.applyUpdate(ydoc, document.state);
|
||||
return ydoc;
|
||||
}
|
||||
|
||||
Logger.info(
|
||||
"database",
|
||||
`Document ${documentId} is not in state, creating from markdown`
|
||||
);
|
||||
const ydoc = markdownToYDoc(document.text, fieldName);
|
||||
const state = Y.encodeStateAsUpdate(ydoc);
|
||||
await document.update(
|
||||
{
|
||||
state: Buffer.from(state),
|
||||
},
|
||||
{
|
||||
hooks: false,
|
||||
transaction,
|
||||
}
|
||||
);
|
||||
return ydoc;
|
||||
});
|
||||
}
|
||||
|
||||
async onStoreDocument({
|
||||
document,
|
||||
context,
|
||||
documentName,
|
||||
}: onStoreDocumentPayload) {
|
||||
const [, documentId] = documentName.split(".");
|
||||
Logger.info("database", `Persisting ${documentId}`);
|
||||
|
||||
try {
|
||||
await documentUpdater({
|
||||
documentId,
|
||||
ydoc: document,
|
||||
userId: context.user?.id,
|
||||
});
|
||||
} catch (err) {
|
||||
Logger.error("Unable to persist document", err, {
|
||||
documentId,
|
||||
userId: context.user?.id,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,77 +0,0 @@
|
||||
import { onChangePayload, onLoadDocumentPayload } from "@hocuspocus/server";
|
||||
import invariant from "invariant";
|
||||
import { debounce } from "lodash";
|
||||
import * as Y from "yjs";
|
||||
import Logger from "@server/logging/logger";
|
||||
import Document from "@server/models/Document";
|
||||
import documentUpdater from "../commands/documentUpdater";
|
||||
import markdownToYDoc from "./utils/markdownToYDoc";
|
||||
|
||||
const DELAY = 3000;
|
||||
|
||||
export default class Persistence {
|
||||
async onLoadDocument({ documentName, ...data }: onLoadDocumentPayload) {
|
||||
const [, documentId] = documentName.split(".");
|
||||
const fieldName = "default";
|
||||
|
||||
// Check if the given field already exists in the given y-doc. This is import
|
||||
// so we don't import a document fresh if it exists already.
|
||||
if (!data.document.isEmpty(fieldName)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const document = await Document.scope("withState").findOne({
|
||||
where: {
|
||||
id: documentId,
|
||||
},
|
||||
});
|
||||
invariant(document, "Document not found");
|
||||
|
||||
if (document.state) {
|
||||
const ydoc = new Y.Doc();
|
||||
Logger.info("database", `Document ${documentId} is in database state`);
|
||||
Y.applyUpdate(ydoc, document.state);
|
||||
return ydoc;
|
||||
}
|
||||
|
||||
Logger.info(
|
||||
"database",
|
||||
`Document ${documentId} is not in state, creating from markdown`
|
||||
);
|
||||
const ydoc = markdownToYDoc(document.text, fieldName);
|
||||
const state = Y.encodeStateAsUpdate(ydoc);
|
||||
await document.update(
|
||||
{
|
||||
state: Buffer.from(state),
|
||||
},
|
||||
{
|
||||
hooks: false,
|
||||
}
|
||||
);
|
||||
return ydoc;
|
||||
}
|
||||
|
||||
onChange = debounce(
|
||||
async ({ document, context, documentName }: onChangePayload) => {
|
||||
const [, documentId] = documentName.split(".");
|
||||
Logger.info("database", `Persisting ${documentId}`);
|
||||
|
||||
try {
|
||||
await documentUpdater({
|
||||
documentId,
|
||||
ydoc: document,
|
||||
userId: context.user?.id,
|
||||
});
|
||||
} catch (err) {
|
||||
Logger.error("Unable to persist document", err, {
|
||||
documentId,
|
||||
userId: context.user?.id,
|
||||
});
|
||||
}
|
||||
},
|
||||
DELAY,
|
||||
{
|
||||
maxWait: DELAY * 3,
|
||||
}
|
||||
);
|
||||
}
|
||||
@@ -10,7 +10,7 @@ if (process.env.DD_API_KEY) {
|
||||
// SOURCE_COMMIT is used by Docker Hub
|
||||
// SOURCE_VERSION is used by Heroku
|
||||
version: process.env.SOURCE_COMMIT || process.env.SOURCE_VERSION,
|
||||
service: "outline",
|
||||
service: process.env.DD_SERVICE || "outline",
|
||||
},
|
||||
{
|
||||
useMock: process.env.NODE_ENV === "test",
|
||||
|
||||
@@ -4,26 +4,28 @@ import { Server } from "@hocuspocus/server";
|
||||
import invariant from "invariant";
|
||||
import Koa from "koa";
|
||||
import WebSocket from "ws";
|
||||
import AuthenticationExtension from "../collaboration/authentication";
|
||||
import LoggerExtension from "../collaboration/logger";
|
||||
import PersistenceExtension from "../collaboration/persistence";
|
||||
import TracingExtension from "../collaboration/tracing";
|
||||
import AuthenticationExtension from "../collaboration/AuthenticationExtension";
|
||||
import LoggerExtension from "../collaboration/LoggerExtension";
|
||||
import MetricsExtension from "../collaboration/MetricsExtension";
|
||||
import PersistenceExtension from "../collaboration/PersistenceExtension";
|
||||
|
||||
export default function init(app: Koa, server: http.Server) {
|
||||
const path = "/collaboration";
|
||||
const wss = new WebSocket.Server({
|
||||
noServer: true,
|
||||
});
|
||||
|
||||
const hocuspocus = Server.configure({
|
||||
debounce: 3000,
|
||||
maxDebounce: 10000,
|
||||
extensions: [
|
||||
new AuthenticationExtension(),
|
||||
// @ts-expect-error ts-migrate(2322) FIXME: Type 'Persistence' is not assignable to type 'Exte... Remove this comment to see the full error message
|
||||
new PersistenceExtension(),
|
||||
new LoggerExtension(),
|
||||
// @ts-expect-error ts-migrate(2322) FIXME: Type 'Persistence' is not assignable to type 'Exte... Remove this comment to see the full error message
|
||||
new TracingExtension(),
|
||||
new MetricsExtension(),
|
||||
],
|
||||
});
|
||||
|
||||
server.on("upgrade", function (req, socket, head) {
|
||||
if (req.url && req.url.indexOf(path) > -1) {
|
||||
const documentName = url.parse(req.url).pathname?.split("/").pop();
|
||||
@@ -34,7 +36,8 @@ export default function init(app: Koa, server: http.Server) {
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
server.on("shutdown", () => {
|
||||
hocuspocus.destroy();
|
||||
return hocuspocus.destroy();
|
||||
});
|
||||
}
|
||||
|
||||
126
yarn.lock
126
yarn.lock
@@ -1276,36 +1276,47 @@
|
||||
dependencies:
|
||||
tslib "^2.1.0"
|
||||
|
||||
"@getoutline/y-prosemirror@^1.0.16":
|
||||
version "1.0.16"
|
||||
resolved "https://registry.yarnpkg.com/@getoutline/y-prosemirror/-/y-prosemirror-1.0.16.tgz#34a29966208113bceb8c46bbf8417853e8885e09"
|
||||
integrity sha512-rJ3NF3Qk9v1/dNKQ25k3aud7TcV8s5175U9stagCDdvwsI67JufgzaWhT0jBhX8tEaZPdQVmXoqe8bf6OC72Cg==
|
||||
"@getoutline/y-prosemirror@^1.0.18":
|
||||
version "1.0.18"
|
||||
resolved "https://registry.yarnpkg.com/@getoutline/y-prosemirror/-/y-prosemirror-1.0.18.tgz#17245c0362d30adb85131c86fb9a59358884b234"
|
||||
integrity sha512-nLxqUHEHJDBwbcMWhlPWlJ4VpdjtajkmKSAWeVTsIEa5HTo1JQSdnADdS/HFSVSkESW8b6TRrOJylyHDn46uYQ==
|
||||
dependencies:
|
||||
lib0 "^0.2.42"
|
||||
|
||||
"@hocuspocus/provider@^1.0.0-alpha.21":
|
||||
version "1.0.0-alpha.21"
|
||||
resolved "https://registry.yarnpkg.com/@hocuspocus/provider/-/provider-1.0.0-alpha.21.tgz#369869e33a7c138041a03bbb80acd61dd77e3632"
|
||||
integrity sha512-24brZ0OIeUInbMBTN2weL06Xmt4KUn3Sj7BbNkxgt7QwHjIqpcqlZrHE8IYg46HTbp8k0KKnc1CCMxb1ui0fRA==
|
||||
"@hocuspocus/common@^1.0.0-alpha.11":
|
||||
version "1.0.0-alpha.11"
|
||||
resolved "https://registry.yarnpkg.com/@hocuspocus/common/-/common-1.0.0-alpha.11.tgz#d598d221465338c1d912251105519e88f8486805"
|
||||
integrity sha512-oOddSLUTr8KrC58KSs5YHzr99ZSI4HZdIkYRoqmrusViF8M850uLXgYce7eG7Xaq4KlvXCSDG+wioQRTFXkCaA==
|
||||
dependencies:
|
||||
"@lifeomic/attempt" "^3.0.0"
|
||||
lib0 "^0.2.42"
|
||||
lib0 "^0.2.47"
|
||||
|
||||
"@hocuspocus/provider@^1.0.0-alpha.36":
|
||||
version "1.0.0-alpha.36"
|
||||
resolved "https://registry.yarnpkg.com/@hocuspocus/provider/-/provider-1.0.0-alpha.36.tgz#a09dd42baa9c88cbd63027a18edcd3f79823a0cf"
|
||||
integrity sha512-vmrbaS2Si408Gau1vv/xH7ln/QbVJtUZsgLz0DwYYWWGcAJffaU1f89B2+sOL8IGRLclybldrVfZR+tFKBMzRw==
|
||||
dependencies:
|
||||
"@hocuspocus/common" "^1.0.0-alpha.11"
|
||||
"@lifeomic/attempt" "^3.0.2"
|
||||
lib0 "^0.2.46"
|
||||
y-protocols "^1.0.5"
|
||||
yjs "^13.5.0"
|
||||
yjs "^13.5.29"
|
||||
|
||||
"@hocuspocus/server@^1.0.0-alpha.78":
|
||||
version "1.0.0-alpha.78"
|
||||
resolved "https://registry.yarnpkg.com/@hocuspocus/server/-/server-1.0.0-alpha.78.tgz#06597ae871e3cfc68dd4fda5e6fbc696c8baf452"
|
||||
integrity sha512-78HbOiJLo2b130UjJk7Z/Olue/qKBeL/CPn2B5/FrDRa41SClftAXipQTSa6J7JYbMi5tUyDP8cO2gckBC2Q3Q==
|
||||
"@hocuspocus/server@^1.0.0-alpha.102":
|
||||
version "1.0.0-alpha.102"
|
||||
resolved "https://registry.yarnpkg.com/@hocuspocus/server/-/server-1.0.0-alpha.102.tgz#6c478032b3b30b45d96cbb744d8f61a6b9a71cf1"
|
||||
integrity sha512-U82HAy9S9gNuPShsUrefJH2Bdv71+6gjIueNW39oLiWjR87Nmuenjzu1gbVcC6sJwjlsj3JJ0E1NDPu0xTDfxQ==
|
||||
dependencies:
|
||||
"@types/async-lock" "^1.1.2"
|
||||
"@types/uuid" "^8.3.0"
|
||||
"@types/ws" "^8.2.0"
|
||||
async-lock "^1.2.8"
|
||||
lib0 "^0.2.41"
|
||||
"@hocuspocus/common" "^1.0.0-alpha.11"
|
||||
"@types/async-lock" "^1.1.3"
|
||||
"@types/uuid" "^8.3.4"
|
||||
"@types/ws" "^8.5.3"
|
||||
async-lock "^1.3.1"
|
||||
kleur "^4.1.4"
|
||||
lib0 "^0.2.46"
|
||||
uuid "^8.3.2"
|
||||
ws "^8.2.3"
|
||||
yjs "^13.5.0"
|
||||
ws "^8.5.0"
|
||||
y-protocols "^1.0.5"
|
||||
yjs "^13.5.29"
|
||||
|
||||
"@icons/material@^0.2.4":
|
||||
version "0.2.4"
|
||||
@@ -1802,10 +1813,10 @@
|
||||
"@babel/runtime" "^7.7.2"
|
||||
regenerator-runtime "^0.13.3"
|
||||
|
||||
"@lifeomic/attempt@^3.0.0":
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@lifeomic/attempt/-/attempt-3.0.0.tgz#75fecc204f8b0ac18b5363b4404bb32450f01859"
|
||||
integrity sha512-Ibk4Vfl46dSrhtH5fHsrTA4waAuyP7/qcr3uo0mO70azRc6LWgJILlMy3B1oOvyiN9jQcdqwsThaQkPKLiYKTg==
|
||||
"@lifeomic/attempt@^3.0.2":
|
||||
version "3.0.3"
|
||||
resolved "https://registry.yarnpkg.com/@lifeomic/attempt/-/attempt-3.0.3.tgz#e742a5b85eb673e2f1746b0f39cb932cbc6145bb"
|
||||
integrity sha512-GlM2AbzrErd/TmLL3E8hAHmb5Q7VhDJp35vIbyPVA5Rz55LZuRr8pwL3qrwwkVNo05gMX1J44gURKb4MHQZo7w==
|
||||
|
||||
"@nicolo-ribaudo/chokidar-2@^2.1.8":
|
||||
version "2.1.8"
|
||||
@@ -2582,10 +2593,10 @@
|
||||
dependencies:
|
||||
"@types/node" "*"
|
||||
|
||||
"@types/async-lock@^1.1.2":
|
||||
version "1.1.3"
|
||||
resolved "https://registry.yarnpkg.com/@types/async-lock/-/async-lock-1.1.3.tgz#0d86017cf87abbcb941c55360e533d37a3f23b3d"
|
||||
integrity sha512-UpeDcjGKsYEQMeqEbfESm8OWJI305I7b9KE4ji3aBjoKWyN5CTdn8izcA1FM1DVDne30R5fNEnIy89vZw5LXJQ==
|
||||
"@types/async-lock@^1.1.3":
|
||||
version "1.1.5"
|
||||
resolved "https://registry.yarnpkg.com/@types/async-lock/-/async-lock-1.1.5.tgz#a82f33e09aef451d6ded7bffae73f9d254723124"
|
||||
integrity sha512-A9ClUfmj6wwZMLRz0NaYzb98YH1exlHdf/cdDSKBfMQJnPOdO8xlEW0Eh2QsTTntGzOFWURcEjYElkZ1IY4GCQ==
|
||||
|
||||
"@types/babel__core@^7.0.0", "@types/babel__core@^7.1.14":
|
||||
version "7.1.17"
|
||||
@@ -3452,10 +3463,10 @@
|
||||
resolved "https://registry.yarnpkg.com/@types/utf8/-/utf8-3.0.0.tgz#8f4875063d2ea966c57a34a25c11333520e83980"
|
||||
integrity sha512-QrhvCktdm5wD48axAnjqSzPH9lOj0MiCYfMX6MSqGs2Jv+txwvdxviXiCEj8zSCWIEDU9SIJ7g9pU5KtxRgYSg==
|
||||
|
||||
"@types/uuid@^8.3.0":
|
||||
version "8.3.1"
|
||||
resolved "https://registry.yarnpkg.com/@types/uuid/-/uuid-8.3.1.tgz#1a32969cf8f0364b3d8c8af9cc3555b7805df14f"
|
||||
integrity sha512-Y2mHTRAbqfFkpjldbkHGY8JIzRN6XqYRliG8/24FcHm2D2PwW24fl5xMRTVGdrb7iMrwCaIEbLWerGIkXuFWVg==
|
||||
"@types/uuid@^8.3.4":
|
||||
version "8.3.4"
|
||||
resolved "https://registry.yarnpkg.com/@types/uuid/-/uuid-8.3.4.tgz#bd86a43617df0594787d38b735f55c805becf1bc"
|
||||
integrity sha512-c/I8ZRb51j+pYGAu5CrFMRxqZ2ke4y2grEBO5AUjgSkSk+qT2Ea+OdWElz/OiMf5MNpn2b17kuVBwZLQJXzihw==
|
||||
|
||||
"@types/validator@*", "@types/validator@^13.7.1":
|
||||
version "13.7.1"
|
||||
@@ -3483,10 +3494,10 @@
|
||||
anymatch "^3.0.0"
|
||||
source-map "^0.6.0"
|
||||
|
||||
"@types/ws@^8.2.0":
|
||||
version "8.2.0"
|
||||
resolved "https://registry.yarnpkg.com/@types/ws/-/ws-8.2.0.tgz#75faefbe2328f3b833cb8dc640658328990d04f3"
|
||||
integrity sha512-cyeefcUCgJlEk+hk2h3N+MqKKsPViQgF5boi9TTHSK+PoR9KWBb/C5ccPcDyAqgsbAYHTwulch725DV84+pSpg==
|
||||
"@types/ws@^8.5.3":
|
||||
version "8.5.3"
|
||||
resolved "https://registry.yarnpkg.com/@types/ws/-/ws-8.5.3.tgz#7d25a1ffbecd3c4f2d35068d0b283c037003274d"
|
||||
integrity sha512-6YOoWjruKj1uLf3INHH7D3qTXwFfEsg1kf3c0uDdSBJwfa/llkwIjrAGV7j7mVgGNbzTQ3HiHKKDXl6bJPD97w==
|
||||
dependencies:
|
||||
"@types/node" "*"
|
||||
|
||||
@@ -4130,10 +4141,10 @@ async-each@^1.0.1:
|
||||
resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.3.tgz#b727dbf87d7651602f06f4d4ac387f47d91b0cbf"
|
||||
integrity sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ==
|
||||
|
||||
async-lock@^1.2.8:
|
||||
version "1.3.0"
|
||||
resolved "https://registry.yarnpkg.com/async-lock/-/async-lock-1.3.0.tgz#0fba111bea8b9693020857eba4f9adca173df3e5"
|
||||
integrity sha512-8A7SkiisnEgME2zEedtDYPxUPzdv3x//E7n5IFktPAtMYSEAV7eNJF0rMwrVyUFj6d/8rgajLantbjcNRQYXIg==
|
||||
async-lock@^1.3.1:
|
||||
version "1.3.1"
|
||||
resolved "https://registry.yarnpkg.com/async-lock/-/async-lock-1.3.1.tgz#f2301c200600cde97acc386453b7126fa8aced3c"
|
||||
integrity sha512-zK7xap9UnttfbE23JmcrNIyueAn6jWshihJqA33U/hEnKprF/lVGBDsBv/bqLm2YMMl1DnpHhUY044eA0t1TUw==
|
||||
|
||||
async@0.9.x:
|
||||
version "0.9.2"
|
||||
@@ -9693,6 +9704,11 @@ kleur@^3.0.3:
|
||||
resolved "https://registry.yarnpkg.com/kleur/-/kleur-3.0.3.tgz#a79c9ecc86ee1ce3fa6206d1216c501f147fc07e"
|
||||
integrity sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==
|
||||
|
||||
kleur@^4.1.4:
|
||||
version "4.1.4"
|
||||
resolved "https://registry.yarnpkg.com/kleur/-/kleur-4.1.4.tgz#8c202987d7e577766d039a8cd461934c01cda04d"
|
||||
integrity sha512-8QADVssbrFjivHWQU7KkMgptGTl6WAcSdlbBPY4uNF+mWr6DGcKrvY2w4FQJoXch7+fKMjj0dRrL75vk3k23OA==
|
||||
|
||||
koa-body@^4.2.0:
|
||||
version "4.2.0"
|
||||
resolved "https://registry.yarnpkg.com/koa-body/-/koa-body-4.2.0.tgz#37229208b820761aca5822d14c5fc55cee31b26f"
|
||||
@@ -9975,10 +9991,10 @@ levn@~0.3.0:
|
||||
prelude-ls "~1.1.2"
|
||||
type-check "~0.3.2"
|
||||
|
||||
lib0@^0.2.35, lib0@^0.2.41, lib0@^0.2.42:
|
||||
version "0.2.42"
|
||||
resolved "https://registry.yarnpkg.com/lib0/-/lib0-0.2.42.tgz#6d8bf1fb8205dec37a953c521c5ee403fd8769b0"
|
||||
integrity sha512-8BNM4MiokEKzMvSxTOC3gnCBisJH+jL67CnSnqzHv3jli3pUvGC8wz+0DQ2YvGr4wVQdb2R2uNNPw9LEpVvJ4Q==
|
||||
lib0@^0.2.35, lib0@^0.2.42, lib0@^0.2.46, lib0@^0.2.47, lib0@^0.2.49:
|
||||
version "0.2.49"
|
||||
resolved "https://registry.yarnpkg.com/lib0/-/lib0-0.2.49.tgz#7addb5075063d66ea2c55749e5aeaa48e36278c8"
|
||||
integrity sha512-ziwYLe/pmI9bjHsAehm4ApuVfZ+q+sbC+vO6Z5+KM+0Fe0MrTLwZSDkJ+cElnhFNQ0P6z/wVkRmc5+vTmImJ9A==
|
||||
dependencies:
|
||||
isomorphic.js "^0.2.4"
|
||||
|
||||
@@ -15390,10 +15406,10 @@ ws@^7.4.6, ws@^7.5.3:
|
||||
resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.6.tgz#e59fc509fb15ddfb65487ee9765c5a51dec5fe7b"
|
||||
integrity sha512-6GLgCqo2cy2A2rjCNFlxQS6ZljG/coZfZXclldI8FB/1G3CCI36Zd8xy2HrFVACi8tfk5XrgLQEk+P0Tnz9UcA==
|
||||
|
||||
ws@^8.2.3:
|
||||
version "8.2.3"
|
||||
resolved "https://registry.yarnpkg.com/ws/-/ws-8.2.3.tgz#63a56456db1b04367d0b721a0b80cae6d8becbba"
|
||||
integrity sha512-wBuoj1BDpC6ZQ1B7DWQBYVLphPWkm8i9Y0/3YdHjHKHiohOJ1ws+3OccDWtH+PoC9DZD5WOTrJvNbWvjS6JWaA==
|
||||
ws@^8.5.0:
|
||||
version "8.5.0"
|
||||
resolved "https://registry.yarnpkg.com/ws/-/ws-8.5.0.tgz#bfb4be96600757fe5382de12c670dab984a1ed4f"
|
||||
integrity sha512-BWX0SWVgLPzYwF8lTzEy1egjhS4S4OEAHfsO8o65WOVsrnSRGaSiUaa9e0ggGlkMTtBlmOpEXiie9RUcBO86qg==
|
||||
|
||||
ws@~7.4.2:
|
||||
version "7.4.6"
|
||||
@@ -15614,12 +15630,12 @@ yeast@0.1.2:
|
||||
resolved "https://registry.yarnpkg.com/yeast/-/yeast-0.1.2.tgz#008e06d8094320c372dbc2f8ed76a0ca6c8ac419"
|
||||
integrity sha1-AI4G2AlDIMNy28L47XagymyKxBk=
|
||||
|
||||
yjs@^13.5.0, yjs@^13.5.12:
|
||||
version "13.5.12"
|
||||
resolved "https://registry.yarnpkg.com/yjs/-/yjs-13.5.12.tgz#7a0cf3119fb368c07243825e989a55de164b3f9c"
|
||||
integrity sha512-/buy1kh8Ls+t733Lgov9hiNxCsjHSCymTuZNahj2hsPNoGbvnSdDmCz9Z4F19Yr1eUAAXQLJF3q7fiBcvPC6Qg==
|
||||
yjs@^13.5.29, yjs@^13.5.34:
|
||||
version "13.5.34"
|
||||
resolved "https://registry.yarnpkg.com/yjs/-/yjs-13.5.34.tgz#ad9ddb8b6c0806e15b289ff0eabc4f06ba238952"
|
||||
integrity sha512-w/XTk5vhCzbyd6uKKJWE6rPUBf9+heOTzgq8DBkcVgBMv7oeJVFQw2sRqY0YvuLZxURd/XVD2dcNnw8qeFH7Tw==
|
||||
dependencies:
|
||||
lib0 "^0.2.41"
|
||||
lib0 "^0.2.49"
|
||||
|
||||
ylru@^1.2.0:
|
||||
version "1.2.1"
|
||||
|
||||
Reference in New Issue
Block a user