Merge branch 'devel' into accounts-remove-underscore

This commit is contained in:
Jesse Rosenberger
2018-06-14 15:44:29 +03:00
committed by GitHub
170 changed files with 4903 additions and 6049 deletions

View File

@@ -41,7 +41,7 @@ run_log_mem_use: &run_log_mem_use
# Log memory usage throughout entire build.
MEMUSELOG=/tmp/memuse.txt /bin/bash -c '\
while true; do\
ps -u $USER -e -o pid,%cpu,%mem,rss:10,vsz:10,command:20 \
ps -e -o user,%cpu,%mem,rss:10,vsz:10,command:20 \
--sort=-%mem >> $MEMUSELOG; \
echo "----------" >> $MEMUSELOG; \
sleep 1; \
@@ -86,11 +86,7 @@ build_machine_environment: &build_machine_environment
# These will be evaled before each command.
PRE_TEST_COMMANDS: |-
ulimit -c unlimited; # Set core dump size as Ubuntu 14.04 lacks prlimit.
ulimit -n 4096; # CircleCI default is soft 1024, hard 4096. Take it all.
# Enable the Garbage Collection `gc` object to be exposed so we can try
# to our own, hopefully more graceful, technique.
TOOL_NODE_FLAGS: --expose-gc
ulimit -a # Display all ulimit settings for transparency.
# This is only to make Meteor self-test not remind us that we can set
# this argument for self-tests.
@@ -115,22 +111,25 @@ jobs:
command: (git submodule sync && git submodule update --init --recursive) || (rm -fr .git/config .git/modules && git submodule deinit -f . && git submodule update --init --recursive)
- restore_cache:
keys:
- dev-bundle-cache-{{ checksum "meteor" }}
- dev-bundle-cache
- v1-dev-bundle-cache-{{ checksum "meteor" }}
- v1-dev-bundle-cache-
- restore_cache:
keys:
- other-deps-cache-{{ .Branch }}-{{ .Revision }}
- other-deps-cache-{{ .Branch }}
- other-deps-cache
- v2-other-deps-cache-{{ .Branch }}-{{ .Revision }}
- v2-other-deps-cache-{{ .Branch }}-
- restore_cache:
keys:
- test-groups-v1-{{ .Branch }}
- test-groups-v1
- v1-test-groups-{{ .Branch }}
- v1-test-groups-
- run:
name: Create Test Results Directory
command: |
sudo mkdir -p ./tmp/results/junit
sudo chmod a+rwx ./tmp/results/junit
# Clear dev_bundle/.npm to ensure consistent test runs.
- run:
name: Clear npm cache
command: ./meteor npm cache clear --force
- run:
name: Get Ready
command: |
@@ -138,10 +137,6 @@ jobs:
./meteor --get-ready
# shouldn't take longer than 20 minutes
no_output_timeout: 20m
# Clear dev_bundle/.npm to ensure consistent test runs.
- run:
name: Clear npm cache
command: ./meteor npm cache clear --force
- run:
<<: *run_save_node_bin
- persist_to_workspace:
@@ -688,16 +683,16 @@ jobs:
npm install --prefix ./scripts/test-balancer
npm start --prefix ./scripts/test-balancer --num-groups ${NUM_GROUPS} --running-avg-length ${RUNNING_AVG_LENGTH}
- save_cache:
key: test-groups-v1-{{ .Branch }}-{{ .BuildNum }}
key: v1-test-groups-{{ .Branch }}-{{ .BuildNum }}
paths:
- ./tmp/test-groups
when: on_success
- save_cache:
key: dev-bundle-cache-{{ checksum "meteor" }}
key: v1-dev-bundle-cache-{{ checksum "meteor" }}
paths:
- "dev_bundle"
- save_cache:
key: other-deps-cache-{{ .Branch }}-{{ .Revision }}
key: v2-other-deps-cache-{{ .Branch }}-{{ .Revision }}
paths:
- ".babel-cache"
- ".meteor"

View File

