@maka/meteor-sdk 0.2.8 → 0.2.10

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 (33) hide show
  1. package/README.md +11 -5
  2. package/isopackets/combined/isopacket-buildinfo.json +1 -1
  3. package/isopackets/combined/npm/node_modules/meteor/babel-compiler/node_modules/.npm-shrinkwrap.json +3 -3
  4. package/isopackets/combined/npm/node_modules/meteor/babel-compiler/node_modules/.package-lock.json +4 -4
  5. package/isopackets/combined/npm/node_modules/meteor/babel-compiler/node_modules/baseline-browser-mapping/dist/index.cjs +1 -1
  6. package/isopackets/combined/npm/node_modules/meteor/babel-compiler/node_modules/baseline-browser-mapping/dist/index.js +1 -1
  7. package/isopackets/combined/npm/node_modules/meteor/babel-compiler/node_modules/baseline-browser-mapping/package.json +1 -1
  8. package/isopackets/combined/npm/node_modules/meteor/boilerplate-generator/node_modules/.package-lock.json +1 -1
  9. package/isopackets/combined/npm/node_modules/meteor/constraint-solver/node_modules/.package-lock.json +1 -1
  10. package/isopackets/combined/npm/node_modules/meteor/ddp-client/node_modules/.package-lock.json +1 -1
  11. package/isopackets/combined/npm/node_modules/meteor/ecmascript/node_modules/.package-lock.json +1 -1
  12. package/isopackets/combined/npm/node_modules/meteor/ecmascript-runtime/node_modules/.package-lock.json +1 -1
  13. package/isopackets/combined/npm/node_modules/meteor/ecmascript-runtime-client/node_modules/.package-lock.json +1 -1
  14. package/isopackets/combined/npm/node_modules/meteor/ecmascript-runtime-server/node_modules/.package-lock.json +1 -1
  15. package/isopackets/combined/npm/node_modules/meteor/fetch/node_modules/.package-lock.json +1 -1
  16. package/isopackets/combined/npm/node_modules/meteor/inter-process-messaging/node_modules/.package-lock.json +1 -1
  17. package/isopackets/combined/npm/node_modules/meteor/logging/node_modules/.package-lock.json +1 -1
  18. package/isopackets/combined/npm/node_modules/meteor/logic-solver/node_modules/.package-lock.json +1 -1
  19. package/isopackets/combined/npm/node_modules/meteor/meteor/node_modules/.package-lock.json +1 -1
  20. package/isopackets/combined/npm/node_modules/meteor/modules/node_modules/.package-lock.json +1 -1
  21. package/isopackets/combined/npm/node_modules/meteor/modules-runtime/node_modules/.package-lock.json +1 -1
  22. package/isopackets/combined/npm/node_modules/meteor/npm-mongo/node_modules/.package-lock.json +1 -1
  23. package/isopackets/combined/npm/node_modules/meteor/package-version-parser/node_modules/.package-lock.json +1 -1
  24. package/isopackets/combined/npm/node_modules/meteor/promise/node_modules/.package-lock.json +1 -1
  25. package/isopackets/combined/npm/node_modules/meteor/react-fast-refresh/node_modules/.package-lock.json +1 -1
  26. package/isopackets/combined/npm/node_modules/meteor/socket-stream-client/node_modules/.package-lock.json +1 -1
  27. package/package.json +1 -1
  28. package/src/project.js +40 -0
  29. package/tools/fs/optimistic.ts +106 -1
  30. package/tools/fs/safe-watcher.ts +40 -0
  31. package/tools/fs/watch.ts +39 -0
  32. package/tools/isobuild/meteor-npm.js +171 -39
  33. package/isopackets/combined/npm/node_modules/meteor/fetch/node_modules/node-fetch/.meteor-portable-2.json +0 -1
