oracledb 7.0.1 → 26.0.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 (74) hide show
  1. package/README.md +16 -6
  2. package/build/Release/oracledb-26.0.0-darwin-arm64.node +0 -0
  3. package/build/Release/oracledb-26.0.0-darwin-arm64.node-buildinfo.txt +1 -0
  4. package/build/Release/oracledb-26.0.0-js-buildinfo.txt +1 -0
  5. package/build/Release/oracledb-26.0.0-linux-arm64.node +0 -0
  6. package/build/Release/oracledb-26.0.0-linux-arm64.node-buildinfo.txt +1 -0
  7. package/build/Release/oracledb-26.0.0-linux-x64.node +0 -0
  8. package/build/Release/oracledb-26.0.0-linux-x64.node-buildinfo.txt +1 -0
  9. package/build/Release/oracledb-26.0.0-win32-x64.node +0 -0
  10. package/build/Release/oracledb-26.0.0-win32-x64.node-buildinfo.txt +1 -0
  11. package/lib/connection.js +71 -8
  12. package/lib/constants.js +4 -0
  13. package/lib/endUserSecurityContext.js +20 -8
  14. package/lib/errors.js +70 -5
  15. package/lib/impl/connection.js +36 -0
  16. package/lib/impl/datahandlers/buffer.js +91 -18
  17. package/lib/impl/datahandlers/oson.js +3 -2
  18. package/lib/impl/resultset.js +32 -11
  19. package/lib/oracledb.js +34 -0
  20. package/lib/pool.js +6 -2
  21. package/lib/queryStream.js +13 -5
  22. package/lib/resultset.js +10 -3
  23. package/lib/securityContextProvider.js +206 -0
  24. package/lib/thin/aq.js +2 -3
  25. package/lib/thin/connection.js +381 -19
  26. package/lib/thin/dbObject.js +17 -8
  27. package/lib/thin/pool.js +3 -2
  28. package/lib/thin/protocol/capabilities.js +37 -4
  29. package/lib/thin/protocol/constants.js +49 -1
  30. package/lib/thin/protocol/messages/auth.js +17 -6
  31. package/lib/thin/protocol/messages/base.js +74 -16
  32. package/lib/thin/protocol/messages/dataType.js +46 -0
  33. package/lib/thin/protocol/messages/directPathLoadStream.js +3 -2
  34. package/lib/thin/protocol/messages/execute.js +10 -4
  35. package/lib/thin/protocol/messages/index.js +4 -0
  36. package/lib/thin/protocol/messages/notification.js +281 -0
  37. package/lib/thin/protocol/messages/subscribe.js +181 -0
  38. package/lib/thin/protocol/messages/withData.js +21 -7
  39. package/lib/thin/protocol/packet.js +2 -4
  40. package/lib/thin/protocol/protocol.js +7 -4
  41. package/lib/thin/resultSet.js +40 -20
  42. package/lib/thin/sqlnet/ezConnectResolver.js +7 -0
  43. package/lib/thin/sqlnet/navNodes.js +3 -3
  44. package/lib/thin/sqlnet/ntTcp.js +24 -8
  45. package/lib/thin/statement.js +6 -1
  46. package/lib/thin/statementCache.js +34 -6
  47. package/lib/thin/subscr.js +363 -0
  48. package/lib/transformer.js +60 -17
  49. package/lib/util.js +46 -8
  50. package/lib/version.js +2 -2
  51. package/package.json +1 -1
  52. package/plugins/configProviders/gcpstorage/index.js +121 -0
  53. package/plugins/configProviders/ociobject/index.js +1 -1
  54. package/plugins/token/cache.js +154 -0
  55. package/plugins/token/endUserSecurityProvider/index.js +377 -0
  56. package/plugins/token/extensionAzure/index.js +160 -28
  57. package/plugins/token/extensionOci/index.js +221 -16
  58. package/plugins/vectorsdk/OracleVecDB.js +346 -0
  59. package/plugins/vectorsdk/index.js +49 -0
  60. package/plugins/vectorsdk/utils.js +370 -0
  61. package/plugins/vectorsdk/vectorEmbedding.js +223 -0
  62. package/plugins/vectorsdk/vectorIndex.js +177 -0
  63. package/plugins/vectorsdk/vectorRecords.js +406 -0
  64. package/plugins/vectorsdk/vectorSchema.js +408 -0
  65. package/plugins/vectorsdk/vectorSearch.js +538 -0
  66. package/build/Release/oracledb-7.0.1-darwin-arm64.node +0 -0
  67. package/build/Release/oracledb-7.0.1-darwin-arm64.node-buildinfo.txt +0 -1
  68. package/build/Release/oracledb-7.0.1-js-buildinfo.txt +0 -1
  69. package/build/Release/oracledb-7.0.1-linux-arm64.node +0 -0
  70. package/build/Release/oracledb-7.0.1-linux-arm64.node-buildinfo.txt +0 -1
  71. package/build/Release/oracledb-7.0.1-linux-x64.node +0 -0
  72. package/build/Release/oracledb-7.0.1-linux-x64.node-buildinfo.txt +0 -1
  73. package/build/Release/oracledb-7.0.1-win32-x64.node +0 -0
  74. package/build/Release/oracledb-7.0.1-win32-x64.node-buildinfo.txt +0 -1
