@maka/meteor-sdk 0.2.8 → 0.2.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (24) hide show
  1. package/README.md +11 -5
  2. package/isopackets/combined/npm/node_modules/meteor/babel-compiler/node_modules/.package-lock.json +1 -1
  3. package/isopackets/combined/npm/node_modules/meteor/boilerplate-generator/node_modules/.package-lock.json +1 -1
  4. package/isopackets/combined/npm/node_modules/meteor/constraint-solver/node_modules/.package-lock.json +1 -1
  5. package/isopackets/combined/npm/node_modules/meteor/ddp-client/node_modules/.package-lock.json +1 -1
  6. package/isopackets/combined/npm/node_modules/meteor/ecmascript/node_modules/.package-lock.json +1 -1
  7. package/isopackets/combined/npm/node_modules/meteor/ecmascript-runtime/node_modules/.package-lock.json +1 -1
  8. package/isopackets/combined/npm/node_modules/meteor/ecmascript-runtime-client/node_modules/.package-lock.json +1 -1
  9. package/isopackets/combined/npm/node_modules/meteor/ecmascript-runtime-server/node_modules/.package-lock.json +1 -1
  10. package/isopackets/combined/npm/node_modules/meteor/fetch/node_modules/.package-lock.json +1 -1
  11. package/isopackets/combined/npm/node_modules/meteor/inter-process-messaging/node_modules/.package-lock.json +1 -1
  12. package/isopackets/combined/npm/node_modules/meteor/logging/node_modules/.package-lock.json +1 -1
  13. package/isopackets/combined/npm/node_modules/meteor/logic-solver/node_modules/.package-lock.json +1 -1
  14. package/isopackets/combined/npm/node_modules/meteor/meteor/node_modules/.package-lock.json +1 -1
  15. package/isopackets/combined/npm/node_modules/meteor/modules/node_modules/.package-lock.json +1 -1
  16. package/isopackets/combined/npm/node_modules/meteor/modules-runtime/node_modules/.package-lock.json +1 -1
  17. package/isopackets/combined/npm/node_modules/meteor/npm-mongo/node_modules/.package-lock.json +1 -1
  18. package/isopackets/combined/npm/node_modules/meteor/package-version-parser/node_modules/.package-lock.json +1 -1
  19. package/isopackets/combined/npm/node_modules/meteor/promise/node_modules/.package-lock.json +1 -1
  20. package/isopackets/combined/npm/node_modules/meteor/react-fast-refresh/node_modules/.package-lock.json +1 -1
  21. package/isopackets/combined/npm/node_modules/meteor/socket-stream-client/node_modules/.package-lock.json +1 -1
  22. package/package.json +1 -1
  23. package/src/project.js +40 -0
  24. package/tools/isobuild/meteor-npm.js +129 -32
package/README.md CHANGED
@@ -243,11 +243,17 @@ per-user cache of completed `node_modules` trees at `~/.meteor-npm-cache`,
243
243
  keyed by shrinkwrap content + Node compatibility version + platform/arch.
244
244
  On the first build after an SDK update, packages whose dependencies
245
245
  didn't change restore from the cache by parallel directory copy instead
246
- of spawning npm -- silently and near-instantly. Cache writes happen in
247
- the background off the build's critical path, entries are pruned to the
248
- 3 newest per package, and everything is best-effort: any cache problem
249
- falls back to a normal npm install, and a stale restore is caught by the
250
- existing shrinkwrap-vs-installed verification.
246
+ of spawning npm -- silently and near-instantly. Cache *misses* are
247
+ handled in parallel too: once `loadProject()` knows the app's package
248
+ set (from `.meteor/versions`), the remaining installs run through a
249
+ small npm worker pool ahead of the build's serial per-package walk
250
+ (bounded to 3 processes -- concurrent npm invocations contend on npm's
251
+ shared content cache), which also keeps those installs' `.npm` churn
252
+ from re-firing the app runner's file watcher mid-build. Cache writes
253
+ happen in the background off the build's critical path, entries are
254
+ pruned to the 3 newest per package, and everything is best-effort: any
255
+ cache problem falls back to a normal npm install, and a stale restore is
256
+ caught by the existing shrinkwrap-vs-installed verification.
251
257
 
252
258
  Control it with `METEOR_PACKAGE_NPM_CACHE`: unset means enabled at the
253
259
  default location, `0`/`false`/`no`/`off` disables it, and any other
