From ae49aa44bb17c8488ee8e08f66fcbbf30d0d1699 Mon Sep 17 00:00:00 2001 From: zodern Date: Fri, 3 Mar 2023 17:07:23 -0600 Subject: [PATCH 01/18] Use __meteor_bootstrap__ to check if fibers enabled --- packages/meteor/asl-helpers-client.js | 2 ++ packages/meteor/asl-helpers.js | 4 +++- tools/isobuild/isopack.js | 15 +++++++++++++-- tools/static-assets/server/boot.js | 4 ++-- tools/tool-env/isopackets.js | 5 ++++- 5 files changed, 24 insertions(+), 6 deletions(-) diff --git a/packages/meteor/asl-helpers-client.js b/packages/meteor/asl-helpers-client.js index 688ae22205..1026afcb80 100644 --- a/packages/meteor/asl-helpers-client.js +++ b/packages/meteor/asl-helpers-client.js @@ -1,3 +1,5 @@ +Meteor.fibersDisabled = true; + Meteor._isPromise = (r) => { return r && typeof r.then === 'function'; }; diff --git a/packages/meteor/asl-helpers.js b/packages/meteor/asl-helpers.js index f140cc9a3c..1ae0571e7f 100644 --- a/packages/meteor/asl-helpers.js +++ b/packages/meteor/asl-helpers.js @@ -2,7 +2,9 @@ const getAslStore = () => (Meteor.isServer && global?.asyncLocalStorage?.getStor const getValueFromAslStore = key => getAslStore()[key]; const updateAslStore = (key, value) => getAslStore()[key] = value; -Meteor._isFibersEnabled = !process.env.DISABLE_FIBERS && Meteor.isServer; +Meteor.fibersDisabled = !!__meteor_bootstrap__.fibersDisabled; +Meteor._isFibersEnabled = !Meteor.fibersDisabled; + Meteor._getAslStore = getAslStore; Meteor._getValueFromAslStore = getValueFromAslStore; Meteor._updateAslStore = updateAslStore; diff --git a/tools/isobuild/isopack.js b/tools/isobuild/isopack.js index b1925feaf4..e366afd1b2 100644 --- a/tools/isobuild/isopack.js +++ b/tools/isobuild/isopack.js @@ -472,8 +472,19 @@ Object.assign(Isopack.prototype, { // case right.) }, async function () { // Make a new Plugin API object for this plugin. - var Plugin = self._makePluginApi(name); - await plugin.load({ Plugin: Plugin, Profile: Profile }); + const Plugin = self._makePluginApi(name); + const __meteor_bootstrap__ = { + fibersDisabled: true, + // Set to null to tell Meteor.startup to call hooks immediately + // XXX: should we fully support startup hooks in build plugins? + startupHooks: null + }; + + await plugin.load({ + Plugin, + Profile, + __meteor_bootstrap__ + }); }); } diff --git a/tools/static-assets/server/boot.js b/tools/static-assets/server/boot.js index ca6f586c25..453d30e779 100644 --- a/tools/static-assets/server/boot.js +++ b/tools/static-assets/server/boot.js @@ -33,7 +33,8 @@ var starJson = JSON.parse(fs.readFileSync(path.join(buildDir, "star.json"))); __meteor_bootstrap__ = { startupHooks: [], serverDir: serverDir, - configJson: configJson + configJson: configJson, + fibersDisabled: true }; __meteor_runtime_config__ = { @@ -504,4 +505,3 @@ var runMain = Profile("Run main()", async function () { }); }); })().catch(e => console.log('error on boot.js', e)); - diff --git a/tools/tool-env/isopackets.js b/tools/tool-env/isopackets.js index d2c21afd6d..acd59e7a40 100644 --- a/tools/tool-env/isopackets.js +++ b/tools/tool-env/isopackets.js @@ -303,7 +303,10 @@ var loadIsopacketFromDisk = async function (isopacketName) { // An incredibly minimalist version of the environment from // tools/server/boot.js. Kind of a hack. var env = { - __meteor_bootstrap__: { startupHooks: [] }, + __meteor_bootstrap__: { + startupHooks: [], + fibersDisabled: true + }, __meteor_runtime_config__: { meteorRelease: "ISOPACKET" } }; env.Profile = Profile; From 6a304c66c185f0999d19e6ce70ee9141ef0e18fe Mon Sep 17 00:00:00 2001 From: zodern Date: Fri, 3 Mar 2023 17:07:42 -0600 Subject: [PATCH 02/18] Re-add async-await plugin --- .../meteor-babel/plugins/async-await.js | 74 +++++++++++++++++++ 1 file changed, 74 insertions(+) create mode 100644 npm-packages/meteor-babel/plugins/async-await.js diff --git a/npm-packages/meteor-babel/plugins/async-await.js b/npm-packages/meteor-babel/plugins/async-await.js new file mode 100644 index 0000000000..ffd97d28af --- /dev/null +++ b/npm-packages/meteor-babel/plugins/async-await.js @@ -0,0 +1,74 @@ +"use strict"; + +module.exports = function (babel) { + const t = babel.types; + + return { + name: "transform-meteor-async-await", + visitor: { + Function: { + exit: function (path) { + const node = path.node; + if (!node.async) { + return; + } + + // The original function becomes a non-async function that + // returns a Promise. + node.async = false; + + // The inner function should inherit lexical environment items + // like `this`, `super`, and `arguments` from the outer + // function, and arrow functions provide exactly that behavior. + const innerFn = t.arrowFunctionExpression( + // The inner function has no parameters of its own, but can + // refer to the outer parameters of the original function. + [], + node.body, + // The inner function called by Promise.asyncApply should be + // async if we have native async/await support. + !!this.opts.useNativeAsyncAwait + ); + + const promiseResultExpression = t.callExpression( + t.memberExpression( + t.identifier("Promise"), + t.identifier("asyncApply"), + false + ), [innerFn] + ); + + // Calling the async function with Promise.asyncApply is + // important to ensure that the part before the first await + // expression runs synchronously in its own Fiber, even when + // there is native support for async/await. + if (node.type === "ArrowFunctionExpression") { + node.body = promiseResultExpression; + } else { + node.body = t.blockStatement([ + t.returnStatement(promiseResultExpression) + ]); + } + } + }, + + AwaitExpression: function (path) { + if (this.opts.useNativeAsyncAwait) { + // No need to transform await expressions if we have native + // support for them. + return; + } + + const node = path.node; + path.replaceWith(t.callExpression( + t.memberExpression( + t.identifier("Promise"), + t.identifier(node.all ? "awaitAll" : "await"), + false + ), + [node.argument] + )); + } + } + }; +}; From 8babb0c8deb1db64cff65b7d3957ba53c605ab02 Mon Sep 17 00:00:00 2001 From: zodern Date: Fri, 3 Mar 2023 17:09:19 -0600 Subject: [PATCH 03/18] Use features to configure async-await plugin --- npm-packages/meteor-babel/options.js | 9 ++++----- packages/babel-compiler/babel-compiler.js | 2 ++ tools/isobuild/builder.js | 3 ++- tools/tool-env/install-babel.js | 3 ++- 4 files changed, 10 insertions(+), 7 deletions(-) diff --git a/npm-packages/meteor-babel/options.js b/npm-packages/meteor-babel/options.js index 7f3db27945..7ff86ac842 100644 --- a/npm-packages/meteor-babel/options.js +++ b/npm-packages/meteor-babel/options.js @@ -188,16 +188,15 @@ function getDefaultsForNode8(features) { ); // TODO [fibers]: instead of removing the code below, consider this comment: // https://github.com/meteor/meteor/pull/12471/files#r1089610144 - const isFiberDisabled = process.env.DISABLE_FIBERS === '1'; const ignoreAsyncPlugin = process.env.IGNORE_ASYNC_PLUGIN === '1'; - if (!ignoreAsyncPlugin) { + if (!features.useNativeAsyncAwait && !ignoreAsyncPlugin) { combined.plugins.push([ require('./plugins/async-await.js'), { - // Do not transform `await x` to `Promise.await(x)`, since Node - // 8 has native support for await expressions. - useNativeAsyncAwait: isFiberDisabled, + // Even though Node 8 supports native async/await, it is not + // compatible with fibers. + useNativeAsyncAwait: false, }, ]); } diff --git a/packages/babel-compiler/babel-compiler.js b/packages/babel-compiler/babel-compiler.js index 879b6b302e..cacf9ebe95 100644 --- a/packages/babel-compiler/babel-compiler.js +++ b/packages/babel-compiler/babel-compiler.js @@ -96,6 +96,8 @@ BCp.processOneFileForTarget = function (inputFile, source) { features.topLevelAwait = arch.startsWith('os.') || enableClientTLA + features.useNativeAsyncAwait = Meteor.fibersDisabled; + if (! features.hasOwnProperty("jscript")) { // Perform some additional transformations to improve compatibility // in older browsers (e.g. wrapping named function expressions, per diff --git a/tools/isobuild/builder.js b/tools/isobuild/builder.js index 98f74a1a19..563d47bf01 100644 --- a/tools/isobuild/builder.js +++ b/tools/isobuild/builder.js @@ -369,7 +369,8 @@ Previous builder: ${previousBuilder.outputPath}, this builder: ${outputPath}` const babel = require("@meteorjs/babel"); const commonBabelOptions = babel.getDefaultOptions({ nodeMajorVersion: parseInt(process.versions.node), - typescript: true + typescript: true, + useNativeAsyncAwait: true }); commonBabelOptions.sourceMaps = true; diff --git a/tools/tool-env/install-babel.js b/tools/tool-env/install-babel.js index fb79789846..a49bcb6a7b 100644 --- a/tools/tool-env/install-babel.js +++ b/tools/tool-env/install-babel.js @@ -11,7 +11,8 @@ function babelRegister() { const cacheDir = path.join(meteorPath, ".babel-cache"); const babelOptions = meteorBabel.getDefaultOptions({ nodeMajorVersion: parseInt(process.versions.node), - typescript: true + typescript: true, + useNativeAsyncAwait: true }); // Make sure that source maps are included in the generated code for From c727788332842f63d43107763ae46f82a0a5fa44 Mon Sep 17 00:00:00 2001 From: zodern Date: Mon, 6 Mar 2023 10:45:29 -0600 Subject: [PATCH 04/18] Rename fibersDisabled to isFibersDisabled --- packages/babel-compiler/babel-compiler.js | 2 +- packages/meteor/asl-helpers-client.js | 2 +- packages/meteor/asl-helpers.js | 4 ++-- tools/isobuild/isopack.js | 2 +- tools/static-assets/server/boot.js | 2 +- tools/tool-env/isopackets.js | 2 +- 6 files changed, 7 insertions(+), 7 deletions(-) diff --git a/packages/babel-compiler/babel-compiler.js b/packages/babel-compiler/babel-compiler.js index cacf9ebe95..2b7e2e8301 100644 --- a/packages/babel-compiler/babel-compiler.js +++ b/packages/babel-compiler/babel-compiler.js @@ -96,7 +96,7 @@ BCp.processOneFileForTarget = function (inputFile, source) { features.topLevelAwait = arch.startsWith('os.') || enableClientTLA - features.useNativeAsyncAwait = Meteor.fibersDisabled; + features.useNativeAsyncAwait = Meteor.isFibersDisabled; if (! features.hasOwnProperty("jscript")) { // Perform some additional transformations to improve compatibility diff --git a/packages/meteor/asl-helpers-client.js b/packages/meteor/asl-helpers-client.js index 1026afcb80..4780867f3a 100644 --- a/packages/meteor/asl-helpers-client.js +++ b/packages/meteor/asl-helpers-client.js @@ -1,4 +1,4 @@ -Meteor.fibersDisabled = true; +Meteor.isFibersDisabled = true; Meteor._isPromise = (r) => { return r && typeof r.then === 'function'; diff --git a/packages/meteor/asl-helpers.js b/packages/meteor/asl-helpers.js index 1ae0571e7f..bd9271b7cb 100644 --- a/packages/meteor/asl-helpers.js +++ b/packages/meteor/asl-helpers.js @@ -2,8 +2,8 @@ const getAslStore = () => (Meteor.isServer && global?.asyncLocalStorage?.getStor const getValueFromAslStore = key => getAslStore()[key]; const updateAslStore = (key, value) => getAslStore()[key] = value; -Meteor.fibersDisabled = !!__meteor_bootstrap__.fibersDisabled; -Meteor._isFibersEnabled = !Meteor.fibersDisabled; +Meteor.isFibersDisabled = !!__meteor_bootstrap__.isFibersDisabled; +Meteor._isFibersEnabled = !Meteor.isFibersDisabled; Meteor._getAslStore = getAslStore; Meteor._getValueFromAslStore = getValueFromAslStore; diff --git a/tools/isobuild/isopack.js b/tools/isobuild/isopack.js index e366afd1b2..31be03ed33 100644 --- a/tools/isobuild/isopack.js +++ b/tools/isobuild/isopack.js @@ -474,7 +474,7 @@ Object.assign(Isopack.prototype, { // Make a new Plugin API object for this plugin. const Plugin = self._makePluginApi(name); const __meteor_bootstrap__ = { - fibersDisabled: true, + isFibersDisabled: true, // Set to null to tell Meteor.startup to call hooks immediately // XXX: should we fully support startup hooks in build plugins? startupHooks: null diff --git a/tools/static-assets/server/boot.js b/tools/static-assets/server/boot.js index 453d30e779..1d2d7210f5 100644 --- a/tools/static-assets/server/boot.js +++ b/tools/static-assets/server/boot.js @@ -34,7 +34,7 @@ __meteor_bootstrap__ = { startupHooks: [], serverDir: serverDir, configJson: configJson, - fibersDisabled: true + isFibersDisabled: true }; __meteor_runtime_config__ = { diff --git a/tools/tool-env/isopackets.js b/tools/tool-env/isopackets.js index acd59e7a40..14f4700791 100644 --- a/tools/tool-env/isopackets.js +++ b/tools/tool-env/isopackets.js @@ -305,7 +305,7 @@ var loadIsopacketFromDisk = async function (isopacketName) { var env = { __meteor_bootstrap__: { startupHooks: [], - fibersDisabled: true + isFibersDisabled: true }, __meteor_runtime_config__: { meteorRelease: "ISOPACKET" } }; From 0be6f3192084fa81717fd51a6458e3214b20c82b Mon Sep 17 00:00:00 2001 From: "Henrique A. Schmaiske" Date: Tue, 7 Mar 2023 15:05:50 -0300 Subject: [PATCH 05/18] fix hmr compare --- .../babel-compiler/.npm/package/npm-shrinkwrap.json | 2 ++ tools/runners/run-hmr.js | 12 +++++++----- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/packages/babel-compiler/.npm/package/npm-shrinkwrap.json b/packages/babel-compiler/.npm/package/npm-shrinkwrap.json index 93f61b4302..5ed1c5ece3 100644 --- a/packages/babel-compiler/.npm/package/npm-shrinkwrap.json +++ b/packages/babel-compiler/.npm/package/npm-shrinkwrap.json @@ -3,6 +3,8 @@ "dependencies": { "@meteorjs/babel": { "version": "7.19.0-beta.1", + "resolved": "https://registry.npmjs.org/@meteorjs/babel/-/babel-7.19.0-beta.1.tgz", + "integrity": "sha512-4dy7oSXEo6Eb2PHfPkMX0VVnkQJ9Kb6Qv6/ssiXOqQRtTRpBAgeWeMzUd42u/8VzxG6l8NoNqIhPSOHZjC2usg==", "dependencies": { "@ampproject/remapping": { "version": "2.1.1", diff --git a/tools/runners/run-hmr.js b/tools/runners/run-hmr.js index a7625dbabd..466bc927cc 100644 --- a/tools/runners/run-hmr.js +++ b/tools/runners/run-hmr.js @@ -184,7 +184,7 @@ export class HMRServer { } } - compare({ name, arch, hmrAvailable, files, cacheKey }, getFileOutput) { + async compare({ name, arch, hmrAvailable, files, cacheKey }, getFileOutput) { if (this.firstBuild = null) { this.firstBuild = Date.now(); } @@ -248,9 +248,11 @@ export class HMRServer { onlyReplaceableChanges && removedFilePaths.length === 0; - function saveFileDetails(file) { + async function saveFileDetails(file) { + + const content = await getFileOutput(file); return { - content: getFileOutput(file).toStringWithSourceMap({}), + content: content.toStringWithSourceMap({}), path: file.absModuleId, meteorInstallOptions: file.meteorInstallOptions }; @@ -260,8 +262,8 @@ export class HMRServer { fileHashes, unreloadableHashes: unreloadable, reloadable, - addedFiles: reloadable ? addedFiles.map(saveFileDetails) : [], - changedFiles: reloadable ? changedFiles.map(saveFileDetails) : [], + addedFiles: reloadable ? await Promise.all(addedFiles.map(saveFileDetails)) : [], + changedFiles: reloadable ? await Promise.all(changedFiles.map(saveFileDetails)) : [], linkedAt: Date.now(), id: this._createId(), name From 35a62a34d35067fc0492cabf7554d7ad87477fc0 Mon Sep 17 00:00:00 2001 From: Gabriel Grubba Date: Tue, 7 Mar 2023 15:18:22 -0300 Subject: [PATCH 06/18] chore: updated babel lock file --- packages/babel-compiler/.npm/package/npm-shrinkwrap.json | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/packages/babel-compiler/.npm/package/npm-shrinkwrap.json b/packages/babel-compiler/.npm/package/npm-shrinkwrap.json index 93f61b4302..d5a644b0f6 100644 --- a/packages/babel-compiler/.npm/package/npm-shrinkwrap.json +++ b/packages/babel-compiler/.npm/package/npm-shrinkwrap.json @@ -3,6 +3,8 @@ "dependencies": { "@meteorjs/babel": { "version": "7.19.0-beta.1", + "resolved": "https://registry.npmjs.org/@meteorjs/babel/-/babel-7.19.0-beta.1.tgz", + "integrity": "sha512-4dy7oSXEo6Eb2PHfPkMX0VVnkQJ9Kb6Qv6/ssiXOqQRtTRpBAgeWeMzUd42u/8VzxG6l8NoNqIhPSOHZjC2usg==", "dependencies": { "@ampproject/remapping": { "version": "2.1.1", @@ -1188,11 +1190,6 @@ "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==" }, - "fibers": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/fibers/-/fibers-5.0.0.tgz", - "integrity": "sha512-UpGv/YAZp7mhKHxDvC1tColrroGRX90sSvh8RMZV9leo+e5+EkRVgCEZPlmXeo3BUNQTZxUaVdLskq1Q2FyCPg==" - }, "find-up": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", From 89dd8cd0620fff786653077ca1ac8f55691951dc Mon Sep 17 00:00:00 2001 From: Gabriel Grubba Date: Tue, 7 Mar 2023 15:18:35 -0300 Subject: [PATCH 07/18] chore: updated client_convenience --- packages/ddp-client/client/client_convenience.js | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/ddp-client/client/client_convenience.js b/packages/ddp-client/client/client_convenience.js index 7fc3222106..35bd3bb480 100644 --- a/packages/ddp-client/client/client_convenience.js +++ b/packages/ddp-client/client/client_convenience.js @@ -47,6 +47,7 @@ Meteor.connection = DDP.connect(ddpUrl, { [ 'subscribe', 'methods', + 'isAsyncCall', 'call', 'callAsync', 'apply', From f2253fe6199bb8d20dc27b99dc58f2ca104d9ed9 Mon Sep 17 00:00:00 2001 From: Gabriel Grubba Date: Tue, 7 Mar 2023 15:18:46 -0300 Subject: [PATCH 08/18] feat: isAsyncCall --- packages/ddp-client/common/livedata_connection.js | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/packages/ddp-client/common/livedata_connection.js b/packages/ddp-client/common/livedata_connection.js index 64726d7d7e..19e2f2680b 100644 --- a/packages/ddp-client/common/livedata_connection.js +++ b/packages/ddp-client/common/livedata_connection.js @@ -511,6 +511,17 @@ export class Connection { return handle; } + /** + * @summary Tells if the method call came from a call or a callAsync. + * @alias Meteor.isAsyncCall + * @locus Anywhere + * @memberOf Meteor + * @importFromPackage meteor + * @returns boolean + */ + isAsyncCall(){ + return DDP._CurrentMethodInvocation._isCallAsyncMethodRunning() + } methods(methods) { Object.entries(methods).forEach(([name, func]) => { if (typeof func !== 'function') { @@ -722,7 +733,6 @@ export class Connection { _apply(name, stubCallValue, args, options, callback) { const self = this; - // We were passed 3 arguments. They may be either (name, args, options) // or (name, args, callback) if (!callback && typeof options === 'function') { From 9eff7676896bcc2320226232dbee348cf2b59f20 Mon Sep 17 00:00:00 2001 From: Gabriel Grubba Date: Tue, 7 Mar 2023 15:18:57 -0300 Subject: [PATCH 09/18] tests: added method to isCallAsync --- packages/ddp-client/test/livedata_test_service.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/packages/ddp-client/test/livedata_test_service.js b/packages/ddp-client/test/livedata_test_service.js index 55d6e49ba8..2bf5b2be38 100644 --- a/packages/ddp-client/test/livedata_test_service.js +++ b/packages/ddp-client/test/livedata_test_service.js @@ -378,3 +378,9 @@ Meteor.methods({ resultByValueArrays[testId].push(value); } }); +/// Helper for "livedata - isAsync call" +Meteor.methods({ + isCallAsync: function () { + return Meteor.isAsyncCall() + } +}) From 4495e1edef80f0e3b25b4cfd1958e6003ad0a987 Mon Sep 17 00:00:00 2001 From: Gabriel Grubba Date: Tue, 7 Mar 2023 15:19:16 -0300 Subject: [PATCH 10/18] tests: added tests for isCallAsync --- packages/ddp-client/test/livedata_tests.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/packages/ddp-client/test/livedata_tests.js b/packages/ddp-client/test/livedata_tests.js index 1a1bd83564..05637dd208 100644 --- a/packages/ddp-client/test/livedata_tests.js +++ b/packages/ddp-client/test/livedata_tests.js @@ -1208,6 +1208,12 @@ testAsyncMulti('livedata - methods with nested stubs', [ }, ]); + Tinytest.addAsync('livedata - isAsync call', async function (test) { + Meteor.call('isCallAsync', (err, result) => test.equal(result, false)) + const result = await Meteor.callAsync('isCallAsync', { returnStubValue: true }) + test.equal(result, true) +}) + // XXX some things to test in greater detail: // staying in simulation mode // time warp From 6ce199676427626c071851127e3d9470e4a5c373 Mon Sep 17 00:00:00 2001 From: Gabriel Grubba Date: Tue, 7 Mar 2023 15:19:30 -0300 Subject: [PATCH 11/18] implemented isAsyncCall in server --- packages/ddp-server/livedata_server.js | 28 +++++++++++++++++++++++--- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/packages/ddp-server/livedata_server.js b/packages/ddp-server/livedata_server.js index 6abacec729..3a8d975601 100644 --- a/packages/ddp-server/livedata_server.js +++ b/packages/ddp-server/livedata_server.js @@ -1726,6 +1726,17 @@ Object.assign(Server.prototype, { self.sessions.delete(session.id); }, + /** + * @summary Tells if the method call came from a call or a callAsync. + * @locus Anywhere + * @memberOf Meteor + * @importFromPackage meteor + * @returns boolean + */ + isAsyncCall: function(){ + return DDP._CurrentMethodInvocation._isCallAsyncMethodRunning() + }, + /** * @summary Defines functions that can be invoked over the network by clients. * @locus Anywhere @@ -1759,7 +1770,20 @@ Object.assign(Server.prototype, { const options = args[0]?.hasOwnProperty('returnStubValue') ? args.shift() : {}; - return this.applyAsync(name, args, options); + DDP._CurrentMethodInvocation._set(); + DDP._CurrentMethodInvocation._setCallAsyncMethodRunning(true); + const promise = new Promise((resolve, reject) => { + DDP._CurrentCallAsyncInvocation._set({ name, hasCallAsyncParent: true }); + this.applyAsync(name, args, { isFromCallAsync: true, ...options }) + .then(resolve) + .catch(reject) + .finally(() => { + DDP._CurrentCallAsyncInvocation._set(); + }); + }); + return promise.finally(() => + DDP._CurrentMethodInvocation._setCallAsyncMethodRunning(false) + ); }, apply: function (name, args, options, callback) { @@ -1771,7 +1795,6 @@ Object.assign(Server.prototype, { } else { options = options || {}; } - const promise = this.applyAsync(name, args, options); // Return the result in whichever way the caller asked for it. Note that we @@ -1799,7 +1822,6 @@ Object.assign(Server.prototype, { new Meteor.Error(404, `Method '${name}' not found`) ); } - // If this is a method call from within another method or publish function, // get the user state from the outer method or publish function, otherwise // don't allow setUserId to be called From 02cbc8603d4b1b2abc77dfcb986d42e944291734 Mon Sep 17 00:00:00 2001 From: Gabriel Grubba Date: Tue, 7 Mar 2023 15:19:39 -0300 Subject: [PATCH 12/18] chore: updated server_convenience --- packages/ddp-server/server_convenience.js | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/ddp-server/server_convenience.js b/packages/ddp-server/server_convenience.js index a8d3a7c2d3..e3adfb5b2e 100755 --- a/packages/ddp-server/server_convenience.js +++ b/packages/ddp-server/server_convenience.js @@ -14,6 +14,7 @@ Meteor.refresh = async function (notification) { _.each( [ 'publish', + 'isAsyncCall', 'methods', 'call', 'callAsync', From 6bdb0529a9b2e055990d8f1574a0609047b41815 Mon Sep 17 00:00:00 2001 From: Gabriel Grubba Date: Tue, 7 Mar 2023 15:25:31 -0300 Subject: [PATCH 13/18] docs: added docs about ddp --- docs/history.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/history.md b/docs/history.md index 70335ec97d..a16bf2c3fb 100644 --- a/docs/history.md +++ b/docs/history.md @@ -56,6 +56,9 @@ * `boilerplate-generator`: - `toHTML` is no longer available (it was already deprecated). Use `toHTMLStream` instead. +* `ddp`: + - Added method `Meteor.isAsyncCall` that can be used to check if the current method call is async or not. + * `oauth`: - `_endOfPopupResponseTemplate` and `_endOfRedirectResponseTemplate` are no longer a property but now a function that returns a promise of the same value as before - the following server methods are now async: From 1affcd7e4f97d98816ec31b04f5c92aa5ae4388d Mon Sep 17 00:00:00 2001 From: Gabriel Grubba Date: Tue, 7 Mar 2023 15:31:18 -0300 Subject: [PATCH 14/18] updated methods in api box --- docs/source/api/methods.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/docs/source/api/methods.md b/docs/source/api/methods.md index 58ae24f15f..fc9328c459 100644 --- a/docs/source/api/methods.md +++ b/docs/source/api/methods.md @@ -80,6 +80,12 @@ with this ID has already been made. Alternatively, you can use Read more about methods and how to use them in the [Methods](http://guide.meteor.com/methods.html) article in the Meteor Guide. +{% apibox "Meteor.isAsyncCall" %} + +This method can be used to determine if the current method invocation is +asynchronous. It returns true if the method is running on the server and came from +an async call(`Meteor.callAsync`) + {% apibox "DDPCommon.MethodInvocation#userId" %} The user id is an arbitrary string — typically the id of the user record From 4ac034b775bd79e5741faa74a37a285e2f5cc327 Mon Sep 17 00:00:00 2001 From: "Henrique A. Schmaiske" Date: Tue, 7 Mar 2023 18:12:22 -0300 Subject: [PATCH 15/18] improve addedFiles and changedFiles performance on HMR --- tools/runners/run-hmr.js | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/tools/runners/run-hmr.js b/tools/runners/run-hmr.js index 466bc927cc..c375d62f99 100644 --- a/tools/runners/run-hmr.js +++ b/tools/runners/run-hmr.js @@ -258,12 +258,26 @@ export class HMRServer { }; } + // TODO: try to improve the performance of this + const iterWithFn = async (iter, fn) => { + let arr = []; + for (let i = 0; i < iter.length; i++) { + try { + const d = await fn(iter[i]); + arr.push(d); + } catch (e) { + console.log(e); + } + } + return arr; + } + const result = { fileHashes, unreloadableHashes: unreloadable, reloadable, - addedFiles: reloadable ? await Promise.all(addedFiles.map(saveFileDetails)) : [], - changedFiles: reloadable ? await Promise.all(changedFiles.map(saveFileDetails)) : [], + addedFiles: reloadable ? await iterWithFn(addedFiles, saveFileDetails) : [], + changedFiles: reloadable ? await iterWithFn(changedFiles, saveFileDetails) : [], linkedAt: Date.now(), id: this._createId(), name From 8954c06959909b464691acd7201c2566a7a6e060 Mon Sep 17 00:00:00 2001 From: denihs Date: Wed, 8 Mar 2023 14:50:32 -0400 Subject: [PATCH 16/18] - small fix on driver.css --- packages/test-in-browser/driver.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/test-in-browser/driver.css b/packages/test-in-browser/driver.css index aab2fc5104..165b5212d7 100644 --- a/packages/test-in-browser/driver.css +++ b/packages/test-in-browser/driver.css @@ -207,7 +207,7 @@ body { color: #ea5555; } -pre { +.exception pre { color: var(--primary-white); color: #F9FAFB; } From 4f6882c08cc385e7ccd8eb6ca240367dfbbf6389 Mon Sep 17 00:00:00 2001 From: zodern Date: Fri, 10 Mar 2023 15:27:03 -0600 Subject: [PATCH 17/18] Fix linking the app client when TLA is disabled --- tools/isobuild/linker.js | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/tools/isobuild/linker.js b/tools/isobuild/linker.js index e762b4bc5e..e72c394814 100644 --- a/tools/isobuild/linker.js +++ b/tools/isobuild/linker.js @@ -60,6 +60,7 @@ var Module = function (options) { // options self.useGlobalNamespace = options.useGlobalNamespace; self.combinedServePath = options.combinedServePath; + self.addEagerRequires = !!options.addEagerRequires; }; Object.assign(Module.prototype, { @@ -209,6 +210,10 @@ Object.assign(Module.prototype, { if (file.mainModule) { result.mainModulePath = file.absModuleId; } + + if (self.addEagerRequires) { + chunks.push(`\nrequire(${JSON.stringify(file.absModuleId)});`); + } } } } else { @@ -1151,6 +1156,10 @@ export var fullLink = Profile("linker.fullLink", async function (inputFiles, { bundleArch, useGlobalNamespace: isApp, combinedServePath, + // To support `/client/compatibility`, we can't use the runtime for the + // app on the client when TLA is disabled since it wraps all of + // the app code in a function. Instead, we have the module add eager requires. + addEagerRequires: !bundleArch.startsWith('os.') && isApp && !enableClientTLA }); // Check if the core-runtime package will already be loaded From a81bf3d5ed8dc00087dd4a330d60d22b65aad9d2 Mon Sep 17 00:00:00 2001 From: zodern Date: Fri, 10 Mar 2023 15:40:25 -0600 Subject: [PATCH 18/18] Fix isFibersDisabled for older Meteor versions --- packages/meteor/asl-helpers.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/meteor/asl-helpers.js b/packages/meteor/asl-helpers.js index bd9271b7cb..c9df5e9828 100644 --- a/packages/meteor/asl-helpers.js +++ b/packages/meteor/asl-helpers.js @@ -2,7 +2,9 @@ const getAslStore = () => (Meteor.isServer && global?.asyncLocalStorage?.getStor const getValueFromAslStore = key => getAslStore()[key]; const updateAslStore = (key, value) => getAslStore()[key] = value; -Meteor.isFibersDisabled = !!__meteor_bootstrap__.isFibersDisabled; +const bootstrap = global.__meteor_bootstrap__; + +Meteor.isFibersDisabled = !!(bootstrap && bootstrap.isFibersDisabled); Meteor._isFibersEnabled = !Meteor.isFibersDisabled; Meteor._getAslStore = getAslStore;