@@ -1,4 +1,4 @@
1
- // Copyright (c) 2023, 2025, Oracle and/or its affiliates.
1
+ // Copyright (c) 2023, 2026, Oracle and/or its affiliates.
2
2
 
3
3
  //-----------------------------------------------------------------------------
4
4
  //
@@ -36,6 +36,12 @@ const util = require('util');
36
36
  const types = require('./types.js');
37
37
  const nodbUtil = require('./util.js');
38
38
 
39
+ const unsupportedJsonFieldNames = new Set([
40
+ '__proto__',
41
+ 'constructor',
42
+ 'prototype'
43
+ ]);
44
+
39
45
  //-----------------------------------------------------------------------------
40
46
  // checkType()
41
47
  //
@@ -78,12 +84,31 @@ function checkType(info, options) {
78
84
  //-----------------------------------------------------------------------------
79
85
  // transformJsonValue()
80
86
  //
81
- // Returns a normalized JSON value. Scalar values are returned unchanged.
82
- // Arrays are returned as a new array with transformed JSON values. Objects are
83
- // returned as new objects with keys "fields" and "values", both of which
84
- // are arrays (with the value transformed to JSON values).
87
+ // Returns a normalized JSON value. Supported scalar values are returned
88
+ // unchanged. Arrays are returned as a new array with transformed JSON values.
89
+ // Objects are returned as new objects with keys "fields" and "values", both of
90
+ // which are arrays (with the value transformed to JSON values).
91
+ // Only enumerable own object properties are included.
92
+ // If rejectUnsupportedTypes is set, unsupported JSON values, circular
93
+ // references, and field names are rejected.
85
94
  //-----------------------------------------------------------------------------
86
- function transformJsonValue(value) {
95
+ function transformJsonValue(value, options = {}, activeValues) {
96
+
97
+ // bigInt cannot be represented in JSON and is always rejected
98
+ if (typeof value === 'bigint') {
99
+ errors.throwErr(errors.ERR_UNSUPPORTED_JSON_VALUE_TYPE, typeof value);
100
+ }
101
+
102
+ // reject unsupported values when requested
103
+ if (options.rejectUnsupportedTypes &&
104
+ (typeof value === 'symbol' || typeof value === 'function')) {
105
+ errors.throwErr(errors.ERR_UNSUPPORTED_JSON_VALUE_TYPE, typeof value);
106
+ }
107
+
108
+ if (options.rejectUnsupportedTypes &&
109
+ typeof value === 'number' && !Number.isFinite(value)) {
110
+ errors.throwErr(errors.ERR_NON_FINITE_JSON_NUMBER);
111
+ }
87
112
 
88
113
  // handle simple scalars
89
114
  if (value === undefined || value === null ||
@@ -93,15 +118,6 @@ function transformJsonValue(value) {
93
118
  value instanceof types.IntervalYM || value instanceof types.IntervalDS)
94
119
  return value;
95
120
 
96
- // arrays are transformed to a new array with processed values
97
- if (Array.isArray(value)) {
98
- const outValue = new Array(value.length);
99
- for (let i = 0; i < value.length; i++) {
100
- outValue[i] = transformJsonValue(value[i]);
101
- }
102
- return outValue;
103
- }
104
-
105
121
  // database objects are treated as empty objects
106
122
  if (value instanceof BaseDbObject)
107
123
  return {fields: [], values: []};
@@ -112,14 +128,41 @@ function transformJsonValue(value) {
112
128
  return value;
113
129
  }
114
130
 
131
+ if (options.rejectUnsupportedTypes) {
132
+ if (!activeValues)
133
+ activeValues = new Set();
134
+ if (activeValues.has(value))
135
+ errors.throwErr(errors.ERR_INVALID_PARAMETER_VALUE, 1);
136
+ activeValues.add(value);
137
+ }
138
+
139
+ // arrays are transformed to a new array with processed values
140
+ if (Array.isArray(value)) {
141
+ const outValue = new Array(value.length);
142
+ for (let i = 0; i < value.length; i++) {
143
+ outValue[i] = transformJsonValue(value[i], options, activeValues);
144
+ }
145
+ if (activeValues)
146
+ activeValues.delete(value);
147
+ return outValue;
148
+ }
149
+
115
150
  // all other objects are transformed to an object with two arrays (fields
116
151
  // and values)
117
152
  const outValue = {};
118
- outValue.fields = Object.getOwnPropertyNames(value);
153
+ outValue.fields = Object.keys(value);
119
154
  outValue.values = new Array(outValue.fields.length);
120
155
  for (let i = 0; i < outValue.fields.length; i++) {
121
- outValue.values[i] = transformJsonValue(value[outValue.fields[i]]);
156
+ if (options.rejectUnsupportedTypes &&
157
+ unsupportedJsonFieldNames.has(outValue.fields[i])) {
158
+ errors.throwErr(errors.ERR_UNSUPPORTED_JSON_FIELD_NAME,
159
+ outValue.fields[i]);
160
+ }
161
+ outValue.values[i] = transformJsonValue(value[outValue.fields[i]], options,
162
+ activeValues);
122
163
  }
164
+ if (activeValues)
165
+ activeValues.delete(value);
123
166
  return outValue;
124
167
 
125
168
  }
package/lib/util.js CHANGED
@@ -33,6 +33,7 @@ const util = require('util');
33
33
  const types = require('./types.js');
34
34
  const constants = require('./constants.js');
35
35
  const traceHandler = require('./traceHandler.js');
36
+ const securityContextProvider = require('./securityContextProvider.js');
36
37
  const crypto = require("crypto");
37
38
 
38
39
  const pemHeaders = [
@@ -271,6 +272,8 @@ function wrapFn(func, serialize, preventConcurrentErrorCode) {
271
272
  let connImpl;
272
273
  const traceEnabled = traceHandler.isEnabled();
273
274
  const traceContext = {fn: func, args: arguments};
275
+ const hook = securityContextProvider.getInvocationHook();
276
+ let hookState;
274
277
 
275
278
  // if concurrent operations are to be prevented, check for that now
276
279
  if (preventConcurrentErrorCode) {
@@ -295,12 +298,29 @@ function wrapFn(func, serialize, preventConcurrentErrorCode) {
295
298
  if (traceEnabled) {
296
299
  traceEnterFn.call(this, traceContext);
297
300
  }
301
+ if (hook?.before) {
302
+ // more attributes like args, sql can be passed to
303
+ // provider later.
304
+ const invocation = {
305
+ target: this,
306
+ connection: connImpl
307
+ };
308
+ hookState = await hook.before(invocation);
309
+ }
298
310
  result = await traceContext.fn.apply(this, arguments);
299
- return result;
300
311
  } catch (err) {
301
312
  tErr = errors.transformErr(err, wrapper);
302
- throw tErr;
303
313
  } finally {
314
+ if (hook?.after && hookState) {
315
+ try {
316
+ await hook.after(hookState);
317
+ } catch (err) {
318
+ // Preserve the operation's error if both fail.
319
+ if (!tErr) {
320
+ tErr = errors.transformErr(err, wrapper);
321
+ }
322
+ }
323
+ }
304
324
  if (connImpl)
305
325
  connImpl._releaseLock();
306
326
  if (preventConcurrentErrorCode) {
@@ -311,6 +331,10 @@ function wrapFn(func, serialize, preventConcurrentErrorCode) {
311
331
  }
312
332
  }
313
333
 
334
+ if (tErr) {
335
+ throw tErr;
336
+ }
337
+ return result;
314
338
  };
315
339
  if (func.name) {
316
340
  Object.defineProperty(wrapper, 'name', { value: func.name });
@@ -563,19 +587,33 @@ function isVectorValue(value) {
563
587
  === Uint8Array.prototype) || value instanceof types.SparseVector);
564
588
  }
565
589
 
566
- //-----------------------------------------------------------------------------
590
+ //---------------------------------------------------------------------------
567
591
  // makeDate()
568
592
  //
569
- // Returns a date from the given components.
570
- //
571
- // -----------------------------------------------------------------------------
593
+ // Creates a Date from the supplied date/time components. When useLocal is
594
+ // true, the components are interpreted in the Node.js process local timezone.
595
+ // Otherwise, they are interpreted using the supplied UTC offset.
596
+ //---------------------------------------------------------------------------
572
597
  function makeDate(useLocal, year, month, day, hour, minute,
573
598
  second, fseconds, offset) {
574
599
  if (useLocal) {
575
600
  return new Date(year, month - 1, day, hour, minute, second, fseconds);
576
601
  }
577
- return new Date(Date.UTC(year, month - 1, day, hour, minute, second,
578
- fseconds) - offset * 60000);
602
+ return new Date(makeUTCDate(year, month, day, hour, minute, second,
603
+ fseconds).getTime() - offset * 60000);
604
+ }
605
+
606
+ //-----------------------------------------------------------------------------
607
+ // makeUTCDate()
608
+ //
609
+ // Creates a UTC date without Date.UTC()'s special handling of years 0 through
610
+ // 99, which is important when calculating historical timezone offsets.
611
+ // -----------------------------------------------------------------------------
612
+ function makeUTCDate(year, month, day, hour, minute, second, fseconds = 0) {
613
+ const date = new Date(0);
614
+ date.setUTCFullYear(year, month - 1, day);
615
+ date.setUTCHours(hour, minute, second, fseconds);
616
+ return date;
579
617
  }
580
618
 
581
619
  //---------------------------------------------------------------------------
package/lib/version.js CHANGED
@@ -29,8 +29,8 @@
29
29
  // Leave the suffix an empty string for production releases.
30
30
 
31
31
  module.exports = {
32
- VERSION_MAJOR: 7,
32
+ VERSION_MAJOR: 26,
33
33
  VERSION_MINOR: 0,
34
- VERSION_PATCH: 1,
34
+ VERSION_PATCH: 0,
35
35
  VERSION_SUFFIX: ''
36
36
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "oracledb",
3
- "version": "7.0.1",
3
+ "version": "26.0.0",
4
4
  "description": "A Node.js module for Oracle Database access from JavaScript and TypeScript",
5
5
  "license": "(Apache-2.0 OR UPL-1.0)",
6
6
  "homepage": "http://oracle.github.io/node-oracledb/",
@@ -0,0 +1,121 @@
1
+ // Copyright (c) 2026, Oracle and/or its affiliates.
2
+ //-----------------------------------------------------------------------------
3
+ //
4
+ // This software is dual-licensed to you under the Universal Permissive License
5
+ // (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl and Apache License
6
+ // 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose
7
+ // either license.
8
+ //
9
+ // If you elect to accept the software under the Apache License, Version 2.0,
10
+ // the following applies:
11
+ //
12
+ // Licensed under the Apache License, Version 2.0 (the "License");
13
+ // you may not use this file except in compliance with the License.
14
+ // You may obtain a copy of the License at
15
+ //
16
+ // https://www.apache.org/licenses/LICENSE-2.0
17
+ //
18
+ // Unless required by applicable law or agreed to in writing, software
19
+ // distributed under the License is distributed on an "AS IS" BASIS,
20
+ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
21
+ // See the License for the specific language governing permissions and
22
+ // limitations under the License.
23
+ //
24
+ //-----------------------------------------------------------------------------
25
+
26
+ "use strict";
27
+
28
+ const util = require("node:util");
29
+ const { base } = require("../base.js");
30
+ const oracledb = require("oracledb");
31
+
32
+ let Storage;
33
+
34
+ class GCPStorageProvider extends base {
35
+ constructor(provider_arg, urlExtendedPart) {
36
+ super(urlExtendedPart);
37
+ this.parseProviderArg(provider_arg);
38
+ }
39
+
40
+ init() {
41
+ ({ Storage } = require("@google-cloud/storage"));
42
+ }
43
+
44
+ parseProviderArg(providerArg) {
45
+ for (const entry of providerArg.split(";")) {
46
+ const [key, ...valueParts] = entry.split("=");
47
+ const value = valueParts.join("=");
48
+
49
+ if (!key || !value) {
50
+ throw new Error(
51
+ "GCP Storage Config Provider argument must use bucket=<bucket>;object=<object>;project=<project> is optional."
52
+ );
53
+ }
54
+
55
+ this._addParam(key.trim(), decodeURIComponent(value.trim()));
56
+ }
57
+
58
+ for (const key of ["bucket", "object"]) {
59
+ if (!this.paramMap.get(key)) {
60
+ throw new Error(
61
+ `GCP Storage Config Provider missing required ${key} value.`
62
+ );
63
+ }
64
+ }
65
+ }
66
+
67
+ async returnConfig() {
68
+ const bucket = this.paramMap.get("bucket");
69
+ const object = this.paramMap.get("object");
70
+
71
+ const storageOptions = {};
72
+ const projectId = this.paramMap.get("project");
73
+ if (projectId) {
74
+ storageOptions.projectId = projectId;
75
+ }
76
+
77
+ // The Storage client manages the lifecycle of its underlying connections,
78
+ // no explicit close is required after downloading the configuration.
79
+ const storage = new Storage(storageOptions);
80
+
81
+ try {
82
+ const [contents] = await storage
83
+ .bucket(bucket)
84
+ .file(object)
85
+ .download();
86
+ return JSON.parse(contents.toString("utf-8"));
87
+ } catch (e) {
88
+ const errmsg = util.format(
89
+ "Failed to retrieve or parse config from GCP Storage: %s\n%s",
90
+ e.message,
91
+ e.stack
92
+ );
93
+ throw new Error(errmsg);
94
+ }
95
+ }
96
+ }
97
+
98
+ module.exports = GCPStorageProvider;
99
+
100
+ async function hookFn(args) {
101
+ const configProvider = new GCPStorageProvider(
102
+ args.provider_arg,
103
+ args.urlExtendedPart
104
+ );
105
+
106
+ try {
107
+ configProvider.init();
108
+ } catch (err) {
109
+ const errmsg = util.format(
110
+ "GCP Storage Config Provider failed to load required modules: %s\n%s",
111
+ err.message,
112
+ err.stack
113
+ );
114
+ throw new Error(errmsg);
115
+ }
116
+
117
+ const cfg = await configProvider.returnConfig();
118
+ return [cfg, null];
119
+ }
120
+
121
+ oracledb.registerConfigurationProviderHook("gcpstorage", hookFn);
@@ -87,7 +87,7 @@ class OCIProvider extends base {
87
87
  if (auth == 'OCI_INSTANCE_PRINCIPAL') {
88
88
  provider = await oci.common.InstancePrincipalsAuthenticationDetailsProviderBuilder().build();
89
89
  } else if (auth == 'OCI_RESOURCE_PRINCIPAL') {
90
- provider = await new oci.common.ResourcePrincipalAuthenticationDetailsProvider.builder();
90
+ provider = oci.common.ResourcePrincipalAuthenticationDetailsProvider.builder();
91
91
  } else {
92
92
  const errmsg = util.format('OCI authentication failed: The authentication parameter value %s may be incorrect', auth);
93
93
  throw new Error(errmsg);
@@ -0,0 +1,154 @@
1
+ // Copyright (c) 2026, Oracle and/or its affiliates.
2
+
3
+ //-----------------------------------------------------------------------------
4
+ //
5
+ // This software is dual-licensed to you under the Universal Permissive License
6
+ // (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl and Apache License
7
+ // 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose
8
+ // either license.
9
+ //
10
+ // If you elect to accept the software under the Apache License, Version 2.0,
11
+ // the following applies:
12
+ //
13
+ // Licensed under the Apache License, Version 2.0 (the "License");
14
+ // you may not use this file except in compliance with the License.
15
+ // You may obtain a copy of the License at
16
+ //
17
+ // https://www.apache.org/licenses/LICENSE-2.0
18
+ //
19
+ // Unless required by applicable law or agreed to in writing, software
20
+ // distributed under the License is distributed on an "AS IS" BASIS,
21
+ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
22
+ // See the License for the specific language governing permissions and
23
+ // limitations under the License.
24
+ //
25
+ // Shared process-wide token-cache support for built-in token extensions.
26
+ //-----------------------------------------------------------------------------
27
+ 'use strict';
28
+
29
+ const crypto = require('crypto');
30
+ const { ObfuscatedValue } = require('../../lib/obfuscation.js');
31
+
32
+ //---------------------------------------------------------------------------
33
+ // hashValue()
34
+ //
35
+ // Hash a secret before it becomes part of a process-wide cache key. A changed
36
+ // secret gets a distinct entry without retaining plaintext credentials in a
37
+ // Map key.
38
+ //---------------------------------------------------------------------------
39
+ function hashValue(value) {
40
+ return crypto.createHash('sha256').update(String(value)).digest('hex');
41
+ }
42
+
43
+ //---------------------------------------------------------------------------
44
+ // TokenCache
45
+ //
46
+ // A process-wide bounded LRU cache with expiry-aware lookup and single-flight
47
+ // acquisition. Cached token values are obfuscated, including object values
48
+ // such as OCI token/private-key pairs. acquire() may be synchronous or async
49
+ // and returns { value, validUntil }. Entries without a future validUntil are
50
+ // returned but intentionally not cached.
51
+ //---------------------------------------------------------------------------
52
+ class TokenCache {
53
+ constructor(maxEntries) {
54
+ this._maxEntries = maxEntries;
55
+ this._entries = new Map();
56
+ this._inFlight = new Map();
57
+ }
58
+
59
+ async get(key, acquire, { enabled = true } = {}) {
60
+ if (enabled) {
61
+ const cached = this._entries.get(key);
62
+ if (cached?.validUntil > Date.now()) {
63
+ // Moving the hit to the end maintains insertion-order LRU semantics.
64
+ this._entries.delete(key);
65
+ this._entries.set(key, cached);
66
+ return {
67
+ value: restoreValue(cached.value),
68
+ validUntil: cached.validUntil,
69
+ isCacheHit: true,
70
+ };
71
+ }
72
+ if (cached) {
73
+ clearValue(cached.value);
74
+ this._entries.delete(key);
75
+ }
76
+ }
77
+
78
+ let request = this._inFlight.get(key);
79
+ if (!request) {
80
+ request = Promise.resolve().then(acquire).then((result) => {
81
+ if (enabled && result?.validUntil > Date.now()) {
82
+ this._evictLeastRecentlyUsed();
83
+ this._entries.set(key, {
84
+ value: protectValue(result.value),
85
+ validUntil: result.validUntil,
86
+ });
87
+ }
88
+ return result;
89
+ });
90
+ this._inFlight.set(key, request);
91
+ }
92
+ try {
93
+ const result = await request;
94
+ return {
95
+ value: result.value,
96
+ validUntil: result.validUntil,
97
+ isCacheHit: false,
98
+ };
99
+ } finally {
100
+ if (this._inFlight.get(key) === request) {
101
+ this._inFlight.delete(key);
102
+ }
103
+ }
104
+ }
105
+
106
+ _evictLeastRecentlyUsed() {
107
+ while (this._entries.size >= this._maxEntries) {
108
+ const oldestKey = this._entries.keys().next().value;
109
+ const oldestEntry = this._entries.get(oldestKey);
110
+ clearValue(oldestEntry.value);
111
+ this._entries.delete(oldestKey);
112
+ }
113
+ }
114
+ }
115
+
116
+ function protectValue(value) {
117
+ if (typeof value === 'string') {
118
+ return new ObfuscatedValue(value);
119
+ }
120
+ if (Array.isArray(value)) {
121
+ return value.map(protectValue);
122
+ }
123
+ if (value && typeof value === 'object') {
124
+ return Object.fromEntries(Object.entries(value).map(([key, entry]) =>
125
+ [key, protectValue(entry)]));
126
+ }
127
+ return value;
128
+ }
129
+
130
+ function restoreValue(value) {
131
+ if (value instanceof ObfuscatedValue) {
132
+ return value.get();
133
+ }
134
+ if (Array.isArray(value)) {
135
+ return value.map(restoreValue);
136
+ }
137
+ if (value && typeof value === 'object') {
138
+ return Object.fromEntries(Object.entries(value).map(([key, entry]) =>
139
+ [key, restoreValue(entry)]));
140
+ }
141
+ return value;
142
+ }
143
+
144
+ function clearValue(value) {
145
+ if (value instanceof ObfuscatedValue) {
146
+ value.clear();
147
+ } else if (Array.isArray(value)) {
148
+ value.forEach(clearValue);
149
+ } else if (value && typeof value === 'object') {
150
+ Object.values(value).forEach(clearValue);
151
+ }
152
+ }
153
+
154
+ module.exports = { TokenCache, hashValue };