@maka/meteor-sdk 0.2.1 → 0.2.3

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 (29) hide show
  1. package/README.md +9 -0
  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 +3 -7
  23. package/src/release.js +37 -1
  24. package/tools/fs/dev-bundle-links.js +1 -1
  25. package/tools/fs/files.ts +20 -7
  26. package/tools/tool-env/source-map-retriever-stack.js +5 -1
  27. package/tools/vendor/source-map-support/LICENSE.md +21 -0
  28. package/tools/vendor/source-map-support/README.md +17 -0
  29. package/tools/vendor/source-map-support/source-map-support.js +433 -0
package/README.md CHANGED
@@ -42,6 +42,15 @@ the target app's own `.meteor/release` (e.g. `"METEOR@3.5.1"`) -- it pins
42
42
  which Meteor release's package versions and build behavior this process
43
43
  uses.
44
44
 
45
+ Passing a specific release requires that release to be present in the
46
+ local package catalog (the Meteor warehouse) -- on a machine that has
47
+ never downloaded it, `init` rejects with a `MeteorSdkError` naming the
48
+ missing release. **Embedders that only need `connectDdp()` (or other
49
+ non-build APIs) should call `init({})` with no release**: that uses
50
+ checkout semantics (the tool copy this package itself ships), needs no
51
+ warehouse or catalog access, and works on a machine whose only Meteor
52
+ footprint is this npm package.
53
+
45
54
  ### `loadProject(appDir)`
46
55
 
47
56
  Resolves an app directory into a `Project`, ready to bundle or run.
