@depup/elastic-apm-node 4.15.0-depup.0

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 (154) hide show
  1. package/LICENSE +26 -0
  2. package/NOTICE.md +442 -0
  3. package/README.md +48 -0
  4. package/changes.json +78 -0
  5. package/index.d.ts +398 -0
  6. package/index.js +11 -0
  7. package/lib/InflightEventSet.js +53 -0
  8. package/lib/activation-method.js +119 -0
  9. package/lib/agent.js +941 -0
  10. package/lib/apm-client/apm-client.js +313 -0
  11. package/lib/apm-client/http-apm-client/CHANGELOG.md +271 -0
  12. package/lib/apm-client/http-apm-client/README.md +485 -0
  13. package/lib/apm-client/http-apm-client/central-config.js +41 -0
  14. package/lib/apm-client/http-apm-client/container-info.js +111 -0
  15. package/lib/apm-client/http-apm-client/detect-hostname.js +96 -0
  16. package/lib/apm-client/http-apm-client/index.js +1975 -0
  17. package/lib/apm-client/http-apm-client/logging.js +31 -0
  18. package/lib/apm-client/http-apm-client/ndjson.js +20 -0
  19. package/lib/apm-client/http-apm-client/truncate.js +434 -0
  20. package/lib/apm-client/noop-apm-client.js +73 -0
  21. package/lib/async-hooks-polyfill.js +58 -0
  22. package/lib/cloud-metadata/aws.js +175 -0
  23. package/lib/cloud-metadata/azure.js +123 -0
  24. package/lib/cloud-metadata/callback-coordination.js +159 -0
  25. package/lib/cloud-metadata/gcp.js +133 -0
  26. package/lib/cloud-metadata/index.js +175 -0
  27. package/lib/config/config.js +458 -0
  28. package/lib/config/normalizers.js +701 -0
  29. package/lib/config/schema.js +1007 -0
  30. package/lib/constants.js +35 -0
  31. package/lib/errors.js +303 -0
  32. package/lib/filters/sanitize-field-names.js +69 -0
  33. package/lib/http-request.js +249 -0
  34. package/lib/instrumentation/azure-functions.js +519 -0
  35. package/lib/instrumentation/context.js +56 -0
  36. package/lib/instrumentation/dropped-spans-stats.js +112 -0
  37. package/lib/instrumentation/elasticsearch-shared.js +63 -0
  38. package/lib/instrumentation/express-utils.js +91 -0
  39. package/lib/instrumentation/generic-span.js +322 -0
  40. package/lib/instrumentation/http-shared.js +424 -0
  41. package/lib/instrumentation/ids.js +39 -0
  42. package/lib/instrumentation/index.js +1127 -0
  43. package/lib/instrumentation/modules/@apollo/server.js +30 -0
  44. package/lib/instrumentation/modules/@aws-sdk/client-dynamodb.js +143 -0
  45. package/lib/instrumentation/modules/@aws-sdk/client-s3.js +230 -0
  46. package/lib/instrumentation/modules/@aws-sdk/client-sns.js +197 -0
  47. package/lib/instrumentation/modules/@aws-sdk/client-sqs.js +336 -0
  48. package/lib/instrumentation/modules/@elastic/elasticsearch.js +343 -0
  49. package/lib/instrumentation/modules/@hapi/hapi.js +221 -0
  50. package/lib/instrumentation/modules/@opentelemetry/api.js +86 -0
  51. package/lib/instrumentation/modules/@opentelemetry/sdk-metrics.js +79 -0
  52. package/lib/instrumentation/modules/@redis/client/dist/lib/client/commands-queue.js +178 -0
  53. package/lib/instrumentation/modules/@redis/client/dist/lib/client/index.js +49 -0
  54. package/lib/instrumentation/modules/@smithy/smithy-client.js +198 -0
  55. package/lib/instrumentation/modules/_lambda-handler.js +40 -0
  56. package/lib/instrumentation/modules/apollo-server-core.js +49 -0
  57. package/lib/instrumentation/modules/aws-sdk/dynamodb.js +155 -0
  58. package/lib/instrumentation/modules/aws-sdk/s3.js +184 -0
  59. package/lib/instrumentation/modules/aws-sdk/sns.js +232 -0
  60. package/lib/instrumentation/modules/aws-sdk/sqs.js +361 -0
  61. package/lib/instrumentation/modules/aws-sdk.js +76 -0
  62. package/lib/instrumentation/modules/bluebird.js +93 -0
  63. package/lib/instrumentation/modules/cassandra-driver.js +280 -0
  64. package/lib/instrumentation/modules/elasticsearch.js +191 -0
  65. package/lib/instrumentation/modules/express-graphql.js +66 -0
  66. package/lib/instrumentation/modules/express-queue.js +28 -0
  67. package/lib/instrumentation/modules/express.js +162 -0
  68. package/lib/instrumentation/modules/fastify.js +172 -0
  69. package/lib/instrumentation/modules/finalhandler.js +41 -0
  70. package/lib/instrumentation/modules/generic-pool.js +85 -0
  71. package/lib/instrumentation/modules/graphql.js +256 -0
  72. package/lib/instrumentation/modules/handlebars.js +22 -0
  73. package/lib/instrumentation/modules/http.js +112 -0
  74. package/lib/instrumentation/modules/http2.js +320 -0
  75. package/lib/instrumentation/modules/https.js +68 -0
  76. package/lib/instrumentation/modules/ioredis.js +94 -0
  77. package/lib/instrumentation/modules/jade.js +18 -0
  78. package/lib/instrumentation/modules/kafkajs.js +476 -0
  79. package/lib/instrumentation/modules/knex.js +91 -0
  80. package/lib/instrumentation/modules/koa-router.js +74 -0
  81. package/lib/instrumentation/modules/koa.js +15 -0
  82. package/lib/instrumentation/modules/memcached.js +99 -0
  83. package/lib/instrumentation/modules/mimic-response.js +45 -0
  84. package/lib/instrumentation/modules/mongodb/lib/cmap/connection_pool.js +40 -0
  85. package/lib/instrumentation/modules/mongodb-core.js +206 -0
  86. package/lib/instrumentation/modules/mongodb.js +259 -0
  87. package/lib/instrumentation/modules/mysql.js +200 -0
  88. package/lib/instrumentation/modules/mysql2.js +140 -0
  89. package/lib/instrumentation/modules/pg.js +148 -0
  90. package/lib/instrumentation/modules/pug.js +18 -0
  91. package/lib/instrumentation/modules/redis.js +176 -0
  92. package/lib/instrumentation/modules/restify.js +52 -0
  93. package/lib/instrumentation/modules/tedious.js +159 -0
  94. package/lib/instrumentation/modules/undici.js +270 -0
  95. package/lib/instrumentation/modules/ws.js +59 -0
  96. package/lib/instrumentation/noop-transaction.js +81 -0
  97. package/lib/instrumentation/run-context/AbstractRunContextManager.js +215 -0
  98. package/lib/instrumentation/run-context/AsyncHooksRunContextManager.js +106 -0
  99. package/lib/instrumentation/run-context/AsyncLocalStorageRunContextManager.js +73 -0
  100. package/lib/instrumentation/run-context/BasicRunContextManager.js +82 -0
  101. package/lib/instrumentation/run-context/RunContext.js +151 -0
  102. package/lib/instrumentation/run-context/index.js +23 -0
  103. package/lib/instrumentation/shimmer.js +123 -0
  104. package/lib/instrumentation/span-compression.js +239 -0
  105. package/lib/instrumentation/span.js +621 -0
  106. package/lib/instrumentation/template-shared.js +43 -0
  107. package/lib/instrumentation/timer.js +84 -0
  108. package/lib/instrumentation/transaction.js +571 -0
  109. package/lib/lambda.js +992 -0
  110. package/lib/load-source-map.js +100 -0
  111. package/lib/logging.js +212 -0
  112. package/lib/metrics/index.js +92 -0
  113. package/lib/metrics/platforms/generic/index.js +40 -0
  114. package/lib/metrics/platforms/generic/process-cpu.js +22 -0
  115. package/lib/metrics/platforms/generic/process-top.js +157 -0
  116. package/lib/metrics/platforms/generic/stats.js +34 -0
  117. package/lib/metrics/platforms/generic/system-cpu.js +51 -0
  118. package/lib/metrics/platforms/linux/index.js +19 -0
  119. package/lib/metrics/platforms/linux/stats.js +213 -0
  120. package/lib/metrics/queue.js +90 -0
  121. package/lib/metrics/registry.js +52 -0
  122. package/lib/metrics/reporter.js +119 -0
  123. package/lib/metrics/runtime.js +77 -0
  124. package/lib/middleware/connect.js +16 -0
  125. package/lib/opentelemetry-bridge/OTelBridgeNonRecordingSpan.js +150 -0
  126. package/lib/opentelemetry-bridge/OTelBridgeRunContext.js +124 -0
  127. package/lib/opentelemetry-bridge/OTelContextManager.js +82 -0
  128. package/lib/opentelemetry-bridge/OTelSpan.js +344 -0
  129. package/lib/opentelemetry-bridge/OTelTracer.js +201 -0
  130. package/lib/opentelemetry-bridge/OTelTracerProvider.js +25 -0
  131. package/lib/opentelemetry-bridge/README.md +244 -0
  132. package/lib/opentelemetry-bridge/index.js +15 -0
  133. package/lib/opentelemetry-bridge/oblog.js +23 -0
  134. package/lib/opentelemetry-bridge/opentelemetry-core-mini/README.md +3 -0
  135. package/lib/opentelemetry-bridge/opentelemetry-core-mini/internal/validators.js +52 -0
  136. package/lib/opentelemetry-bridge/opentelemetry-core-mini/trace/TraceState.js +109 -0
  137. package/lib/opentelemetry-bridge/otelutils.js +99 -0
  138. package/lib/opentelemetry-bridge/setup.js +76 -0
  139. package/lib/opentelemetry-metrics/ElasticApmMetricExporter.js +285 -0
  140. package/lib/opentelemetry-metrics/index.js +50 -0
  141. package/lib/parsers.js +225 -0
  142. package/lib/propwrap.js +147 -0
  143. package/lib/stacktraces.js +537 -0
  144. package/lib/symbols.js +15 -0
  145. package/lib/tracecontext/index.js +118 -0
  146. package/lib/tracecontext/traceparent.js +185 -0
  147. package/lib/tracecontext/tracestate.js +388 -0
  148. package/lib/wildcard-matcher.js +52 -0
  149. package/loader.mjs +7 -0
  150. package/package.json +299 -0
  151. package/start.d.ts +8 -0
  152. package/start.js +29 -0
  153. package/types/aws-lambda.d.ts +98 -0
  154. package/types/connect.d.ts +23 -0
