Merge pull request #13236 from meteor/fix/docs-removed-subs

Fix subscription still resetting documents
This commit is contained in:
Leonardo Venturini
2024-07-23 09:55:54 -03:00
committed by GitHub
9 changed files with 163 additions and 83 deletions

View File

@@ -2,9 +2,9 @@
"lockfileVersion": 4,
"dependencies": {
"@types/node": {
"version": "20.14.10",
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.14.10.tgz",
"integrity": "sha512-MdiXf+nDuMvY0gJKxyfZ7/6UFsETO7mGKF54MVD/ekJS6HdFtpZFBgrh6Pseu64XTb2MLyFPlbW6hj8HYRQNOQ=="
"version": "20.14.11",
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.14.11.tgz",
"integrity": "sha512-kprQpL8MMeszbz6ojB5/tU8PLN4kesnN8Gjzw349rDlNgsSzg90lAVj3llK99Dh7JON+t9AuscPPFW6mPbTnSA=="
},
"@types/notp": {
"version": "2.0.5",

View File

@@ -233,9 +233,9 @@
"integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="
},
"semver": {
"version": "7.6.2",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz",
"integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w=="
"version": "7.6.3",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz",
"integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A=="
},
"set-blocking": {
"version": "2.0.0",

View File

@@ -1034,6 +1034,9 @@ export class Connection {
// Always queues the call before sending the message
// Used, for example, on subscription.[id].stop() to make sure a "sub" message is always called before an "unsub" message
// https://github.com/meteor/meteor/issues/13212
//
// This is part of the actual fix for the rest check:
// https://github.com/meteor/meteor/pull/13236
_sendQueued(obj) {
this._send(obj, true);
}

View File

@@ -396,13 +396,6 @@ var Session = function (server, version, socket, options) {
};
Object.assign(Session.prototype, {
_checkPublishPromiseBeforeSend(f) {
if (!this._publishCursorPromise) {
f();
return;
}
this._publishCursorPromise.finally(() => f());
},
sendReady: function (subscriptionIds) {
var self = this;
if (self._isSending) {
@@ -556,13 +549,11 @@ Object.assign(Session.prototype, {
// It should be a JSON object (it will be stringified).
send: function (msg) {
const self = this;
this._checkPublishPromiseBeforeSend(() => {
if (self.socket) {
if (Meteor._printSentDDP)
Meteor._debug('Sent DDP', DDPCommon.stringifyDDP(msg));
self.socket.send(DDPCommon.stringifyDDP(msg));
}
});
if (self.socket) {
if (Meteor._printSentDDP)
Meteor._debug("Sent DDP", DDPCommon.stringifyDDP(msg));
self.socket.send(DDPCommon.stringifyDDP(msg));
}
},
// Send a connection error.
@@ -627,6 +618,7 @@ Object.assign(Session.prototype, {
var processNext = function () {
var msg = self.inQueue && self.inQueue.shift();
if (!msg) {
self.workerRunning = false;
return;
@@ -653,6 +645,7 @@ Object.assign(Session.prototype, {
msg,
unblock
);
if (Meteor._isPromise(result)) {
result.finally(() => unblock());
} else {
@@ -1207,16 +1200,16 @@ Object.assign(Subscription.prototype, {
resultOrThenable && typeof resultOrThenable.then === 'function';
if (isThenable) {
try {
self._publishHandlerResult(await resultOrThenable);
await self._publishHandlerResult(await resultOrThenable);
} catch(e) {
self.error(e)
}
} else {
self._publishHandlerResult(resultOrThenable);
await self._publishHandlerResult(resultOrThenable);
}
},
_publishHandlerResult: function (res) {
async _publishHandlerResult (res) {
// SPECIAL CASE: Instead of writing their own callbacks that invoke
// this.added/changed/ready/etc, the user can just return a collection
// cursor or array of cursors from the publish function; we call their
@@ -1239,11 +1232,15 @@ Object.assign(Subscription.prototype, {
return c && c._publishCursor;
};
if (isCursor(res)) {
this._publishCursorPromise = res._publishCursor(self).then(() => {
// _publishCursor only returns after the initial added callbacks have run.
// mark subscription as ready.
self.ready();
}).catch((e) => self.error(e));
try {
await res._publishCursor(self);
} catch (e) {
self.error(e);
return;
}
// _publishCursor only returns after the initial added callbacks have run.
// mark subscription as ready.
self.ready();
} else if (_.isArray(res)) {
// Check all the elements are cursors
if (! _.all(res, isCursor)) {
@@ -1254,6 +1251,7 @@ Object.assign(Subscription.prototype, {
// XXX we should support overlapping cursors, but that would require the
// merge box to allow overlap within a subscription
var collectionNames = {};
for (var i = 0; i < res.length; ++i) {
var collectionName = res[i]._getCollectionName();
if (_.has(collectionNames, collectionName)) {
@@ -1263,15 +1261,15 @@ Object.assign(Subscription.prototype, {
return;
}
collectionNames[collectionName] = true;
};
}
this._publishCursorPromise = Promise.all(
res.map(c => c._publishCursor(self))
)
.then(() => {
self.ready();
})
.catch((e) => self.error(e));
try {
await Promise.all(res.map(cur => cur._publishCursor(self)));
} catch (e) {
self.error(e);
return;
}
self.ready();
} else if (res) {
// Truthy values other than cursors or arrays are probably a
// user mistake (possible returning a Mongo document via, say,
@@ -1409,7 +1407,6 @@ Object.assign(Subscription.prototype, {
ids.add(id);
}
this._session._publishCursorPromise = this._publishCursorPromise;
this._session.added(this._subscriptionHandle, collectionName, id, fields);
},

View File

@@ -442,3 +442,75 @@ Tinytest.addAsync("livedata server - waiting for Promise", (test, onComplete) =>
.then(onComplete);
})
);
/**
* https://github.com/meteor/meteor/issues/13212
*/
Tinytest.addAsync('livedata server - publish cursor is properly awaited', async function (test) {
const messages = []
let sub = null;
const { clientConn } = await getTestConnections(test)
const send = clientConn._stream.send
clientConn._stream.send = function (...args) {
send.apply(this, args)
messages.push(args[0])
}
clientConn._stream.on('message', message => messages.push(message));
const coll = new Mongo.Collection('items', {
defineMutationMethods: false,
});
for (let i = 0; i < 10; i++) {
await coll.removeAsync({ _id: `item_${i}` })
await coll.insertAsync({ _id: `item_${i}`, title: `Item #${i}` });
}
const publicationName = `publication_${Random.id()}`
delete Meteor.server.publish_handlers[publicationName];
Meteor.publish(publicationName, async function (count) {
return coll.find({}, { limit: count });
});
const reactiveVar = new ReactiveVar(1);
const computation = Tracker.autorun(() => {
sub = clientConn.subscribe(publicationName, reactiveVar.get());
});
await sleep(100)
reactiveVar.set(2);
await sleep(100)
const expectedMessages = ['sub', 'added', 'ready', 'sub', 'unsub', 'added', 'ready', 'nosub']
/**
* There shouldn't ever be `removed` messages here, otherwise the UI will glitch
*/
const parsedMessages = messages.map(m => EJSON.parse(m).msg)
test.equal(parsedMessages, expectedMessages)
computation.stop();
});
function getTestConnections(test) {
return new Promise((resolve, reject) => {
makeTestConnection(test, (clientConn, serverConn) => {
resolve({ clientConn, serverConn });
}, reject);
})
}
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}

View File

@@ -49,6 +49,7 @@ Package.onUse(function (api) {
Package.onTest(function (api) {
api.use('ecmascript', ['client', 'server']);
api.use('ejson', ['client', 'server']);
api.use('livedata', ['client', 'server']);
api.use('mongo', ['client', 'server']);
api.use('test-helpers', ['client', 'server']);

View File

@@ -2,9 +2,9 @@
"lockfileVersion": 4,
"dependencies": {
"@types/node": {
"version": "20.14.10",
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.14.10.tgz",
"integrity": "sha512-MdiXf+nDuMvY0gJKxyfZ7/6UFsETO7mGKF54MVD/ekJS6HdFtpZFBgrh6Pseu64XTb2MLyFPlbW6hj8HYRQNOQ=="
"version": "20.14.11",
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.14.11.tgz",
"integrity": "sha512-kprQpL8MMeszbz6ojB5/tU8PLN4kesnN8Gjzw349rDlNgsSzg90lAVj3llK99Dh7JON+t9AuscPPFW6mPbTnSA=="
},
"@types/nodemailer": {
"version": "6.4.14",

View File

@@ -181,9 +181,9 @@
"integrity": "sha512-15ElZT88peoHnq5TEoEtZwoXTXRxNrk60TZNdpl/TUBJ5oNJ9Dqb5Z4ryb8ofN6nm9aFf59GVAerFDz8iUoHBA=="
},
"@mongodb-js/saslprep": {
"version": "1.1.7",
"resolved": "https://registry.npmjs.org/@mongodb-js/saslprep/-/saslprep-1.1.7.tgz",
"integrity": "sha512-dCHW/oEX0KJ4NjDULBo3JiOaK5+6axtpBbS+ao2ZInoAL9/YRQLhXzSNAFz7hP4nzLkIqsfYAK/PDE3+XHny0Q=="
"version": "1.1.8",
"resolved": "https://registry.npmjs.org/@mongodb-js/saslprep/-/saslprep-1.1.8.tgz",
"integrity": "sha512-qKwC/M/nNNaKUBMQ0nuzm47b7ZYWQHN3pcXq4IIcoSBc2hOIrflAxJduIvvqmhoz3gR2TacTAs8vlsCVPkiEdQ=="
},
"@smithy/abort-controller": {
"version": "3.1.1",
@@ -196,9 +196,9 @@
"integrity": "sha512-SkW5LxfkSI1bUC74OtfBbdz+grQXYiPYolyu8VfpLIjEoN/sHVBlLeGXMQ1vX4ejkgfv6sxVbQJ32yF2cl1veA=="
},
"@smithy/core": {
"version": "2.2.6",
"resolved": "https://registry.npmjs.org/@smithy/core/-/core-2.2.6.tgz",
"integrity": "sha512-tBbVIv/ui7/lLTKayYJJvi8JLVL2SwOQTbNFEOrvzSE3ktByvsa1erwBOnAMo8N5Vu30g7lN4lLStrU75oDGuw=="
"version": "2.2.7",
"resolved": "https://registry.npmjs.org/@smithy/core/-/core-2.2.7.tgz",
"integrity": "sha512-Wwd9QWKaYdR+n/oIqJbuwSr9lHuv7sa1e3Zu4wIToZl0sS7xapTYYqQtXP1hKKtIWz0jl8AhvOfNwkfT5jjV0w=="
},
"@smithy/credential-provider-imds": {
"version": "3.1.4",
@@ -206,9 +206,9 @@
"integrity": "sha512-NKyH01m97Xa5xf3pB2QOF3lnuE8RIK0hTVNU5zvZAwZU8uspYO4DHQVlK+Y5gwSrujTfHvbfd1D9UFJAc0iYKQ=="
},
"@smithy/fetch-http-handler": {
"version": "3.2.1",
"resolved": "https://registry.npmjs.org/@smithy/fetch-http-handler/-/fetch-http-handler-3.2.1.tgz",
"integrity": "sha512-0w0bgUvZmfa0vHN8a+moByhCJT07WN6AHKEhFSOLsDpnszm+5dLVv5utGaqbhOrZ/aF5x3xuPMs/oMCd+4O5xg=="
"version": "3.2.2",
"resolved": "https://registry.npmjs.org/@smithy/fetch-http-handler/-/fetch-http-handler-3.2.2.tgz",
"integrity": "sha512-3LaWlBZObyGrOOd7e5MlacnAKEwFBmAeiW/TOj2eR9475Vnq30uS2510+tnKbxrGjROfNdOhQqGo5j3sqLT6bA=="
},
"@smithy/hash-node": {
"version": "3.0.3",
@@ -226,9 +226,9 @@
"integrity": "sha512-+Fsu6Q6C4RSJiy81Y8eApjEB5gVtM+oFKTffg+jSuwtvomJJrhUJBu2zS8wjXSgH/g1MKEWrzyChTBe6clb5FQ=="
},
"@smithy/middleware-content-length": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/@smithy/middleware-content-length/-/middleware-content-length-3.0.3.tgz",
"integrity": "sha512-Dbz2bzexReYIQDWMr+gZhpwBetNXzbhnEMhYKA6urqmojO14CsXjnsoPYO8UL/xxcawn8ZsuVU61ElkLSltIUQ=="
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/@smithy/middleware-content-length/-/middleware-content-length-3.0.4.tgz",
"integrity": "sha512-wySGje/KfhsnF8YSh9hP16pZcl3C+X6zRsvSfItQGvCyte92LliilU3SD0nR7kTlxnAJwxY8vE/k4Eoezj847Q=="
},
"@smithy/middleware-endpoint": {
"version": "3.0.5",
@@ -236,9 +236,9 @@
"integrity": "sha512-V4acqqrh5tDxUEGVTOgf2lYMZqPQsoGntCrjrJZEeBzEzDry2d2vcI1QCXhGltXPPY+BMc6eksZMguA9fIY8vA=="
},
"@smithy/middleware-retry": {
"version": "3.0.9",
"resolved": "https://registry.npmjs.org/@smithy/middleware-retry/-/middleware-retry-3.0.9.tgz",
"integrity": "sha512-Mrv9omExU1gA7Y0VEJG2LieGfPYtwwcEiOnVGZ54a37NEMr66TJ0glFslOJFuKWG6izg5DpKIUmDV9rRxjm47Q=="
"version": "3.0.10",
"resolved": "https://registry.npmjs.org/@smithy/middleware-retry/-/middleware-retry-3.0.10.tgz",
"integrity": "sha512-+6ibpv6jpkTNJS6yErQSEjbxCWf1/jMeUSlpSlUiTYf73LGR9riSRlIrL1+JEW0eEpb6MelQ04BIc38aj8GtxQ=="
},
"@smithy/middleware-serde": {
"version": "3.0.3",
@@ -256,9 +256,9 @@
"integrity": "sha512-YvnElQy8HR4vDcAjoy7Xkx9YT8xZP4cBXcbJSgm/kxmiQu08DwUwj8rkGnyoJTpfl/3xYHH+d8zE+eHqoDCSdQ=="
},
"@smithy/node-http-handler": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/@smithy/node-http-handler/-/node-http-handler-3.1.2.tgz",
"integrity": "sha512-Td3rUNI7qqtoSLTsJBtsyfoG4cF/XMFmJr6Z2dX8QNzIi6tIW6YmuyFml8mJ2cNpyWNqITKbROMOFrvQjmsOvw=="
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/@smithy/node-http-handler/-/node-http-handler-3.1.3.tgz",
"integrity": "sha512-UiKZm8KHb/JeOPzHZtRUfyaRDO1KPKPpsd7iplhiwVGOeVdkiVJ5bVe7+NhWREMOKomrDIDdSZyglvMothLg0Q=="
},
"@smithy/property-provider": {
"version": "3.1.3",
@@ -266,9 +266,9 @@
"integrity": "sha512-zahyOVR9Q4PEoguJ/NrFP4O7SMAfYO1HLhB18M+q+Z4KFd4V2obiMnlVoUFzFLSPeVt1POyNWneHHrZaTMoc/g=="
},
"@smithy/protocol-http": {
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/@smithy/protocol-http/-/protocol-http-4.0.3.tgz",
"integrity": "sha512-x5jmrCWwQlx+Zv4jAtc33ijJ+vqqYN+c/ZkrnpvEe/uDas7AT7A/4Rc2CdfxgWv4WFGmEqODIrrUToPN6DDkGw=="
"version": "4.0.4",
"resolved": "https://registry.npmjs.org/@smithy/protocol-http/-/protocol-http-4.0.4.tgz",
"integrity": "sha512-fAA2O4EFyNRyYdFLVIv5xMMeRb+3fRKc/Rt2flh5k831vLvUmNFXcydeg7V3UeEhGURJI4c1asmGJBjvmF6j8Q=="
},
"@smithy/querystring-builder": {
"version": "3.0.3",
@@ -296,9 +296,9 @@
"integrity": "sha512-3BcPylEsYtD0esM4Hoyml/+s7WP2LFhcM3J2AGdcL2vx9O60TtfpDOL72gjb4lU8NeRPeKAwR77YNyyGvMbuEA=="
},
"@smithy/smithy-client": {
"version": "3.1.7",
"resolved": "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-3.1.7.tgz",
"integrity": "sha512-nZbJZB0XI3YnaFBWGDBr7kjaew6O0oNYNmopyIz6gKZEbxzrtH7rwvU1GcVxcSFoOwWecLJEe79fxEMljHopFQ=="
"version": "3.1.8",
"resolved": "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-3.1.8.tgz",
"integrity": "sha512-nUNGCa0NgvtD0eM45732EBp1H9JQITChMBegGtPRhJD00v3hiFF6tibiOihcYwP5mbp9Kui+sOCl86rDT/Ew2w=="
},
"@smithy/types": {
"version": "3.3.0",
@@ -336,14 +336,14 @@
"integrity": "sha512-pbjk4s0fwq3Di/ANL+rCvJMKM5bzAQdE5S/6RL5NXgMExFAi6UgQMPOm5yPaIWPpr+EOXKXRonJ3FoxKf4mCJQ=="
},
"@smithy/util-defaults-mode-browser": {
"version": "3.0.9",
"resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-browser/-/util-defaults-mode-browser-3.0.9.tgz",
"integrity": "sha512-WKPcElz92MAQG09miBdb0GxEH/MwD5GfE8g07WokITq5g6J1ROQfYCKC1wNnkqAGfrSywT7L0rdvvqlBplqiyA=="
"version": "3.0.10",
"resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-browser/-/util-defaults-mode-browser-3.0.10.tgz",
"integrity": "sha512-WgaNxh33md2zvlD+1TSceVmM7DIy7qYMtuhOat+HYoTntsg0QTbNvoB/5DRxEwSpN84zKf9O34yqzRRtxJZgFg=="
},
"@smithy/util-defaults-mode-node": {
"version": "3.0.9",
"resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-node/-/util-defaults-mode-node-3.0.9.tgz",
"integrity": "sha512-dQLrUqFxqpf0GvEKEuFdgXcdZwz6oFm752h4d6C7lQz+RLddf761L2r7dSwGWzESMMB3wKj0jL+skRhEGlecjw=="
"version": "3.0.10",
"resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-node/-/util-defaults-mode-node-3.0.10.tgz",
"integrity": "sha512-3x/pcNIFyaAEQqXc3qnQsCFLlTz/Mwsfl9ciEPU56/Dk/g1kTFjkzyLbUNJaeOo5HT01VrpJBKrBuN94qbPm9A=="
},
"@smithy/util-endpoints": {
"version": "2.0.5",
@@ -366,9 +366,9 @@
"integrity": "sha512-AFw+hjpbtVApzpNDhbjNG5NA3kyoMs7vx0gsgmlJF4s+yz1Zlepde7J58zpIRIsdjc+emhpAITxA88qLkPF26w=="
},
"@smithy/util-stream": {
"version": "3.0.6",
"resolved": "https://registry.npmjs.org/@smithy/util-stream/-/util-stream-3.0.6.tgz",
"integrity": "sha512-w9i//7egejAIvplX821rPWWgaiY1dxsQUw0hXX7qwa/uZ9U3zplqTQ871jWadkcVB9gFDhkPWYVZf4yfFbZ0xA=="
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/@smithy/util-stream/-/util-stream-3.1.0.tgz",
"integrity": "sha512-QEMvyv58QIptWA8cpQPbHagJOAlrbCt3ueB9EShwdFfVMYAviXdVtksszQQq+o+dv5dalUMWUbUHUDSJgkF9xg=="
},
"@smithy/util-uri-escape": {
"version": "3.0.0",
@@ -381,9 +381,9 @@
"integrity": "sha512-rUeT12bxFnplYDe815GXbq/oixEGHfRFFtcTF3YdDi/JaENIM6aSYYLJydG83UNzLXeRI5K8abYd/8Sp/QM0kA=="
},
"@types/node": {
"version": "20.14.10",
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.14.10.tgz",
"integrity": "sha512-MdiXf+nDuMvY0gJKxyfZ7/6UFsETO7mGKF54MVD/ekJS6HdFtpZFBgrh6Pseu64XTb2MLyFPlbW6hj8HYRQNOQ=="
"version": "20.14.11",
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.14.11.tgz",
"integrity": "sha512-kprQpL8MMeszbz6ojB5/tU8PLN4kesnN8Gjzw349rDlNgsSzg90lAVj3llK99Dh7JON+t9AuscPPFW6mPbTnSA=="
},
"@types/webidl-conversions": {
"version": "7.0.3",

View File

@@ -32,9 +32,9 @@
"integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w=="
},
"@types/node": {
"version": "20.14.10",
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.14.10.tgz",
"integrity": "sha512-MdiXf+nDuMvY0gJKxyfZ7/6UFsETO7mGKF54MVD/ekJS6HdFtpZFBgrh6Pseu64XTb2MLyFPlbW6hj8HYRQNOQ=="
"version": "20.14.11",
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.14.11.tgz",
"integrity": "sha512-kprQpL8MMeszbz6ojB5/tU8PLN4kesnN8Gjzw349rDlNgsSzg90lAVj3llK99Dh7JON+t9AuscPPFW6mPbTnSA=="
},
"@types/qs": {
"version": "6.9.15",
@@ -308,14 +308,21 @@
"integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg=="
},
"mime-db": {
"version": "1.52.0",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
"integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg=="
"version": "1.53.0",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.53.0.tgz",
"integrity": "sha512-oHlN/w+3MQ3rba9rqFr6V/ypF10LSkdwUysQL7GkXoTgIWeV+tcXGA852TBxH+gsh8UWoyhR1hKcoMJTuWflpg=="
},
"mime-types": {
"version": "2.1.35",
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
"integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw=="
"integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
"dependencies": {
"mime-db": {
"version": "1.52.0",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
"integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg=="
}
}
},
"ms": {
"version": "2.0.0",