From 8941cb61177a6c73006c7f7f9727dde758e01ac0 Mon Sep 17 00:00:00 2001 From: Bruce Johnson Date: Wed, 1 Sep 2021 09:46:54 -0700 Subject: [PATCH 1/4] use callback-hook package --- packages/webapp/package.js | 1 + packages/webapp/webapp_server.js | 16 +++++++--------- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/packages/webapp/package.js b/packages/webapp/package.js index 07d8deb0c4..6178ea386c 100644 --- a/packages/webapp/package.js +++ b/packages/webapp/package.js @@ -35,6 +35,7 @@ Package.onUse(function (api) { 'boilerplate-generator', 'webapp-hashing', 'inter-process-messaging', + 'callback-hook' ], 'server'); // At response serving time, webapp uses browser-policy if it is loaded. If diff --git a/packages/webapp/webapp_server.js b/packages/webapp/webapp_server.js index df91dbaa6a..69c3a34e6d 100644 --- a/packages/webapp/webapp_server.js +++ b/packages/webapp/webapp_server.js @@ -356,10 +356,10 @@ WebApp.decodeRuntimeConfig = function (rtimeConfig) { const runtimeConfig = { // hooks will contain the callback functions // set by the caller to addRuntimeConfigHook - hooks: [], + hooks: new Hook(), // updateHooks will contain the callback functions - // set by the caller to addUpdatedConfigHook - updateHooks: [], + // set by the caller to addUpdatedNotifyHook + updateHooks: new Hook(), // isUpdatedByArch is an object containing fields for each arch // that this server supports. // - Each field will be true when the server updates the runtimeConfig for that arch. @@ -372,13 +372,12 @@ WebApp.decodeRuntimeConfig = function (rtimeConfig) { }; WebApp.addRuntimeConfigHook = function (hook) { - if(typeof hook !== 'function') throw new Error('WebApp.addRuntimeConfigHook must be a function'); - runtimeConfig.hooks.push(hook); + return runtimeConfig.hooks.register(hook); } function getBoilerplateAsync(request, arch) { let boilerplate = boilerplateByArch[arch]; - runtimeConfig.hooks.forEach((hook) => { + runtimeConfig.hooks.each((hook) => { const meteorRuntimeConfig = hook({ arch, request, @@ -421,8 +420,7 @@ function getBoilerplateAsync(request, arch) { // - manifest // - runtimeConfig WebApp.addUpdatedNotifyHook = function(hook) { - if(typeof hook !== 'function') throw new Error('WebApp.addUpdatedNotifyHook must be a function'); - runtimeConfig.updateHooks.push(hook); + return runtimeConfig.updateHooks.register(hook); } WebAppInternals.generateBoilerplateInstance = function (arch, @@ -435,7 +433,7 @@ WebAppInternals.generateBoilerplateInstance = function (arch, ...__meteor_runtime_config__, ...(additionalOptions.runtimeConfigOverrides || {}) }; - runtimeConfig.updateHooks.forEach((cb) => { + runtimeConfig.updateHooks.each((cb) => { cb({arch, manifest, runtimeConfig: rtimeConfig}); }); From 44cdfb883d232b45a17809a6b88a7e33548474a3 Mon Sep 17 00:00:00 2001 From: Bruce Johnson Date: Wed, 1 Sep 2021 09:58:39 -0700 Subject: [PATCH 2/4] update History.md --- History.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/History.md b/History.md index 4aab1c0a96..9a043df7be 100644 --- a/History.md +++ b/History.md @@ -23,7 +23,8 @@ * `webapp@1.12` - npm dependencies have been updated - - Added option to change runtime config in your app, [read more](https://github.com/meteor/meteor/pull/11506) + - Added hook to change runtime config delivered to the client app, [read more](https://github.com/meteor/meteor/pull/11506) + - Added hook to get notified when the app is updated, [read more](https://github.com/meteor/meteor/pull/11607) - `@vlasky/whomst@0.1.7` - Added `addUpdateNotifyHook` that gets called when runtime configuration is updated From 5aa606d60db2089105db2cecb92cb76da81cb43b Mon Sep 17 00:00:00 2001 From: Bruce Johnson Date: Wed, 1 Sep 2021 11:32:29 -0700 Subject: [PATCH 3/4] go back to forEach on the hook (supported by callback-hook) --- packages/webapp/webapp_server.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/webapp/webapp_server.js b/packages/webapp/webapp_server.js index 69c3a34e6d..1b26ba2680 100644 --- a/packages/webapp/webapp_server.js +++ b/packages/webapp/webapp_server.js @@ -377,7 +377,7 @@ WebApp.addRuntimeConfigHook = function (hook) { function getBoilerplateAsync(request, arch) { let boilerplate = boilerplateByArch[arch]; - runtimeConfig.hooks.each((hook) => { + runtimeConfig.hooks.forEach((hook) => { const meteorRuntimeConfig = hook({ arch, request, @@ -433,7 +433,7 @@ WebAppInternals.generateBoilerplateInstance = function (arch, ...__meteor_runtime_config__, ...(additionalOptions.runtimeConfigOverrides || {}) }; - runtimeConfig.updateHooks.each((cb) => { + runtimeConfig.updateHooks.forEach((cb) => { cb({arch, manifest, runtimeConfig: rtimeConfig}); }); From 6c6116edcd7554b7ad0ccdb486842de79498b983 Mon Sep 17 00:00:00 2001 From: Bruce Johnson Date: Fri, 3 Sep 2021 14:15:26 -0700 Subject: [PATCH 4/4] Add apibox documentation --- packages/webapp/webapp_server.js | 140 ++++++++++++++++++++++++++++--- 1 file changed, 129 insertions(+), 11 deletions(-) diff --git a/packages/webapp/webapp_server.js b/packages/webapp/webapp_server.js index 1b26ba2680..a07b9cfff4 100644 --- a/packages/webapp/webapp_server.js +++ b/packages/webapp/webapp_server.js @@ -345,12 +345,26 @@ function getBoilerplate(request, arch) { return getBoilerplateAsync(request, arch).await(); } +/** + * @summary Takes a runtime configuration object and + * returns an encoded runtime string. + * @locus Server + * @param {Object} rtimeConfig + * @returns {String} +*/ WebApp.encodeRuntimeConfig = function (rtimeConfig) { return JSON.stringify(encodeURIComponent(JSON.stringify(rtimeConfig))); } -WebApp.decodeRuntimeConfig = function (rtimeConfig) { - return JSON.parse(decodeURIComponent(JSON.parse(rtimeConfig))); +/** + * @summary Takes an encoded runtime string and returns + * a runtime configuration object. + * @locus Server + * @param {String} rtimeConfigString + * @returns {Object} +*/ +WebApp.decodeRuntimeConfig = function (rtimeConfigStr) { + return JSON.parse(decodeURIComponent(JSON.parse(rtimeConfigStr))); } const runtimeConfig = { @@ -371,8 +385,55 @@ WebApp.decodeRuntimeConfig = function (rtimeConfig) { isUpdatedByArch: {} }; -WebApp.addRuntimeConfigHook = function (hook) { - return runtimeConfig.hooks.register(hook); +/** + * @name addRuntimeConfigHookCallback(options) + * @locus Server + * @isprototype true + * @summary Callback for `addRuntimeConfigHook`. + * + * If the handler returns a _falsy_ value the hook will not + * modify the runtime configuration. + * + * If the handler returns a _String_ the hook will substitute + * the string for the encoded configuration string. + * + * **Warning:** the hook does not check the return value at all it is + * the responsibility of the caller to get the formatting correct using + * the helper functions. + * + * `addRuntimeConfigHookCallback` takes only one `Object` argument + * with the following fields: + * @param {Object} options + * @param {String} options.arch The architecture of the client + * requesting a new runtime configuration. This can be one of + * `web.browser`, `web.browser.legacy` or `web.cordova`. + * @param {Object} options.request + * A NodeJs [IncomingMessage](https://nodejs.org/api/http.html#http_class_http_incomingmessage) + * https://nodejs.org/api/http.html#http_class_http_incomingmessage + * `Object` that can be used to get information about the incoming request. + * @param {String} options.encodedCurrentConfig The current configuration object + * encoded as a string for inclusion in the root html. + * @param {Boolean} options.updated `true` if the config for this architecture + * has been updated since last called, otherwise `false`. This flag can be used + * to cache the decoding/encoding for each architecture. + */ + +/** + * @summary Hook that calls back when the meteor runtime configuration, + * `__meteor_runtime_config__` is being sent to any client. + * + * **returns**: _Object_ `{ stop: function, callback: function }` + * - `stop` _Function_ Call `stop()` to stop getting callbacks. + * - `callback` _Function_ The passed in `callback`. + * @locus Server + * @param {addRuntimeConfigHookCallback} callback + * See `addRuntimeConfigHookCallback` description. + * @returns {Object} {{ stop: function, callback: function }} + * Call the returned `stop()` to stop getting callbacks. + * The passed in `callback` is returned also. +*/ +WebApp.addRuntimeConfigHook = function (callback) { + return runtimeConfig.hooks.register(callback); } function getBoilerplateAsync(request, arch) { @@ -414,13 +475,32 @@ function getBoilerplateAsync(request, arch) { })); } -// Notification hook whenever the runtime configuration is updated -// hook will pass an object with the following fields: -// - arch -// - manifest -// - runtimeConfig -WebApp.addUpdatedNotifyHook = function(hook) { - return runtimeConfig.updateHooks.register(hook); +/** + * @name addUpdatedNotifyHookCallback(options) + * @summary callback handler for `addupdatedNotifyHook` + * @isprototype true + * @locus Server + * @param {Object} options + * @param {String} options.arch The architecture that is being updated. + * This can be one of `web.browser`, `web.browser.legacy` or `web.cordova`. + * @param {Object} options.manifest The new updated manifest object for + * this `arch`. + * @param {Object} options.runtimeConfig The new updated configuration + * object for this `arch`. + */ + + +/** + * @summary Hook that runs when the meteor runtime configuration + * is updated. Typically the configuration only changes during development mode. + * @locus Server + * @param {addUpdatedNotifyHookCallback} handler + * The `handler` is called on every change to an `arch` runtime configuration. + * See `addUpdatedNotifyHookCallback`. + * @returns {Object} {{ stop: function, callback: function }} +*/ +WebApp.addUpdatedNotifyHook = function(handler) { + return runtimeConfig.updateHooks.register(handler); } WebAppInternals.generateBoilerplateInstance = function (arch, @@ -1030,6 +1110,44 @@ function runWebAppServer() { // other handlers added by package and application code. app.use(WebAppInternals.meteorInternalHandlers = connect()); + + /** + * @name connectHandlersCallback(req, res, next) + * @locus Server + * @isprototype true + * @summary callback handler for `WebApp.connectHandlers` + * @param {Object} req + * a Node.js + * [IncomingMessage](https://nodejs.org/api/http.html#http_class_http_incomingmessage) + * object with some extra properties. This argument can be used + * to get information about the incoming request. + * @param {Object} res + * a Node.js + * [ServerResponse](http://nodejs.org/api/http.html#http_class_http_serverresponse) + * object. Use this to write data that should be sent in response to the + * request, and call `res.end()` when you are done. + * @param {Function} next + * Calling this function will pass on the handling of + * this request to the next relevant handler. + * + */ + + /** + * @method connectHandlers + * @memberof WebApp + * @locus Server + * @summary Register a handler for all HTTP requests. + * @param {String} [path] + * This handler will only be called on paths that match + * this string. The match has to border on a `/` or a `.`. + * + * For example, `/hello` will match `/hello/world` and + * `/hello.world`, but not `/hello_world`. + * @param {connectHandlersCallback} handler + * A handler function that will be called on HTTP requests. + * See `connectHandlersCallback` + * + */ // Packages and apps can add handlers to this via WebApp.connectHandlers. // They are inserted before our default handler. var packageAndAppHandlers = connect();