@@ -23,6 +23,7 @@ import {
23
23
  import { wrap as wrapOptimistic } from "optimism";
24
24
  import {
25
25
  dirtyNodeModulesDirectory,
26
+ dirtyReplacedDirectory,
26
27
  optimisticLStat,
27
28
  optimisticStatOrNull,
28
29
  optimisticReadJsonOrNull,
@@ -791,6 +792,7 @@ async function restoreNodeModulesFromNpmDepsCache(packageName, packageNpmDir) {
791
792
  await files.cp_r(cachedNodeModules, tmpDir, { preserveSymlinks: true });
792
793
  await files.renameDirAlmostAtomically(tmpDir, nodeModulesDir);
793
794
  dirtyNodeModulesDirectory(nodeModulesDir);
795
+ dirtyReplacedDirectory(nodeModulesDir);
794
796
  return true;
795
797
  } catch (e) {
796
798
  try {
@@ -893,6 +895,71 @@ function pruneNpmDepsCache(packageCacheDir, keepDir) {
893
895
  } catch (e) {}
894
896
  }
895
897
 
898
+ // Install a package's npm deps purely from its shipped
899
+ // npm-shrinkwrap.json -- no evaluated Npm.depends needed, which is what
900
+ // makes prewarm-time (pre-package.js) installs possible. Mirrors
901
+ // updateExistingNpmDirectory's preserved-shrinkwrap branch exactly:
902
+ // mapped shrinkwrap + minimal package.json into a temp dir, `npm
903
+ // install`, then completeNpmDirectory (which also seeds the cache).
904
+ // The top-level dependency map is derived from the shrinkwrap itself
905
+ // (exact versions; resolved URLs for non-registry deps) -- a superset
906
+ // of the real Npm.depends, which npm accepts since every entry is
907
+ // pinned to what the lock installs. If the shipped shrinkwrap turns
908
+ // out stale relative to the package's actual Npm.depends, the build's
909
+ // own subtree verification catches it and reinstalls normally.
910
+ // Callers must hold the npm package lock for packageNpmDir.
911
+ async function preinstallNpmDepsFromShrinkwrap(packageName, packageNpmDir) {
912
+ const shrinkwrappedDependenciesTree =
913
+ getShrinkwrappedDependenciesTree(packageNpmDir);
914
+ const npmDependencies = treeToDependencies(
915
+ minimizeDependencyTree(shrinkwrappedDependenciesTree));
916
+ if (_.isEmpty(npmDependencies)) {
917
+ return false;
918
+ }
919
+ const cacheKey = npmDepsCacheKey(packageNpmDir);
920
+
921
+ const newPackageNpmDir =
922
+ convertColonsInPath(packageNpmDir) + '-prewarm-' + utils.randomToken();
923
+ tmpDirs.push(newPackageNpmDir);
924
+ try {
925
+ makeNewPackageNpmDir(newPackageNpmDir);
926
+
927
+ const mappedDependencies = Object.entries(
928
+ shrinkwrappedDependenciesTree.dependencies
929
+ ).reduce((acc, [name, info]) => {
930
+ return { ...acc, [`node_modules/${name}`]: info };
931
+ }, {});
932
+
933
+ files.writeFile(
934
+ files.pathJoin(newPackageNpmDir, 'npm-shrinkwrap.json'),
935
+ JSON.stringify({
936
+ ...shrinkwrappedDependenciesTree,
937
+ dependencies: mappedDependencies,
938
+ }, null, 2)
939
+ );
940
+ files.writeFile(
941
+ files.pathJoin(newPackageNpmDir, 'package.json'),
942
+ JSON.stringify({ dependencies: npmDependencies }, null, 2)
943
+ );
944
+
945
+ logUpdateDependencies(packageName, npmDependencies);
946
+ await installFromShrinkwrap(newPackageNpmDir);
947
+
948
+ files.unlink(files.pathJoin(newPackageNpmDir, 'npm-shrinkwrap.json'));
949
+ files.unlink(files.pathJoin(newPackageNpmDir, 'package.json'));
950
+
951
+ await completeNpmDirectory(
952
+ packageName, newPackageNpmDir, packageNpmDir, npmDependencies,
953
+ cacheKey);
954
+ return true;
955
+ } finally {
956
+ if (files.exists(newPackageNpmDir)) {
957
+ await files.rm_recursive_deferred(newPackageNpmDir);
958
+ }
959
+ tmpDirs = _.without(tmpDirs, newPackageNpmDir);
960
+ }
961
+ }
962
+
896
963
  // Restore every restorable package under packagesDir from the cache, in
897
964
  // parallel, before the (serial) per-package build pipeline reaches
898
965
  // them. Purely filesystem-driven: a candidate is any package dir with a
@@ -900,69 +967,129 @@ function pruneNpmDepsCache(packageCacheDir, keepDir) {
900
967
  // package.js evaluation is needed. Safe to run concurrently with a
901
968
  // build -- each restore holds the same cross-process lock
902
969
  // updateDependencies() takes, and re-checks its precondition under it.
903
- // Returns the number of packages restored.
970
+ //
971
+ // Options:
972
+ // - onlyPackages: array of package names to consider (REQUIRED for
973
+ // installOnMiss -- without a scope, cold-cache installs would cover
974
+ // every bundled package instead of just the app's).
975
+ // - installOnMiss: after the restore phase, npm-install the remaining
976
+ // misses from their shipped shrinkwraps, in parallel.
977
+ // - concurrency (restore pool, default 8), installConcurrency (npm
978
+ // pool, default 3 -- kept small because concurrent npm processes
979
+ // contend on npm's shared content cache).
980
+ //
981
+ // Returns {restored, installed}.
904
982
  meteorNpm.prewarmNpmDepsCache = async function (packagesDir, options) {
905
983
  options = options || {};
984
+ const none = { restored: 0, installed: 0 };
906
985
  if (npmDepsCacheDisabled()) {
907
- return 0;
986
+ return none;
908
987
  }
909
988
  packagesDir = files.convertToStandardPath(packagesDir);
910
989
 
990
+ const only = options.onlyPackages &&
991
+ new Set(options.onlyPackages);
911
992
  const candidates = [];
993
+ // A dir is a candidate when it has a shipped shrinkwrap but no
994
+ // installed tree. `name` keys the cache entry, so it must match what
995
+ // the normal install path passes as packageName: the package name for
996
+ // .npm/package, the plugin name for .npm/plugin/<pluginName>.
997
+ function considerCandidate(name, packageNpmDir) {
998
+ if (! files.exists(
999
+ files.pathJoin(packageNpmDir, "npm-shrinkwrap.json"))) {
1000
+ return;
1001
+ }
1002
+ if (files.exists(files.pathJoin(
1003
+ packageNpmDir, "node_modules", ".package-lock.json"))) {
1004
+ return;
1005
+ }
1006
+ candidates.push({ name, packageNpmDir });
1007
+ }
912
1008
  try {
913
1009
  files.readdir(packagesDir).forEach(name => {
914
- const packageNpmDir =
915
- files.pathJoin(packagesDir, name, ".npm", "package");
916
- if (! files.exists(
917
- files.pathJoin(packageNpmDir, "npm-shrinkwrap.json"))) {
1010
+ if (only && ! only.has(name)) {
918
1011
  return;
919
1012
  }
920
- if (files.exists(files.pathJoin(
921
- packageNpmDir, "node_modules", ".package-lock.json"))) {
1013
+ considerCandidate(
1014
+ name, files.pathJoin(packagesDir, name, ".npm", "package"));
1015
+ // Build plugins keep their own npm trees at .npm/plugin/<plugin
1016
+ // name> -- these install during the runner's FIRST build, i.e.
1017
+ // inside the file-watch window, where the resulting .npm churn
1018
+ // can restart the build (post-update "flapping"). Prewarming them
1019
+ // here moves that work before the watcher arms.
1020
+ const pluginRoot = files.pathJoin(packagesDir, name, ".npm", "plugin");
1021
+ let pluginNames;
1022
+ try {
1023
+ pluginNames = files.readdir(pluginRoot);
1024
+ } catch (e) {
922
1025
  return;
923
1026
  }
924
- candidates.push({ name, packageNpmDir });
1027
+ pluginNames.forEach(pluginName => {
1028
+ if (pluginName.startsWith(".") ||
1029
+ pluginName.endsWith(".lock") ||
1030
+ pluginName.includes("-new-") ||
1031
+ pluginName.includes("-prewarm-")) {
1032
+ return;
1033
+ }
1034
+ considerCandidate(
1035
+ pluginName, files.pathJoin(pluginRoot, pluginName));
1036
+ });
925
1037
  });
926
1038
  } catch (e) {
927
- return 0;
1039
+ return none;
928
1040
  }
929
1041
  if (! candidates.length) {
930
- return 0;
1042
+ return none;
931
1043
  }
932
1044
 
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);
1045
+ function installedAlready(candidate) {
1046
+ return files.exists(files.pathJoin(
1047
+ candidate.packageNpmDir, "node_modules", ".package-lock.json"));
1048
+ }
1049
+
1050
+ async function runPool(queue, size, fn) {
1051
+ let nextIndex = 0;
1052
+ let completed = 0;
1053
+ async function worker() {
1054
+ while (nextIndex < queue.length) {
1055
+ const candidate = queue[nextIndex++];
1056
+ try {
1057
+ // Re-check under the lock: a concurrent build (or the other
1058
+ // prewarm phase) may have handled this package already.
1059
+ const ok = await withNpmPackageLock(
1060
+ candidate.packageNpmDir,
1061
+ async () => ! installedAlready(candidate) && fn(candidate)
1062
+ );
1063
+ if (ok) {
1064
+ completed++;
1065
+ }
1066
+ } catch (e) {
1067
+ // Best-effort; the build's own updateDependencies() will
1068
+ // handle this package the normal way.
1069
+ if (options.debugThrow) {
1070
+ console.error("prewarm error for " + candidate.name + ":",
1071
+ (e && e.stack) || e);
951
1072
  }
952
- );
953
- if (ok) {
954
- restored++;
955
1073
  }
956
- } catch (e) {
957
- // Best-effort; the build's own updateDependencies() will handle
958
- // this package the normal way.
959
1074
  }
960
1075
  }
1076
+ await Promise.all(
1077
+ _.times(Math.min(size, queue.length || 1), worker));
1078
+ return completed;
1079
+ }
1080
+
1081
+ const restored = await runPool(
1082
+ candidates, options.concurrency || 8,
1083
+ c => restoreNodeModulesFromNpmDepsCache(c.name, c.packageNpmDir));
1084
+
1085
+ let installed = 0;
1086
+ if (options.installOnMiss && only) {
1087
+ const misses = candidates.filter(c => ! installedAlready(c));
1088
+ installed = await runPool(
1089
+ misses, options.installConcurrency || 3,
1090
+ c => preinstallNpmDepsFromShrinkwrap(c.name, c.packageNpmDir));
961
1091
  }
962
- const concurrency = Math.min(
963
- options.concurrency || 8, candidates.length);
964
- await Promise.all(_.times(concurrency, worker));
965
- return restored;
1092
+ return { restored, installed };
966
1093
  };
967
1094
 
968
1095
  var updateExistingNpmDirectory = async function (packageName, newPackageNpmDir,
@@ -1293,6 +1420,11 @@ async function completeNpmDirectory(
1293
1420
  await files.renameDirAlmostAtomically(newPackageNpmDir, packageNpmDir);
1294
1421
 
1295
1422
  dirtyNodeModulesDirectory(files.pathJoin(packageNpmDir, "node_modules"));
1423
+ // The whole .npm dir was just atomically replaced; any optimistic
1424
+ // result cached during the swap window (e.g. a null hash for
1425
+ // npm-shrinkwrap.json) must be forgotten deterministically -- watcher
1426
+ // events can't be relied on for this (see dirtyReplacedDirectory).
1427
+ dirtyReplacedDirectory(packageNpmDir);
1296
1428
 
1297
1429
  if (! _.isEmpty(npmDependencies)) {
1298
1430
  scheduleNpmDepsCachePopulate(