@gobing-ai/ts-utils 0.4.14 → 0.4.15

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.
package/dist/object.d.ts CHANGED
@@ -4,6 +4,13 @@ export declare function isPlainObject(value: unknown): value is Record<string, u
4
4
  * Recursively merge `source` into `target`, returning a new object. Nested plain objects merge;
5
5
  * arrays and scalars from `source` replace the target wholesale (a source array overrides, never
6
6
  * extends). Inputs are not mutated.
7
+ *
8
+ * A `__proto__` key in `source` is skipped: plain assignment would invoke the inherited
9
+ * `__proto__` setter and hand the returned object an attacker-controlled prototype, so
10
+ * `deepMerge(defaults, JSON.parse(userInput))` could resolve absent keys through it. Sibling
11
+ * keys like `constructor` need no guard here — `result` is a fresh object at every level
12
+ * (`{ ...target }`), so assigning them shadows an own property rather than mutating
13
+ * `Object.prototype`.
7
14
  */
8
15
  export declare function deepMerge(target: Record<string, unknown>, source: Record<string, unknown>): Record<string, unknown>;
9
16
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"object.d.ts","sourceRoot":"","sources":["../src/object.ts"],"names":[],"mappings":"AAAA,2GAA2G;AAC3G,wBAAgB,aAAa,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAE9E;AAED;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAUnH;AAED;;;GAGG;AACH,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,SAAK,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAW7F;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAetF"}
1
+ {"version":3,"file":"object.d.ts","sourceRoot":"","sources":["../src/object.ts"],"names":[],"mappings":"AAAA,2GAA2G;AAC3G,wBAAgB,aAAa,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAE9E;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,SAAS,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAWnH;AAED;;;GAGG;AACH,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,SAAK,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAW7F;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAetF"}
package/dist/object.js CHANGED
@@ -6,10 +6,19 @@ export function isPlainObject(value) {
6
6
  * Recursively merge `source` into `target`, returning a new object. Nested plain objects merge;
7
7
  * arrays and scalars from `source` replace the target wholesale (a source array overrides, never
8
8
  * extends). Inputs are not mutated.
9
+ *
10
+ * A `__proto__` key in `source` is skipped: plain assignment would invoke the inherited
11
+ * `__proto__` setter and hand the returned object an attacker-controlled prototype, so
12
+ * `deepMerge(defaults, JSON.parse(userInput))` could resolve absent keys through it. Sibling
13
+ * keys like `constructor` need no guard here — `result` is a fresh object at every level
14
+ * (`{ ...target }`), so assigning them shadows an own property rather than mutating
15
+ * `Object.prototype`.
9
16
  */
10
17
  export function deepMerge(target, source) {
11
18
  const result = { ...target };
12
19
  for (const [key, value] of Object.entries(source)) {
20
+ if (key === '__proto__')
21
+ continue;
13
22
  if (isPlainObject(value) && isPlainObject(result[key])) {
14
23
  result[key] = deepMerge(result[key], value);
15
24
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gobing-ai/ts-utils",
3
- "version": "0.4.14",
3
+ "version": "0.4.15",
4
4
  "description": "Zero-dependency TypeScript utilities for dates, cursors, errors, output, origins, roles, and API responses.",
5
5
  "keywords": [
6
6
  "typescript",
package/src/object.ts CHANGED
@@ -7,10 +7,18 @@ export function isPlainObject(value: unknown): value is Record<string, unknown>
7
7
  * Recursively merge `source` into `target`, returning a new object. Nested plain objects merge;
8
8
  * arrays and scalars from `source` replace the target wholesale (a source array overrides, never
9
9
  * extends). Inputs are not mutated.
10
+ *
11
+ * A `__proto__` key in `source` is skipped: plain assignment would invoke the inherited
12
+ * `__proto__` setter and hand the returned object an attacker-controlled prototype, so
13
+ * `deepMerge(defaults, JSON.parse(userInput))` could resolve absent keys through it. Sibling
14
+ * keys like `constructor` need no guard here — `result` is a fresh object at every level
15
+ * (`{ ...target }`), so assigning them shadows an own property rather than mutating
16
+ * `Object.prototype`.
10
17
  */
11
18
  export function deepMerge(target: Record<string, unknown>, source: Record<string, unknown>): Record<string, unknown> {
12
19
  const result = { ...target };
13
20
  for (const [key, value] of Object.entries(source)) {
21
+ if (key === '__proto__') continue;
14
22
  if (isPlainObject(value) && isPlainObject(result[key])) {
15
23
  result[key] = deepMerge(result[key] as Record<string, unknown>, value);
16
24
  } else {