@@ -1,5 +1,5 @@
1
1
  {
2
- "name": "package-new-1m6rn6thduz",
2
+ "name": "package-new-14mcukbut2o",
3
3
  "lockfileVersion": 3,
4
4
  "requires": true,
5
5
  "packages": {
@@ -1,5 +1,5 @@
1
1
  {
2
- "name": "package-new-e9rbm1cl3n4",
2
+ "name": "package-new-1nxrqkqgiun",
3
3
  "lockfileVersion": 3,
4
4
  "requires": true,
5
5
  "packages": {
@@ -1,5 +1,5 @@
1
1
  {
2
- "name": "package-new-1ul11s6qh6",
2
+ "name": "package-new-lhgmlf5mlyk",
3
3
  "lockfileVersion": 3,
4
4
  "requires": true,
5
5
  "packages": {
@@ -1,5 +1,5 @@
1
1
  {
2
- "name": "package-new-ee0ne0pml8l",
2
+ "name": "package-new-9dm5oc7j4sc",
3
3
  "lockfileVersion": 3,
4
4
  "requires": true,
5
5
  "packages": {
@@ -1,5 +1,5 @@
1
1
  {
2
- "name": "package-new-1g24wbdxvx8",
2
+ "name": "package-new-1wcn7u5f6o9",
3
3
  "lockfileVersion": 3,
4
4
  "requires": true,
5
5
  "packages": {
@@ -1,5 +1,5 @@
1
1
  {
2
- "name": "package-new-6fxj13oxx1b",
2
+ "name": "package-new-1kdw71by1kb",
3
3
  "lockfileVersion": 3,
4
4
  "requires": true,
5
5
  "packages": {
@@ -1,5 +1,5 @@
1
1
  {
2
- "name": "package-new-16q2eii8237",
2
+ "name": "package-new-11ay5a2qmvv",
3
3
  "lockfileVersion": 3,
4
4
  "requires": true,
5
5
  "packages": {
@@ -1,5 +1,5 @@
1
1
  {
2
- "name": "package-new-g8qjgrro1ac",
2
+ "name": "package-new-jkr5smb2te",
3
3
  "lockfileVersion": 3,
4
4
  "requires": true,
5
5
  "packages": {
@@ -1,5 +1,5 @@
1
1
  {
2
- "name": "package-new-286qo524b55",
2
+ "name": "package-new-x0lqsl14am",
3
3
  "lockfileVersion": 3,
4
4
  "requires": true,
5
5
  "packages": {
@@ -1,5 +1,5 @@
1
1
  {
2
- "name": "package-new-1pcp8sbti9w",
2
+ "name": "package-new-xth6zuvyoge",
3
3
  "lockfileVersion": 3,
4
4
  "requires": true,
5
5
  "packages": {
@@ -1,5 +1,5 @@
1
1
  {
2
- "name": "package-new-1c4mjv2utk7h",
2
+ "name": "package-new-3l78651i8vb",
3
3
  "lockfileVersion": 3,
4
4
  "requires": true,
5
5
  "packages": {
@@ -1,5 +1,5 @@
1
1
  {
2
- "name": "package-new-9t84b3my7i",
2
+ "name": "package-new-obu6cxhlj2",
3
3
  "lockfileVersion": 3,
4
4
  "requires": true,
5
5
  "packages": {
@@ -1,5 +1,5 @@
1
1
  {
2
- "name": "package-new-1bjt87sifq2",
2
+ "name": "package-new-27q6iwo9mjek",
3
3
  "lockfileVersion": 3,
4
4
  "requires": true,
5
5
  "packages": {
@@ -1,5 +1,5 @@
1
1
  {
2
- "name": "package-new-6gguidiwzx",
2
+ "name": "package-new-16qpf002t31",
3
3
  "lockfileVersion": 3,
4
4
  "requires": true,
5
5
  "packages": {
@@ -1,5 +1,5 @@
1
1
  {
2
- "name": "package-new-ovtntj9ibd",
2
+ "name": "package-new-1avxcuqbu7h",
3
3
  "lockfileVersion": 3,
4
4
  "requires": true,
5
5
  "packages": {
@@ -1,5 +1,5 @@
1
1
  {
2
- "name": "package-new-t8jk4dq32z",
2
+ "name": "package-new-1om3fpd6efo",
3
3
  "lockfileVersion": 3,
4
4
  "requires": true,
5
5
  "packages": {
@@ -1,5 +1,5 @@
1
1
  {
2
- "name": "package-new-1t8h3r5p5mc",
2
+ "name": "package-new-dclewbgria6",
3
3
  "lockfileVersion": 3,
4
4
  "requires": true,
5
5
  "packages": {
@@ -1,5 +1,5 @@
1
1
  {
2
- "name": "package-new-19ro17vxabi",
2
+ "name": "package-new-mt7pq41l8d9",
3
3
  "lockfileVersion": 3,
4
4
  "requires": true,
5
5
  "packages": {
@@ -1,5 +1,5 @@
1
1
  {
2
- "name": "package-new-1mbjo8u1bdw",
2
+ "name": "package-new-i4l2akdfgip",
3
3
  "lockfileVersion": 3,
4
4
  "requires": true,
5
5
  "packages": {
@@ -1,5 +1,5 @@
1
1
  {
2
- "name": "package-new-1bskl16cqu8",
2
+ "name": "package-new-4dhnqh88rfe",
3
3
  "lockfileVersion": 3,
4
4
  "requires": true,
5
5
  "packages": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@maka/meteor-sdk",
3
- "version": "0.2.8",
3
+ "version": "0.2.9",
4
4
  "description": "Programmatic Node API over the Meteor build tool (bundle/run/create/etc.) -- for driving Meteor's build system from plain Node code instead of shelling out to a meteor CLI (there isn't one anymore; see README.md). \"dependencies\" is generated by scripts/write-tool-package-json.js from scripts/dev-bundle-tool-package.js at the monorepo root -- do not hand-edit that field, edit that file and re-run the script instead.",
5
5
  "main": "src/index.js",
6
6
  "exports": {
package/src/project.js CHANGED
@@ -65,6 +65,19 @@ async function loadProject(projectDir) {
65
65
  projectDir: standardProjectDir,
66
66
  });
67
67
 
68
+ // Second-stage npm-deps prewarm (bootstrap.js fired the restore-only
69
+ // first stage): now that an app is known, its .meteor/versions names
70
+ // the exact core-package set the build will need, so cache MISSES can
71
+ // be npm-installed too -- in parallel (small pool; concurrent npm
72
+ // processes contend on npm's shared content cache) and BEFORE the
73
+ // build's serial per-package walk, which also keeps those installs'
74
+ // .npm churn from re-firing the app runner's file watcher mid-build.
75
+ // Un-awaited: every prewarm operation holds the same cross-process
76
+ // per-package lock updateDependencies() takes, so the build below
77
+ // simply waits on (or wins) each package's lock. Best-effort by
78
+ // design -- on any failure the build installs serially as before.
79
+ startAppNpmDepsPrewarm(standardProjectDir);
80
+
68
81
  await runCaptured("preparing project", () =>
69
82
  projectContext.prepareProjectForBuild()
70
83
  );
@@ -72,4 +85,31 @@ async function loadProject(projectDir) {
72
85
  return new Project(projectContext);
73
86
  }
74
87
 
88
+ function startAppNpmDepsPrewarm(standardProjectDir) {
89
+ try {
90
+ const files = require("../tools/fs/files");
91
+ const versionsFile = files.pathJoin(
92
+ standardProjectDir, ".meteor", "versions");
93
+ // name@version lines; author:package names never match the bundled
94
+ // core-package directory names, so no special-casing needed. A
95
+ // missing versions file (brand-new app) just skips this stage.
96
+ const names = files.readFile(versionsFile, "utf8")
97
+ .split("\n")
98
+ .map((line) => line.trim().split("@")[0])
99
+ .filter(Boolean);
100
+ if (!names.length) {
101
+ return;
102
+ }
103
+ const meteorNpm = require("../tools/isobuild/meteor-npm.js");
104
+ Promise.resolve(
105
+ meteorNpm.prewarmNpmDepsCache(
106
+ path.resolve(__dirname, "..", "packages"),
107
+ { onlyPackages: names, installOnMiss: true }
108
+ )
109
+ ).catch(() => {});
110
+ } catch (e) {
111
+ // Best-effort: the build's own per-package install path still works.
112
+ }
113
+ }
114
+
75
115
  module.exports = { loadProject, Project };
@@ -893,6 +893,71 @@ function pruneNpmDepsCache(packageCacheDir, keepDir) {
893
893
  } catch (e) {}
894
894
  }
895
895
 
896
+ // Install a package's npm deps purely from its shipped
897
+ // npm-shrinkwrap.json -- no evaluated Npm.depends needed, which is what
898
+ // makes prewarm-time (pre-package.js) installs possible. Mirrors
899
+ // updateExistingNpmDirectory's preserved-shrinkwrap branch exactly:
900
+ // mapped shrinkwrap + minimal package.json into a temp dir, `npm
901
+ // install`, then completeNpmDirectory (which also seeds the cache).
902
+ // The top-level dependency map is derived from the shrinkwrap itself
903
+ // (exact versions; resolved URLs for non-registry deps) -- a superset
904
+ // of the real Npm.depends, which npm accepts since every entry is
905
+ // pinned to what the lock installs. If the shipped shrinkwrap turns
906
+ // out stale relative to the package's actual Npm.depends, the build's
907
+ // own subtree verification catches it and reinstalls normally.
908
+ // Callers must hold the npm package lock for packageNpmDir.
909
+ async function preinstallNpmDepsFromShrinkwrap(packageName, packageNpmDir) {
910
+ const shrinkwrappedDependenciesTree =
911
+ getShrinkwrappedDependenciesTree(packageNpmDir);
912
+ const npmDependencies = treeToDependencies(
913
+ minimizeDependencyTree(shrinkwrappedDependenciesTree));
914
+ if (_.isEmpty(npmDependencies)) {
915
+ return false;
916
+ }
917
+ const cacheKey = npmDepsCacheKey(packageNpmDir);
918
+
919
+ const newPackageNpmDir =
920
+ convertColonsInPath(packageNpmDir) + '-prewarm-' + utils.randomToken();
921
+ tmpDirs.push(newPackageNpmDir);
922
+ try {
923
+ makeNewPackageNpmDir(newPackageNpmDir);
924
+
925
+ const mappedDependencies = Object.entries(
926
+ shrinkwrappedDependenciesTree.dependencies
927
+ ).reduce((acc, [name, info]) => {
928
+ return { ...acc, [`node_modules/${name}`]: info };
929
+ }, {});
930
+
931
+ files.writeFile(
932
+ files.pathJoin(newPackageNpmDir, 'npm-shrinkwrap.json'),
933
+ JSON.stringify({
934
+ ...shrinkwrappedDependenciesTree,
935
+ dependencies: mappedDependencies,
936
+ }, null, 2)
937
+ );
938
+ files.writeFile(
939
+ files.pathJoin(newPackageNpmDir, 'package.json'),
940
+ JSON.stringify({ dependencies: npmDependencies }, null, 2)
941
+ );
942
+
943
+ logUpdateDependencies(packageName, npmDependencies);
944
+ await installFromShrinkwrap(newPackageNpmDir);
945
+
946
+ files.unlink(files.pathJoin(newPackageNpmDir, 'npm-shrinkwrap.json'));
947
+ files.unlink(files.pathJoin(newPackageNpmDir, 'package.json'));
948
+
949
+ await completeNpmDirectory(
950
+ packageName, newPackageNpmDir, packageNpmDir, npmDependencies,
951
+ cacheKey);
952
+ return true;
953
+ } finally {
954
+ if (files.exists(newPackageNpmDir)) {
955
+ await files.rm_recursive_deferred(newPackageNpmDir);
956
+ }
957
+ tmpDirs = _.without(tmpDirs, newPackageNpmDir);
958
+ }
959
+ }
960
+
896
961
  // Restore every restorable package under packagesDir from the cache, in
897
962
  // parallel, before the (serial) per-package build pipeline reaches
898
963
  // them. Purely filesystem-driven: a candidate is any package dir with a
@@ -900,17 +965,34 @@ function pruneNpmDepsCache(packageCacheDir, keepDir) {
900
965
  // package.js evaluation is needed. Safe to run concurrently with a
901
966
  // build -- each restore holds the same cross-process lock
902
967
  // updateDependencies() takes, and re-checks its precondition under it.
903
- // Returns the number of packages restored.
968
+ //
969
+ // Options:
970
+ // - onlyPackages: array of package names to consider (REQUIRED for
971
+ // installOnMiss -- without a scope, cold-cache installs would cover
972
+ // every bundled package instead of just the app's).
973
+ // - installOnMiss: after the restore phase, npm-install the remaining
974
+ // misses from their shipped shrinkwraps, in parallel.
975
+ // - concurrency (restore pool, default 8), installConcurrency (npm
976
+ // pool, default 3 -- kept small because concurrent npm processes
977
+ // contend on npm's shared content cache).
978
+ //
979
+ // Returns {restored, installed}.
904
980
  meteorNpm.prewarmNpmDepsCache = async function (packagesDir, options) {
905
981
  options = options || {};
982
+ const none = { restored: 0, installed: 0 };
906
983
  if (npmDepsCacheDisabled()) {
907
- return 0;
984
+ return none;
908
985
  }
909
986
  packagesDir = files.convertToStandardPath(packagesDir);
910
987
 
988
+ const only = options.onlyPackages &&
989
+ new Set(options.onlyPackages);
911
990
  const candidates = [];
912
991
  try {
913
992
  files.readdir(packagesDir).forEach(name => {
993
+ if (only && ! only.has(name)) {
994
+ return;
995
+ }
914
996
  const packageNpmDir =
915
997
  files.pathJoin(packagesDir, name, ".npm", "package");
916
998
  if (! files.exists(
@@ -924,45 +1006,60 @@ meteorNpm.prewarmNpmDepsCache = async function (packagesDir, options) {
924
1006
  candidates.push({ name, packageNpmDir });
925
1007
  });
926
1008
  } catch (e) {
927
- return 0;
1009
+ return none;
928
1010
  }
929
1011
  if (! candidates.length) {
930
- return 0;
1012
+ return none;
931
1013
  }
932
1014
 
933
- let restored = 0;
934
- let nextIndex = 0;
935
- async function worker() {
936
- while (nextIndex < candidates.length) {
937
- const candidate = candidates[nextIndex++];
938
- try {
939
- const ok = await withNpmPackageLock(
940
- candidate.packageNpmDir,
941
- async () => {
942
- // Re-check under the lock: a concurrent build may have
943
- // installed (or restored) this package already.
944
- if (files.exists(files.pathJoin(
945
- candidate.packageNpmDir,
946
- "node_modules", ".package-lock.json"))) {
947
- return false;
948
- }
949
- return restoreNodeModulesFromNpmDepsCache(
950
- candidate.name, candidate.packageNpmDir);
1015
+ function installedAlready(candidate) {
1016
+ return files.exists(files.pathJoin(
1017
+ candidate.packageNpmDir, "node_modules", ".package-lock.json"));
1018
+ }
1019
+
1020
+ async function runPool(queue, size, fn) {
1021
+ let nextIndex = 0;
1022
+ let completed = 0;
1023
+ async function worker() {
1024
+ while (nextIndex < queue.length) {
1025
+ const candidate = queue[nextIndex++];
1026
+ try {
1027
+ // Re-check under the lock: a concurrent build (or the other
1028
+ // prewarm phase) may have handled this package already.
1029
+ const ok = await withNpmPackageLock(
1030
+ candidate.packageNpmDir,
1031
+ async () => ! installedAlready(candidate) && fn(candidate)
1032
+ );
1033
+ if (ok) {
1034
+ completed++;
1035
+ }
1036
+ } catch (e) {
1037
+ // Best-effort; the build's own updateDependencies() will
1038
+ // handle this package the normal way.
1039
+ if (options.debugThrow) {
1040
+ console.error("prewarm error for " + candidate.name + ":",
1041
+ (e && e.stack) || e);
951
1042
  }
952
- );
953
- if (ok) {
954
- restored++;
955
1043
  }
956
- } catch (e) {
957
- // Best-effort; the build's own updateDependencies() will handle
958
- // this package the normal way.
959
1044
  }
960
1045
  }
1046
+ await Promise.all(
1047
+ _.times(Math.min(size, queue.length || 1), worker));
1048
+ return completed;
1049
+ }
1050
+
1051
+ const restored = await runPool(
1052
+ candidates, options.concurrency || 8,
1053
+ c => restoreNodeModulesFromNpmDepsCache(c.name, c.packageNpmDir));
1054
+
1055
+ let installed = 0;
1056
+ if (options.installOnMiss && only) {
1057
+ const misses = candidates.filter(c => ! installedAlready(c));
1058
+ installed = await runPool(
1059
+ misses, options.installConcurrency || 3,
1060
+ c => preinstallNpmDepsFromShrinkwrap(c.name, c.packageNpmDir));
961
1061
  }
962
- const concurrency = Math.min(
963
- options.concurrency || 8, candidates.length);
964
- await Promise.all(_.times(concurrency, worker));
965
- return restored;
1062
+ return { restored, installed };
966
1063
  };
967
1064
 
968
1065
  var updateExistingNpmDirectory = async function (packageName, newPackageNpmDir,