@@ -1,5 +1,5 @@
1
1
  {
2
- "name": "package-new-1r7dbz0c8wg",
2
+ "name": "package-new-6xobneyfbqr",
3
3
  "lockfileVersion": 3,
4
4
  "requires": true,
5
5
  "packages": {
@@ -1,5 +1,5 @@
1
1
  {
2
- "name": "package-new-nktb6c4q13",
2
+ "name": "package-new-r3e8f88flkl",
3
3
  "lockfileVersion": 3,
4
4
  "requires": true,
5
5
  "packages": {
@@ -1,5 +1,5 @@
1
1
  {
2
- "name": "package-new-c03yv5kvt5c",
2
+ "name": "package-new-4pbying366l",
3
3
  "lockfileVersion": 3,
4
4
  "requires": true,
5
5
  "packages": {
@@ -1,5 +1,5 @@
1
1
  {
2
- "name": "package-new-1cnw8a67ov9",
2
+ "name": "package-new-w88s7v8a2tb",
3
3
  "lockfileVersion": 3,
4
4
  "requires": true,
5
5
  "packages": {
@@ -1,5 +1,5 @@
1
1
  {
2
- "name": "package-new-1tf9jwmaca",
2
+ "name": "package-new-f69i13ow6p7",
3
3
  "lockfileVersion": 3,
4
4
  "requires": true,
5
5
  "packages": {
@@ -1,5 +1,5 @@
1
1
  {
2
- "name": "package-new-10sya38usjv",
2
+ "name": "package-new-p1w5mkk0978",
3
3
  "lockfileVersion": 3,
4
4
  "requires": true,
5
5
  "packages": {
@@ -1,5 +1,5 @@
1
1
  {
2
- "name": "package-new-3ivjp0fe2px",
2
+ "name": "package-new-1ib48dwuck5",
3
3
  "lockfileVersion": 3,
4
4
  "requires": true,
5
5
  "packages": {
@@ -1,5 +1,5 @@
1
1
  {
2
- "name": "package-new-1lw6fy3x045i",
2
+ "name": "package-new-1157kjfj2gw",
3
3
  "lockfileVersion": 3,
4
4
  "requires": true,
5
5
  "packages": {
@@ -1,5 +1,5 @@
1
1
  {
2
- "name": "package-new-18pj1q2114u",
2
+ "name": "package-new-1wg8ssdz0fmf",
3
3
  "lockfileVersion": 3,
4
4
  "requires": true,
5
5
  "packages": {
@@ -1,5 +1,5 @@
1
1
  {
2
- "name": "package-new-13o6x1vmt33",
2
+ "name": "package-new-1vnwfx4b68v",
3
3
  "lockfileVersion": 3,
4
4
  "requires": true,
5
5
  "packages": {
@@ -1,5 +1,5 @@
1
1
  {
2
- "name": "package-new-1og5l3im8lt",
2
+ "name": "package-new-kid7k7quu7",
3
3
  "lockfileVersion": 3,
4
4
  "requires": true,
5
5
  "packages": {
@@ -1,5 +1,5 @@
1
1
  {
2
- "name": "package-new-iywg8a3j6ob",
2
+ "name": "package-new-1a6dsn3qfc2",
3
3
  "lockfileVersion": 3,
4
4
  "requires": true,
5
5
  "packages": {
@@ -1,5 +1,5 @@
1
1
  {
2
- "name": "package-new-1gksx5vtdqd",
2
+ "name": "package-new-v6v3rjtfql",
3
3
  "lockfileVersion": 3,
4
4
  "requires": true,
5
5
  "packages": {
@@ -1,5 +1,5 @@
1
1
  {
2
- "name": "package-new-iylmf9l00qp",
2
+ "name": "package-new-1lii7blq24r",
3
3
  "lockfileVersion": 3,
4
4
  "requires": true,
5
5
  "packages": {
@@ -1,5 +1,5 @@
1
1
  {
2
- "name": "package-new-5efm5qfjhvg",
2
+ "name": "package-new-1wg5bygb6ij",
3
3
  "lockfileVersion": 3,
4
4
  "requires": true,
5
5
  "packages": {
@@ -1,5 +1,5 @@
1
1
  {
2
- "name": "package-new-1d84t9k1ydz",
2
+ "name": "package-new-uir4qgmp1sp",
3
3
  "lockfileVersion": 3,
4
4
  "requires": true,
5
5
  "packages": {
@@ -1,5 +1,5 @@
1
1
  {
2
- "name": "package-new-1goqz676srul",
2
+ "name": "package-new-461z05pva2w",
3
3
  "lockfileVersion": 3,
4
4
  "requires": true,
5
5
  "packages": {
@@ -1,5 +1,5 @@
1
1
  {
2
- "name": "package-new-xw6nddmuwr",
2
+ "name": "package-new-23rno2x3x0o",
3
3
  "lockfileVersion": 3,
4
4
  "requires": true,
5
5
  "packages": {
@@ -1,5 +1,5 @@
1
1
  {
2
- "name": "package-new-owokmgbm4hl",
2
+ "name": "package-new-1w81jifsunlg",
3
3
  "lockfileVersion": 3,
4
4
  "requires": true,
5
5
  "packages": {
@@ -1,5 +1,5 @@
1
1
  {
2
- "name": "package-new-16asc201r64",
2
+ "name": "package-new-1b9umwwq6uc",
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.1",
3
+ "version": "0.2.3",
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": {
@@ -41,14 +41,11 @@
41
41
  "babel-runtime": "7.0.0-beta.3",
42
42
  "@types/underscore": "1.11.15",
43
43
  "underscore": "1.13.7",
44
- "source-map-support": "https://github.com/meteor/node-source-map-support/tarball/1912478769d76e5df4c365e147f25896aee6375e",
44
+ "source-map-v01": "npm:source-map@0.1.32",
45
45
  "@types/semver": "7.5.8",
46
46
  "semver": "7.6.3",
47
47
  "request": "2.88.2",
48
- "uuid": "8.3.2",
49
48
  "graceful-fs": "4.2.11",
50
- "fstream": "https://github.com/meteor/fstream/tarball/cf4ea6c175355cec7bee38311e170d08c4078a5d",
51
- "tar": "6.1.11",
52
49
  "tar-fs": "2.1.1",
53
50
  "source-map": "0.7.4",
54
51
  "chalk": "4.1.2",
@@ -57,8 +54,7 @@
57
54
  "is-reachable": "3.1.0",
58
55
  "wordwrap": "1.0.0",
59
56
  "moment": "2.30.1",
60
- "rimraf": "2.6.2",
61
- "glob": "11.0.1",
57
+ "glob": "11.1.0",
62
58
  "ignore": "7.0.5",
63
59
  "commonmark": "0.15.0",
64
60
  "escope": "4.0.0",
package/src/release.js CHANGED
@@ -36,7 +36,43 @@ async function init(options) {
36
36
  // release cached (or be reachable); see release.load's own doc comment
37
37
  // in meteor-tool for the exact fetch/cache behavior.
38
38
  const releaseName = options.release == null ? null : options.release;
39
- const releaseObject = await release.load(releaseName);
39
+ let releaseObject;
40
+ try {
41
+ releaseObject = await release.load(releaseName);
42
+ } catch (e) {
43
+ // release.NoSuchReleaseError is an EMPTY constructor -- not even an
44
+ // Error, no .message -- so embedders logging err.message printed
45
+ // "undefined" and the real cause (release not in the local package
46
+ // catalog, e.g. a machine with no populated Meteor warehouse) was
47
+ // invisible. Cost a real debugging evening in the field; wrap it
48
+ // (and any other message-less throw from release.load) in a proper
49
+ // MeteorSdkError that names the release and where the catalog lives.
50
+ let warehouse = "~/.meteor";
51
+ try {
52
+ warehouse = require("../tools/packaging/tropohouse.js").default.root;
53
+ } catch (_) {
54
+ // Best effort -- the default hint above is close enough.
55
+ }
56
+ if (e instanceof release.NoSuchReleaseError) {
57
+ throw new MeteorSdkError(
58
+ "init(): release " + JSON.stringify(releaseName) + " is not in " +
59
+ "the local package catalog (warehouse: " + warehouse + "). " +
60
+ "On a machine that has never downloaded that Meteor release " +
61
+ "this is expected -- either install/download the release " +
62
+ "first, or, for embedders that only need connectDdp() and " +
63
+ "other non-build APIs, call init({}) with no release (checkout " +
64
+ "semantics, no catalog needed)."
65
+ );
66
+ }
67
+ if (e instanceof Error) {
68
+ throw e;
69
+ }
70
+ throw new MeteorSdkError(
71
+ "init(): release.load(" + JSON.stringify(releaseName) + ") failed " +
72
+ "with a message-less throw (" + Object.prototype.toString.call(e) +
73
+ "); warehouse: " + warehouse
74
+ );
75
+ }
40
76
  // forced is always true: init({release}) is the embedder explicitly
41
77
  // choosing the release for this process -- the moral equivalent of the
42
78
  // CLI's --release flag, which is exactly what release.forced means.
@@ -22,7 +22,7 @@ exports.makeLink = function (target, linkPath) {
22
22
  fs.renameSync(tempPath, linkPath);
23
23
  } catch (e) {
24
24
  // If renaming fails, try unlinking first.
25
- require("rimraf").sync(linkPath);
25
+ require("fs").rmSync(linkPath, { recursive: true, force: true });
26
26
  fs.renameSync(tempPath, linkPath);
27
27
  }
28
28
  };
package/tools/fs/files.ts CHANGED
@@ -30,7 +30,6 @@ import { realpathSync } from './fsFixPath';
30
30
 
31
31
  const _ = require('underscore');
32
32
 
33
- const rimraf = require('rimraf');
34
33
  const sourcemap = require('source-map');
35
34
  const sourceMapRetrieverStack = require('../tool-env/source-map-retriever-stack.js');
36
35
 
@@ -322,7 +321,16 @@ export function getCurrentNodeBinDir() {
322
321
  // Return the top-level directory for this meteor install or checkout
323
322
  export function getCurrentToolsDir() {
324
323
  if (!process.env.SANDBOX && process.env.METEOR_WAREHOUSE_DIR) {
325
- return pathDirname(realpathSync(pathJoin(process.env.METEOR_WAREHOUSE_DIR, 'meteor')));
324
+ // Only follow the warehouse's `meteor` link when it actually exists:
325
+ // an empty/fresh METEOR_WAREHOUSE_DIR (observed: SDK embedders
326
+ // pointing the env var at a scratch dir) made realpathSync throw
327
+ // ENOENT uncaught through getToolBundleRoot() and everything above
328
+ // it. Falling through to the __dirname-based answer keeps the
329
+ // running tool copy resolvable regardless of warehouse state.
330
+ const warehouseMeteor = pathJoin(process.env.METEOR_WAREHOUSE_DIR, 'meteor');
331
+ if (exists(warehouseMeteor)) {
332
+ return pathDirname(realpathSync(warehouseMeteor));
333
+ }
326
334
  }
327
335
 
328
336
  return pathDirname(pathDirname(convertToStandardPath(__dirname)));
@@ -457,16 +465,21 @@ export function realpathOrNull(path: string) {
457
465
 
458
466
  export function rm_recursive_async(path: string) {
459
467
  return new Promise<void>((resolve, reject) => {
460
- rimraf(convertToOSPath(path), (err: Error) => err
461
- ? reject(err)
462
- : resolve());
468
+ // fs.rm with force+maxRetries replaces the old rimraf dependency
469
+ // (Node's built-in grew the same EPERM/EBUSY retry behavior it
470
+ // existed for).
471
+ fs.rm(
472
+ convertToOSPath(path),
473
+ { recursive: true, force: true, maxRetries: 3 },
474
+ (err) => err ? reject(err) : resolve()
475
+ );
463
476
  });
464
477
  }
465
478
 
466
479
  // Like rm -r.
467
480
  export const rm_recursive = Profile("files.rm_recursive", async (path: string) => {
468
481
  try {
469
- rimraf.sync(convertToOSPath(path));
482
+ fs.rmSync(convertToOSPath(path), { recursive: true, force: true });
470
483
  } catch (e: any) {
471
484
  if ((e.code === "ENOTEMPTY" ||
472
485
  e.code === "EPERM")) {
@@ -1734,7 +1747,7 @@ export const rename = isWindowsLikeFilesystem() ? function (from: string, to: st
1734
1747
  // Despite previous failures, the top-level destination directory
1735
1748
  // may have been successfully created, so we must remove it to
1736
1749
  // avoid moving the source file *into* the destination directory.
1737
- rimraf.sync(osTo);
1750
+ fs.rmSync(osTo, { recursive: true, force: true });
1738
1751
  wrappedRename(from, to);
1739
1752
  resolve();
1740
1753
  } catch (err: any) {
@@ -1,4 +1,8 @@
1
- import sourceMapSupport from 'source-map-support';
1
+ // Vendored Meteor fork -- see tools/vendor/source-map-support/README.md
2
+ // for why this isn't the npm package (fork-only install({wrapCallSite})
3
+ // support) or a GitHub tarball URL anymore (npm 12 blocks those by
4
+ // default with EALLOWREMOTE, breaking consumers' installs).
5
+ import sourceMapSupport from '../vendor/source-map-support/source-map-support.js';
2
6
 
3
7
  // Why this file exists:
4
8
  // We have two places in the tool where we need to do source maps:
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2014 Evan Wallace
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,17 @@
1
+ Vendored copy of Meteor's source-map-support fork
2
+ (https://github.com/meteor/node-source-map-support, commit 1912478,
3
+ package version 0.3.2), previously consumed as a GitHub tarball-URL
4
+ dependency -- npm 12 defaults `allow-remote` to "none", which made every
5
+ `npm install` of a package depending on this SDK fail with EALLOWREMOTE.
6
+
7
+ The fork can't be replaced with the npm-published upstream: the tool
8
+ relies on fork-only behavior, most importantly `install({ wrapCallSite })`
9
+ (upstream doesn't accept a wrapCallSite override), used by
10
+ tools/tool-env/source-map-retriever-stack.js to strip meteor://.app/ URL
11
+ prefixes from stack frames.
12
+
13
+ The single edit vs. the fork: `require('source-map')` on line 1 became
14
+ `require('source-map-v01')` -- an npm alias for source-map@0.1.32 declared
15
+ in scripts/dev-bundle-tool-package.js, because this fork predates the
16
+ async SourceMapConsumer API of the source-map@0.7.x the tool itself
17
+ depends on.
@@ -0,0 +1,433 @@
1
+ var SourceMapConsumer = require('source-map-v01').SourceMapConsumer;
2
+ var path = require('path');
3
+ var fs = require('fs');
4
+
5
+ // Only install once if called multiple times
6
+ var alreadyInstalled = false;
7
+
8
+ // If true, the caches are reset before a stack trace formatting operation
9
+ var emptyCacheBetweenOperations = false;
10
+
11
+ // Maps a file path to a string containing the file contents
12
+ var fileContentsCache = {};
13
+
14
+ // Maps a file path to a source map for that file
15
+ var sourceMapCache = {};
16
+
17
+ // Regex for detecting source maps
18
+ var reSourceMap = /^data:application\/json[^,]+base64,/;
19
+
20
+ function isInBrowser() {
21
+ return ((typeof window !== 'undefined') && (typeof XMLHttpRequest === 'function'));
22
+ }
23
+
24
+ function hasGlobalProcessEventEmitter() {
25
+ return ((typeof process === 'object') && (process !== null) && (typeof process.on === 'function'));
26
+ }
27
+
28
+ function retrieveFile(path) {
29
+ // Trim the path to make sure there is no extra whitespace.
30
+ path = path.trim();
31
+ if (path in fileContentsCache) {
32
+ return fileContentsCache[path];
33
+ }
34
+
35
+ try {
36
+ // Use SJAX if we are in the browser
37
+ if (isInBrowser()) {
38
+ var xhr = new XMLHttpRequest();
39
+ xhr.open('GET', path, false);
40
+ xhr.send(null);
41
+ var contents = null
42
+ if (xhr.readyState === 4 && xhr.status === 200) {
43
+ contents = xhr.responseText
44
+ }
45
+ }
46
+
47
+ // Otherwise, use the filesystem
48
+ else {
49
+ var contents = fs.readFileSync(path, 'utf8');
50
+ }
51
+ } catch (e) {
52
+ var contents = null;
53
+ }
54
+
55
+ return fileContentsCache[path] = contents;
56
+ }
57
+
58
+ // Support URLs relative to a directory, but be careful about a protocol prefix
59
+ // in case we are in the browser (i.e. directories may start with "http://")
60
+ function supportRelativeURL(file, url) {
61
+ if (!file) return url;
62
+ var dir = path.dirname(file);
63
+ var match = /^\w+:\/\/[^\/]*/.exec(dir);
64
+ var protocol = match ? match[0] : '';
65
+ return protocol + path.resolve(dir.slice(protocol.length), url);
66
+ }
67
+
68
+ function retrieveSourceMapURL(source) {
69
+ var fileData;
70
+
71
+ if (isInBrowser()) {
72
+ var xhr = new XMLHttpRequest();
73
+ xhr.open('GET', source, false);
74
+ xhr.send(null);
75
+ fileData = xhr.readyState === 4 ? xhr.responseText : null;
76
+
77
+ // Support providing a sourceMappingURL via the SourceMap header
78
+ var sourceMapHeader = xhr.getResponseHeader("SourceMap") ||
79
+ xhr.getResponseHeader("X-SourceMap");
80
+ if (sourceMapHeader) {
81
+ return sourceMapHeader;
82
+ }
83
+ }
84
+
85
+ // Get the URL of the source map
86
+ fileData = retrieveFile(source);
87
+ var re = /\/\/[#@]\s*sourceMappingURL=([^'"]+)\s*$/mg;
88
+ // Keep executing the search to find the *last* sourceMappingURL to avoid
89
+ // picking up sourceMappingURLs from comments, strings, etc.
90
+ var lastMatch, match;
91
+ while (match = re.exec(fileData)) lastMatch = match;
92
+ if (!lastMatch) return null;
93
+ return lastMatch[1];
94
+ };
95
+
96
+ // Can be overridden by the retrieveSourceMap option to install. Takes a
97
+ // generated source filename; returns a {map, optional url} object, or null if
98
+ // there is no source map. The map field may be either a string or the parsed
99
+ // JSON object (ie, it must be a valid argument to the SourceMapConsumer
100
+ // constructor).
101
+ function retrieveSourceMap(source) {
102
+ var sourceMappingURL = retrieveSourceMapURL(source);
103
+ if (!sourceMappingURL) return null;
104
+
105
+ // Read the contents of the source map
106
+ var sourceMapData;
107
+ if (reSourceMap.test(sourceMappingURL)) {
108
+ // Support source map URL as a data url
109
+ var rawData = sourceMappingURL.slice(sourceMappingURL.indexOf(',') + 1);
110
+ sourceMapData = new Buffer(rawData, "base64").toString();
111
+ sourceMappingURL = null;
112
+ } else {
113
+ // Support source map URLs relative to the source URL
114
+ sourceMappingURL = supportRelativeURL(source, sourceMappingURL);
115
+ sourceMapData = retrieveFile(sourceMappingURL);
116
+ }
117
+
118
+ if (!sourceMapData) {
119
+ return null;
120
+ }
121
+
122
+ return {
123
+ url: sourceMappingURL,
124
+ map: sourceMapData
125
+ };
126
+ }
127
+
128
+ function mapSourcePosition(position) {
129
+ var sourceMap = sourceMapCache[position.source];
130
+ if (!sourceMap) {
131
+ // Call the (overrideable) retrieveSourceMap function to get the source map.
132
+ var urlAndMap = retrieveSourceMap(position.source);
133
+ if (urlAndMap) {
134
+ sourceMap = sourceMapCache[position.source] = {
135
+ url: urlAndMap.url,
136
+ map: new SourceMapConsumer(urlAndMap.map)
137
+ };
138
+
139
+ // Load all sources stored inline with the source map into the file cache
140
+ // to pretend like they are already loaded. They may not exist on disk.
141
+ if (sourceMap.map.sourcesContent) {
142
+ sourceMap.map.sources.forEach(function(source, i) {
143
+ var contents = sourceMap.map.sourcesContent[i];
144
+ if (contents) {
145
+ var url = supportRelativeURL(sourceMap.url, source);
146
+ fileContentsCache[url] = contents;
147
+ }
148
+ });
149
+ }
150
+ } else {
151
+ sourceMap = sourceMapCache[position.source] = {
152
+ url: null,
153
+ map: null
154
+ };
155
+ }
156
+ }
157
+
158
+ // Resolve the source URL relative to the URL of the source map
159
+ if (sourceMap && sourceMap.map) {
160
+ var originalPosition = sourceMap.map.originalPositionFor(position);
161
+
162
+ // Only return the original position if a matching line was found. If no
163
+ // matching line is found then we return position instead, which will cause
164
+ // the stack trace to print the path and line for the compiled file. It is
165
+ // better to give a precise location in the compiled file than a vague
166
+ // location in the original file.
167
+ if (originalPosition.source !== null) {
168
+ originalPosition.source = supportRelativeURL(
169
+ sourceMap.url, originalPosition.source);
170
+ return originalPosition;
171
+ }
172
+ }
173
+
174
+ return position;
175
+ }
176
+
177
+ // Parses code generated by FormatEvalOrigin(), a function inside V8:
178
+ // https://code.google.com/p/v8/source/browse/trunk/src/messages.js
179
+ function mapEvalOrigin(origin) {
180
+ // Most eval() calls are in this format
181
+ var match = /^eval at ([^(]+) \((.+):(\d+):(\d+)\)$/.exec(origin);
182
+ if (match) {
183
+ var position = mapSourcePosition({
184
+ source: match[2],
185
+ line: match[3],
186
+ column: match[4] - 1
187
+ });
188
+ return 'eval at ' + match[1] + ' (' + position.source + ':' +
189
+ position.line + ':' + (position.column + 1) + ')';
190
+ }
191
+
192
+ // Parse nested eval() calls using recursion
193
+ match = /^eval at ([^(]+) \((.+)\)$/.exec(origin);
194
+ if (match) {
195
+ return 'eval at ' + match[1] + ' (' + mapEvalOrigin(match[2]) + ')';
196
+ }
197
+
198
+ // Make sure we still return useful information if we didn't find anything
199
+ return origin;
200
+ }
201
+
202
+ // This is copied almost verbatim from the V8 source code at
203
+ // https://code.google.com/p/v8/source/browse/trunk/src/messages.js. The
204
+ // implementation of wrapCallSite() used to just forward to the actual source
205
+ // code of CallSite.prototype.toString but unfortunately a new release of V8
206
+ // did something to the prototype chain and broke the shim. The only fix I
207
+ // could find was copy/paste.
208
+ function CallSiteToString() {
209
+ var fileName;
210
+ var fileLocation = "";
211
+ if (this.isNative()) {
212
+ fileLocation = "native";
213
+ } else {
214
+ fileName = this.getScriptNameOrSourceURL();
215
+ if (!fileName && this.isEval()) {
216
+ fileLocation = this.getEvalOrigin();
217
+ fileLocation += ", "; // Expecting source position to follow.
218
+ }
219
+
220
+ if (fileName) {
221
+ fileLocation += fileName;
222
+ } else {
223
+ // Source code does not originate from a file and is not native, but we
224
+ // can still get the source position inside the source string, e.g. in
225
+ // an eval string.
226
+ fileLocation += "<anonymous>";
227
+ }
228
+ var lineNumber = this.getLineNumber();
229
+ if (lineNumber != null) {
230
+ fileLocation += ":" + lineNumber;
231
+ var columnNumber = this.getColumnNumber();
232
+ if (columnNumber) {
233
+ fileLocation += ":" + columnNumber;
234
+ }
235
+ }
236
+ }
237
+
238
+ var line = "";
239
+ var functionName = this.getFunctionName();
240
+ var addSuffix = true;
241
+ var isConstructor = this.isConstructor();
242
+ var isMethodCall = !(this.isToplevel() || isConstructor);
243
+ if (isMethodCall) {
244
+ var typeName = this.getTypeName();
245
+ var methodName = this.getMethodName();
246
+ if (functionName) {
247
+ if (typeName && functionName.indexOf(typeName) != 0) {
248
+ line += typeName + ".";
249
+ }
250
+ line += functionName;
251
+ if (methodName && functionName.indexOf("." + methodName) != functionName.length - methodName.length - 1) {
252
+ line += " [as " + methodName + "]";
253
+ }
254
+ } else {
255
+ line += typeName + "." + (methodName || "<anonymous>");
256
+ }
257
+ } else if (isConstructor) {
258
+ line += "new " + (functionName || "<anonymous>");
259
+ } else if (functionName) {
260
+ line += functionName;
261
+ } else {
262
+ line += fileLocation;
263
+ addSuffix = false;
264
+ }
265
+ if (addSuffix) {
266
+ line += " (" + fileLocation + ")";
267
+ }
268
+ return line;
269
+ }
270
+
271
+ function cloneCallSite(frame) {
272
+ var object = {};
273
+ Object.getOwnPropertyNames(Object.getPrototypeOf(frame)).forEach(function(name) {
274
+ object[name] = /^(?:is|get)/.test(name) ? function() { return frame[name].call(frame); } : frame[name];
275
+ });
276
+ object.toString = CallSiteToString;
277
+ return object;
278
+ }
279
+
280
+ function wrapCallSite(frame) {
281
+ // Most call sites will return the source file from getFileName(), but code
282
+ // passed to eval() ending in "//# sourceURL=..." will return the source file
283
+ // from getScriptNameOrSourceURL() instead
284
+ var source = frame.getFileName() || frame.getScriptNameOrSourceURL();
285
+ if (source) {
286
+ var line = frame.getLineNumber();
287
+ var column = frame.getColumnNumber() - 1;
288
+
289
+ // Fix position in Node where some (internal) code is prepended.
290
+ // See https://github.com/evanw/node-source-map-support/issues/36
291
+ if (line === 1 && !isInBrowser() && !frame.isEval()) {
292
+ column -= 62;
293
+ }
294
+
295
+ var position = mapSourcePosition({
296
+ source: source,
297
+ line: line,
298
+ column: column
299
+ });
300
+ frame = cloneCallSite(frame);
301
+ frame.getFileName = function() { return position.source; };
302
+ frame.getLineNumber = function() { return position.line; };
303
+ frame.getColumnNumber = function() { return position.column + 1; };
304
+ frame.getScriptNameOrSourceURL = function() { return position.source; };
305
+ return frame;
306
+ }
307
+
308
+ // Code called using eval() needs special handling
309
+ var origin = frame.isEval() && frame.getEvalOrigin();
310
+ if (origin) {
311
+ origin = mapEvalOrigin(origin);
312
+ frame = cloneCallSite(frame);
313
+ frame.getEvalOrigin = function() { return origin; };
314
+ return frame;
315
+ }
316
+
317
+ // If we get here then we were unable to change the source position
318
+ return frame;
319
+ }
320
+
321
+ // This function is part of the V8 stack trace API, for more info see:
322
+ // http://code.google.com/p/v8/wiki/JavaScriptStackTraceApi
323
+ function prepareStackTrace(error, stack) {
324
+ if (emptyCacheBetweenOperations) {
325
+ fileContentsCache = {};
326
+ sourceMapCache = {};
327
+ }
328
+
329
+ return error + stack.map(function(frame) {
330
+ return '\n at ' + wrapCallSite(frame);
331
+ }).join('');
332
+ }
333
+
334
+ // Generate position and snippet of original source with pointer
335
+ function getErrorSource(error) {
336
+ var match = /\n at [^(]+ \((.*):(\d+):(\d+)\)/.exec(error.stack);
337
+ if (match) {
338
+ var source = match[1];
339
+ var line = +match[2];
340
+ var column = +match[3];
341
+
342
+ // Support the inline sourceContents inside the source map
343
+ var contents = fileContentsCache[source];
344
+
345
+ // Support files on disk
346
+ if (!contents && fs.existsSync(source)) {
347
+ contents = fs.readFileSync(source, 'utf8');
348
+ }
349
+
350
+ // Format the line from the original source code like node does
351
+ if (contents) {
352
+ var code = contents.split(/(?:\r\n|\r|\n)/)[line - 1];
353
+ if (code) {
354
+ return source + ':' + line + '\n' + code + '\n' +
355
+ new Array(column).join(' ') + '^';
356
+ }
357
+ }
358
+ }
359
+ return null;
360
+ }
361
+
362
+ function printErrorAndExit (error) {
363
+ var source = getErrorSource(error);
364
+
365
+ if (source) {
366
+ console.error();
367
+ console.error(source);
368
+ }
369
+
370
+ console.error(error.stack);
371
+ process.exit(1);
372
+ }
373
+
374
+ function shimEmitUncaughtException () {
375
+ var origEmit = process.emit;
376
+
377
+ process.emit = function (type) {
378
+ if (type === 'uncaughtException') {
379
+ var hasStack = (arguments[1] && arguments[1].stack);
380
+ var hasListeners = (this.listeners(type).length > 0);
381
+
382
+ if (hasStack && !hasListeners) {
383
+ return printErrorAndExit(arguments[1]);
384
+ }
385
+ }
386
+
387
+ return origEmit.apply(this, arguments);
388
+ }
389
+ }
390
+
391
+ exports.wrapCallSite = wrapCallSite;
392
+ exports.getErrorSource = getErrorSource;
393
+ exports.mapSourcePosition = mapSourcePosition;
394
+ exports.retrieveSourceMap = retrieveSourceMap;
395
+
396
+ exports.install = function(options) {
397
+ if (!alreadyInstalled) {
398
+ alreadyInstalled = true;
399
+ Error.prepareStackTrace = prepareStackTrace;
400
+
401
+ // Configure options
402
+ options = options || {};
403
+ var installHandler = 'handleUncaughtExceptions' in options ?
404
+ options.handleUncaughtExceptions : true;
405
+ emptyCacheBetweenOperations = 'emptyCacheBetweenOperations' in options ?
406
+ options.emptyCacheBetweenOperations : false;
407
+
408
+ // Allow sources to be found by methods other than reading the files
409
+ // directly from disk.
410
+ if (options.retrieveFile)
411
+ retrieveFile = options.retrieveFile;
412
+
413
+ // Allow source maps to be found by methods other than reading the files
414
+ // directly from disk.
415
+ if (options.retrieveSourceMap)
416
+ retrieveSourceMap = options.retrieveSourceMap;
417
+
418
+ // Allow stack frames to be wrapped by custom methods.
419
+ if (options.wrapCallSite)
420
+ wrapCallSite = options.wrapCallSite;
421
+
422
+ // Provide the option to not install the uncaught exception handler. This is
423
+ // to support other uncaught exception handlers (in test frameworks, for
424
+ // example). If this handler is not installed and there are no other uncaught
425
+ // exception handlers, uncaught exceptions will be caught by node's built-in
426
+ // exception handler and the process will still be terminated. However, the
427
+ // generated JavaScript code will be shown above the stack trace instead of
428
+ // the original source code.
429
+ if (installHandler && hasGlobalProcessEventEmitter()) {
430
+ shimEmitUncaughtException();
431
+ }
432
+ }
433
+ };