package/lib/parsers.js ADDED
@@ -0,0 +1,225 @@
1
+ /*
2
+ * Copyright Elasticsearch B.V. and other contributors where applicable.
3
+ * Licensed under the BSD 2-Clause License; you may not use this file except in
4
+ * compliance with the BSD 2-Clause License.
5
+ */
6
+
7
+ 'use strict';
8
+
9
+ const url = require('url');
10
+
11
+ const basicAuth = require('basic-auth');
12
+ const getUrlFromRequest = require('original-url');
13
+ const parseHttpHeadersFromReqOrRes = require('http-headers');
14
+ const cookie = require('cookie');
15
+ const stringify = require('fast-safe-stringify');
16
+
17
+ const REDACTED = require('./constants').REDACTED;
18
+ const {
19
+ redactKeysFromObject,
20
+ redactKeysFromPostedFormVariables,
21
+ } = require('./filters/sanitize-field-names');
22
+
23
+ // When redacting individual cookie field values, this string is used instead
24
+ // of `[REDACTED]`. The APM spec says:
25
+ // > The replacement string SHOULD be `[REDACTED]`.
26
+ // We diverge from spec here because, for better or worse, the `cookie` module
27
+ // does `encodeURIComponent/decodeURIComponent` encoding on cookie fields. If we
28
+ // used the brackets, then the reconstructed cookie would look like
29
+ // `foo=bar; session-id=%5BREDACTED%5D`, which isn't helpful.
30
+ const COOKIE_VAL_REDACTED = 'REDACTED';
31
+
32
+ /**
33
+ * Extract appropriate `{transaction,error}.context.request` from an HTTP
34
+ * request object. This handles header and body capture and redaction
35
+ * according to the agent config.
36
+ *
37
+ * @param {Object} req - Typically `req` is a Node.js `http.IncomingMessage`
38
+ * (https://nodejs.org/api/all.html#all_http_class-httpincomingmessage).
39
+ * However, some cases (e.g. Lambda and Azure Functions instrumentation)
40
+ * create a pseudo-req object that matches well enough for this function.
41
+ * Some relevant fields: (TODO: document all used fields)
42
+ * - `headers` - Required. An object.
43
+ * - `body` - The incoming request body, if available. The `json` and
44
+ * `payload` fields are also checked to accomodate some web frameworks.
45
+ * - `bodyIsBase64Encoded` - An optional boolean. If `true`, then the `body`
46
+ * needs to be base64-decoded before inclusion and redaction. Used by
47
+ * Lambda instrumentation in some cases (e.g. for ELB triggers).
48
+ * @param {Object} conf - The full agent configuration.
49
+ * @param {String} type - 'errors' or 'transactions'. Indicates if this req
50
+ * is being captured for an APM error or transaction event.
51
+ */
52
+ function getContextFromRequest(req, conf, type) {
53
+ var captureBody = conf.captureBody === type || conf.captureBody === 'all';
54
+
55
+ var context = {
56
+ http_version: req.httpVersion,
57
+ method: req.method,
58
+ url: getUrlFromRequest(req),
59
+ headers: undefined,
60
+ };
61
+ if (req.socket && req.socket.remoteAddress) {
62
+ context.socket = {
63
+ remote_address: req.socket.remoteAddress,
64
+ };
65
+ }
66
+
67
+ if (conf.captureHeaders) {
68
+ context.headers = redactKeysFromObject(
69
+ req.headers,
70
+ conf.sanitizeFieldNamesRegExp,
71
+ );
72
+
73
+ if (context.headers.cookie && context.headers.cookie !== REDACTED) {
74
+ let cookies = cookie.parse(req.headers.cookie);
75
+ cookies = redactKeysFromObject(
76
+ cookies,
77
+ conf.sanitizeFieldNamesRegExp,
78
+ COOKIE_VAL_REDACTED,
79
+ );
80
+ try {
81
+ context.headers.cookie = Object.keys(cookies)
82
+ .map((k) => cookie.serialize(k, cookies[k]))
83
+ .join('; ');
84
+ } catch (_err) {
85
+ // Fallback to full redaction if there is an issue re-serializing.
86
+ context.headers.cookie = REDACTED;
87
+ }
88
+ }
89
+ }
90
+
91
+ var contentLength = parseInt(req.headers['content-length'], 10);
92
+ var transferEncoding = req.headers['transfer-encoding'];
93
+ var chunked =
94
+ typeof transferEncoding === 'string' &&
95
+ transferEncoding.toLowerCase() === 'chunked';
96
+ var body = req.json || req.body || req.payload;
97
+ var haveBody = body && (chunked || contentLength > 0);
98
+
99
+ if (haveBody) {
100
+ if (!captureBody) {
101
+ context.body = '[REDACTED]';
102
+ } else if (Buffer.isBuffer(body)) {
103
+ context.body = '<Buffer>';
104
+ } else {
105
+ if (typeof body === 'string' && req.bodyIsBase64Encoded === true) {
106
+ body = Buffer.from(body, 'base64').toString('utf8');
107
+ }
108
+ body = redactKeysFromPostedFormVariables(
109
+ body,
110
+ req.headers,
111
+ conf.sanitizeFieldNamesRegExp,
112
+ );
113
+ if (typeof body !== 'string') {
114
+ body = tryJsonStringify(body) || stringify(body);
115
+ }
116
+ context.body = body;
117
+ }
118
+ }
119
+
120
+ // TODO: Tempoary fix for https://github.com/elastic/apm-agent-nodejs/issues/813
121
+ if (context.url && context.url.port) {
122
+ context.url.port = String(context.url.port);
123
+ }
124
+
125
+ return context;
126
+ }
127
+
128
+ /**
129
+ * Extract appropriate `{transaction,error}.context.response` from an HTTP
130
+ * response object. This handles header redaction according to the agent config.
131
+ *
132
+ * @param {Object} res - Typically `res` is a Node.js `http.ServerResponse`
133
+ * (https://nodejs.org/api/http.html#class-httpserverresponse).
134
+ * However, some cases (e.g. Lambda and Azure Functions instrumentation)
135
+ * create a pseudo-res object that matches well enough for this function.
136
+ * Some relevant fields: (TODO: document all used fields)
137
+ * - `statusCode` - Required. A number.
138
+ * - `headers` - An object.
139
+ * - `headersSent` - Boolean indicating if the headers have been sent
140
+ * (https://nodejs.org/api/http.html#outgoingmessageheaderssent)
141
+ * - `finished` - Boolean indicating if `response.end()` has been called
142
+ * (https://nodejs.org/api/http.html#responsefinished)
143
+ * @param {Object} conf - The full agent configuration.
144
+ * @param {Boolean} isError - Indicates if this response contains an error and
145
+ * some extra fields should be added to the context
146
+ */
147
+ function getContextFromResponse(res, conf, isError) {
148
+ var context = {
149
+ status_code: res.statusCode,
150
+ headers: undefined,
151
+ };
152
+
153
+ if (conf.captureHeaders) {
154
+ context.headers = res.headers || parseHttpHeadersFromReqOrRes(res, true);
155
+ context.headers = redactKeysFromObject(
156
+ context.headers,
157
+ conf.sanitizeFieldNamesRegExp,
158
+ );
159
+ }
160
+
161
+ if (isError) {
162
+ context.headers_sent = res.headersSent;
163
+ if (typeof res.finished === 'boolean') {
164
+ context.finished = res.finished;
165
+ } else {
166
+ context.finished = res.writableEnded;
167
+ }
168
+ }
169
+
170
+ return context;
171
+ }
172
+
173
+ /**
174
+ * Extract appropriate `{transaction,error}.context.user` from an HTTP
175
+ * request object.
176
+ *
177
+ * @param {Object} req - Typically `req` is a Node.js `http.IncomingMessage`.
178
+ * However, some cases (e.g. Lambda and Azure Functions instrumentation)
179
+ * create a pseudo-req object that matches well enough for this function.
180
+ * Some relevant fields: (TODO: document all used fields)
181
+ * - `headers` - Required. An object.
182
+ */
183
+ function getUserContextFromRequest(req) {
184
+ var user = req.user || basicAuth(req) || req.session;
185
+ if (!user) {
186
+ return;
187
+ }
188
+
189
+ var context = {};
190
+
191
+ if (typeof user.id === 'string' || typeof user.id === 'number') {
192
+ context.id = user.id;
193
+ } else if (typeof user._id === 'string' || typeof user._id === 'number') {
194
+ context.id = user._id;
195
+ }
196
+
197
+ if (typeof user.username === 'string') {
198
+ context.username = user.username;
199
+ } else if (typeof user.name === 'string') {
200
+ context.username = user.name;
201
+ }
202
+
203
+ if (typeof user.email === 'string') {
204
+ context.email = user.email;
205
+ }
206
+
207
+ return context;
208
+ }
209
+
210
+ function parseUrl(urlStr) {
211
+ return new url.URL(urlStr, 'relative:///');
212
+ }
213
+
214
+ function tryJsonStringify(obj) {
215
+ try {
216
+ return JSON.stringify(obj);
217
+ } catch (e) {}
218
+ }
219
+
220
+ module.exports = {
221
+ getContextFromRequest,
222
+ getContextFromResponse,
223
+ getUserContextFromRequest,
224
+ parseUrl,
225
+ };
@@ -0,0 +1,147 @@
1
+ /*
2
+ * Copyright Elasticsearch B.V. and other contributors where applicable.
3
+ * Licensed under the BSD 2-Clause License; you may not use this file except in
4
+ * compliance with the BSD 2-Clause License.
5
+ */
6
+
7
+ 'use strict';
8
+
9
+ // Utilities to wrap properties of an object.
10
+ //
11
+ // This is similar to "./instrumentation/shimmer.js". However, it uses a
12
+ // different technique to support wrapping properties that are only available
13
+ // via a getter (i.e. their property descriptor is `.writable === false`).
14
+
15
+ /*
16
+ * This block is derived from esbuild's bundling support.
17
+ * https://github.com/evanw/esbuild/blob/v0.14.42/internal/runtime/runtime.go#L22
18
+ *
19
+ * License:
20
+ * MIT License
21
+ *
22
+ * Copyright (c) 2020 Evan Wallace
23
+ *
24
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
25
+ * of this software and associated documentation files (the "Software"), to deal
26
+ * in the Software without restriction, including without limitation the rights
27
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
28
+ * copies of the Software, and to permit persons to whom the Software is
29
+ * furnished to do so, subject to the following conditions:
30
+ *
31
+ * The above copyright notice and this permission notice shall be included in all
32
+ * copies or substantial portions of the Software.
33
+ *
34
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
35
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
36
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
37
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
38
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
39
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
40
+ * SOFTWARE.
41
+ */
42
+ var __defProp = Object.defineProperty;
43
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
44
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
45
+ var __getOwnPropNames = Object.getOwnPropertyNames;
46
+ var __copyProps = (to, from, except, desc) => {
47
+ if ((from && typeof from === 'object') || typeof from === 'function') {
48
+ for (const key of __getOwnPropNames(from)) {
49
+ if (!__hasOwnProp.call(to, key) && key !== except) {
50
+ __defProp(to, key, {
51
+ get: () => from[key],
52
+ enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable,
53
+ });
54
+ }
55
+ }
56
+ }
57
+ return to;
58
+ };
59
+
60
+ /**
61
+ * Return a new object that is a copy of `obj`, with its `subpath` property
62
+ * replaced with the return value of `wrapper(original)`.
63
+ *
64
+ * For example:
65
+ * var os = wrap(require('os'), 'platform', (orig) => {
66
+ * return function wrappedPlatform () {
67
+ * return orig().toUpperCase()
68
+ * }
69
+ * })
70
+ * console.log(os.platform()) // => DARWIN
71
+ *
72
+ * The subpath can indicate a nested property. Each property in that subpath,
73
+ * except the last, must identify an *Object*.
74
+ *
75
+ * Limitations:
76
+ * - This doesn't handle possible Symbol properties on the copied object(s).
77
+ * - This cannot wrap a property of a function, because we cannot create a
78
+ * copy of the function.
79
+ *
80
+ * @param {Object} obj
81
+ * @param {String} subpath - The property subpath on `obj` to wrap. This may
82
+ * point to a nested property by using a '.' to separate levels. For example:
83
+ * var fs = wrap(fs, 'promises.sync', (orig) => { ... })
84
+ * @param {Function} wrapper - A function of the form `function (orig)`, where
85
+ * `orig` is the original property value. This must synchronously return the
86
+ * new property value.
87
+ * @returns {Object} A new object with the wrapped property.
88
+ * @throws {TypeError} if the subpath points to a non-existant property, or if
89
+ * any but the last subpath part points to a non-Object.
90
+ */
91
+ function wrap(obj, subpath, wrapper) {
92
+ const parts = subpath.split('.');
93
+ const namespaces = [obj];
94
+ let namespace = obj;
95
+ let key;
96
+ let val;
97
+
98
+ // 1. Traverse the subpath parts to sanity check and get references to the
99
+ // Objects that will will be copying.
100
+ for (let i = 0; i < parts.length; i++) {
101
+ key = parts[i];
102
+ val = namespace[key];
103
+ if (!val) {
104
+ throw new TypeError(
105
+ `cannot wrap "${subpath}": "<obj>.${parts
106
+ .slice(0, i)
107
+ .join('.')}" is ${typeof val}`,
108
+ );
109
+ } else if (i < parts.length - 1) {
110
+ if (typeof val !== 'object') {
111
+ throw new TypeError(
112
+ `cannot wrap "${subpath}": "<obj>.${parts
113
+ .slice(0, i)
114
+ .join('.')}" is not an Object`,
115
+ );
116
+ }
117
+ namespace = val;
118
+ namespaces.push(namespace);
119
+ }
120
+ }
121
+
122
+ // 2. Now work backwards, wrapping each namespace with a new object that has a
123
+ // copy of all the properties, except the one that we've wrapped.
124
+ for (let i = parts.length - 1; i >= 0; i--) {
125
+ key = parts[i];
126
+ namespace = namespaces[i];
127
+ if (i === parts.length - 1) {
128
+ const orig = namespace[key];
129
+ val = wrapper(orig);
130
+ } else {
131
+ val = namespaces[i + 1];
132
+ }
133
+ const desc = __getOwnPropDesc(namespace, key);
134
+ const wrappedNamespace = __defProp({}, key, {
135
+ value: val,
136
+ enumerable: !desc || desc.enumerable,
137
+ });
138
+ __copyProps(wrappedNamespace, namespace, key);
139
+ namespaces[i] = wrappedNamespace;
140
+ }
141
+
142
+ return namespaces[0];
143
+ }
144
+
145
+ module.exports = {
146
+ wrap,
147
+ };