@@ -1,5 +1,143 @@
## v.NEXT
## v1.7.0.3, 2018-06-13
* Fixed [Issue #9991](https://github.com/meteor/meteor/issues/9991),
introduced in
[Meteor 1.7.0.2](https://github.com/meteor/meteor/pull/9990)
by [PR #9977](https://github.com/meteor/meteor/pull/9977).
## v1.7.0.2, 2018-06-13
* Node has been updated to version
[8.11.3](https://nodejs.org/en/blog/release/v8.11.3/), an important
[security release](https://nodejs.org/en/blog/vulnerability/june-2018-security-releases/).
* The `meteor-babel` npm package has been updated to version
[7.0.0-beta.51](https://github.com/babel/babel/releases/tag/v7.0.0-beta.51).
* Meteor apps created with `meteor create` or `meteor create --minimal`
will now have a directory called `tests/` rather than `test/`, so that
test code will not be eagerly loaded if you decide to remove the
`meteor.mainModule` configuration from `package.json`, thanks to
[PR #9977](https://github.com/meteor/meteor/pull/9977) by
[@robfallows](https://github.com/robfallows).
[Issue #9961](https://github.com/meteor/meteor/issues/9961)
## v1.7.0.1, 2018-05-29
* Reverted an [optimization](https://github.com/meteor/meteor/pull/9825)
introduced in Meteor 1.7 to stop scanning `node_modules` for files that
might be of interest to compiler plugins, since the intended workarounds
(creating symlinks) did not satisfy all existing use cases. We will
revisit this optimization in Meteor 1.7.1.
[mozfet/meteor-autoform-materialize#43](https://github.com/mozfet/meteor-autoform-materialize/issues/43)
* After updating to Meteor 1.7 or 1.7.0.1, you should update the
`@babel/runtime` npm package (as well as other Babel-related packages)
to their latest versions, along with the `meteor-node-stubs` package,
by running the following command:
```sh
meteor npm install @babel/runtime@latest meteor-node-stubs@latest
```
## v1.7, 2018-05-28
* More than 80% of internet users worldwide have access to a web browser
that natively supports the latest ECMAScript features and keeps itself
updated automatically, which means new features become available almost
as soon as they ship. In other words, the future we envisioned when we
first began [compiling code with
Babel](https://blog.meteor.com/how-much-does-ecmascript-2015-cost-2ded41d70914)
is finally here, yet most web frameworks and applications still compile
a single client-side JavaScript bundle that must function simultaneously
in the oldest and the newest browsers the application developer wishes
to support.
That choice is understandable, because the alternative is daunting: not
only must you build multiple JavaScript and CSS bundles for different
browsers, with different dependency graphs and compilation rules and
webpack configurations, but your server must also be able to detect the
capabilities of each visiting client, so that it can deliver the
appropriate assets at runtime. Testing a matrix of different browsers
and application versions gets cumbersome quickly, so it's no surprise
that responsible web developers would rather ship a single, well-tested
bundle, and forget about taking advantage of modern features until
legacy browsers have disappeared completely.
With Meteor 1.7, this awkward balancing act is no longer necessary,
because Meteor now automatically builds two sets of client-side assets,
one tailored to the capabilities of modern browsers, and the other
designed to work in all supported browsers, thus keeping legacy browsers
working exactly as they did before. Best of all, the entire Meteor
community relies on the same system, so any bugs or differences in
behavior can be identified and fixed quickly.
In this system, a "modern" browser can be loosely defined as one with
full native support for `async` functions and `await` expressions, which
includes more than 80% of the world market, and 85% of the US market
([source](https://caniuse.com/#feat=async-functions)). This standard may
seem extremely strict, since `async`/`await` was [just finalized in
ECMAScript 2017](http://2ality.com/2016/10/async-function-tips.html),
but the statistics clearly justify it. As another example, any modern
browser can handle native `class` syntax, though newer syntax like class
fields may still need to be compiled for now, whereas a legacy browser
will need compilation for both advanced and basic `class` syntax. And of
course you can safely assume that any modern browser has a native
`Promise` implementation, because `async` functions must return
`Promise`s. The list goes on and on.
This boundary between modern and legacy browsers is designed to be tuned
over time, not only by the Meteor framework itself but also by each
individual Meteor application. For example, here's how the minimum
versions for native ECMAScript `class` support might be expressed:
```js
import { setMinimumBrowserVersions } from "meteor/modern-browsers";
setMinimumBrowserVersions({
chrome: 49,
firefox: 45,
edge: 12,
ie: Infinity, // Sorry, IE11.
mobile_safari: [9, 2], // 9.2.0+
opera: 36,
safari: 9,
electron: 1,
}, "classes");
```
The minimum modern version for each browser is simply the maximum of all
versions passed to `setMinimumBrowserVersions` for that browser. The
Meteor development server decides which assets to deliver to each client
based on the `User-Agent` string of the HTTP request. In production,
different bundles are named with unique hashes, which prevents cache
collisions, though Meteor also sets the `Vary: User-Agent` HTTP response
header to let well-behaved clients know they should cache modern and
legacy resources separately.
For the most part, the modern/legacy system will transparently determine
how your code is compiled, bundled, and delivered&mdash;and yes, it
works with every existing part of Meteor, including dynamic `import()`
and even [the old `appcache`
package](https://github.com/meteor/meteor/pull/9776). However, if you're
writing dynamic code that depends on modern features, you can use the
boolean `Meteor.isModern` flag to detect the status of the current
environment (Node 8 is modern, too, of course). If you're writing a
Meteor package, you can call `api.addFiles(files, "legacy")` in your
`package.js` configuration file to add extra files to the legacy bundle,
or `api.addFiles(files, "client")` to add files to all client bundles,
or `api.addFiles(files, "web.browser")` to add files only to the modern
bundle, and the same rules apply to `api.mainModule`. Just be sure to
call `setMinimumBrowserVersions` (in server startup code) to enforce
your assumptions about ECMAScript feature support.
We think this modern/legacy system is one of the most powerful features
we've added since we first introduced the `ecmascript` package in Meteor
1.2, and we look forward to other frameworks attempting to catch up.
[PR #9439](https://github.com/meteor/meteor/pull/9439)
* Although Meteor does not recompile packages installed in `node_modules`
by default, compilation of specific npm packages (for example, to
support older browsers that the package author neglected) can now be
@@ -20,7 +158,7 @@
import("the-package").then(...)
```
This reuse of compiled code is the critical new feature that was added
in Meteor 1.6.2.
in Meteor 1.7.
* Install the package normally with `meteor npm install the-package`,
then create a symbolic link *to* the installed package elsewhere in
@@ -44,7 +182,22 @@
application code. [PR #9771](https://github.com/meteor/meteor/pull/9771)
[Feature #6](https://github.com/meteor/meteor-feature-requests/issues/6)
* The `npm` package has been upgraded to version 5.8.0, and our
> ~Note: since compilation of npm packages can now be enabled using the
techniques described above, Meteor will no longer automatically scan
`node_modules` directories for modules that can be compiled by
compiler plugins. If you have been using that functionality to import
compiled-to-JS modules from `node_modules`, you should start using the
symlinking strategy instead.~ **Follow-up note: this optimization was
reverted in Meteor 1.7.0.1 (see [above](#v1701-2018-05-29)).**
* Node has been updated to version
[8.11.2](https://nodejs.org/en/blog/release/v8.11.2/), officially fixing
a [cause](https://github.com/nodejs/node/issues/19274) of frequent
segmentation faults in Meteor applications that was introduced in Node
8.10.0. Meteor 1.6.1.1 shipped with a custom build of Node that patched
this problem, but that approach was never intended to be permanent.
* The `npm` package has been upgraded to version 5.10.0, and our
[fork](https://github.com/meteor/pacote/tree/v7.6.1-meteor) of its
`pacote` dependency has been rebased against version 7.6.1.
@@ -101,12 +254,32 @@
test files across your codebase; just make sure you import the ones you
want to run. [PR #9714](https://github.com/meteor/meteor/pull/9714)
* The `meteor create` command now supports a `--minimal` option, which
creates an app with as few Meteor packages as possible, in order to
minimize client bundle size while still demonstrating advanced features
such as server-side rendering. This starter application is a solid
foundation for any application that doesn't need Mongo or DDP.
* The `meteor-babel` npm package has been updated to version
7.0.0-beta.46.
7.0.0-beta.49-1. Note: while Babel has recently implemented support for
a new kind of `babel.config.js` configuration file (see [this
PR](https://github.com/babel/babel/pull/7358)), and future versions of
Meteor will no doubt embrace this functionality, Meteor 1.7 supports
only `.babelrc` files as a means of customizing the default Babel
configuration provided by Meteor. In other words, if your project
contains a `babel.config.js` file, it will be ignored by Meteor 1.7.
* The `reify` npm package has been updated to version 0.15.1.
* The `reify` npm package has been updated to version 0.16.2.
* The `optimism` npm package has been updated to version 0.4.0.
* The `meteor-node-stubs` package, which provides stub implementations for
any Node built-in modules used by the client (such as `path` and
`http`), has a new minor version (0.4.1) that may help with Windows
installation problems. To install the new version, run
```sh
meteor npm install meteor-node-stubs@latest
```
* The `optimism` npm package has been updated to version 0.6.3.
* The `minifier-js` package has been updated to use `uglify-es` 3.3.9.
@@ -115,10 +288,10 @@
`selftest.skip.define('some test', ...` will skip running "some test".
[PR #9579](https://github.com/meteor/meteor/pull/9579)
* Mongo has been upgraded to version 3.6.3 for 64-bit systems, and 3.2.19
* Mongo has been upgraded to version 3.6.4 for 64-bit systems, and 3.2.19
for 32-bit systems. [PR #9632](https://github.com/meteor/meteor/pull/9632)
**NOTE:** After upgrading an application to use Mongo 3.6.2, it has been
**NOTE:** After upgrading an application to use Mongo 3.6.4, it has been
observed ([#9591](https://github.com/meteor/meteor/issues/9591))
that attempting to run that application with an older version of
Meteor (via `meteor --release X`), that uses an older version of Mongo, can
@@ -132,10 +305,20 @@
```
[PR #9632](https://github.com/meteor/meteor/pull/9632)
* The `mongodb` driver package has been updated from version 2.2.34 to
version 3.0.7. [PR #9790](https://github.com/meteor/meteor/pull/9790)
[PR #9831](https://github.com/meteor/meteor/pull/9831)
[Feature #268](https://github.com/meteor/meteor-feature-requests/issues/268)
* The `cordova-plugin-meteor-webapp` package depended on by the Meteor
`webapp` package has been updated to version 1.6.0.
[PR #9761](https://github.com/meteor/meteor/pull/9761)
* Any settings read from a JSON file passed with the `--settings` option
during Cordova run/build/deploy will be exposed in `mobile-config.js`
via the `App.settings` property, similar to `Meteor.settings`.
[PR #9873](https://github.com/meteor/meteor/pull/9873)
* The `@babel/plugin-proposal-class-properties` plugin provided by
`meteor-babel` now runs with the `loose:true` option, as required by
other (optional) plugins like `@babel/plugin-proposal-decorators`.
@@ -175,6 +358,15 @@
[Feature #24](https://github.com/meteor/meteor-feature-requests/issues/24)
[PR #9657](https://github.com/meteor/meteor/pull/9657)
## v1.6.1.2, 2018-05-28
* Meteor 1.6.1.2 is a very small release intended to fix
[#9863](https://github.com/meteor/meteor/issues/9863) by making
[#9887](https://github.com/meteor/meteor/pull/9887) available to Windows
users without forcing them to update to Meteor 1.7 (yet). Thanks very
much to [@zodern](https://github.com/zodern) for identifying a solution
to this problem. [PR #9910](https://github.com/meteor/meteor/pull/9910)
## v1.6.1.1, 2018-04-02
* Node has been updated to version

4
meteor
View File

@@ -1,6 +1,6 @@
#!/usr/bin/env bash
BUNDLE_VERSION=8.11.1.2
BUNDLE_VERSION=8.11.3.1
# OS Check. Put here because here is where we download the precompiled
# bundles that are arch specific.
@@ -133,6 +133,6 @@ fi
# screw up their meteor installs by have a ~/node_modules
exec "$DEV_BUNDLE/bin/node" \
--expose-gc \
--max-old-space-size=4096 \
${TOOL_NODE_FLAGS} \
"$METEOR" "$@"

View File

@@ -46,7 +46,10 @@ IF EXIST "%~dp0\.git" (
SET NODE_PATH=%~dp0\dev_bundle\lib\node_modules
SET BABEL_CACHE_DIR=%~dp0\.babel-cache
"%~dp0\dev_bundle\bin\node.exe" %TOOL_NODE_FLAGS% "%~dp0\tools\index.js" %*
"%~dp0\dev_bundle\bin\node.exe" ^
%TOOL_NODE_FLAGS% ^
"%~dp0\tools\index.js" %*
ENDLOCAL
EXIT /b %ERRORLEVEL%

View File

@@ -192,7 +192,11 @@ CollectionPrototype._defineMutationMethods = function(options) {
throw new Meteor.Error(403, "Access denied");
}
} catch (e) {
if (e.name === 'MongoError' || e.name === 'MinimongoError') {
if (
e.name === 'MongoError' ||
e.name === 'BulkWriteError' ||
e.name === 'MinimongoError'
) {
throw new Meteor.Error(409, e.toString());
} else {
throw e;

View File

@@ -1,4 +1,6 @@
import { Meteor } from 'meteor/meteor'
import { isModern } from "meteor/modern-browsers";
import { WebApp } from "meteor/webapp";
import crypto from 'crypto';
import fs from 'fs';
import path from 'path';
@@ -37,12 +39,14 @@ Meteor.AppCache = {
const browserDisabled = request => disabledBrowsers[request.browser.name];
const isDynamic = resource =>
// Cache of previously computed app.manifest files.
const manifestCache = new Map;
const shouldSkip = resource =>
resource.type === 'dynamic js' ||
(resource.type === 'json' &&
// TODO Update this test with PR #9439.
resource.url.startsWith('/dynamic/') &&
resource.url.endsWith('.map'));
(resource.url.endsWith('.map') ||
resource.url.endsWith('.stats.json?meteor_js_resource=true')));
WebApp.addHtmlAttributeHook(request =>
browserDisabled(request) ?
@@ -55,6 +59,8 @@ WebApp.connectHandlers.use((req, res, next) => {
return next();
}
const request = WebApp.categorizeRequest(req);
// Browsers will get confused if we unconditionally serve the
// manifest and then disable the app cache for that browser. If
// the app cache had previously been enabled for a browser, it
@@ -65,12 +71,44 @@ WebApp.connectHandlers.use((req, res, next) => {
// use"). Returning a 404 gets the browser to really turn off the
// app cache.
if (browserDisabled(WebApp.categorizeRequest(req))) {
if (browserDisabled(request)) {
res.writeHead(404);
res.end();
return;
}
const cacheInfo = {
modern: isModern(request.browser),
};
cacheInfo.arch = cacheInfo.modern
? "web.browser"
: "web.browser.legacy";
cacheInfo.clientHash = WebApp.clientHash(cacheInfo.arch);
if (Package.autoupdate) {
const version = Package.autoupdate.Autoupdate.autoupdateVersion;
if (version !== cacheInfo.clientHash) {
cacheInfo.autoupdateVersion = version;
}
}
const cacheKey = JSON.stringify(cacheInfo);
if (! manifestCache.has(cacheKey)) {
manifestCache.set(cacheKey, computeManifest(cacheInfo));
}
const manifest = manifestCache.get(cacheKey);
res.setHeader('Content-Type', 'text/cache-manifest');
res.setHeader('Content-Length', manifest.length);
return res.end(manifest);
});
function computeManifest(cacheInfo) {
let manifest = "CACHE MANIFEST\n\n";
// After the browser has downloaded the app files from the server and
@@ -80,61 +118,82 @@ WebApp.connectHandlers.use((req, res, next) => {
//
// So to ensure that the client updates if client resources change,
// include a hash of client resources in the manifest.
manifest += `# ${WebApp.clientHash()}\n`;
manifest += `# ${cacheInfo.clientHash}\n`;
// When using the autoupdate package, also include
// AUTOUPDATE_VERSION. Otherwise the client will get into an
// infinite loop of reloads when the browser doesn't fetch the new
// app HTML which contains the new version, and autoupdate will
// reload again trying to get the new code.
if (Package.autoupdate) {
const version = Package.autoupdate.Autoupdate.autoupdateVersion;
if (version !== WebApp.clientHash())
manifest += `# ${version}\n`;
if (cacheInfo.autoupdateVersion) {
manifest += `# ${cacheInfo.autoupdateVersion}\n`;
}
manifest += "\n";
manifest += "CACHE:\n";
manifest += "/\n";
WebApp.clientPrograms[WebApp.defaultArch].manifest.forEach(resource => {
if (resource.where === 'client' &&
! RoutePolicy.classify(resource.url) &&
! isDynamic(resource)) {
manifest += resource.url;
// If the resource is not already cacheable (has a query
// parameter, presumably with a hash or version of some sort),
// put a version with a hash in the cache.
//
// Avoid putting a non-cacheable asset into the cache, otherwise
// the user can't modify the asset until the cache headers
// expire.
if (!resource.cacheable)
manifest += `?${resource.hash}`;
manifest += "\n";
eachResource(cacheInfo, resource => {
const { url } = resource;
if (resource.where !== 'client' ||
RoutePolicy.classify(url) ||
shouldSkip(resource)) {
return;
}
manifest += url;
// If the resource is not already cacheable (has a query parameter,
// presumably with a hash or version of some sort), put a version with
// a hash in the cache.
//
// Avoid putting a non-cacheable asset into the cache, otherwise the
// user can't modify the asset until the cache headers expire.
if (! resource.cacheable) {
manifest += `?${resource.hash}`;
}
manifest += "\n";
});
manifest += "\n";
manifest += "FALLBACK:\n";
manifest += "/ /\n";
// Add a fallback entry for each uncacheable asset we added above.
//
// This means requests for the bare url ("/image.png" instead of
// "/image.png?hash") will work offline. Online, however, the browser
// will send a request to the server. Users can remove this extra
// request to the server and have the asset served from cache by
// specifying the full URL with hash in their code (manually, with
// some sort of URL rewriting helper)
WebApp.clientPrograms[WebApp.defaultArch].manifest.forEach(resource => {
if (resource.where === 'client' &&
! RoutePolicy.classify(resource.url) &&
! resource.cacheable &&
! isDynamic(resource)) {
manifest += `${resource.url} ${resource.url}?${resource.hash}\n`;
eachResource(cacheInfo, (resource, arch, prefix) => {
const { url } = resource;
if (resource.where !== 'client' ||
RoutePolicy.classify(url) ||
shouldSkip(resource)) {
return;
}
if (! resource.cacheable) {
// Add a fallback entry for each uncacheable asset we added above.
//
// This means requests for the bare url ("/image.png" instead of
// "/image.png?hash") will work offline. Online, however, the
// browser will send a request to the server. Users can remove this
// extra request to the server and have the asset served from cache
// by specifying the full URL with hash in their code (manually,
// with some sort of URL rewriting helper)
manifest += `${url} ${url}?${resource.hash}\n`;
}
if (resource.type === 'asset' &&
prefix.length > 0 &&
url.startsWith(prefix)) {
// If the URL has a prefix like /__browser.legacy or /__cordova, add
// a fallback from the un-prefixed URL to the fully prefixed URL, so
// that legacy/cordova browsers can load assets offline without
// using an explicit prefix. When the client is online, these assets
// will simply come from the modern web.browser bundle, which does
// not prefix its asset URLs. Using a fallback rather than just
// duplicating the resources in the manifest is important because of
// appcache size limits.
manifest += `${url.slice(prefix.length)} ${url}?${resource.hash}\n`;
}
});
@@ -151,38 +210,61 @@ WebApp.connectHandlers.use((req, res, next) => {
manifest += "*\n";
// content length needs to be based on bytes
const body = Buffer.from(manifest);
return Buffer.from(manifest, "utf8");
}
res.setHeader('Content-Type', 'text/cache-manifest');
res.setHeader('Content-Length', body.length);
return res.end(body);
});
function eachResource({
modern,
arch,
}, callback) {
const manifest = WebApp.clientPrograms[arch].manifest;
const sizeCheck = () => {
let totalSize = 0;
WebApp.clientPrograms[WebApp.defaultArch].manifest.forEach(resource => {
if (resource.where === 'client' &&
! RoutePolicy.classify(resource.url) &&
! isDynamic(resource)) {
totalSize += resource.size;
let prefix = "";
if (! modern) {
manifest.some(({ url }) => {
if (url && url.startsWith("/__")) {
prefix = url.split("/", 2).join("/");
return true;
}
});
}
manifest.forEach(resource => {
callback(resource, arch, prefix);
});
}
function sizeCheck() {
[ // Check size of each known architecture independently.
"web.browser",
"web.browser.legacy",
].forEach(arch => {
let totalSize = 0;
WebApp.clientPrograms[arch].manifest.forEach(resource => {
if (resource.where === 'client' &&
! RoutePolicy.classify(resource.url) &&
! shouldSkip(resource)) {
totalSize += resource.size;
}
});
if (totalSize > 5 * 1024 * 1024) {
Meteor._debug([
"** You are using the appcache package but the total size of the",
`** cached resources is ${(totalSize / 1024 / 1024).toFixed(1)}MB.`,
"**",
"** This is over the recommended maximum of 5MB and may break your",
"** app in some browsers! See http://docs.meteor.com/#appcache",
"** for more information and fixes."
].join("\n"));
}
});
if (totalSize > 5 * 1024 * 1024) {
Meteor._debug(
"** You are using the appcache package but the total size of the\n" +
"** cached resources is " +
`${(totalSize / 1024 / 1024).toFixed(1)}MB.\n` +
"**\n" +
"** This is over the recommended maximum of 5 MB and may break your\n" +
"** app in some browsers! See http://docs.meteor.com/#appcache\n" +
"** for more information and fixes.\n"
);
}
};
}
// Run the size check after user code has had a chance to run. That way,
// the size check can take into account files that the user does not
// want cached. Otherwise, the size check warning will still print even
// if the user excludes their large files with
// `Meteor.AppCache.config({onlineOnly: files})`.
Meteor.startup(() => ! _disableSizeCheck ? sizeCheck() : null);
Meteor.startup(() => _disableSizeCheck || sizeCheck());

View File

@@ -1,6 +1,6 @@
Package.describe({
summary: "Enable the application cache in the browser",
version: "1.1.2",
version: "1.2.0",
});
Package.onUse(api => {

File diff suppressed because it is too large Load Diff

View File

@@ -9,6 +9,7 @@ BabelCompiler = function BabelCompiler(extraFeatures) {
this.extraFeatures = extraFeatures;
this._babelrcCache = null;
this._babelrcWarnings = Object.create(null);
this.cacheDirectory = null;
};
var BCp = BabelCompiler.prototype;
@@ -20,15 +21,27 @@ var hasOwn = Object.prototype.hasOwnProperty;
var isMeteorPre144 = semver.lt(process.version, "4.8.1");
BCp.processFilesForTarget = function (inputFiles) {
var compiler = this;
// Reset this cache for each batch processed.
this._babelrcCache = null;
inputFiles.forEach(function (inputFile) {
var toBeAdded = this.processOneFileForTarget(inputFile);
if (toBeAdded) {
inputFile.addJavaScript(toBeAdded);
if (inputFile.supportsLazyCompilation) {
inputFile.addJavaScript({
path: inputFile.getPathInPackage(),
hash: inputFile.getSourceHash(),
bare: !! inputFile.getFileOptions().bare
}, function () {
return compiler.processOneFileForTarget(inputFile);
});
} else {
var toBeAdded = compiler.processOneFileForTarget(inputFile);
if (toBeAdded) {
inputFile.addJavaScript(toBeAdded);
}
}
}, this);
});
};
// Returns an object suitable for passing to inputFile.addJavaScript, or
@@ -55,8 +68,11 @@ BCp.processOneFileForTarget = function (inputFile, source) {
sourceMap: null,
bare: !! fileOptions.bare
};
var cacheDeps = {
sourceHash: toBeAdded.hash
var cacheOptions = {
cacheDirectory: this.cacheDirectory,
cacheDeps: {
sourceHash: toBeAdded.hash,
},
};
// If you need to exclude a specific file within a package from Babel
@@ -71,11 +87,14 @@ BCp.processOneFileForTarget = function (inputFile, source) {
! excludedFileExtensionPattern.test(inputFilePath)) {
var extraFeatures = Object.assign({}, this.extraFeatures);
var arch = inputFile.getArch();
if (inputFile.getArch().startsWith("os.")) {
if (arch.startsWith("os.")) {
// Start with a much simpler set of Babel presets and plugins if
// we're compiling for Node 8.
extraFeatures.nodeMajorVersion = parseInt(process.versions.node);
} else if (arch === "web.browser") {
extraFeatures.modernBrowsers = true;
}
if (! extraFeatures.hasOwnProperty("jscript")) {
@@ -87,9 +106,13 @@ BCp.processOneFileForTarget = function (inputFile, source) {
var babelOptions = Babel.getDefaultOptions(extraFeatures);
this.inferExtraBabelOptions(inputFile, babelOptions, cacheDeps);
this.inferExtraBabelOptions(
inputFile,
babelOptions,
cacheOptions.cacheDeps,
);
babelOptions.sourceMap = true;
babelOptions.sourceMaps = true;
babelOptions.filename =
babelOptions.sourceFileName = packageName
? "packages/" + packageName + "/" + inputFilePath
@@ -97,7 +120,7 @@ BCp.processOneFileForTarget = function (inputFile, source) {
try {
var result = profile('Babel.compile', function () {
return Babel.compile(source, babelOptions, cacheDeps);
return Babel.compile(source, babelOptions, cacheOptions);
});
} catch (e) {
if (e.loc) {
@@ -140,7 +163,7 @@ BCp.processOneFileForTarget = function (inputFile, source) {
};
BCp.setDiskCacheDirectory = function (cacheDir) {
Babel.setCacheDir(cacheDir);
this.cacheDirectory = cacheDir;
};
function profile(name, func) {
@@ -170,57 +193,64 @@ BCp._inferFromBabelRc = function (inputFile, babelOptions, cacheDeps) {
if (babelrcPath) {
if (! hasOwn.call(this._babelrcCache, babelrcPath)) {
try {
this._babelrcCache[babelrcPath] =
JSON.parse(inputFile.readAndWatchFile(babelrcPath));
this._babelrcCache[babelrcPath] = {
controlFilePath: babelrcPath,
controlFileData: JSON.parse(
inputFile.readAndWatchFile(babelrcPath)),
deps: Object.create(null),
};
} catch (e) {
if (e instanceof SyntaxError) {
e.message = ".babelrc is not a valid JSON file: " + e.message;
}
throw e;
}
}
return this._inferHelper(
inputFile,
babelOptions,
babelrcPath,
this._babelrcCache[babelrcPath],
cacheDeps
);
const cacheEntry = this._babelrcCache[babelrcPath];
if (this._inferHelper(inputFile, cacheEntry)) {
merge(babelOptions, cacheEntry, "presets");
merge(babelOptions, cacheEntry, "plugins");
Object.assign(cacheDeps, cacheEntry.deps);
return true;
}
}
};
BCp._inferFromPackageJson = function (inputFile, babelOptions, cacheDeps) {
var pkgJsonPath = inputFile.findControlFile("package.json");
if (pkgJsonPath) {
if (! hasOwn.call(this._babelrcCache, pkgJsonPath)) {
this._babelrcCache[pkgJsonPath] = JSON.parse(
inputFile.readAndWatchFile(pkgJsonPath)
).babel || null;
}
const cacheEntry = hasOwn.call(this._babelrcCache, pkgJsonPath)
? this._babelrcCache[pkgJsonPath]
: this._babelrcCache[pkgJsonPath] = {
controlFilePath: pkgJsonPath,
controlFileData: JSON.parse(
inputFile.readAndWatchFile(pkgJsonPath)
).babel || null,
deps: Object.create(null),
};
return this._inferHelper(
inputFile,
babelOptions,
pkgJsonPath,
this._babelrcCache[pkgJsonPath],
cacheDeps
);
if (this._inferHelper(inputFile, cacheEntry)) {
merge(babelOptions, cacheEntry, "presets");
merge(babelOptions, cacheEntry, "plugins");
Object.assign(cacheDeps, cacheEntry.deps);
return true;
}
}
};
BCp._inferHelper = function (
inputFile,
babelOptions,
controlFilePath,
babelrc,
cacheDeps
) {
if (! babelrc) {
BCp._inferHelper = function (inputFile, cacheEntry) {
if (! cacheEntry.controlFileData) {
return false;
}
if (hasOwn.call(cacheEntry, "finalInferHelperResult")) {
// We've already run _inferHelper and populated
// cacheEntry.{presets,plugins}, so we can return early here.
return cacheEntry.finalInferHelperResult;
}
var compiler = this;
function walkBabelRC(obj, path) {
@@ -281,7 +311,7 @@ BCp._inferHelper = function (
// The value is a string that we need to require.
const result = requireWithPath(value, path);
if (result && result.module) {
cacheDeps[result.name] = result.version;
cacheEntry.deps[result.name] = result.version;
return walkBabelRC(result.module, path);
}
@@ -307,20 +337,23 @@ BCp._inferHelper = function (
prefixes.push("");
try {
return requireWithPrefixes(inputFile, id, prefixes, controlFilePath);
return requireWithPrefixes(
inputFile, id, prefixes,
cacheEntry.controlFilePath
);
} catch (e) {
if (e.code !== "MODULE_NOT_FOUND") {
throw e;
}
if (! hasOwn.call(compiler._babelrcWarnings, id)) {
compiler._babelrcWarnings[id] = controlFilePath;
compiler._babelrcWarnings[id] = cacheEntry.controlFilePath;
console.error(
"Warning: unable to resolve " +
JSON.stringify(id) +
" in " + path.join(".") +
" of " + controlFilePath + ", due to:"
" of " + cacheEntry.controlFilePath + ", due to:"
);
console.error(e.stack || e);
@@ -330,26 +363,29 @@ BCp._inferHelper = function (
}
}
const clean = walkBabelRC(babelrc);
merge(babelOptions, clean, "presets");
merge(babelOptions, clean, "plugins");
const { controlFileData } = cacheEntry;
const clean = walkBabelRC(controlFileData);
merge(cacheEntry, clean, "presets");
merge(cacheEntry, clean, "plugins");
if (babelrc && babelrc.env) {
if (controlFileData &&
controlFileData.env) {
const envKey =
process.env.BABEL_ENV ||
process.env.NODE_ENV ||
"development";
const clean = walkBabelRC(babelrc.env[envKey]);
const clean = walkBabelRC(controlFileData.env[envKey]);
if (clean) {
merge(babelOptions, clean, "presets");
merge(babelOptions, clean, "plugins");
merge(cacheEntry, clean, "presets");
merge(cacheEntry, clean, "plugins");
}
}
return !! (babelOptions.presets ||
babelOptions.plugins);
return cacheEntry.finalInferHelperResult =
!! (cacheEntry.presets ||
cacheEntry.plugins);
};
function merge(babelOptions, babelrc, name) {
@@ -373,12 +409,14 @@ function requireWithPrefixes(inputFile, id, prefixes, controlFilePath) {
// Call inputFile.resolve here rather than inputFile.require so
// that the import doesn't fail due to missing transitive
// dependencies imported by the preset or plugin.
if (inputFile.resolve(prefix + id)) {
if (inputFile.resolve(prefix + id, controlFilePath)) {
presetOrPluginId = prefix + id;
}
presetOrPluginMeta = inputFile.require(
packageNameFromTopLevelModuleId(prefix + id) + "/package.json");
packageNameFromTopLevelModuleId(prefix + id) + "/package.json",
controlFilePath
);
return true;
@@ -403,7 +441,11 @@ function requireWithPrefixes(inputFile, id, prefixes, controlFilePath) {
// to compile application code the same way Meteor does.
return null;
}
presetOrPlugin = inputFile.require(presetOrPluginId);
presetOrPlugin = inputFile.require(
presetOrPluginId,
controlFilePath
);
}
} else {

View File

@@ -9,13 +9,7 @@ function getMeteorBabel() {
function getDefaultOptions(extraFeatures) {
// See https://github.com/meteor/babel/blob/master/options.js for more
// information about what the default options are.
var options = getMeteorBabel().getDefaultOptions(extraFeatures);
// The sourceMap option should probably be removed from the default
// options returned by meteorBabel.getDefaultOptions.
delete options.sourceMap;
return options;
return getMeteorBabel().getDefaultOptions(extraFeatures);
}
Babel = {
@@ -28,11 +22,16 @@ Babel = {
return getMeteorBabel().parse(source);
},
compile: function (source, options) {
options = options || getDefaultOptions();
return getMeteorBabel().compile(source, options);
compile: function (source, babelOptions, cacheOptions) {
return getMeteorBabel().compile(
source,
babelOptions || getDefaultOptions(),
cacheOptions,
);
},
// This method is deprecated in favor of passing
// cacheDeps.cacheDirectory to Babel.compile (see above).
setCacheDir: function (cacheDir) {
getMeteorBabel().setCacheDir(cacheDir);
},
@@ -44,5 +43,9 @@ Babel = {
getMinifierOptions: function (extraFeatures) {
return getMeteorBabel().getMinifierOptions(extraFeatures);
},
getMinimumModernBrowserVersions: function () {
return Npm.require("meteor-babel/modern-versions.js").get();
}
};

View File

@@ -6,19 +6,21 @@ Package.describe({
// isn't possible because you can't publish a non-recommended
// release with package versions that don't have a pre-release
// identifier at the end (eg, -dev)
version: '7.0.8'
version: '7.2.0'
});
Npm.depends({
'meteor-babel': '7.0.0-beta.46'
'meteor-babel': '7.0.0-beta.51'
});
Package.onUse(function (api) {
api.use('ecmascript-runtime', 'server');
api.use('modern-browsers');
api.addFiles([
'babel.js',
'babel-compiler.js'
'babel-compiler.js',
'versions.js',
], 'server');
api.export('Babel', 'server');

View File

@@ -0,0 +1,11 @@
// Make sure code compiled with features.modernBrowsers is delivered only
// to browsers that satisfy the assumptions of meteor-babel's modern Babel
// configuration.
Package["modern-browsers"].setMinimumBrowserVersions(
Babel.getMinimumModernBrowserVersions(),
// Although module.id is the recommended source string to pass as the
// second argument to setMinimumBrowserVersions, we can't use module.id
// here because babel-compiler cannot depend on the modules package. We
// can still make this string look like any other module.id, though.
"/node_modules/meteor/babel-compiler/versions.js"
);

View File

@@ -22,7 +22,7 @@ let shouldWarnAboutToHTMLDeprecation = ! Meteor.isProduction;
export class Boilerplate {
constructor(arch, manifest, options = {}) {
const { headTemplate, closeTemplate } = _getTemplate(arch);
const { headTemplate, closeTemplate } = getTemplate(arch);
this.headTemplate = headTemplate;
this.closeTemplate = closeTemplate;
this.baseData = null;
@@ -154,12 +154,16 @@ export class Boilerplate {
// Returns a template function that, when called, produces the boilerplate
// html as a string.
const _getTemplate = arch => {
if (arch === 'web.browser') {
function getTemplate(arch) {
const prefix = arch.split(".", 2).join(".");
if (prefix === "web.browser") {
return WebBrowserTemplate;
} else if (arch === 'web.cordova') {
return WebCordovaTemplate;
} else {
throw new Error('Unsupported arch: ' + arch);
}
};
if (prefix === "web.cordova") {
return WebCordovaTemplate;
}
throw new Error("Unsupported arch: " + arch);
}

View File

@@ -1 +0,0 @@
node_modules

View File

@@ -1,7 +0,0 @@
This directory and the files immediately inside it are automatically generated
when you change this package's NPM dependencies. Commit the files in this
directory (npm-shrinkwrap.json, .gitignore, and this README) to source control
so that others run the same versions of sub-dependencies.
You should NOT check in the node_modules directory that Meteor automatically
creates; if you are using git, the .gitignore file tells git to ignore it.

View File

@@ -1,15 +0,0 @@
{
"lockfileVersion": 1,
"dependencies": {
"async": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/async/-/async-1.4.0.tgz",
"integrity": "sha1-Nfhvg8WeBCHQmc2akdgnj7V4wA0="
},
"lru-cache": {
"version": "2.6.4",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-2.6.4.tgz",
"integrity": "sha1-JnUZDM0bBwHsL2UqTQ09QA12wN0="
}
}
}

View File

@@ -2,9 +2,7 @@ const fs = Plugin.fs;
const path = Plugin.path;
const createHash = Npm.require('crypto').createHash;
const assert = Npm.require('assert');
const Future = Npm.require('fibers/future');
const LRU = Npm.require('lru-cache');
const async = Npm.require('async');
// Base class for CachingCompiler and MultiFileCachingCompiler.
CachingCompilerBase = class CachingCompilerBase {
@@ -283,14 +281,12 @@ CachingCompiler = class CachingCompiler extends CachingCompilerBase {
const cacheMisses = [];
const arches = this._cacheDebugEnabled && Object.create(null);
const future = new Future;
async.eachLimit(inputFiles, this._maxParallelism, (inputFile, cb) => {
return Promise.all(inputFiles.map(async (inputFile) => {
if (arches) {
arches[inputFile.getArch()] = 1;
}
let error = null;
try {
const getResult = async () => {
const cacheKey = this._deepHash(this.getCacheKey(inputFile));
let compileResult = this._cache.get(cacheKey);
@@ -303,7 +299,7 @@ CachingCompiler = class CachingCompiler extends CachingCompilerBase {
if (! compileResult) {
cacheMisses.push(inputFile.getDisplayPath());
compileResult = this.compileOneFile(inputFile);
compileResult = await this.compileOneFile(inputFile);
if (! compileResult) {
// compileOneFile should have called inputFile.error.
@@ -316,17 +312,27 @@ CachingCompiler = class CachingCompiler extends CachingCompilerBase {
this._writeCacheAsync(cacheKey, compileResult);
}
this.addCompileResult(inputFile, compileResult);
} catch (e) {
error = e;
} finally {
cb(error);
}
}, future.resolver());
future.wait();
return compileResult;
};
if (this.compileOneFileLater &&
inputFile.supportsLazyCompilation &&
! this._cacheDebugEnabled) {
await this.compileOneFileLater(inputFile, getResult);
} else {
const result = await getResult();
if (result) {
this.addCompileResult(inputFile, result);
}
}
})).then(() => {
if (! this._cacheDebugEnabled) {
return;
}
if (this._cacheDebugEnabled) {
cacheMisses.sort();
this._cacheDebug(
`Ran (#${
++this._callCount
@@ -336,7 +342,7 @@ CachingCompiler = class CachingCompiler extends CachingCompilerBase {
JSON.stringify(Object.keys(arches).sort())
}`
);
}
});
}
_cacheFilename(cacheKey) {

View File

@@ -1,7 +1,5 @@
const path = Plugin.path;
const Future = Npm.require('fibers/future');
const LRU = Npm.require('lru-cache');
const async = Npm.require('async');
// MultiFileCachingCompiler is like CachingCompiler, but for implementing
// languages which allow files to reference each other, such as CSS
@@ -92,20 +90,12 @@ extends CachingCompilerBase {
cacheKeyMap.set(importPath, this._getCacheKeyWithPath(inputFile));
});
const allProcessedFuture = new Future;
async.eachLimit(inputFiles, this._maxParallelism, (inputFile, cb) => {
return Promise.all(inputFiles.map(async (inputFile) => {
if (arches) {
arches[inputFile.getArch()] = 1;
}
let error = null;
try {
// If this isn't a root, skip it (and definitely don't waste time
// looking for a cache file that won't be there).
if (!this.isRoot(inputFile)) {
return;
}
const getResult = async () => {
const absoluteImportPath = this.getAbsoluteImportPath(inputFile);
const cacheKey = cacheKeyMap.get(absoluteImportPath);
let cacheEntry = this._cache.get(cacheKey);
@@ -119,13 +109,19 @@ extends CachingCompilerBase {
if (! (cacheEntry && this._cacheEntryValid(cacheEntry, cacheKeyMap))) {
cacheMisses.push(inputFile.getDisplayPath());
const compileOneFileReturn = this.compileOneFile(inputFile, allFiles);
const compileOneFileReturn =
await this.compileOneFile(inputFile, allFiles);
if (! compileOneFileReturn) {
// compileOneFile should have called inputFile.error.
// We don't cache failures for now.
// We don't cache failures for now.
return;
}
const {compileResult, referencedImportPaths} = compileOneFileReturn;
const {
compileResult,
referencedImportPaths,
} = compileOneFileReturn;
cacheEntry = {
compileResult,
@@ -148,17 +144,27 @@ extends CachingCompilerBase {
this._writeCacheAsync(cacheKey, cacheEntry);
}
this.addCompileResult(inputFile, cacheEntry.compileResult);
} catch (e) {
error = e;
} finally {
cb(error);
}
}, allProcessedFuture.resolver());
allProcessedFuture.wait();
return cacheEntry.compileResult;
};
if (this.compileOneFileLater &&
inputFile.supportsLazyCompilation &&
! this._cacheDebugEnabled) {
await this.compileOneFileLater(inputFile, getResult);
} else if (this.isRoot(inputFile)) {
const result = await getResult();
if (result) {
this.addCompileResult(inputFile, result);
}
}
})).then(() => {
if (! this._cacheDebugEnabled) {
return;
}
if (this._cacheDebugEnabled) {
cacheMisses.sort();
this._cacheDebug(
`Ran (#${
++this._callCount
@@ -166,8 +172,9 @@ extends CachingCompilerBase {
JSON.stringify(cacheMisses)
} ${
JSON.stringify(Object.keys(arches).sort())
}`);
}
}`
);
});
}
// Returns a hash that incorporates both this.getCacheKey(inputFile) and

View File

@@ -1,15 +1,10 @@
Package.describe({
name: 'caching-compiler',
version: '1.1.12',
version: '1.2.0',
summary: 'An easy way to make compiler plugins cache',
documentation: 'README.md'
});
Npm.depends({
'lru-cache': '2.6.4',
'async': '1.4.0'
});
Package.onUse(function(api) {
api.use(['ecmascript', 'random']);
api.addFiles(['caching-compiler.js'], 'server');

View File

@@ -2,9 +2,9 @@
"lockfileVersion": 1,
"dependencies": {
"lolex": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/lolex/-/lolex-1.4.0.tgz",
"integrity": "sha1-LycSsbwYDendzF06epbvPAuxYq0="
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/lolex/-/lolex-2.3.1.tgz",
"integrity": "sha512-mQuW55GhduF3ppo+ZRUTz1PRjEh1hS5BbqU7d8D0ez2OKxHDod7StPPeAVKisZR5aLkHZjdGWSL42LSONUJsZw=="
}
}
}

View File

@@ -5,7 +5,7 @@ Package.describe({
});
Npm.depends({
lolex: '1.4.0'
lolex: '2.3.1'
});
Package.onUse((api) => {

View File

@@ -11,6 +11,7 @@ DDPServer._Crossbar = function (options) {
// keys 'trigger', 'callback'. As a hack, the empty string means "no
// collection".
self.listenersByCollection = {};
self.listenersByCollectionCount = {};
self.factPackage = options.factPackage || "livedata";
self.factName = options.factName || null;
};
@@ -48,8 +49,10 @@ _.extend(DDPServer._Crossbar.prototype, {
var record = {trigger: EJSON.clone(trigger), callback: callback};
if (! _.has(self.listenersByCollection, collection)) {
self.listenersByCollection[collection] = {};
self.listenersByCollectionCount[collection] = 0;
}
self.listenersByCollection[collection][id] = record;
self.listenersByCollectionCount[collection]++;
if (self.factName && Package['facts-base']) {
Package['facts-base'].Facts.incrementServerFact(
@@ -63,8 +66,10 @@ _.extend(DDPServer._Crossbar.prototype, {
self.factPackage, self.factName, -1);
}
delete self.listenersByCollection[collection][id];
if (_.isEmpty(self.listenersByCollection[collection])) {
self.listenersByCollectionCount[collection]--;
if (self.listenersByCollectionCount[collection] === 0) {
delete self.listenersByCollection[collection];
delete self.listenersByCollectionCount[collection];
}
}
};

View File

@@ -1,6 +1,6 @@
Package.describe({
summary: "Meteor's latency-compensated distributed data server",
version: '2.1.2',
version: '2.2.0',
documentation: null
});

View File

@@ -121,11 +121,15 @@ var fetchURL = require("./common.js").fetchURL;
function fetchMissing(missingTree) {
return new Promise(function (resolve, reject) {
// Always match the protocol (http or https) and the domain:port of
// the current page.
var url = "//" + location.host + fetchURL;
HTTP.call("POST", url, {
// If the hostname of the URL returned by Meteor.absoluteUrl differs
// from location.host, then we'll be making a cross-origin request
// here, but that's fine because the dynamic-import server sets
// appropriate CORS headers to enable fetching dynamic modules from
// any origin. Browsers that check CORS do so by sending an additional
// preflight OPTIONS request, which may add latency to the first
// dynamic import() request, so it's a good idea for ROOT_URL to match
// location.host if possible, though not strictly necessary.
HTTP.call("POST", Meteor.absoluteUrl(fetchURL), {
query: secretKey ? "key=" + secretKey : void 0,
data: missingTree
}, function (error, result) {

View File

@@ -1,6 +1,6 @@
Package.describe({
name: "dynamic-import",
version: "0.3.0",
version: "0.4.1",
summary: "Runtime support for Meteor 1.5 dynamic import(...) syntax",
documentation: "README.md"
});
@@ -12,6 +12,7 @@ Package.onUse(function (api) {
api.use("modules");
api.use("promise");
api.use("http");
api.use("modern-browsers");
api.mainModule("client.js", "client");
api.mainModule("server.js", "server");

View File

@@ -7,6 +7,7 @@ const {
normalize: pathNormalize,
} = require("path");
const { fetchURL } = require("./common.js");
const { isModern } = require("meteor/modern-browsers");
const hasOwn = Object.prototype.hasOwnProperty;
require("./security.js");
@@ -61,20 +62,41 @@ function randomId(n) {
}
function middleware(request, response) {
assert.strictEqual(request.method, "POST");
const chunks = [];
request.on("data", chunk => chunks.push(chunk));
request.on("end", () => {
response.setHeader("Content-Type", "application/json");
response.end(JSON.stringify(readTree(
JSON.parse(Buffer.concat(chunks)),
getPlatform(request)
)));
});
// Allow dynamic import() requests from any origin.
response.setHeader("Access-Control-Allow-Origin", "*");
if (request.method === "OPTIONS") {
const acrh = request.headers["access-control-request-headers"];
response.setHeader(
"Access-Control-Allow-Headers",
typeof acrh === "string" ? acrh : "*"
);
response.setHeader("Access-Control-Allow-Methods", "POST");
response.end();
} else if (request.method === "POST") {
const chunks = [];
request.on("data", chunk => chunks.push(chunk));
request.on("end", () => {
response.setHeader("Content-Type", "application/json");
response.end(JSON.stringify(readTree(
JSON.parse(Buffer.concat(chunks)),
getPlatform(request)
), null, 2));
});
} else {
response.writeHead(405, {
"Cache-Control": "no-cache"
});
response.end(`method ${request.method} not allowed`);
}
}
function getPlatform(request) {
let platform = "web.browser";
const { identifyBrowser } = Package.webapp.WebAppInternals;
const browser = identifyBrowser(request.headers["user-agent"]);
let platform = isModern(browser)
? "web.browser"
: "web.browser.legacy";
// If the __dynamicImport request includes a secret key, and it matches
// dynamicImportInfo[platform].key, use platform instead of the default

View File

@@ -64,3 +64,5 @@ require('core-js/modules/es6.number.parse-int');
// Typed Arrays
require('core-js/modules/es6.typed.uint8-array');
require('core-js/modules/es6.typed.uint32-array');
require("./modern.js");

View File

@@ -0,0 +1,11 @@
require("core-js/modules/es6.object.is");
require("core-js/modules/es6.function.name");
require("core-js/modules/es6.number.is-finite");
require("core-js/modules/es6.number.is-nan");
require("core-js/modules/es7.array.flatten");
require("core-js/modules/es7.array.flat-map");
require("core-js/modules/es7.object.values");
require("core-js/modules/es7.object.entries");
require("core-js/modules/es7.object.get-own-property-descriptors");
require("core-js/modules/es7.string.pad-start");
require("core-js/modules/es7.string.pad-end");

View File

@@ -1,16 +1,26 @@
Package.describe({
name: "ecmascript-runtime-client",
version: "0.6.2",
version: "0.7.1",
summary: "Polyfills for new ECMAScript 2015 APIs like Map and Set",
git: "https://github.com/meteor/meteor/tree/devel/packages/ecmascript-runtime-client",
documentation: "README.md"
});
Package.onUse(function(api) {
api.use("modules", "client");
api.use("promise", "client");
api.mainModule("runtime.js", "client");
api.export("Symbol", "client");
api.export("Map", "client");
api.export("Set", "client");
// If the es5-shim package is installed, make sure it loads before
// ecmascript-runtime-server, since the runtime uses some ES5 APIs like
// Object.defineProperties that are buggy in older browsers.
api.use("es5-shim", { weak: true });
api.use("modules");
api.use("promise");
api.use("modern-browsers");
api.mainModule("versions.js", "server");
api.mainModule("modern.js", "client");
api.mainModule("legacy.js", "legacy");
api.export("Symbol", "legacy");
api.export("Map", "legacy");
api.export("Set", "legacy");
});

View File

@@ -0,0 +1,18 @@
const {
setMinimumBrowserVersions,
} = require("meteor/modern-browsers");
setMinimumBrowserVersions({
chrome: 49,
edge: 12,
// Since there is no IE11, this effectively excludes Internet Explorer
// (pre-Edge) from the modern classification. #9818 #9839
ie: 12,
firefox: 45,
mobileSafari: 10,
opera: 38,
safari: 10,
// Electron 1.6.0+ matches Chromium 55, per
// https://github.com/Kilian/electron-to-chromium/blob/master/full-versions.js
electron: [1, 6],
}, module.id);

View File

@@ -2,9 +2,9 @@
"lockfileVersion": 1,
"dependencies": {
"core-js": {
"version": "2.4.1",
"resolved": "https://registry.npmjs.org/core-js/-/core-js-2.4.1.tgz",
"integrity": "sha1-TekR5mew6ukSTjQlS1OupvxhjT4="
"version": "2.5.1",
"resolved": "https://registry.npmjs.org/core-js/-/core-js-2.5.1.tgz",
"integrity": "sha1-rmh03GaTd4m4B1T/VCjfZoGcpQs="
}
}
}

View File

@@ -1,16 +1,16 @@
Package.describe({
name: "ecmascript-runtime-server",
version: "0.5.0",
version: "0.7.0",
summary: "Polyfills for new ECMAScript 2015 APIs like Map and Set",
git: "https://github.com/meteor/meteor/tree/devel/packages/ecmascript-runtime-client",
documentation: "README.md"
});
Npm.depends({
"core-js": "2.4.1"
"core-js": "2.5.1"
});
Package.onUse(function(api) {
api.use("modules", "server");
api.use("modules");
api.mainModule("runtime.js", "server");
});

View File

@@ -1,13 +1,13 @@
Package.describe({
name: "ecmascript-runtime",
version: "0.5.0",
version: "0.7.0",
summary: "Polyfills for new ECMAScript 2015 APIs like Map and Set",
git: "https://github.com/meteor/ecmascript-runtime",
documentation: "README.md"
});
Package.onUse(function(api) {
api.imply("ecmascript-runtime-client", "client");
api.imply("ecmascript-runtime-client");
api.imply("ecmascript-runtime-server", "server");
});

View File

@@ -1,7 +1,8 @@
ECMAScript = {
compileForShell(command) {
const babelOptions = Babel.getDefaultOptions();
babelOptions.sourceMap = false;
delete babelOptions.sourceMap;
delete babelOptions.sourceMaps;
babelOptions.ast = false;
return Babel.compile(command, babelOptions).code;
}

View File

@@ -1,6 +1,6 @@
Package.describe({
name: 'ecmascript',
version: '0.10.8',
version: '0.11.1',
summary: 'Compiler plugin that supports ES2015+ in all .js files',
documentation: 'README.md'
});

View File

@@ -2,30 +2,24 @@ const isNode8OrLater = Meteor.isServer &&
parseInt(process.versions.node) >= 8;
Tinytest.add("ecmascript - runtime - template literals", (test) => {
function dump(pieces) {
var copy = {};
// Can't use _.extend({}, pieces) because es5-shim adds enumerable
// methods to Array.prototype, and _.extend has no own property check.
_.each(_.keys(pieces), key => copy[key] = pieces[key]);
return [copy, _.toArray(arguments).slice(1)];
function dump(strings, ...expressions) {
const copy = Object.create(null);
Object.assign(copy, strings);
copy.raw = strings.raw;
return [copy, expressions];
};
const foo = 'B';
// uses `babelHelpers.taggedTemplateLiteralLoose`
test.equal(`\u0041${foo}C`, 'ABC');
const expected = [{
0: 'A',
1: 'C',
raw: ['\\u0041', 'C']
const foo = "B";
test.equal(`\u0041${foo}C`, "ABC");
test.equal(dump`\u0041${foo}C`, [{
0: "A",
1: "C",
raw: ["\\u0041", "C"]
}, [
'B'
]];
if (isNode8OrLater) {
delete expected[0].raw;
}
test.equal(dump`\u0041${foo}C`, expected);
"B"
]]);
});
Tinytest.add("ecmascript - runtime - classes - basic", (test) => {

View File

@@ -0,0 +1,5 @@
require("./import_globals.js");
require("es5-shim/es5-shim.js");
require("es5-shim/es5-sham.js");
require("./console.js");
require("./export_globals.js");

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View File

@@ -1,51 +0,0 @@
"use strict";
// This script should be invoked before publishing the es5-shim package
// using the following command:
//
// meteor node minify.js
//
// Any changes to the es5-shim-sham.min.js file should then be committed.
const {
readdirSync,
readFileSync,
writeFileSync,
} = require("fs");
const {
join: pathJoin
} = require("path");
const uglify =
require("../minifier-js/.npm/package/node_modules/uglify-es");
const sourceFilePattern = /^es5-shim-sham\.js$/;
readdirSync(__dirname).some(item => {
if (! sourceFilePattern.test(item)) {
return false;
}
const parts = item.split(".");
parts.push("min", parts.pop());
const absSourcePath = pathJoin(__dirname, item);
const absTargetPath = pathJoin(__dirname, parts.join("."));
const source = readFileSync(absSourcePath, "utf8");
// Compress with options similar to those used in
// packages/minifier-js/minifier.js.
const result = uglify.minify(source, {
compress: {
drop_debugger: false,
unused: false,
dead_code: true
}
});
console.log("Minifying " + item + " and saving to " + absTargetPath);
writeFileSync(absTargetPath, result.code);
return true;
});

View File

@@ -1,6 +1,6 @@
Package.describe({
name: "es5-shim",
version: "4.7.3",
version: "4.8.0",
summary: "Shims and polyfills to improve ECMAScript 5 support",
documentation: "README.md"
});
@@ -11,15 +11,5 @@ Npm.depends({
Package.onUse(function(api) {
api.use("modules");
api.use("server-render");
api.use("shim-common");
api.addFiles("console.js", "client");
api.mainModule("cordova.js", "web.cordova");
api.mainModule("server.js", "server");
api.addAssets([
"es5-shim-sham.js",
"es5-shim-sham.min.js",
], "client");
api.mainModule("client.js", "legacy");
});

View File

@@ -1,24 +0,0 @@
const { onPageLoad } = require("meteor/server-render");
const {
doNotNeedShim,
makeScript,
} = require("meteor/shim-common");
const minimumMajorVersions = {
chrome: 23,
firefox: 21,
ie: 10,
safari: 6,
phantomjs: 2,
};
onPageLoad(sink => {
if (doNotNeedShim(sink.request,
minimumMajorVersions,
"force_es5_shim")) {
return;
}
sink.appendToHead(
makeScript("es5-shim/es5-shim-sham")
);
});

View File

@@ -31,7 +31,7 @@ Facebook.requestCredential = (options, credentialRequestCompleteCallback) => {
const loginStyle = OAuth._loginStyle('facebook', config, options);
let loginUrl =
`https://www.facebook.com/v2.12/dialog/oauth?client_id=${config.appId}` +
`https://www.facebook.com/v3.0/dialog/oauth?client_id=${config.appId}` +
`&redirect_uri=${OAuth._redirectUri('facebook', config)}` +
`&display=${display}&scope=${scope}` +
`&state=${OAuth._stateParam(loginStyle, credentialToken, options && options.redirectUrl)}`;

View File

@@ -2,10 +2,11 @@ Facebook = {};
import crypto from 'crypto';
Facebook.handleAuthFromAccessToken = (accessToken, expiresAt) => {
// include all fields from facebook
// http://developers.facebook.com/docs/reference/login/public-profile-and-friend-list/
const whitelisted = ['id', 'email', 'name', 'first_name',
'last_name', 'link', 'gender', 'locale', 'age_range'];
// include basic fields from facebook
// https://developers.facebook.com/docs/facebook-login/permissions/
const whitelisted = ['id', 'email', 'name', 'first_name', 'last_name',
'middle_name', 'name_format', 'picture', 'short_name', 'age_range',
'birthday', 'friends', 'gender', 'hometown', 'link', 'location'];
const identity = getIdentity(accessToken, whitelisted);
@@ -53,7 +54,7 @@ const getTokenResponse = query => {
try {
// Request an access token
responseContent = HTTP.get(
"https://graph.facebook.com/v2.12/oauth/access_token", {
"https://graph.facebook.com/v3.0/oauth/access_token", {
params: {
client_id: config.appId,
redirect_uri: OAuth._redirectUri('facebook', config),
@@ -92,7 +93,7 @@ const getIdentity = (accessToken, fields) => {
hmac.update(accessToken);
try {
return HTTP.get("https://graph.facebook.com/v2.12/me", {
return HTTP.get("https://graph.facebook.com/v3.0/me", {
params: {
access_token: accessToken,
appsecret_proof: hmac.digest('hex'),

View File

@@ -1,6 +1,6 @@
Package.describe({
summary: "Facebook OAuth flow",
version: "1.4.1",
version: "1.5.1"
});
Package.onUse(api => {

View File

@@ -18,7 +18,7 @@ var hasOwn = Object.prototype.hasOwnProperty;
* @param {Number} options.timeout Maximum time in milliseconds to wait for the request before failing. There is no timeout by default.
* @param {Boolean} options.followRedirects If `true`, transparently follow HTTP redirects. Cannot be set to `false` on the client. Default `true`.
* @param {Object} options.npmRequestOptions On the server, `HTTP.call` is implemented by using the [npm `request` module](https://www.npmjs.com/package/request). Any options in this object will be passed directly to the `request` invocation.
* @param {Function} options.beforeSend On the client, this will be called before the request is sent to allow for more direct manipulation of the underlying XMLHttpRequest object, which will be passed as the first argument. If the callback returns `false`, the request will be not be send.
* @param {Function} options.beforeSend On the client, this will be called before the request is sent to allow for more direct manipulation of the underlying XMLHttpRequest object, which will be passed as the first argument. If the callback returns `false`, the request will be not be sent.
* @param {Function} [asyncCallback] Optional callback. If passed, the method runs asynchronously, instead of synchronously, and calls asyncCallback. On the client, this callback is required.
*/
HTTP.call = function(method, url, options, callback) {

View File

@@ -485,16 +485,22 @@ if (Meteor.isServer) {
// the x-suppress-error header).
WebApp.suppressConnectErrors();
var do_test = function (path, code, match) {
HTTP.get(
url_base() + path,
{headers: {'x-suppress-error': 'true'}},
expect(function(error, result) {
test.equal(result.statusCode, code);
if (match)
test.matches(result.content, match);
}));
};
function do_test(path, code, match) {
const prefix = Meteor.isModern
? "" // No prefix for web.browser (modern).
: "/__browser.legacy";
HTTP.get(url_base() + prefix + path, {
headers: {
"x-suppress-error": "true"
}
}, expect(function(error, result) {
test.equal(result.statusCode, code);
if (match) {
test.matches(result.content, match);
}
}));
}
// existing static file
do_test("/packages/local-test_http/test_static.serveme", 200, /static file serving/);

View File

@@ -1,6 +1,6 @@
Package.describe({
name: 'less',
version: '2.7.12',
version: '2.8.0',
summary: 'Leaner CSS language',
documentation: 'README.md'
});

View File

@@ -1,6 +1,5 @@
const path = Plugin.path;
const less = Npm.require('less');
const Future = Npm.require('fibers/future');
Plugin.registerCompiler({
// *.lessimport has been deprecated since 0.7.1, but it still works. We
@@ -45,49 +44,66 @@ class LessCompiler extends MultiFileCachingCompiler {
/\.lessimport$/.test(pathInPackage));
}
compileOneFileLater(inputFile, getResult) {
inputFile.addStylesheet({
path: inputFile.getPathInPackage(),
}, async () => {
const result = await getResult();
return result && {
data: result.css,
sourceMap: result.sourceMap,
};
});
}
compileOneFile(inputFile, allFiles) {
const importPlugin = new MeteorImportLessPlugin(allFiles);
const f = new Future;
let output;
try {
less.render(inputFile.getContentsAsBuffer().toString('utf8'), {
filename: this.getAbsoluteImportPath(inputFile),
plugins: [importPlugin],
// Generate a source map, and include the source files in the
// sourcesContent field. (Note that source files which don't themselves
// produce text (eg, are entirely variable definitions) won't end up in
// the source map!)
sourceMap: { outputSourceFiles: true }
}, f.resolver());
output = f.wait();
} catch (e) {
return less.render(inputFile.getContentsAsBuffer().toString('utf8'), {
filename: this.getAbsoluteImportPath(inputFile),
plugins: [importPlugin],
// Generate a source map, and include the source files in the
// sourcesContent field. (Note that source files which don't
// themselves produce text (eg, are entirely variable definitions)
// won't end up in the source map!)
sourceMap: { outputSourceFiles: true }
}).then(output => {
if (output.map) {
const map = JSON.parse(output.map);
map.sources = map.sources.map(decodeFilePath);
output.map = map;
}
const compileResult = {
css: output.css,
sourceMap: output.map,
};
const referencedImportPaths = [];
output.imports.forEach((path) => {
// Some files that show up in output.imports are not actually files; for
// example @import url("...");
if (allFiles.has(path)) {
referencedImportPaths.push(path);
}
});
return {
compileResult,
referencedImportPaths,
};
}, e => {
inputFile.error({
message: e.message,
sourcePath: decodeFilePath(e.filename),
line: e.line,
column: e.column
});
return null;
}
if (output.map) {
const map = JSON.parse(output.map);
map.sources = map.sources.map(decodeFilePath);
output.map = map;
}
const compileResult = {css: output.css, sourceMap: output.map};
const referencedImportPaths = [];
output.imports.forEach((path) => {
// Some files that show up in output.imports are not actually files; for
// example @import url("...");
if (allFiles.has(path)) {
referencedImportPaths.push(path);
}
});
return {compileResult, referencedImportPaths};
}
addCompileResult(inputFile, compileResult) {

View File

@@ -1,6 +1,6 @@
Package.describe({
summary: "The Meteor command-line tool",
version: '1.6.1_1'
version: '1.7.0_3'
});
Package.includeTool();

View File

@@ -2,4 +2,5 @@ Tinytest.add("environment - browser basics", function (test) {
test.isTrue(Meteor.isClient);
test.isFalse(Meteor.isServer);
test.isFalse(Meteor.isCordova);
test.equal(typeof Meteor.isModern, "boolean");
});

View File

@@ -1,4 +1,5 @@
meteorEnv = __meteor_runtime_config__.meteorEnv;
var config = __meteor_runtime_config__;
meteorEnv = config.meteorEnv;
/**
* @summary The Meteor namespace
@@ -36,15 +37,32 @@ Meteor = {
* @type {Boolean}
*/
isServer: false,
isCordova: false
/**
* @summary Boolean variable. True if running in Cordova environment.
* @locus Anywhere
* @static
* @type {Boolean}
*/
isCordova: false,
/**
* @summary Boolean variable. True if running in a "modern" JS
* environment, as determined by the `modern` package.
* @locus Anywhere
* @static
* @type {Boolean}
*/
isModern: config.isModern
};
if (typeof __meteor_runtime_config__ === 'object' &&
__meteor_runtime_config__.PUBLIC_SETTINGS) {
if (config.PUBLIC_SETTINGS) {
/**
* @summary `Meteor.settings` contains deployment-specific configuration options. You can initialize settings by passing the `--settings` option (which takes the name of a file containing JSON data) to `meteor run` or `meteor deploy`. When running your server directly (e.g. from a bundle), you instead specify settings by putting the JSON directly into the `METEOR_SETTINGS` environment variable. If the settings object contains a key named `public`, then `Meteor.settings.public` will be available on the client as well as the server. All other properties of `Meteor.settings` are only defined on the server. You can rely on `Meteor.settings` and `Meteor.settings.public` being defined objects (not undefined) on both client and server even if there are no settings specified. Changes to `Meteor.settings.public` at runtime will be picked up by new client connections.
* @locus Anywhere
* @type {Object}
*/
Meteor.settings = { 'public': __meteor_runtime_config__.PUBLIC_SETTINGS };
Meteor.settings = {
"public": config.PUBLIC_SETTINGS
};
}

View File

@@ -8,3 +8,7 @@ Meteor.isCordova = true;
Meteor.isProduction = meteorEnv.NODE_ENV === "production";
Meteor.isDevelopment = meteorEnv.NODE_ENV !== "production";
// For now, since we can't send different bundles to different Cordova
// browsers at runtime, all Cordova clients must be regarded as legacy.
Meteor.isModern = false;

View File

@@ -2,7 +2,7 @@
Package.describe({
summary: "Core Meteor environment",
version: '1.8.6'
version: '1.9.0'
});
Package.registerBuildPlugin({

View File

@@ -12,7 +12,10 @@ Meteor = {
isDevelopment: meteorEnv.NODE_ENV !== "production",
isClient: false,
isServer: true,
isCordova: false
isCordova: false,
// Server code runs in Node 8+, which is decidedly "modern" by any
// reasonable definition.
isModern: true
};
Meteor.settings = {};

View File

@@ -23,11 +23,17 @@ Meteor.absoluteUrl = function (path, options) {
if (!/^http[s]?:\/\//i.test(url)) // url starts with 'http://' or 'https://'
url = 'http://' + url; // we will later fix to https if options.secure is set
if (!/\/$/.test(url)) // url ends with '/'
url += '/';
if (! url.endsWith("/")) {
url += "/";
}
if (path)
if (path) {
// join url and path with a / separator
while (path.startsWith("/")) {
path = path.slice(1);
}
url += path;
}
// turn http to https if secure option is set, and we're not talking
// to localhost.
@@ -44,11 +50,27 @@ Meteor.absoluteUrl = function (path, options) {
};
// allow later packages to override default options
Meteor.absoluteUrl.defaultOptions = { };
if (typeof __meteor_runtime_config__ === "object" &&
__meteor_runtime_config__.ROOT_URL)
Meteor.absoluteUrl.defaultOptions.rootUrl = __meteor_runtime_config__.ROOT_URL;
var defaultOptions = Meteor.absoluteUrl.defaultOptions = {};
// available only in a browser environment
var location = typeof window === "object" && window.location;
if (typeof __meteor_runtime_config__ === "object" &&
__meteor_runtime_config__.ROOT_URL) {
defaultOptions.rootUrl = __meteor_runtime_config__.ROOT_URL;
} else if (location &&
location.protocol &&
location.host) {
defaultOptions.rootUrl = location.protocol + "//" + location.host;
}
// Make absolute URLs use HTTPS by default if the current window.location
// uses HTTPS. Since this is just a default, it can be overridden by
// passing { secure: false } if necessary.
if (location &&
location.protocol === "https:") {
defaultOptions.secure = true;
}
Meteor._relativeToSiteRootUrl = function (link) {
if (typeof __meteor_runtime_config__ === "object" &&

View File

@@ -11,7 +11,7 @@ Tinytest.add("absolute-url - basics", function(test) {
test.equal(Meteor.absoluteUrl('foo', {rootUrl: prefix + 'asdf.com/'}),
'http://asdf.com/foo');
test.equal(Meteor.absoluteUrl('/foo', {rootUrl: prefix + 'asdf.com'}),
'http://asdf.com//foo');
'http://asdf.com/foo');
test.equal(Meteor.absoluteUrl('#foo', {rootUrl: prefix + 'asdf.com'}),
'http://asdf.com/#foo');

View File

@@ -0,0 +1,7 @@
# modern-browsers
[Source code of released version](https://github.com/meteor/meteor/tree/master/packages/modern-browsers) | [Source code of development version](https://github.com/meteor/meteor/tree/devel/packages/modern-browsers)
***
API for defining the boundary between modern and legacy JavaScript
clients, with runtime support for choosing between the `web.browser`
(modern) bundle architecture and `web.browser.legacy`.

View File

@@ -0,0 +1,52 @@
## Remaining work
- [x] Come up with a system for constraining minimum browser versions.
- [x] Research minimum versions for key ECMAScript features.
- [x] Use the minimum versions in `webapp` to determine JS bundle.
- [x] Import different `core-js` polyfills in `ecmascript-runtime-client`
depending on modern/legacy classification.
- [x] Really vet the set of imported `core-js` polyfills based on known
minimum versions imposed by `setMinimumBrowserVersions`.
- [x] Make sure the new url prefixes aren't too disruptive for public
assets like images.
- [x] Make sure Cordova isn't automatically treated as a modern
environment.
- [ ] Create an `isobuild:web-browser-legacy` pseudopackage.
- [ ] Add tests to the `modules` test app.
- [x] Expose `Meteor.isModern` on both client and server.
- [ ] Make sure in-browser tests run with both `web.browser` and
`web.browser.legacy`.
- [x] Use `web.browser.legacy` to handle `es5-shim` instead.
- [x] Use `web.browser.legacy` to handle SockJS instead.
- [x] Load `SockJS` using dynamic `import()` if necessary in modern
`web.browser` clients.
- [x] Use different plugins in babel-compiler for `web.browser.legacy`.
- [x] Fix dynamic module source map URLs (prepend `/__arch`).
- [x] Fix tests failing because of changes to static resource URLs.
- [ ] In development, save time by only rebuilding `web.browser` (modern)?
- [ ] Try adding a `web.worker` platform and see if it works as expected.
- [ ] Update `History.md` to reflect all these changes.
- [ ] Write a blog post about the new modern/legacy system.
- [ ] Update `compiler.BUILT_BY` and `LINKER_CACHE_SALT` to force
recompilation and relinking.

View File

@@ -0,0 +1,32 @@
import { Tinytest } from "meteor/tinytest";
import { isModern } from "meteor/modern-browsers";
Tinytest.add('modern-browsers - versions - basic', function (test) {
test.isTrue(isModern({
name: "chrome",
major: 60,
}));
test.isTrue(isModern({
name: "chromeMobile",
major: 60,
}));
test.isFalse(isModern({
name: "firefox",
major: 25,
}));
test.isTrue(isModern({
name: "safari",
major: 10,
minor: 2,
}));
test.isFalse(isModern({
name: "safari",
major: 9,
minor: 5,
patch: 2,
}));
});

View File

@@ -0,0 +1,185 @@
const minimumVersions = Object.create(null);
const hasOwn = Object.prototype.hasOwnProperty;
// By default, any minimum versions specified for chrome should apply to
// chromeMobile too, per https://github.com/meteor/meteor/pull/9793,
// though it should also be possible to specify minimum versions
// specifically for chromeMobile. This map defines that aliasing behavior
// in a generic way that could work for other browsers as well.
const browserAliases = {
chrome: [
"chromeMobile",
"chromeMobileIOS",
],
// If a call to setMinimumBrowserVersions specifies Edge 12 as a minimum
// version, that means no version of Internet Explorer pre-Edge should
// be classified as modern. This edge:["ie"] alias effectively enforces
// that logic, because there is no IE12. #9818 #9839
edge: ["ie"],
// The webapp package converts browser names to camel case, so
// mobile_safari and mobileSafari should be synonymous.
mobile_safari: ["mobileSafari"],
};
// Expand the given minimum versions by reusing chrome versions for
// chromeMobile (according to browserAliases above).
function applyAliases(versions) {
Object.keys(browserAliases).forEach(original => {
if (hasOwn.call(versions, original)) {
browserAliases[original].forEach(alias => {
if (! hasOwn.call(versions, alias)) {
versions[alias] = versions[original];
}
});
}
});
return versions;
}
// TODO Should it be possible for callers to setMinimumBrowserVersions to
// forbid any version of a particular browser?
// Given a { name, major, minor, patch } object like the one provided by
// webapp via request.browser, return true if that browser qualifies as
// "modern" according to all requested version constraints.
function isModern(browser) {
return browser &&
typeof browser.name === "string" &&
hasOwn.call(minimumVersions, browser.name) &&
greaterThanOrEqualTo([
~~browser.major,
~~browser.minor,
~~browser.patch,
], minimumVersions[browser.name].version);
}
// Any package that depends on the modern-browsers package can call this
// function to communicate its expectations for the minimum browser
// versions that qualify as "modern." The final decision between
// web.browser.legacy and web.browser will be based on the maximum of all
// requested minimum versions for each browser.
function setMinimumBrowserVersions(versions, source) {
applyAliases(versions);
Object.keys(versions).forEach(browserName => {
if (hasOwn.call(minimumVersions, browserName) &&
! greaterThan(versions[browserName],
minimumVersions[browserName].version)) {
return;
}
minimumVersions[browserName] = {
version: copy(versions[browserName]),
source: source || getCaller("setMinimumBrowserVersions")
};
});
}
function getCaller(calleeName) {
const error = new Error;
Error.captureStackTrace(error);
const lines = error.stack.split("\n");
let caller;
lines.some((line, i) => {
if (line.indexOf(calleeName) >= 0) {
caller = lines[i + 1].trim();
return true;
}
});
return caller;
}
Object.assign(exports, {
isModern,
setMinimumBrowserVersions,
});
// For making defensive copies of [major, minor, ...] version arrays, so
// they don't change unexpectedly.
function copy(version) {
if (typeof version === "number") {
return version;
}
if (Array.isArray(version)) {
return version.map(copy);
}
return version;
}
function greaterThanOrEqualTo(a, b) {
return ! greaterThan(b, a);
}
function greaterThan(a, b) {
const as = (typeof a === "number") ? [a] : a;
const bs = (typeof b === "number") ? [b] : b;
const maxLen = Math.max(as.length, bs.length);
for (let i = 0; i < maxLen; ++i) {
a = (i < as.length) ? as[i] : 0;
b = (i < bs.length) ? bs[i] : 0;
if (a > b) {
return true;
}
if (a < b) {
return false;
}
}
return false;
}
function makeSource(feature) {
return module.id + " (" + feature + ")"
}
setMinimumBrowserVersions({
chrome: 49,
edge: 12,
firefox: 45,
mobileSafari: [9, 2],
opera: 36,
safari: 9,
// Electron 1.0.0+ matches Chromium 49, per
// https://github.com/Kilian/electron-to-chromium/blob/master/full-versions.js
electron: 1,
}, makeSource("classes"));
setMinimumBrowserVersions({
chrome: 39,
edge: 13,
firefox: 26,
mobileSafari: 10,
opera: 26,
safari: 10,
// Disallow any version of PhantomJS.
phantomjs: Infinity,
electron: [0, 20],
}, makeSource("generator functions"));
setMinimumBrowserVersions({
chrome: 41,
edge: 13,
firefox: 34,
mobileSafari: [9, 2],
opera: 29,
safari: [9, 1],
electron: [0, 24],
}, makeSource("template literals"));
setMinimumBrowserVersions({
chrome: 38,
edge: 12,
firefox: 36,
mobileSafari: 9,
opera: 25,
safari: 9,
electron: [0, 20],
}, makeSource("symbols"));

View File

@@ -0,0 +1,19 @@
Package.describe({
name: "modern-browsers",
version: "0.1.1",
summary: "API for defining the boundary between modern and legacy " +
"JavaScript clients",
documentation: "README.md"
});
Package.onUse(function(api) {
api.use("modules");
api.mainModule("modern.js", "server");
});
Package.onTest(function(api) {
api.use("ecmascript");
api.use("tinytest");
api.use("modern-browsers");
api.mainModule("modern-tests.js", "server");
});

View File

@@ -7,9 +7,9 @@
"integrity": "sha512-jd5MkIUlbbmb07nXH0DT3y7rDVtkzDi4XZOUVWAer8ajmF/DTSSbl5oNFyDOl/OXA33Bl79+ypHhl2pN20VeOQ=="
},
"reify": {
"version": "0.15.1",
"resolved": "https://registry.npmjs.org/reify/-/reify-0.15.1.tgz",
"integrity": "sha512-XUIO34oFNXyb8cYRw3eVN0oqD3LwxaBFml5cHZf3Uiw6v+pfPB0D7kxKCdBjvaa1cneDtUqqQ94MPQkJt2kEWg=="
"version": "0.16.2",
"resolved": "https://registry.npmjs.org/reify/-/reify-0.16.2.tgz",
"integrity": "sha512-9kL/IYcFiBbwpQFScNcFBJ5zhCEJTNujeDEEv5SoSg5er0V5CDbef2zNEk9FBeI9oehGOG5zM4APXgp5n3Llbw=="
},
"semver": {
"version": "5.5.0",

View File

@@ -1,12 +1,12 @@
Package.describe({
name: "modules",
version: "0.11.6",
version: "0.12.0",
summary: "CommonJS module system",
documentation: "README.md"
});
Npm.depends({
reify: "0.15.1"
reify: "0.16.2"
});
Package.onUse(function(api) {

View File

@@ -1,5 +1,3 @@
var Module = module.constructor;
var Mp = Module.prototype;
require("reify/lib/runtime").enable(Mp);
Mp.importSync = Mp.importSync || Mp.import;
Mp.import = Mp.import || Mp.importSync;
require("reify/lib/runtime").enable(
module.constructor.prototype
);

View File

@@ -687,6 +687,8 @@ Object.assign(Mongo.Collection.prototype, {
/**
* @summary Returns the [`Collection`](http://mongodb.github.io/node-mongodb-native/2.2/api/Collection.html) object corresponding to this collection from the [npm `mongodb` driver module](https://www.npmjs.com/package/mongodb) which is wrapped by `Mongo.Collection`.
* @locus Server
* @memberof Mongo.Collection
* @instance
*/
rawCollection() {
var self = this;
@@ -699,6 +701,8 @@ Object.assign(Mongo.Collection.prototype, {
/**
* @summary Returns the [`Db`](http://mongodb.github.io/node-mongodb-native/2.2/api/Db.html) object corresponding to this collection's database connection from the [npm `mongodb` driver module](https://www.npmjs.com/package/mongodb) which is wrapped by `Mongo.Collection`.
* @locus Server
* @memberof Mongo.Collection
* @instance
*/
rawDatabase() {
var self = this;

View File

@@ -170,11 +170,13 @@ MongoConnection = function (url, options) {
url,
mongoOptions,
Meteor.bindEnvironment(
function (err, db) {
function (err, client) {
if (err) {
throw err;
}
var db = client.db();
// First, figure out what the current primary is, if any.
if (db.serverConfig.isMasterDoc) {
self._primary = db.serverConfig.isMasterDoc.primary;
@@ -201,14 +203,15 @@ MongoConnection = function (url, options) {
}));
// Allow the constructor to return.
connectFuture['return'](db);
connectFuture['return']({ client, db });
},
connectFuture.resolver() // onException
)
);
// Wait for the connection to be successful; throws on failure.
self.db = connectFuture.wait();
// Wait for the connection to be successful (throws on failure) and assign the
// results (`client` and `db`) to `self`.
Object.assign(self, connectFuture.wait());
if (options.oplogUrl && ! Package['disable-oplog']) {
self._oplogHandle = new OplogHandle(options.oplogUrl, self.db.databaseName);
@@ -231,7 +234,7 @@ MongoConnection.prototype.close = function() {
// Use Future.wrap so that errors get thrown. This happens to
// work even outside a fiber since the 'close' method is not
// actually asynchronous.
Future.wrap(_.bind(self.db.close, self.db))(true).wait();
Future.wrap(_.bind(self.client.close, self.client))(true).wait();
};
// Returns the Mongo Collection object; may yield.
@@ -947,7 +950,8 @@ MongoConnection.prototype._createSynchronousCursor = function(
var mongoOptions = {
sort: cursorOptions.sort,
limit: cursorOptions.limit,
skip: cursorOptions.skip
skip: cursorOptions.skip,
projection: cursorOptions.fields
};
// Do we want a tailable cursor (which only works on capped collections)?
@@ -973,7 +977,7 @@ MongoConnection.prototype._createSynchronousCursor = function(
var dbCursor = collection.find(
replaceTypes(cursorDescription.selector, replaceMeteorAtomWithMongo),
cursorOptions.fields, mongoOptions);
mongoOptions);
if (typeof cursorOptions.maxTimeMs !== 'undefined') {
dbCursor = dbCursor.maxTimeMS(cursorOptions.maxTimeMs);
@@ -1001,21 +1005,33 @@ var SynchronousCursor = function (dbCursor, cursorDescription, options) {
self._transform = null;
}
// Need to specify that the callback is the first argument to nextObject,
// since otherwise when we try to call it with no args the driver will
// interpret "undefined" first arg as an options hash and crash.
self._synchronousNextObject = Future.wrap(
dbCursor.nextObject.bind(dbCursor), 0);
self._synchronousCount = Future.wrap(dbCursor.count.bind(dbCursor));
self._visitedIds = new LocalCollection._IdMap;
};
_.extend(SynchronousCursor.prototype, {
_nextObject: function () {
// Returns a Promise for the next object from the underlying cursor (before
// the Mongo->Meteor type replacement).
_rawNextObjectPromise: function () {
const self = this;
return new Promise((resolve, reject) => {
self._dbCursor.next((err, doc) => {
if (err) {
reject(err);
} else {
resolve(doc);
}
});
});
},
// Returns a Promise for the next object from the cursor, skipping those whose
// IDs we've already seen and replacing Mongo atoms with Meteor atoms.
_nextObjectPromise: async function () {
var self = this;
while (true) {
var doc = self._synchronousNextObject().wait();
var doc = await self._rawNextObjectPromise();
if (!doc) return null;
doc = replaceTypes(doc, replaceMongoAtomWithMeteor);
@@ -1038,6 +1054,35 @@ _.extend(SynchronousCursor.prototype, {
}
},
// Returns a promise which is resolved with the next object (like with
// _nextObjectPromise) or rejected if the cursor doesn't return within
// timeoutMS ms.
_nextObjectPromiseWithTimeout: function (timeoutMS) {
const self = this;
if (!timeoutMS) {
return self._nextObjectPromise();
}
const nextObjectPromise = self._nextObjectPromise();
const timeoutErr = new Error('Client-side timeout waiting for next object');
const timeoutPromise = new Promise((resolve, reject) => {
const timer = setTimeout(() => {
reject(timeoutErr);
}, timeoutMS);
});
return Promise.race([nextObjectPromise, timeoutPromise])
.catch((err) => {
if (err === timeoutErr) {
self.close();
}
throw err;
});
},
_nextObject: function () {
var self = this;
return self._nextObjectPromise().await();
},
forEach: function (callback, thisArg) {
var self = this;
@@ -1124,7 +1169,13 @@ SynchronousCursor.prototype[Symbol.iterator] = function () {
};
};
MongoConnection.prototype.tail = function (cursorDescription, docCallback) {
// Tails the cursor described by cursorDescription, most likely on the
// oplog. Calls docCallback with each document found. Ignores errors and just
// restarts the tail on error.
//
// If timeoutMS is set, then if we don't get a new document every timeoutMS,
// kill and restart the cursor. This is primarily a workaround for #8598.
MongoConnection.prototype.tail = function (cursorDescription, docCallback, timeoutMS) {
var self = this;
if (!cursorDescription.options.tailable)
throw new Error("Can only tail a tailable cursor");
@@ -1139,14 +1190,15 @@ MongoConnection.prototype.tail = function (cursorDescription, docCallback) {
if (stopped)
return;
try {
doc = cursor._nextObject();
doc = cursor._nextObjectPromiseWithTimeout(timeoutMS).await();
} catch (err) {
// There's no good way to figure out if this was actually an error
// from Mongo. Ah well. But either way, we need to retry the cursor
// (unless the failure was because the observe got stopped).
// There's no good way to figure out if this was actually an error from
// Mongo, or just client-side (including our own timeout error). Ah
// well. But either way, we need to retry the cursor (unless the failure
// was because the observe got stopped).
doc = null;
}
// Since cursor._nextObject can yield, we need to check again to see if
// Since we awaited a promise above, we need to check again to see if
// we've been stopped before calling the callback.
if (stopped)
return;

View File

@@ -3234,7 +3234,7 @@ Meteor.isServer && Tinytest.add(
Meteor.isServer && Tinytest.add("mongo-livedata - npm modules", function (test) {
// Make sure the version number looks like a version number.
test.matches(MongoInternals.NpmModules.mongodb.version, /^2\.(\d+)\.(\d+)/);
test.matches(MongoInternals.NpmModules.mongodb.version, /^3\.(\d+)\.(\d+)/);
test.equal(typeof(MongoInternals.NpmModules.mongodb.module), 'function');
test.equal(typeof(MongoInternals.NpmModules.mongodb.module.connect),
'function');

View File

@@ -3,6 +3,7 @@ var Future = Npm.require('fibers/future');
OPLOG_COLLECTION = 'oplog.rs';
var TOO_FAR_BEHIND = process.env.METEOR_OPLOG_TOO_FAR_BEHIND || 2000;
var TAIL_TIMEOUT = +process.env.METEOR_OPLOG_TAIL_TIMEOUT || 30000;
var showTS = function (ts) {
return "Timestamp(" + ts.getHighBits() + ", " + ts.getLowBits() + ")";
@@ -96,8 +97,7 @@ _.extend(OplogHandle.prototype, {
var originalCallback = callback;
callback = Meteor.bindEnvironment(function (notification) {
// XXX can we avoid this clone by making oplog.js careful?
originalCallback(EJSON.clone(notification));
originalCallback(notification);
}, function (err) {
Meteor._debug("Error in oplog callback", err);
});
@@ -236,11 +236,19 @@ _.extend(OplogHandle.prototype, {
var cursorDescription = new CursorDescription(
OPLOG_COLLECTION, oplogSelector, {tailable: true});
// Start tailing the oplog.
//
// We restart the low-level oplog query every 30 seconds if we didn't get a
// doc. This is a workaround for #8598: the Node Mongo driver has at least
// one bug that can lead to query callbacks never getting called (even with
// an error) when leadership failover occur.
self._tailHandle = self._oplogTailConnection.tail(
cursorDescription, function (doc) {
cursorDescription,
function (doc) {
self._entryQueue.push(doc);
self._maybeStartWorker();
}
},
TAIL_TIMEOUT
);
self._readyFuture.return();
},

View File

@@ -9,7 +9,7 @@
Package.describe({
summary: "Adaptor for using MongoDB and Minimongo over DDP",
version: '1.4.7'
version: '1.5.0'
});
Npm.depends({

View File

@@ -7,7 +7,7 @@ import {
} from "./common.js";
import * as classes from "./classNames.js";
import "./style.css";
import("./style.css");
Meteor.startup(() => {
import("./sunburst.js").then(s => main(s.Sunburst));

View File

@@ -1,5 +1,5 @@
Package.describe({
version: '1.1.3',
version: '1.2.0',
summary: 'Meteor bundle analysis and visualization.',
documentation: 'README.md',
});

View File

@@ -33,21 +33,38 @@ function getStatBundles() {
f.absolutePath.endsWith(".stats.json");
// Read the stat file, but if it's in any way unusable just return null.
const readOrNull = file => {
function readOrNull(file) {
try {
return JSON.parse(fsReadFileSync(file, "utf8"));
} catch (err) {
return null;
}
};
}
return Object.keys(WebAppInternals.staticFiles)
.map(staticFile => WebAppInternals.staticFiles[staticFile])
.filter(statFileFilter)
.map(statFile => ({
name: statFile.hash,
stats: readOrNull(statFile.absolutePath),
}));
const {
staticFiles,
staticFilesByArch,
} = WebAppInternals;
const files = [];
if (staticFilesByArch) {
Object.keys(staticFilesByArch).forEach(arch => {
const staticFiles = staticFilesByArch[arch];
Object.keys(staticFiles).forEach(path => {
files.push(staticFiles[path]);
});
});
} else if (staticFiles) {
Object.keys(staticFiles).forEach(path => {
files.push(staticFiles[path]);
});
}
return files.filter(statFileFilter).map(file => ({
name: file.hash,
stats: readOrNull(file.absolutePath),
}));
}
function _childModules(node) {

View File

@@ -2,54 +2,19 @@
"lockfileVersion": 1,
"dependencies": {
"bson": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/bson/-/bson-1.0.4.tgz",
"integrity": "sha1-k8ENOeqltYQVy8QFLz5T5WKwtyw="
},
"buffer-shims": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/buffer-shims/-/buffer-shims-1.0.0.tgz",
"integrity": "sha1-mXjOMXOIxkmth5MCjDR37wRKi1E="
},
"core-util-is": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
"integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac="
},
"es6-promise": {
"version": "3.2.1",
"resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-3.2.1.tgz",
"integrity": "sha1-7FYjOGgDKQkgcXDDlEjiREndH8Q="
},
"inherits": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
"integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4="
},
"isarray": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
"integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE="
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/bson/-/bson-1.0.6.tgz",
"integrity": "sha512-D8zmlb46xfuK2gGvKmUjIklQEouN2nQ0LEHHeZ/NoHM2LDiMk2EYzZ5Ntw/Urk+bgMDosOZxaRzXxvhI5TcAVQ=="
},
"mongodb": {
"version": "2.2.34",
"resolved": "https://registry.npmjs.org/mongodb/-/mongodb-2.2.34.tgz",
"integrity": "sha1-o09Zu+thdUrsQy3nLD/iFSakTBo="
"version": "3.0.7",
"resolved": "https://registry.npmjs.org/mongodb/-/mongodb-3.0.7.tgz",
"integrity": "sha512-n/14kMJEoARXz1qhpNPhUocqy+z5130jhqgEIX1Tsl8UVpHrndQ8et+VmgC4yPK/I8Tcgc93JEMQCHTekBUnNA=="
},
"mongodb-core": {
"version": "2.1.18",
"resolved": "https://registry.npmjs.org/mongodb-core/-/mongodb-core-2.1.18.tgz",
"integrity": "sha1-TEYTm986HwMt7ZHbSfOO7AFlkFA="
},
"process-nextick-args": {
"version": "1.0.7",
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz",
"integrity": "sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M="
},
"readable-stream": {
"version": "2.2.7",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.2.7.tgz",
"integrity": "sha1-BwV6y+JGeyIELTb5jFrVBwVOlbE="
"version": "3.0.7",
"resolved": "https://registry.npmjs.org/mongodb-core/-/mongodb-core-3.0.7.tgz",
"integrity": "sha512-z6YufO7s40wLiv2ssFshqoLS4+Kf+huhHq6KZ7gDArsKNzXYjAwTMnhEIJ9GQ8fIfBGs5tBLNPfbIDoCKGPmOw=="
},
"require_optional": {
"version": "1.0.1",
@@ -61,25 +26,10 @@
"resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-2.0.0.tgz",
"integrity": "sha1-lICrIOlP+h2egKgEx+oUdhGWa1c="
},
"safe-buffer": {
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz",
"integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg=="
},
"semver": {
"version": "5.4.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-5.4.1.tgz",
"integrity": "sha512-WfG/X9+oATh81XtllIo/I8gOiY9EXRdv1cQdyykeXK17YcUW3EXUAi2To4pcH6nZtJPr7ZOpM5OMyWJZm+8Rsg=="
},
"string_decoder": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz",
"integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ=="
},
"util-deprecate": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
"integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8="
"version": "5.5.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-5.5.0.tgz",
"integrity": "sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA=="
}
}
}

View File

@@ -3,12 +3,12 @@
Package.describe({
summary: "Wrapper around the mongo npm package",
version: "2.2.34",
version: "3.0.7",
documentation: null
});
Npm.depends({
mongodb: "2.2.34"
mongodb: "3.0.7"
});
Package.onUse(function (api) {

View File

@@ -1,3 +1,2 @@
require("meteor-promise").makeCompatible(
exports.Promise = require("./common.js").Promise
);
require("./extensions.js");
require("meteor-promise").makeCompatible(Promise);

View File

@@ -1,15 +1,6 @@
var global = this;
var proto = Promise.prototype;
var hasOwn = Object.prototype.hasOwnProperty;
if (typeof global.Promise === "function") {
exports.Promise = global.Promise;
} else {
exports.Promise = global.Promise =
require("promise/lib/es6-extensions");
}
var proto = exports.Promise.prototype;
proto.done = function (onFulfilled, onRejected) {
var self = this;

View File

@@ -0,0 +1,8 @@
// In legacy environments, load a polyfill if global.Promise was not
// defined in modern.js.
if (typeof global.Promise === "function") {
Promise = global.Promise;
} else {
Promise = global.Promise =
require("promise/lib/es6-extensions");
}

View File

@@ -0,0 +1,3 @@
// Initialize the package-scoped Promise variable with global.Promise in
// all environments, even if it's not defined.
Promise = global.Promise;

View File

@@ -1,6 +1,6 @@
Package.describe({
name: "promise",
version: "0.10.2",
version: "0.11.1",
summary: "ECMAScript 2015 Promise polyfill with Fiber support",
git: "https://github.com/meteor/promise",
documentation: "README.md"
@@ -13,6 +13,9 @@ Npm.depends({
Package.onUse(function(api) {
api.use("modules");
api.use("modern-browsers");
api.addFiles("modern.js");
api.addFiles("legacy.js", "legacy");
api.mainModule("client.js", "client");
api.mainModule("server.js", "server");
api.export("Promise");

View File

@@ -1,6 +1,23 @@
require("./extensions.js");
require("meteor-promise").makeCompatible(
exports.Promise = require("./common.js").Promise,
Promise,
// Allow every Promise callback to run in a Fiber drawn from a pool of
// reusable Fibers.
require("fibers")
);
// Reference: https://caniuse.com/#feat=promises
require("meteor/modern-browsers").setMinimumBrowserVersions({
chrome: 32,
edge: 12,
// Since there is no IE11, this effectively excludes Internet Explorer
// (pre-Edge) from the modern classification. #9818 #9839
ie: 12,
firefox: 29,
mobileSafari: 8,
opera: 20,
safari: [7, 1],
// https://github.com/Kilian/electron-to-chromium/blob/master/full-versions.js
electron: [0, 20],
}, module.id);

View File

@@ -1,6 +1,6 @@
Package.describe({
name: "server-render",
version: "0.3.0",
version: "0.3.1",
summary: "Generic support for server-side rendering in Meteor apps",
documentation: "README.md"
});
@@ -15,7 +15,7 @@ Npm.depends({
Package.onUse(function(api) {
api.use("ecmascript");
api.use("webapp");
api.mainModule("client.js", "client");
api.mainModule("client.js", "client", { lazy: true });
api.mainModule("server.js", "server");
});

View File

@@ -1,8 +0,0 @@
# shim-common
[Source code of released version](https://github.com/meteor/meteor/tree/master/packages/shim-common) | [Source code of development version](https://github.com/meteor/meteor/tree/devel/packages/shim-common)
***
Shared utilities for packages like
[`sockjs-shim`](https://github.com/meteor/meteor/tree/devel/packages/sockjs-shim)
and
[`es5-shim`](https://github.com/meteor/meteor/tree/devel/packages/es5-shim).

View File

@@ -1,11 +0,0 @@
Package.describe({
name: "shim-common",
version: "0.1.0",
summary: "Shared utilities for packages like sockjs-shim and es5-shim",
documentation: "README.md"
});
Package.onUse(function(api) {
api.use("ecmascript");
api.mainModule("server.js", "server");
});

View File

@@ -1,38 +0,0 @@
"use strict";
export const hasOwn = Object.prototype.hasOwnProperty;
export function doNotNeedShim(
// The HTTP request object, as exposed (for example) by sink.request.
request,
// Map from lowercase browser names to the minimum major version of that
// browser that no longer needs the shim.
minimumMajorVersions = {},
// Optional URL query parameter that can be used to force the shim to be
// injected into the HTTP response.
queryForceParam,
) {
const { browser, url } = request;
if (queryForceParam) {
const query = url && url.query;
const forced = query && query[queryForceParam];
if (forced) {
return false;
}
}
if (browser &&
hasOwn.call(minimumMajorVersions, browser.name) &&
browser.major >= minimumMajorVersions[browser.name]) {
return true;
}
return false;
}
export function makeScript(packagePath) {
return '\n<script src="/packages/' + packagePath + (
Meteor.isProduction ? ".min.js" : ".js"
) + '"></script>';
}

View File

@@ -2,9 +2,14 @@ import {
toSockjsUrl,
toWebsocketUrl,
} from "./urls.js";
import "./sockjs-0.3.4.js";
import { StreamClientCommon } from "./common.js";
// Statically importing SockJS here will prevent native WebSocket usage
// below (in favor of SockJS), but will ensure maximum compatibility for
// clients stuck in unusual networking environments.
import "./sockjs-0.3.4.js";
export class ClientStream extends StreamClientCommon {
// @param url {String} URL to Meteor app
// "http://subdomain.meteor.com/" or "/" or
@@ -184,11 +189,16 @@ export class ClientStream extends StreamClientCommon {
};
this.socket.onclose = () => {
if (this.lastError) {
this._lostConnection(this.lastError);
} else {
Promise.resolve(
// If the socket is closing because there was an error, and we
// didn't load SockJS before, try loading it dynamically before
// retrying the connection.
this.lastError &&
! hasSockJS &&
import("./sockjs-0.3.4.js")
).done(() => {
this._lostConnection();
}
});
};
this.socket.onerror = error => {

View File

@@ -1,6 +1,6 @@
Package.describe({
name: "socket-stream-client",
version: "0.1.0",
version: "0.2.2",
summary: "Provides the ClientStream abstraction used by ddp-client",
documentation: "README.md"
});
@@ -12,8 +12,14 @@ Npm.depends({
Package.onUse(function(api) {
api.use("ecmascript");
api.use("modern-browsers");
api.use("retry"); // TODO Try to remove this.
api.use("dynamic-import");
api.addFiles("sockjs-0.3.4.js", "legacy");
api.mainModule("browser.js", "client", { lazy: true });
api.addFiles("server.js", "server");
api.mainModule("node.js", "server", { lazy: true });
});

View File

@@ -0,0 +1,14 @@
import {
setMinimumBrowserVersions,
} from "meteor/modern-browsers";
setMinimumBrowserVersions({
chrome: 16,
edge: 12,
firefox: 11,
ie: 10,
mobileSafari: [6, 1],
phantomjs: 2,
safari: 7,
electron: [0, 20],
}, module.id);

View File

@@ -0,0 +1 @@
console.log("LEGACY");

View File

@@ -0,0 +1 @@
console.log("MODERN");

View File

@@ -1,6 +1,6 @@
Package.describe({
summary: "Serves a Meteor app over HTTP",
version: '1.5.0'
version: '1.6.1'
});
Npm.depends({"basic-auth-connect": "1.0.0",
@@ -27,8 +27,14 @@ Cordova.depends({
Package.onUse(function (api) {
api.use('ecmascript');
api.use(['logging', 'underscore', 'routepolicy', 'boilerplate-generator',
'webapp-hashing'], 'server');
api.use([
'logging',
'underscore',
'routepolicy',
'modern-browsers',
'boilerplate-generator',
'webapp-hashing'
], 'server');
// At response serving time, webapp uses browser-policy if it is loaded. If
// browser-policy is loaded, then it must be loaded after webapp
@@ -51,4 +57,7 @@ Package.onTest(function (api) {
api.addFiles('webapp_tests.js', 'server');
api.addFiles('webapp_client_tests.js', 'client');
api.addFiles('socket_file_tests.js', 'server');
api.addAssets('modern_test_asset.js', 'web.browser');
api.addAssets('legacy_test_asset.js', 'legacy');
});

View File

@@ -14,6 +14,7 @@ import query from "qs-middleware";
import parseRequest from "parseurl";
import basicAuth from "basic-auth-connect";
import { lookup as lookupUserAgent } from "useragent";
import { isModern } from "meteor/modern-browsers";
import send from "send";
import {
removeExistingSocketFile,
@@ -26,6 +27,8 @@ var LONG_SOCKET_TIMEOUT = 120*1000;
export const WebApp = {};
export const WebAppInternals = {};
const hasOwn = Object.prototype.hasOwnProperty;
// backwards compat to 2.0 of connect
connect.basicAuth = basicAuth;
@@ -36,7 +39,9 @@ WebAppInternals.NpmModules = {
}
};
WebApp.defaultArch = 'web.browser';
// Though we might prefer to use web.browser (modern) as the default
// architecture, safety requires a more compatible defaultArch.
WebApp.defaultArch = 'web.browser.legacy';
// XXX maps archs to manifests
WebApp.clientPrograms = {};
@@ -321,38 +326,39 @@ WebAppInternals.generateBoilerplateInstance = function (arch,
_.clone(__meteor_runtime_config__),
additionalOptions.runtimeConfigOverrides || {}
);
return new Boilerplate(arch, manifest,
_.extend({
pathMapper: function (itemPath) {
return pathJoin(archPath[arch], itemPath); },
baseDataExtension: {
additionalStaticJs: _.map(
additionalStaticJs || [],
function (contents, pathname) {
return {
pathname: pathname,
contents: contents
};
}
),
// Convert to a JSON string, then get rid of most weird characters, then
// wrap in double quotes. (The outermost JSON.stringify really ought to
// just be "wrap in double quotes" but we use it to be safe.) This might
// end up inside a <script> tag so we need to be careful to not include
// "</script>", but normal {{spacebars}} escaping escapes too much! See
// https://github.com/meteor/meteor/issues/3730
meteorRuntimeConfig: JSON.stringify(
encodeURIComponent(JSON.stringify(runtimeConfig))),
rootUrlPathPrefix: __meteor_runtime_config__.ROOT_URL_PATH_PREFIX || '',
bundledJsCssUrlRewriteHook: bundledJsCssUrlRewriteHook,
inlineScriptsAllowed: WebAppInternals.inlineScriptsAllowed(),
inline: additionalOptions.inline
}
}, additionalOptions)
);
return new Boilerplate(arch, manifest, _.extend({
pathMapper(itemPath) {
return pathJoin(archPath[arch], itemPath);
},
baseDataExtension: {
additionalStaticJs: _.map(
additionalStaticJs || [],
function (contents, pathname) {
return {
pathname: pathname,
contents: contents
};
}
),
// Convert to a JSON string, then get rid of most weird characters, then
// wrap in double quotes. (The outermost JSON.stringify really ought to
// just be "wrap in double quotes" but we use it to be safe.) This might
// end up inside a <script> tag so we need to be careful to not include
// "</script>", but normal {{spacebars}} escaping escapes too much! See
// https://github.com/meteor/meteor/issues/3730
meteorRuntimeConfig: JSON.stringify(
encodeURIComponent(JSON.stringify(runtimeConfig))),
rootUrlPathPrefix: __meteor_runtime_config__.ROOT_URL_PATH_PREFIX || '',
bundledJsCssUrlRewriteHook: bundledJsCssUrlRewriteHook,
inlineScriptsAllowed: WebAppInternals.inlineScriptsAllowed(),
inline: additionalOptions.inline
}
}, additionalOptions));
};
// A mapping from url path to "info". Where "info" has the following fields:
// A mapping from url path to architecture (e.g. "web.browser") to static
// file information with the following fields:
// - type: the type of file to be served
// - cacheable: optionally, whether the file should be cached or not
// - sourceMapUrl: optionally, the url of the source map
@@ -361,11 +367,11 @@ WebAppInternals.generateBoilerplateInstance = function (arch,
// - content: the stringified content that should be served at this path
// - absolutePath: the absolute path on disk to the file
var staticFiles;
var staticFilesByArch;
// Serve static files from the manifest or added with
// `addStaticJs`. Exported for tests.
WebAppInternals.staticFilesMiddleware = function (staticFiles, req, res, next) {
WebAppInternals.staticFilesMiddleware = function (staticFilesByArch, req, res, next) {
if ('GET' != req.method && 'HEAD' != req.method && 'OPTIONS' != req.method) {
next();
return;
@@ -397,7 +403,12 @@ WebAppInternals.staticFilesMiddleware = function (staticFiles, req, res, next) {
return;
}
if (!_.has(staticFiles, pathname)) {
const info = getStaticFileInfo(
pathname,
identifyBrowser(req.headers["user-agent"]),
);
if (! info) {
next();
return;
}
@@ -406,14 +417,20 @@ WebAppInternals.staticFilesMiddleware = function (staticFiles, req, res, next) {
// 'send' and yield to the event loop, we never call another handler with
// 'next'.
var info = staticFiles[pathname];
// Cacheable files are files that should never change. Typically
// named by their hash (eg meteor bundled js and css files).
// We cache them ~forever (1yr).
var maxAge = info.cacheable
? 1000 * 60 * 60 * 24 * 365
: 0;
const maxAge = info.cacheable
? 1000 * 60 * 60 * 24 * 365
: 0;
if (info.cacheable) {
// Since we use req.headers["user-agent"] to determine whether the
// client should receive modern or legacy resources, tell the client
// to invalidate cached resources when/if its user agent string
// changes in the future.
res.setHeader("Vary", "User-Agent");
}
// Set the X-SourceMap header, which current Chrome, FireFox, and Safari
// understand. (The SourceMap header is slightly more spec-correct but FF
@@ -445,32 +462,87 @@ WebAppInternals.staticFilesMiddleware = function (staticFiles, req, res, next) {
res.end();
} else {
send(req, info.absolutePath, {
maxage: maxAge,
dotfiles: 'allow', // if we specified a dotfile in the manifest, serve it
lastModified: false // don't set last-modified based on the file date
}).on('error', function (err) {
Log.error("Error serving static file " + err);
res.writeHead(500);
res.end();
})
.on('directory', function () {
Log.error("Unexpected directory " + info.absolutePath);
res.writeHead(500);
res.end();
})
.pipe(res);
maxage: maxAge,
dotfiles: 'allow', // if we specified a dotfile in the manifest, serve it
lastModified: false // don't set last-modified based on the file date
}).on('error', function (err) {
Log.error("Error serving static file " + err);
res.writeHead(500);
res.end();
}).on('directory', function () {
Log.error("Unexpected directory " + info.absolutePath);
res.writeHead(500);
res.end();
}).pipe(res);
}
};
var getUrlPrefixForArch = function (arch) {
// XXX we rely on the fact that arch names don't contain slashes
// in that case we would need to uri escape it
function getStaticFileInfo(originalPath, browser) {
const { arch, path } = getArchAndPath(originalPath, browser);
// We add '__' to the beginning of non-standard archs to "scope" the url
// to Meteor internals.
return arch === WebApp.defaultArch ?
'' : '/' + '__' + arch.replace(/^web\./, '');
};
if (! hasOwn.call(WebApp.clientPrograms, arch)) {
return null;
}
// Get a list of all available static file architectures, with arch
// first in the list if it exists.
const staticArchList = Object.keys(staticFilesByArch);
const archIndex = staticArchList.indexOf(arch);
if (archIndex > 0) {
staticArchList.unshift(staticArchList.splice(archIndex, 1)[0]);
}
let info = null;
staticArchList.some(arch => {
const staticFiles = staticFilesByArch[arch];
// If staticFiles contains originalPath with the arch inferred above,
// use that information.
if (hasOwn.call(staticFiles, originalPath)) {
return info = staticFiles[originalPath];
}
// If getArchAndPath returned an alternate path, try that instead.
if (path !== originalPath &&
hasOwn.call(staticFiles, path)) {
return info = staticFiles[path];
}
});
return info;
}
function getArchAndPath(path, browser) {
const pathParts = path.split("/");
const archKey = pathParts[1];
if (archKey.startsWith("__")) {
const archCleaned = "web." + archKey.slice(2);
if (hasOwn.call(WebApp.clientPrograms, archCleaned)) {
pathParts.splice(1, 1); // Remove the archKey part.
return {
arch: archCleaned,
path: pathParts.join("/"),
};
}
}
// TODO Perhaps one day we could infer Cordova clients here, so that we
// wouldn't have to use prefixed "/__cordova/..." URLs.
const arch = isModern(browser)
? "web.browser"
: "web.browser.legacy";
if (hasOwn.call(WebApp.clientPrograms, arch)) {
return { arch, path };
}
return {
arch: WebApp.defaultArch,
path,
};
}
// Parse the passed in port value. Return the port as-is if it's a String
// (e.g. a Windows Server style named pipe), otherwise return the port as an
@@ -496,8 +568,16 @@ function runWebAppServer() {
WebAppInternals.reloadClientPrograms = function () {
syncQueue.runTask(function() {
staticFiles = {};
var generateClientProgram = function (clientPath, arch) {
staticFilesByArch = Object.create(null);
function generateClientProgram(clientPath, arch) {
function addStaticFile(path, item) {
if (! hasOwn.call(staticFilesByArch, arch)) {
staticFilesByArch[arch] = Object.create(null);
}
staticFilesByArch[arch][path] = item;
}
// read the control for the client we'll be serving up
var clientJsonPath = pathJoin(__meteor_bootstrap__.serverDir,
clientPath);
@@ -510,27 +590,25 @@ function runWebAppServer() {
if (! clientJsonPath || ! clientDir || ! clientJson)
throw new Error("Client config file not parsed.");
var urlPrefix = getUrlPrefixForArch(arch);
var manifest = clientJson.manifest;
_.each(manifest, function (item) {
if (item.url && item.where === "client") {
staticFiles[urlPrefix + getItemPathname(item.url)] = {
addStaticFile(getItemPathname(item.url), {
absolutePath: pathJoin(clientDir, item.path),
cacheable: item.cacheable,
hash: item.hash,
// Link from source to its map
sourceMapUrl: item.sourceMapUrl,
type: item.type
};
});
if (item.sourceMap) {
// Serve the source map too, under the specified URL. We assume all
// source maps are cacheable.
staticFiles[urlPrefix + getItemPathname(item.sourceMapUrl)] = {
addStaticFile(getItemPathname(item.sourceMapUrl), {
absolutePath: pathJoin(clientDir, item.sourceMap),
cacheable: true
};
});
}
}
});
@@ -556,13 +634,13 @@ function runWebAppServer() {
const manifestUrl = manifestUrlPrefix +
getItemPathname("/manifest.json");
staticFiles[manifestUrl] = {
addStaticFile(manifestUrl, {
content: JSON.stringify(program),
cacheable: false,
hash: program.version,
type: "json"
};
};
});
}
try {
var clientPaths = __meteor_bootstrap__.configJson.clientPaths;
@@ -572,7 +650,7 @@ function runWebAppServer() {
});
// Exported for tests.
WebAppInternals.staticFiles = staticFiles;
WebAppInternals.staticFilesByArch = staticFilesByArch;
} catch (e) {
Log.error("Error reloading the client program: " + e.stack);
process.exit(1);
@@ -603,28 +681,41 @@ function runWebAppServer() {
ROOT_URL: process.env.MOBILE_ROOT_URL ||
Meteor.absoluteUrl()
}
}
},
"web.browser": {
runtimeConfigOverrides: {
isModern: true,
}
},
"web.browser.legacy": {
runtimeConfigOverrides: {
isModern: false,
}
},
};
syncQueue.runTask(function() {
const allCss = [];
_.each(WebApp.clientPrograms, function (program, archName) {
boilerplateByArch[archName] =
WebAppInternals.generateBoilerplateInstance(
archName, program.manifest,
defaultOptionsForArch[archName]);
archName,
program.manifest,
defaultOptionsForArch[archName],
);
const cssFiles = boilerplateByArch[archName].baseData.css;
cssFiles.forEach(file => allCss.push({
url: bundledJsCssUrlRewriteHook(file.url),
}));
});
// Clear the memoized boilerplate cache.
memoizedBoilerplate = {};
// Configure CSS injection for the default arch
// XXX implement the CSS injection for all archs?
var cssFiles = boilerplateByArch[WebApp.defaultArch].baseData.css;
// Rewrite all CSS files (which are written directly to <style> tags)
// by autoupdate_client to use the CDN prefix/etc
var allCss = _.map(cssFiles, function(cssFile) {
return { url: bundledJsCssUrlRewriteHook(cssFile.url) };
});
WebAppInternals.refreshableAssets = { allCss };
});
};
@@ -687,7 +778,7 @@ function runWebAppServer() {
// Serve static files from the manifest.
// This is inspired by the 'static' middleware.
app.use(function (req, res, next) {
WebAppInternals.staticFilesMiddleware(staticFiles, req, res, next);
WebAppInternals.staticFilesMiddleware(staticFilesByArch, req, res, next);
});
// Core Meteor packages like dynamic-import can add handlers before
@@ -765,21 +856,13 @@ function runWebAppServer() {
return;
}
// /packages/asdfsad ... /__cordova/dafsdf.js
var pathname = parseRequest(req).pathname;
var archKey = pathname.split('/')[1];
var archKeyCleaned = 'web.' + archKey.replace(/^__/, '');
if (!/^__/.test(archKey) || !_.has(archPath, archKeyCleaned)) {
archKey = WebApp.defaultArch;
} else {
archKey = archKeyCleaned;
}
return getBoilerplateAsync(
request,
archKey
).then(({ stream, statusCode, headers: newHeaders }) => {
getArchAndPath(
parseRequest(req).pathname,
request.browser,
).arch,
).then(({ stream, statusCode, headers: newHeaders }) => {
if (!statusCode) {
statusCode = res.statusCode ? res.statusCode : 200;
}
@@ -860,7 +943,12 @@ function runWebAppServer() {
onListeningCallbacks.push(f);
else
f();
}
},
// This can be overridden by users who want to modify how listening works
// (eg, to run a proxy like Apollo Engine Proxy in front of the server).
startListening: function (httpServer, listenOptions, cb) {
httpServer.listen(listenOptions, cb);
},
});
// Let the rest of the packages (and Meteor.startup hooks) insert connect
@@ -870,7 +958,7 @@ function runWebAppServer() {
WebAppInternals.generateBoilerplate();
const startHttpServer = listenOptions => {
httpServer.listen(listenOptions, Meteor.bindEnvironment(() => {
WebApp.startListening(httpServer, listenOptions, Meteor.bindEnvironment(() => {
if (process.env.METEOR_PRINT_ON_LISTEN) {
console.log("LISTENING");
}

View File

@@ -2,6 +2,7 @@ const url = require("url");
const crypto = require("crypto");
const http = require("http");
const streamToString = require("stream-to-string");
import { isModern } from "meteor/modern-browsers";
const additionalScript = "(function () { var foo = 1; })";
WebAppInternals.addStaticJs(additionalScript);
@@ -44,16 +45,19 @@ MockResponse.prototype.getBody = function () {
};
Tinytest.add("webapp - content-type header", function (test) {
const staticFiles = WebAppInternals.staticFilesByArch["web.browser"];
const cssResource = _.find(
_.keys(WebAppInternals.staticFiles),
_.keys(staticFiles),
function (url) {
return WebAppInternals.staticFiles[url].type === "css";
return staticFiles[url].type === "css";
}
);
const jsResource = _.find(
_.keys(WebAppInternals.staticFiles),
_.keys(staticFiles),
function (url) {
return WebAppInternals.staticFiles[url].type === "js";
return staticFiles[url].type === "js";
}
);
@@ -65,6 +69,83 @@ Tinytest.add("webapp - content-type header", function (test) {
"application/javascript; charset=utf-8");
});
const modernUserAgent =
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_4) " +
"AppleWebKit/537.36 (KHTML, like Gecko) " +
"Chrome/68.0.3440.15 Safari/537.36";
const legacyUserAgent = "legacy";
Tinytest.addAsync("webapp - modern/legacy static files", test => {
test.equal(isModern(WebAppInternals.identifyBrowser(modernUserAgent)), true);
test.equal(isModern(WebAppInternals.identifyBrowser(legacyUserAgent)), false);
const promises = [];
Object.keys(WebAppInternals.staticFilesByArch).forEach(arch => {
const staticFiles = WebAppInternals.staticFilesByArch[arch];
Object.keys(staticFiles).forEach(path => {
const { type } = staticFiles[path];
if (type !== "asset") {
return;
}
const pathMatch = /\/(modern|legacy)_test_asset\.js$/.exec(path);
if (! pathMatch) {
return;
}
const absUrl = url.resolve(Meteor.absoluteUrl(), path);
[ // Try to request the modern/legacy assets with both modern and
// legacy User Agent strings. (#9953)
modernUserAgent,
legacyUserAgent,
].forEach(ua => promises.push(new Promise((resolve, reject) => {
HTTP.get(absUrl, {
headers: {
"User-Agent": ua
}
}, (error, response) => {
if (error) {
reject(error);
return;
}
if (response.statusCode !== 200) {
reject(new Error(`Bad status code ${
response.statusCode
} for ${path}`));
return;
}
const contentType = response.headers["content-type"];
if (! contentType.startsWith("application/javascript")) {
reject(new Error(`Bad Content-Type ${contentType} for ${path}`));
return;
}
const expectedText = pathMatch[1].toUpperCase();
const index = response.content.indexOf(expectedText);
if (index < 0) {
reject(new Error(`Missing ${
JSON.stringify(expectedText)
} text in ${path}`));
return;
}
resolve(path);
});
})));
});
});
test.isTrue(promises.length > 0);
return Promise.all(promises);
});
Tinytest.addAsync(
"webapp - additional static javascript",
async function (test) {
@@ -98,10 +179,12 @@ Tinytest.addAsync(
req.method = "GET";
req.url = "/" + additionalScriptPathname;
let nextCalled = false;
WebAppInternals.staticFilesMiddleware(
staticFilesOpts, req, res, function () {
nextCalled = true;
});
WebAppInternals.staticFilesMiddleware({
"web.browser": {},
"web.browser.legacy": {},
}, req, res, function () {
nextCalled = true;
});
test.isTrue(nextCalled);
// When inline scripts are disallowed, the script body should not be
@@ -130,8 +213,10 @@ Tinytest.addAsync(
req.headers = {};
req.method = "GET";
req.url = "/" + additionalScriptPathname;
WebAppInternals.staticFilesMiddleware(staticFilesOpts, req, res,
function () { });
WebAppInternals.staticFilesMiddleware({
"web.browser": {},
"web.browser.legacy": {},
}, req, res, function () {});
const resBody = res.getBody();
test.isTrue(resBody.indexOf(additionalScript) !== -1);
test.equal(res.statusCode, 200);

View File

@@ -1,6 +1,6 @@
{
"track": "METEOR",
"version": "1.6.1.1-rc.0",
"version": "1.7.0.3-rc.0",
"recommended": false,
"official": false,
"description": "Meteor"

View File

@@ -1,12 +1,12 @@
{
"track": "METEOR",
"version": "1.6.1.1",
"version": "1.7.0.3",
"recommended": false,
"official": true,
"patchFrom": [
"1.6",
"1.6.0.1",
"1.6.1"
"1.7",
"1.7.0.1",
"1.7.0.2"
],
"description": "The Official Meteor Distribution"
}

View File

@@ -7,7 +7,7 @@
require 'tmpdir'
mongo_install_urls = {
"3.6.3" => "https://fastdl.mongodb.org/osx/mongodb-osx-ssl-x86_64-3.6.3.tgz",
"3.6.4" => "https://fastdl.mongodb.org/osx/mongodb-osx-ssl-x86_64-3.6.4.tgz",
"3.2.19" => "https://fastdl.mongodb.org/osx/mongodb-osx-x86_64-3.2.19.tgz",
"3.0.5" => "https://fastdl.mongodb.org/osx/mongodb-osx-x86_64-3.0.5.tgz",
"2.6.10" => "http://downloads.mongodb.org/osx/mongodb-osx-x86_64-2.6.10.tgz"
@@ -29,7 +29,7 @@ puts "Putting output in: #{path_to_output}/"
test_env = "TEST_PACKAGES_EXCLUDE=\"less\""
["3.6.3", "3.2.19", "3.0.5", "2.6.10"].each do |mongo_version|
["3.6.4", "3.2.19", "3.0.5", "2.6.10"].each do |mongo_version|
puts "Installing and testing with Mongo #{mongo_version}..."
Dir.mktmpdir "mongo_install" do |mongo_install_dir|

View File

@@ -5,13 +5,13 @@ set -u
UNAME=$(uname)
ARCH=$(uname -m)
NODE_VERSION=8.11.1
MONGO_VERSION_64BIT=3.6.3
NODE_VERSION=8.11.3
MONGO_VERSION_64BIT=3.6.4
MONGO_VERSION_32BIT=3.2.19
NPM_VERSION=5.8.0
NPM_VERSION=5.10.0
# If we built Node from source on Jenkins, this is the build number.
NODE_BUILD_NUMBER=129
NODE_BUILD_NUMBER=
if [ "$UNAME" == "Linux" ] ; then
if [ "$ARCH" != "i686" -a "$ARCH" != "x86_64" ] ; then

View File

@@ -10,17 +10,17 @@ var packageJson = {
dependencies: {
// Explicit dependency because we are replacing it with a bundled version
// and we want to make sure there are no dependencies on a higher version
npm: "5.8.0",
npm: "5.10.0",
pacote: "https://github.com/meteor/pacote/tarball/2c16c509074bbba8ca5dd410caf808412ce79e6c",
"node-gyp": "3.6.2",
"node-pre-gyp": "0.6.36",
"meteor-babel": "7.0.0-beta.46",
"meteor-babel": "7.0.0-beta.51",
"meteor-promise": "0.8.6",
promise: "8.0.1",
reify: "0.15.1",
reify: "0.16.2",
fibers: "2.0.0",
// So that Babel can emit require("@babel/runtime/helpers/...") calls.
"@babel/runtime": "7.0.0-beta.46",
"@babel/runtime": "7.0.0-beta.51",
// For backwards compatibility with isopackets that still depend on
// babel-runtime rather than @babel/runtime.
"babel-runtime": "7.0.0-beta.3",
@@ -52,9 +52,8 @@ var packageJson = {
split2: "2.2.0",
multipipe: "2.0.1",
pathwatcher: "7.1.1",
optimism: "0.4.0",
'lru-cache': '4.1.1',
longjohn: '0.2.12'
optimism: "0.6.3",
'lru-cache': '4.1.3'
}
};

View File

@@ -20,9 +20,11 @@ $BUNDLE_VERSION = Read-VariableFromShellScript "${dirCheckout}\meteor" 'BUNDLE_V
# extract the major package versions from the build-dev-bundle-common script.
$MONGO_VERSION_64BIT = Read-VariableFromShellScript $shCommon 'MONGO_VERSION_64BIT'
$MONGO_VERSION_32BIT = Read-VariableFromShellScript $shCommon 'MONGO_VERSION_32BIT'
$NODE_VERSION = Read-VariableFromShellScript $shCommon 'NODE_VERSION'
$NPM_VERSION = Read-VariableFromShellScript $shCommon 'NPM_VERSION'
$NODE_VERSION = Read-VariableFromShellScript $shCommon 'NODE_VERSION'
# 7-zip path.
$system7zip = "C:\Program Files\7-zip\7z.exe"
@@ -107,7 +109,11 @@ Function Add-Python {
}
Function Add-NodeAndNpm {
$nodeUrlBase = 'https://nodejs.org/dist'
if ("${NODE_VERSION}" -match "-rc\.\d+$") {
$nodeUrlBase = 'https://nodejs.org/download/rc'
} else {
$nodeUrlBase = 'https://nodejs.org/dist'
}
if ($PLATFORM -eq "windows_x86") {
$nodeArchitecture = 'win-x86'
@@ -245,11 +251,23 @@ Function Add-Mongo {
$shell.Namespace("$DIR\mongodb").copyhere($item, 0x14) # 0x10 - overwrite, 0x4 - no dialog
}
Write-Host "Putting MongoDB mongod.exe in \mongodb\bin\" -ForegroundColor Magenta
Write-Host "Putting MongoDB mongod.exe in mongodb\bin" -ForegroundColor Magenta
cp "$DIR\mongodb\$mongo_name\bin\mongod.exe" $DIR\mongodb\bin
Write-Host "Putting MongoDB mongo.exe in \mongodb\bin\" -ForegroundColor Magenta
Write-Host "Putting MongoDB mongo.exe in mongodb\bin" -ForegroundColor Magenta
cp "$DIR\mongodb\$mongo_name\bin\mongo.exe" $DIR\mongodb\bin
# https://jira.mongodb.org/browse/SERVER-19086
$libeay32dll = "$DIR\mongodb\$mongo_name\bin\libeay32.dll"
if (Test-Path $libeay32dll) {
Write-Host "Putting MongoDB libeay32.dll in mongodb\bin" -ForegroundColor Magenta
cp $libeay32dll $DIR\mongodb\bin
}
$ssleay32dll = "$DIR\mongodb\$mongo_name\bin\ssleay32.dll"
if (Test-Path $ssleay32dll) {
Write-Host "Putting MongoDB ssleay32.dll in mongodb\bin" -ForegroundColor Magenta
cp $ssleay32dll $DIR\mongodb\bin
}
Write-Host "Removing the old Mongo zip..." -ForegroundColor Magenta
rm -Recurse -Force $mongo_zip
Write-Host "Removing the old Mongo directory..." -ForegroundColor Magenta

View File

@@ -42,8 +42,15 @@ downloadOfficialNode() {
curl "${NODE_URL}" | tar zx --strip-components 1
}
downloadReleaseCandidateNode() {
NODE_URL="https://nodejs.org/download/rc/v${NODE_VERSION}/${NODE_TGZ}"
echo "Downloading Node from ${NODE_URL}" >&2
curl "${NODE_URL}" | tar zx --strip-components 1
}
# Try each strategy in the following order:
extractNodeFromTarGz || downloadNodeFromS3 || downloadOfficialNode
extractNodeFromTarGz || downloadNodeFromS3 || \
downloadOfficialNode || downloadReleaseCandidateNode
# Download Mongo from mongodb.com. Will download a 64-bit version of Mongo
# by default. Will download a 32-bit version of Mongo if using a 32-bit based

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