@powerduck/conf-patch 0.3.1 → 0.3.2

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/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # @powerduckie/confedit
1
+ # @powerduck/conf-patch
2
2
 
3
3
  A production-grade configuration editor with a clean **two-layer architecture**:
4
4
 
@@ -37,9 +37,9 @@ RFC 6902 JSON Patch semantics, comment and formatting preservation, OpenAPI vali
37
37
  ## Installation
38
38
 
39
39
  ```bash
40
- npm install @powerduckie/confedit
41
- pnpm add @powerduckie/confedit
42
- yarn add @powerduckie/confedit
40
+ npm install @powerduck/conf-patch
41
+ pnpm add @powerduck/conf-patch
42
+ yarn add @powerduck/conf-patch
43
43
  ```
44
44
 
45
45
  ## Module System Support
@@ -50,20 +50,20 @@ This package supports both **CommonJS (`require`)** and **ES Modules (`import`)*
50
50
 
51
51
  ```javascript
52
52
  // Full library (includes file IO)
53
- const { setConfigValue, readConfigFile } = require("@powerduckie/confedit");
53
+ const { setConfigValue, readConfigFile } = require("@powerduck/conf-patch");
54
54
 
55
55
  // Core layer only (browser-safe, no fs dependency)
56
- const { patchContent, setContentValue } = require("@powerduckie/confedit/core");
56
+ const { patchContent, setContentValue } = require("@powerduck/conf-patch/core");
57
57
  ```
58
58
 
59
59
  ### ES Modules (modern Node.js / browsers / bundlers)
60
60
 
61
61
  ```typescript
62
62
  // Full library
63
- import { setConfigValue, readConfigFile } from "@powerduckie/confedit";
63
+ import { setConfigValue, readConfigFile } from "@powerduck/conf-patch";
64
64
 
65
65
  // Core layer only (browser-safe)
66
- import { patchContent, setContentValue } from "@powerduckie/confedit/core";
66
+ import { patchContent, setContentValue } from "@powerduck/conf-patch/core";
67
67
  ```
68
68
 
69
69
  ### Build Outputs
@@ -79,12 +79,12 @@ The package does not set `"type": "module"`, so `.js` files are treated as Commo
79
79
 
80
80
  ### Browser Usage (Core Layer Only)
81
81
 
82
- > **Important:** For browser usage, import from `@powerduckie/confedit/core` (subpath export).
82
+ > **Important:** For browser usage, import from `@powerduck/conf-patch/core` (subpath export).
83
83
  > This ensures the file layer (which depends on `node:fs`) is not bundled into your browser code.
84
84
  > The core entry is only ~9KB gzipped and has zero Node.js dependencies.
85
85
 
86
86
  ```typescript
87
- import { patchContent, setContentValue, deleteContentValue } from "@powerduckie/confedit/core";
87
+ import { patchContent, setContentValue, deleteContentValue } from "@powerduck/conf-patch/core";
88
88
 
89
89
  // Patch a JSON string (no filesystem access)
90
90
  const updated = patchContent(
@@ -106,7 +106,7 @@ localStorage.setItem("config", updated);
106
106
  ### Node.js / Electron Usage (File Layer)
107
107
 
108
108
  ```typescript
109
- import { setConfigValue, readConfigFile, patchConfigFile } from "@powerduckie/confedit";
109
+ import { setConfigValue, readConfigFile, patchConfigFile } from "@powerduck/conf-patch";
110
110
 
111
111
  // Set a nested value in a file (atomic, lock-guarded)
112
112
  await setConfigValue("config.yaml", ["database", "port"], 5432);
@@ -126,7 +126,7 @@ await patchConfigFile("config.jsonc", [
126
126
 
127
127
  ```javascript
128
128
  // In the Electron main process (CommonJS)
129
- const { setConfigValue, readConfigFile } = require("@powerduckie/confedit");
129
+ const { setConfigValue, readConfigFile } = require("@powerduck/conf-patch");
130
130
 
131
131
  ipcMain.handle("config:set", async (_event, { filePath, path, value }) => {
132
132
  try {
@@ -228,7 +228,7 @@ interface JsonPatchOp {
228
228
  ### OpenAPI Validation
229
229
 
230
230
  ```typescript
231
- import { validateOpenAPISpec, validateOpenAPIFile, OpenApiValidationError } from "@powerduckie/confedit";
231
+ import { validateOpenAPISpec, validateOpenAPIFile, OpenApiValidationError } from "@powerduck/conf-patch";
232
232
 
233
233
  // Validate raw content (JSON or YAML)
234
234
  try {
@@ -54,7 +54,7 @@ interface PatchContentOptions {
54
54
  *
55
55
  * @example
56
56
  * ```typescript
57
- * import { patchContent } from "@powerduckie/confedit";
57
+ * import { patchContent } from "@powerduck/conf-patch";
58
58
  *
59
59
  * const updated = patchContent(
60
60
  * '{"name": "app"}',
@@ -81,7 +81,7 @@ declare function patchContent(content: string, ops: JsonPatchOp[], format: Confi
81
81
  *
82
82
  * @example
83
83
  * ```typescript
84
- * import { setContentValue } from "@powerduckie/confedit";
84
+ * import { setContentValue } from "@powerduck/conf-patch";
85
85
  *
86
86
  * const updated = setContentValue(
87
87
  * "name: app\n",
@@ -104,7 +104,7 @@ declare function setContentValue(content: string, path: readonly (string | numbe
104
104
  *
105
105
  * @example
106
106
  * ```typescript
107
- * import { deleteContentValue } from "@powerduckie/confedit";
107
+ * import { deleteContentValue } from "@powerduck/conf-patch";
108
108
  *
109
109
  * const updated = deleteContentValue(
110
110
  * '{"name": "app", "legacy": true}',
@@ -54,7 +54,7 @@ interface PatchContentOptions {
54
54
  *
55
55
  * @example
56
56
  * ```typescript
57
- * import { patchContent } from "@powerduckie/confedit";
57
+ * import { patchContent } from "@powerduck/conf-patch";
58
58
  *
59
59
  * const updated = patchContent(
60
60
  * '{"name": "app"}',
@@ -81,7 +81,7 @@ declare function patchContent(content: string, ops: JsonPatchOp[], format: Confi
81
81
  *
82
82
  * @example
83
83
  * ```typescript
84
- * import { setContentValue } from "@powerduckie/confedit";
84
+ * import { setContentValue } from "@powerduck/conf-patch";
85
85
  *
86
86
  * const updated = setContentValue(
87
87
  * "name: app\n",
@@ -104,7 +104,7 @@ declare function setContentValue(content: string, path: readonly (string | numbe
104
104
  *
105
105
  * @example
106
106
  * ```typescript
107
- * import { deleteContentValue } from "@powerduckie/confedit";
107
+ * import { deleteContentValue } from "@powerduck/conf-patch";
108
108
  *
109
109
  * const updated = deleteContentValue(
110
110
  * '{"name": "app", "legacy": true}',
package/dist/core.d.mts CHANGED
@@ -1 +1 @@
1
- export { C as ConfigFormat, J as JsonPatchOp, a as JsonPathSegment, b as PatchContentOptions, c as assertConfigFormat, d as assertNonEmptyString, e as assertPatchOperations, f as assertPatchPath, g as createError, h as deleteContentValue, i as getErrorMessage, p as patchContent, s as setContentValue } from './core-CDrue4z-.mjs';
1
+ export { C as ConfigFormat, J as JsonPatchOp, a as JsonPathSegment, b as PatchContentOptions, c as assertConfigFormat, d as assertNonEmptyString, e as assertPatchOperations, f as assertPatchPath, g as createError, h as deleteContentValue, i as getErrorMessage, p as patchContent, s as setContentValue } from './core-ymvYwGVG.mjs';
package/dist/core.d.ts CHANGED
@@ -1 +1 @@
1
- export { C as ConfigFormat, J as JsonPatchOp, a as JsonPathSegment, b as PatchContentOptions, c as assertConfigFormat, d as assertNonEmptyString, e as assertPatchOperations, f as assertPatchPath, g as createError, h as deleteContentValue, i as getErrorMessage, p as patchContent, s as setContentValue } from './core-CDrue4z-.js';
1
+ export { C as ConfigFormat, J as JsonPatchOp, a as JsonPathSegment, b as PatchContentOptions, c as assertConfigFormat, d as assertNonEmptyString, e as assertPatchOperations, f as assertPatchPath, g as createError, h as deleteContentValue, i as getErrorMessage, p as patchContent, s as setContentValue } from './core-ymvYwGVG.js';
package/dist/core.js CHANGED
@@ -1 +1 @@
1
- var t,e=Object.defineProperty,r=Object.getOwnPropertyDescriptor,o=Object.getOwnPropertyNames,n=Object.prototype.hasOwnProperty,a={};((t,r)=>{for(var o in r)e(t,o,{get:r[o],enumerable:!0})})(a,{assertConfigFormat:()=>assertConfigFormat,assertNonEmptyString:()=>assertNonEmptyString,assertPatchOperations:()=>assertPatchOperations,assertPatchPath:()=>assertPatchPath,createError:()=>createError2,deleteContentValue:()=>deleteContentValue,getErrorMessage:()=>getErrorMessage2,patchContent:()=>patchContent,setContentValue:()=>setContentValue}),module.exports=(t=a,((t,a,i,s)=>{if(a&&"object"==typeof a||"function"==typeof a)for(let p of o(a))n.call(t,p)||p===i||e(t,p,{get:()=>a[p],enumerable:!(s=r(a,p))||s.enumerable});return t})(e({},"__esModule",{value:!0}),t));var i=require("jsonc-parser"),s={insertSpaces:!0,tabSize:2,eol:"\n"};function validateOperation(t){if(null===t||"object"!=typeof t)throw new TypeError("Patch operation must be an object.");if(!Array.isArray(t.path)||0===t.path.length)throw new Error("Patch operation path must be a non-empty array.");if("add"!==t.op&&"replace"!==t.op&&"remove"!==t.op)throw new Error(`Unsupported JSON patch operation: ${String(t.op)}`);if(("add"===t.op||"replace"===t.op)&&!Object.prototype.hasOwnProperty.call(t,"value"))throw new Error(`Patch operation "${t.op}" requires a value.`)}function normalizePath(t){return t.map(t=>{if("number"==typeof t){if(!Number.isSafeInteger(t)||t<0)throw new Error(`Invalid array index: ${t}`);return t}if("string"!=typeof t)throw new TypeError(`Patch path segments must be strings or numbers; received ${typeof t}.`);return t})}function applyAdd(t,e,r){const o=function(t,e){if(1===e.length){if("object"!==t.type&&"array"!==t.type)throw new Error("Cannot add a root child to a scalar JSON value.");return t}const r=e.slice(0,-1),o=(0,i.findNodeAtLocation)(t,r);if(void 0===o)throw new Error(`Cannot add value because its parent does not exist at path: ${formatPath(r)}`);if("object"!==o.type&&"array"!==o.type)throw new Error(`Cannot add value because its parent is not an object or array at path: ${formatPath(r)}`);return o}(getTree(t),e),n=e[e.length-1];if("array"===o.type){const a=function(t,e){if("number"!=typeof t)throw new Error(`Array index must be a number at path: ${formatPath(e)}`);if(!Number.isSafeInteger(t)||t<0)throw new Error(`Invalid array index ${t} at path: ${formatPath(e)}`);return t}(n,e),i=o.children?.length??0;if(a>i)throw new Error(`Cannot add at array index ${a}; array length is ${i} at path: ${formatPath(e.slice(0,-1))}`);return applyModify(t,e,r,!0)}if("object"===o.type){if("string"!=typeof n)throw new Error(`Object property path segment must be a string at path: ${formatPath(e)}`);return applyModify(t,e,r,!1)}throw new Error(`Cannot add a child to non-container value at path: ${formatPath(e.slice(0,-1))}`)}function applyReplace(t,e,r){const o=getTree(t);if(void 0===(0,i.findNodeAtLocation)(o,e))throw new Error(`Cannot replace a value that does not exist at path: ${formatPath(e)}`);return applyModify(t,e,r,!1)}function applyRemove(t,e){const r=getTree(t);if(void 0===(0,i.findNodeAtLocation)(r,e))throw new Error(`Cannot remove a value that does not exist at path: ${formatPath(e)}`);return applyModify(t,e,void 0,!1)}function applyModify(t,e,r,o){const n=(0,i.modify)(t,e,r,{formattingOptions:s,isArrayInsertion:o});if(0===n.length)throw new Error(`No JSONC edit was generated for path: ${formatPath(e)}`);return(0,i.applyEdits)(t,n)}function getTree(t){const e=[],r=(0,i.parseTree)(t,e,{allowTrailingComma:!0,disallowComments:!1});if(void 0===r||e.length>0)throw new Error(`The source text is not valid JSON or JSONC${function(t){if(0===t.length)return"";return` (parse errors: ${t.map(t=>`code=${t.error}, offset=${t.offset}`).join("; ")})`}(e)}.`);return r}function formatPath(t){return`[${t.map(t=>JSON.stringify(t)).join(", ")}]`}function safeStringify(t){try{return JSON.stringify(t)}catch{return"[unserializable patch operation]"}}function getErrorMessage(t){return t instanceof Error?t.message:String(t)}function createError(t,e){const r=new Error(t);try{Object.defineProperty(r,"cause",{configurable:!0,enumerable:!1,value:e,writable:!0})}catch{}return r}var p=require("yaml");function applyYamlOperation(t,e){!function(t){if(!Array.isArray(t.path)||0===t.path.length)throw new Error("[confedit] Patch path must be a non-empty array.");if("add"!==t.op&&"replace"!==t.op&&"remove"!==t.op)throw new Error(`[confedit] Unsupported patch operation: ${String(t.op)}.`)}(e);const r=e.path,o=function(t,e){if(0===e.length)throw new Error("[confedit] Replacing the YAML document root is not supported.");if(1===e.length){if(null===t.contents)throw new Error("[confedit] Cannot patch an empty YAML document without a root container.");return t.contents}const r=e.slice(0,-1),o=t.getIn(r,!0);if(null==o)throw new Error(`[confedit] Missing parent path: ${formatPath2(r)}.`);if(!(0,p.isMap)(o)&&!(0,p.isSeq)(o))throw new Error(`[confedit] Parent at ${formatPath2(r)} is not a YAML map or sequence.`);return o}(t,r),n=r[r.length-1];if((0,p.isMap)(o))!function(t,e,r,o){if("string"!=typeof r)throw new Error(`[confedit] YAML map keys must be strings at ${formatPath2(o.path)}.`);const n=e.has(r);switch(o.op){case"add":return void e.set(r,t.createNode(o.value));case"replace":if(!n)throw new Error(`[confedit] Cannot replace missing value at ${formatPath2(o.path)}.`);return void e.set(r,t.createNode(o.value));case"remove":if(!n)throw new Error(`[confedit] Cannot remove missing value at ${formatPath2(o.path)}.`);return void e.delete(r);default:throw new Error(`[confedit] Unsupported patch operation: ${String(o.op)}.`)}}(t,o,n,e);else{if(!(0,p.isSeq)(o))throw new Error(`[confedit] Cannot apply patch at ${formatPath2(r)} because its parent is not a YAML map or sequence.`);!function(t,e,r,o){if("number"!=typeof r||!Number.isSafeInteger(r)||r<0)throw new Error(`[confedit] YAML sequence indexes must be non-negative integers at ${formatPath2(o.path)}.`);const n=e.items.length;switch(o.op){case"add":if(r>n)throw new Error(`[confedit] Cannot insert at index ${r}; sequence length is ${n}.`);return void e.items.splice(r,0,t.createNode(o.value));case"replace":if(r>=n)throw new Error(`[confedit] Cannot replace index ${r}; sequence length is ${n}.`);return void(e.items[r]=t.createNode(o.value));case"remove":if(r>=n)throw new Error(`[confedit] Cannot remove index ${r}; sequence length is ${n}.`);return void e.items.splice(r,1);default:throw new Error(`[confedit] Unsupported patch operation: ${String(o.op)}.`)}}(t,o,n,e)}}function formatPath2(t){return`[${t.map(t=>JSON.stringify(t)).join(", ")}]`}function assertNonEmptyString(t,e){if("string"!=typeof t||0===t.length)throw new TypeError(`[confedit] ${e} must be a non-empty string.`)}function assertPatchPath(t,e="path"){if(!Array.isArray(t)||0===t.length)throw new TypeError(`[confedit] ${e} must be a non-empty array.`);for(const[r,o]of t.entries())if("string"!=typeof o){if("number"!=typeof o||!Number.isSafeInteger(o)||o<0)throw new TypeError(`[confedit] ${e}[${r}] must be a non-empty string or a non-negative integer.`)}else if(0===o.length)throw new TypeError(`[confedit] ${e}[${r}] must not be an empty string.`)}function assertPatchOperations(t){if(!Array.isArray(t))throw new TypeError("[confedit] ops must be an array.");for(const[e,r]of t.entries()){if(null===r||"object"!=typeof r)throw new TypeError(`[confedit] Patch operation at index ${e} must be an object.`);if("add"!==r.op&&"replace"!==r.op&&"remove"!==r.op)throw new Error(`[confedit] Unsupported patch operation at index ${e}: ${String(r.op)}.`);if(assertPatchPath(r.path,`ops[${e}].path`),("add"===r.op||"replace"===r.op)&&!Object.prototype.hasOwnProperty.call(r,"value"))throw new TypeError(`[confedit] Patch operation at index ${e} requires a value.`)}}function assertConfigFormat(t){if("json"!==t&&"jsonc"!==t&&"yaml"!==t)throw new Error(`[confedit] Unsupported configuration format: ${String(t)}.`)}function getErrorMessage2(t){return t instanceof Error?t.message:String(t)}function createError2(t,e){const r=new Error(t);try{Object.defineProperty(r,"cause",{configurable:!0,enumerable:!1,value:e,writable:!0})}catch{}return r}function patchContent(t,e,r,o={}){if("string"!=typeof t)throw new TypeError("[confedit] content must be a string.");if(assertPatchOperations(e),assertConfigFormat(r),0===e.length)return t;const n=o.strict??!0;switch(r){case"json":case"jsonc":return function(t,e,r=!0){if("string"!=typeof t)throw new TypeError("[confedit] sourceText must be a string.");if(!Array.isArray(e))throw new TypeError("[confedit] ops must be an array.");let o=t;for(const t of e)try{validateOperation(t);const e=normalizePath(t.path);switch(t.op){case"add":o=applyAdd(o,e,t.value);break;case"replace":o=applyReplace(o,e,t.value);break;case"remove":o=applyRemove(o,e);break;default:throw new Error(`[confedit] Unsupported JSON patch operation: ${String(t.op)}`)}}catch(e){const o=`[confedit] Failed to apply JSON patch ${safeStringify(t)}: ${getErrorMessage(e)}`;if(r)throw createError(o,e);console.warn(o)}return o}(t,e,n);case"yaml":return function(t,e,r=!0){const o=(0,p.parseDocument)(t,{prettyErrors:!0,strict:!0});if(o.errors.length>0)throw new Error(`[confedit] Invalid YAML source: ${o.errors.map(t=>t.message).join("; ")}`);for(const t of e)try{applyYamlOperation(o,t)}catch(e){if(r)throw e;console.warn(`[confedit yaml patch warn] Skip operation ${JSON.stringify(t)}`,e)}return o.toString()}(t,e,n)}}function setContentValue(t,e,r,o){return assertPatchPath(e),patchContent(t,[{op:"add",path:[...e],value:r}],o)}function deleteContentValue(t,e,r){return assertPatchPath(e),patchContent(t,[{op:"remove",path:[...e]}],r)}
1
+ "use strict";var t,e=Object.defineProperty,r=Object.getOwnPropertyDescriptor,o=Object.getOwnPropertyNames,n=Object.prototype.hasOwnProperty,a={};((t,r)=>{for(var o in r)e(t,o,{get:r[o],enumerable:!0})})(a,{assertConfigFormat:()=>assertConfigFormat,assertNonEmptyString:()=>assertNonEmptyString,assertPatchOperations:()=>assertPatchOperations,assertPatchPath:()=>assertPatchPath,createError:()=>createError2,deleteContentValue:()=>deleteContentValue,getErrorMessage:()=>getErrorMessage2,patchContent:()=>patchContent,setContentValue:()=>setContentValue}),module.exports=(t=a,((t,a,i,s)=>{if(a&&"object"==typeof a||"function"==typeof a)for(let p of o(a))n.call(t,p)||p===i||e(t,p,{get:()=>a[p],enumerable:!(s=r(a,p))||s.enumerable});return t})(e({},"__esModule",{value:!0}),t));var i=require("jsonc-parser"),s={insertSpaces:!0,tabSize:2,eol:"\n"};function validateOperation(t){if(null===t||"object"!=typeof t)throw new TypeError("Patch operation must be an object.");if(!Array.isArray(t.path)||0===t.path.length)throw new Error("Patch operation path must be a non-empty array.");if("add"!==t.op&&"replace"!==t.op&&"remove"!==t.op)throw new Error(`Unsupported JSON patch operation: ${String(t.op)}`);if(("add"===t.op||"replace"===t.op)&&!Object.prototype.hasOwnProperty.call(t,"value"))throw new Error(`Patch operation "${t.op}" requires a value.`)}function normalizePath(t){return t.map(t=>{if("number"==typeof t){if(!Number.isSafeInteger(t)||t<0)throw new Error(`Invalid array index: ${t}`);return t}if("string"!=typeof t)throw new TypeError(`Patch path segments must be strings or numbers; received ${typeof t}.`);return t})}function applyAdd(t,e,r){const o=function(t,e){if(1===e.length){if("object"!==t.type&&"array"!==t.type)throw new Error("Cannot add a root child to a scalar JSON value.");return t}const r=e.slice(0,-1),o=(0,i.findNodeAtLocation)(t,r);if(void 0===o)throw new Error(`Cannot add value because its parent does not exist at path: ${formatPath(r)}`);if("object"!==o.type&&"array"!==o.type)throw new Error(`Cannot add value because its parent is not an object or array at path: ${formatPath(r)}`);return o}(getTree(t),e),n=e[e.length-1];if("array"===o.type){const a=function(t,e){if("number"!=typeof t)throw new Error(`Array index must be a number at path: ${formatPath(e)}`);if(!Number.isSafeInteger(t)||t<0)throw new Error(`Invalid array index ${t} at path: ${formatPath(e)}`);return t}(n,e),i=o.children?.length??0;if(a>i)throw new Error(`Cannot add at array index ${a}; array length is ${i} at path: ${formatPath(e.slice(0,-1))}`);return applyModify(t,e,r,!0)}if("object"===o.type){if("string"!=typeof n)throw new Error(`Object property path segment must be a string at path: ${formatPath(e)}`);return applyModify(t,e,r,!1)}throw new Error(`Cannot add a child to non-container value at path: ${formatPath(e.slice(0,-1))}`)}function applyReplace(t,e,r){const o=getTree(t);if(void 0===(0,i.findNodeAtLocation)(o,e))throw new Error(`Cannot replace a value that does not exist at path: ${formatPath(e)}`);return applyModify(t,e,r,!1)}function applyRemove(t,e){const r=getTree(t);if(void 0===(0,i.findNodeAtLocation)(r,e))throw new Error(`Cannot remove a value that does not exist at path: ${formatPath(e)}`);return applyModify(t,e,void 0,!1)}function applyModify(t,e,r,o){const n=(0,i.modify)(t,e,r,{formattingOptions:s,isArrayInsertion:o});if(0===n.length)throw new Error(`No JSONC edit was generated for path: ${formatPath(e)}`);return(0,i.applyEdits)(t,n)}function getTree(t){const e=[],r=(0,i.parseTree)(t,e,{allowTrailingComma:!0,disallowComments:!1});if(void 0===r||e.length>0)throw new Error(`The source text is not valid JSON or JSONC${function(t){if(0===t.length)return"";return` (parse errors: ${t.map(t=>`code=${t.error}, offset=${t.offset}`).join("; ")})`}(e)}.`);return r}function formatPath(t){return`[${t.map(t=>JSON.stringify(t)).join(", ")}]`}function safeStringify(t){try{return JSON.stringify(t)}catch{return"[unserializable patch operation]"}}function getErrorMessage(t){return t instanceof Error?t.message:String(t)}function createError(t,e){const r=new Error(t);try{Object.defineProperty(r,"cause",{configurable:!0,enumerable:!1,value:e,writable:!0})}catch{}return r}var p=require("yaml");function applyYamlOperation(t,e){!function(t){if(!Array.isArray(t.path)||0===t.path.length)throw new Error("[confedit] Patch path must be a non-empty array.");if("add"!==t.op&&"replace"!==t.op&&"remove"!==t.op)throw new Error(`[confedit] Unsupported patch operation: ${String(t.op)}.`)}(e);const r=e.path,o=function(t,e){if(0===e.length)throw new Error("[confedit] Replacing the YAML document root is not supported.");if(1===e.length){if(null===t.contents)throw new Error("[confedit] Cannot patch an empty YAML document without a root container.");return t.contents}const r=e.slice(0,-1),o=t.getIn(r,!0);if(null==o)throw new Error(`[confedit] Missing parent path: ${formatPath2(r)}.`);if(!(0,p.isMap)(o)&&!(0,p.isSeq)(o))throw new Error(`[confedit] Parent at ${formatPath2(r)} is not a YAML map or sequence.`);return o}(t,r),n=r[r.length-1];if((0,p.isMap)(o))!function(t,e,r,o){if("string"!=typeof r)throw new Error(`[confedit] YAML map keys must be strings at ${formatPath2(o.path)}.`);const n=e.has(r);switch(o.op){case"add":return void e.set(r,t.createNode(o.value));case"replace":if(!n)throw new Error(`[confedit] Cannot replace missing value at ${formatPath2(o.path)}.`);return void e.set(r,t.createNode(o.value));case"remove":if(!n)throw new Error(`[confedit] Cannot remove missing value at ${formatPath2(o.path)}.`);return void e.delete(r);default:throw new Error(`[confedit] Unsupported patch operation: ${String(o.op)}.`)}}(t,o,n,e);else{if(!(0,p.isSeq)(o))throw new Error(`[confedit] Cannot apply patch at ${formatPath2(r)} because its parent is not a YAML map or sequence.`);!function(t,e,r,o){if("number"!=typeof r||!Number.isSafeInteger(r)||r<0)throw new Error(`[confedit] YAML sequence indexes must be non-negative integers at ${formatPath2(o.path)}.`);const n=e.items.length;switch(o.op){case"add":if(r>n)throw new Error(`[confedit] Cannot insert at index ${r}; sequence length is ${n}.`);return void e.items.splice(r,0,t.createNode(o.value));case"replace":if(r>=n)throw new Error(`[confedit] Cannot replace index ${r}; sequence length is ${n}.`);return void(e.items[r]=t.createNode(o.value));case"remove":if(r>=n)throw new Error(`[confedit] Cannot remove index ${r}; sequence length is ${n}.`);return void e.items.splice(r,1);default:throw new Error(`[confedit] Unsupported patch operation: ${String(o.op)}.`)}}(t,o,n,e)}}function formatPath2(t){return`[${t.map(t=>JSON.stringify(t)).join(", ")}]`}function assertNonEmptyString(t,e){if("string"!=typeof t||0===t.length)throw new TypeError(`[confedit] ${e} must be a non-empty string.`)}function assertPatchPath(t,e="path"){if(!Array.isArray(t)||0===t.length)throw new TypeError(`[confedit] ${e} must be a non-empty array.`);for(const[r,o]of t.entries())if("string"!=typeof o){if("number"!=typeof o||!Number.isSafeInteger(o)||o<0)throw new TypeError(`[confedit] ${e}[${r}] must be a non-empty string or a non-negative integer.`)}else if(0===o.length)throw new TypeError(`[confedit] ${e}[${r}] must not be an empty string.`)}function assertPatchOperations(t){if(!Array.isArray(t))throw new TypeError("[confedit] ops must be an array.");for(const[e,r]of t.entries()){if(null===r||"object"!=typeof r)throw new TypeError(`[confedit] Patch operation at index ${e} must be an object.`);if("add"!==r.op&&"replace"!==r.op&&"remove"!==r.op)throw new Error(`[confedit] Unsupported patch operation at index ${e}: ${String(r.op)}.`);if(assertPatchPath(r.path,`ops[${e}].path`),("add"===r.op||"replace"===r.op)&&!Object.prototype.hasOwnProperty.call(r,"value"))throw new TypeError(`[confedit] Patch operation at index ${e} requires a value.`)}}function assertConfigFormat(t){if("json"!==t&&"jsonc"!==t&&"yaml"!==t)throw new Error(`[confedit] Unsupported configuration format: ${String(t)}.`)}function getErrorMessage2(t){return t instanceof Error?t.message:String(t)}function createError2(t,e){const r=new Error(t);try{Object.defineProperty(r,"cause",{configurable:!0,enumerable:!1,value:e,writable:!0})}catch{}return r}function patchContent(t,e,r,o={}){if("string"!=typeof t)throw new TypeError("[confedit] content must be a string.");if(assertPatchOperations(e),assertConfigFormat(r),0===e.length)return t;const n=o.strict??!0;switch(r){case"json":case"jsonc":return function(t,e,r=!0){if("string"!=typeof t)throw new TypeError("[confedit] sourceText must be a string.");if(!Array.isArray(e))throw new TypeError("[confedit] ops must be an array.");let o=t;for(const t of e)try{validateOperation(t);const e=normalizePath(t.path);switch(t.op){case"add":o=applyAdd(o,e,t.value);break;case"replace":o=applyReplace(o,e,t.value);break;case"remove":o=applyRemove(o,e);break;default:throw new Error(`[confedit] Unsupported JSON patch operation: ${String(t.op)}`)}}catch(e){const o=`[confedit] Failed to apply JSON patch ${safeStringify(t)}: ${getErrorMessage(e)}`;if(r)throw createError(o,e);console.warn(o)}return o}(t,e,n);case"yaml":return function(t,e,r=!0){const o=(0,p.parseDocument)(t,{prettyErrors:!0,strict:!0});if(o.errors.length>0)throw new Error(`[confedit] Invalid YAML source: ${o.errors.map(t=>t.message).join("; ")}`);for(const t of e)try{applyYamlOperation(o,t)}catch(e){if(r)throw e;console.warn(`[confedit yaml patch warn] Skip operation ${JSON.stringify(t)}`,e)}return o.toString()}(t,e,n)}}function setContentValue(t,e,r,o){return assertPatchPath(e),patchContent(t,[{op:"add",path:[...e],value:r}],o)}function deleteContentValue(t,e,r){return assertPatchPath(e),patchContent(t,[{op:"remove",path:[...e]}],r)}
package/dist/index.d.mts CHANGED
@@ -1,5 +1,5 @@
1
- import { P as PatchConfigOptions, J as JsonPatchOp, C as ConfigFormat } from './core-CDrue4z-.mjs';
2
- export { F as FileLockOptions, a as JsonPathSegment, b as PatchContentOptions, c as assertConfigFormat, d as assertNonEmptyString, e as assertPatchOperations, f as assertPatchPath, g as createError, h as deleteContentValue, i as getErrorMessage, p as patchContent, s as setContentValue } from './core-CDrue4z-.mjs';
1
+ import { P as PatchConfigOptions, J as JsonPatchOp, C as ConfigFormat } from './core-ymvYwGVG.mjs';
2
+ export { F as FileLockOptions, a as JsonPathSegment, b as PatchContentOptions, c as assertConfigFormat, d as assertNonEmptyString, e as assertPatchOperations, f as assertPatchPath, g as createError, h as deleteContentValue, i as getErrorMessage, p as patchContent, s as setContentValue } from './core-ymvYwGVG.mjs';
3
3
  import { OpenAPIV2, OpenAPIV3, OpenAPIV3_1 } from 'openapi-types';
4
4
 
5
5
  /**
@@ -44,7 +44,7 @@ interface WriteConfigOptions {
44
44
  *
45
45
  * @example
46
46
  * ```typescript
47
- * import { writeConfigFile } from "@powerduckie/confedit";
47
+ * import { writeConfigFile } from "@powerduck/conf-patch";
48
48
  *
49
49
  * await writeConfigFile("config.json", '{"name": "app"}');
50
50
  * ```
@@ -63,7 +63,7 @@ declare function writeConfigFile(filePath: string, content: string, options?: Wr
63
63
  *
64
64
  * @example
65
65
  * ```typescript
66
- * import { patchConfigFile } from "@powerduckie/confedit";
66
+ * import { patchConfigFile } from "@powerduck/conf-patch";
67
67
  *
68
68
  * await patchConfigFile("config.json", [
69
69
  * { op: "replace", path: ["server", "host"], value: "0.0.0.0" },
@@ -88,7 +88,7 @@ declare function patchConfigFile(filePath: string, ops: JsonPatchOp[], options?:
88
88
  *
89
89
  * @example
90
90
  * ```typescript
91
- * import { setConfigValue } from "@powerduckie/confedit";
91
+ * import { setConfigValue } from "@powerduck/conf-patch";
92
92
  *
93
93
  * await setConfigValue("config.yaml", ["database", "port"], 5432);
94
94
  * ```
@@ -105,7 +105,7 @@ declare function setConfigValue(filePath: string, path: readonly (string | numbe
105
105
  *
106
106
  * @example
107
107
  * ```typescript
108
- * import { deleteConfigValue } from "@powerduckie/confedit";
108
+ * import { deleteConfigValue } from "@powerduck/conf-patch";
109
109
  *
110
110
  * await deleteConfigValue("config.json", ["features", "betaPreview"]);
111
111
  * ```
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { P as PatchConfigOptions, J as JsonPatchOp, C as ConfigFormat } from './core-CDrue4z-.js';
2
- export { F as FileLockOptions, a as JsonPathSegment, b as PatchContentOptions, c as assertConfigFormat, d as assertNonEmptyString, e as assertPatchOperations, f as assertPatchPath, g as createError, h as deleteContentValue, i as getErrorMessage, p as patchContent, s as setContentValue } from './core-CDrue4z-.js';
1
+ import { P as PatchConfigOptions, J as JsonPatchOp, C as ConfigFormat } from './core-ymvYwGVG.js';
2
+ export { F as FileLockOptions, a as JsonPathSegment, b as PatchContentOptions, c as assertConfigFormat, d as assertNonEmptyString, e as assertPatchOperations, f as assertPatchPath, g as createError, h as deleteContentValue, i as getErrorMessage, p as patchContent, s as setContentValue } from './core-ymvYwGVG.js';
3
3
  import { OpenAPIV2, OpenAPIV3, OpenAPIV3_1 } from 'openapi-types';
4
4
 
5
5
  /**
@@ -44,7 +44,7 @@ interface WriteConfigOptions {
44
44
  *
45
45
  * @example
46
46
  * ```typescript
47
- * import { writeConfigFile } from "@powerduckie/confedit";
47
+ * import { writeConfigFile } from "@powerduck/conf-patch";
48
48
  *
49
49
  * await writeConfigFile("config.json", '{"name": "app"}');
50
50
  * ```
@@ -63,7 +63,7 @@ declare function writeConfigFile(filePath: string, content: string, options?: Wr
63
63
  *
64
64
  * @example
65
65
  * ```typescript
66
- * import { patchConfigFile } from "@powerduckie/confedit";
66
+ * import { patchConfigFile } from "@powerduck/conf-patch";
67
67
  *
68
68
  * await patchConfigFile("config.json", [
69
69
  * { op: "replace", path: ["server", "host"], value: "0.0.0.0" },
@@ -88,7 +88,7 @@ declare function patchConfigFile(filePath: string, ops: JsonPatchOp[], options?:
88
88
  *
89
89
  * @example
90
90
  * ```typescript
91
- * import { setConfigValue } from "@powerduckie/confedit";
91
+ * import { setConfigValue } from "@powerduck/conf-patch";
92
92
  *
93
93
  * await setConfigValue("config.yaml", ["database", "port"], 5432);
94
94
  * ```
@@ -105,7 +105,7 @@ declare function setConfigValue(filePath: string, path: readonly (string | numbe
105
105
  *
106
106
  * @example
107
107
  * ```typescript
108
- * import { deleteConfigValue } from "@powerduckie/confedit";
108
+ * import { deleteConfigValue } from "@powerduck/conf-patch";
109
109
  *
110
110
  * await deleteConfigValue("config.json", ["features", "betaPreview"]);
111
111
  * ```
package/dist/index.js CHANGED
@@ -1 +1 @@
1
- Object.create;var e,t=Object.defineProperty,r=Object.getOwnPropertyDescriptor,o=Object.getOwnPropertyNames,n=(Object.getPrototypeOf,Object.prototype.hasOwnProperty),__copyProps=(e,a,i,s)=>{if(a&&"object"==typeof a||"function"==typeof a)for(let c of o(a))n.call(e,c)||c===i||t(e,c,{get:()=>a[c],enumerable:!(s=r(a,c))||s.enumerable});return e},a={};((e,r)=>{for(var o in r)t(e,o,{get:r[o],enumerable:!0})})(a,{OpenApiValidationError:()=>I,assertConfigFormat:()=>assertConfigFormat,assertNonEmptyString:()=>assertNonEmptyString,assertPatchOperations:()=>assertPatchOperations,assertPatchPath:()=>assertPatchPath,createError:()=>createError2,deleteConfigValue:()=>deleteConfigValue,deleteContentValue:()=>deleteContentValue,detectFormat:()=>detectFormat,getErrorMessage:()=>getErrorMessage2,normalizeFilePath:()=>normalizeFilePath,patchConfigFile:()=>patchConfigFile,patchContent:()=>patchContent,readConfigFile:()=>readConfigFile,releaseAllLocalLocks:()=>releaseAllLocalLocks,setConfigValue:()=>setConfigValue,setContentValue:()=>setContentValue,validateOpenAPIFile:()=>validateOpenAPIFile,validateOpenAPISpec:()=>validateOpenAPISpec,withFileLock:()=>withFileLock,writeConfigFile:()=>writeConfigFile}),module.exports=(e=a,__copyProps(t({},"__esModule",{value:!0}),e));var i=require("jsonc-parser"),s={insertSpaces:!0,tabSize:2,eol:"\n"};function validateOperation(e){if(null===e||"object"!=typeof e)throw new TypeError("Patch operation must be an object.");if(!Array.isArray(e.path)||0===e.path.length)throw new Error("Patch operation path must be a non-empty array.");if("add"!==e.op&&"replace"!==e.op&&"remove"!==e.op)throw new Error(`Unsupported JSON patch operation: ${String(e.op)}`);if(("add"===e.op||"replace"===e.op)&&!Object.prototype.hasOwnProperty.call(e,"value"))throw new Error(`Patch operation "${e.op}" requires a value.`)}function normalizePath(e){return e.map(e=>{if("number"==typeof e){if(!Number.isSafeInteger(e)||e<0)throw new Error(`Invalid array index: ${e}`);return e}if("string"!=typeof e)throw new TypeError(`Patch path segments must be strings or numbers; received ${typeof e}.`);return e})}function applyAdd(e,t,r){const o=function(e,t){if(1===t.length){if("object"!==e.type&&"array"!==e.type)throw new Error("Cannot add a root child to a scalar JSON value.");return e}const r=t.slice(0,-1),o=(0,i.findNodeAtLocation)(e,r);if(void 0===o)throw new Error(`Cannot add value because its parent does not exist at path: ${formatPath(r)}`);if("object"!==o.type&&"array"!==o.type)throw new Error(`Cannot add value because its parent is not an object or array at path: ${formatPath(r)}`);return o}(getTree(e),t),n=t[t.length-1];if("array"===o.type){const a=function(e,t){if("number"!=typeof e)throw new Error(`Array index must be a number at path: ${formatPath(t)}`);if(!Number.isSafeInteger(e)||e<0)throw new Error(`Invalid array index ${e} at path: ${formatPath(t)}`);return e}(n,t),i=o.children?.length??0;if(a>i)throw new Error(`Cannot add at array index ${a}; array length is ${i} at path: ${formatPath(t.slice(0,-1))}`);return applyModify(e,t,r,!0)}if("object"===o.type){if("string"!=typeof n)throw new Error(`Object property path segment must be a string at path: ${formatPath(t)}`);return applyModify(e,t,r,!1)}throw new Error(`Cannot add a child to non-container value at path: ${formatPath(t.slice(0,-1))}`)}function applyReplace(e,t,r){const o=getTree(e);if(void 0===(0,i.findNodeAtLocation)(o,t))throw new Error(`Cannot replace a value that does not exist at path: ${formatPath(t)}`);return applyModify(e,t,r,!1)}function applyRemove(e,t){const r=getTree(e);if(void 0===(0,i.findNodeAtLocation)(r,t))throw new Error(`Cannot remove a value that does not exist at path: ${formatPath(t)}`);return applyModify(e,t,void 0,!1)}function applyModify(e,t,r,o){const n=(0,i.modify)(e,t,r,{formattingOptions:s,isArrayInsertion:o});if(0===n.length)throw new Error(`No JSONC edit was generated for path: ${formatPath(t)}`);return(0,i.applyEdits)(e,n)}function getTree(e){const t=[],r=(0,i.parseTree)(e,t,{allowTrailingComma:!0,disallowComments:!1});if(void 0===r||t.length>0)throw new Error(`The source text is not valid JSON or JSONC${function(e){if(0===e.length)return"";return` (parse errors: ${e.map(e=>`code=${e.error}, offset=${e.offset}`).join("; ")})`}(t)}.`);return r}function formatPath(e){return`[${e.map(e=>JSON.stringify(e)).join(", ")}]`}function safeStringify(e){try{return JSON.stringify(e)}catch{return"[unserializable patch operation]"}}function getErrorMessage(e){return e instanceof Error?e.message:String(e)}function createError(e,t){const r=new Error(e);try{Object.defineProperty(r,"cause",{configurable:!0,enumerable:!1,value:t,writable:!0})}catch{}return r}var c=require("yaml");function applyYamlOperation(e,t){!function(e){if(!Array.isArray(e.path)||0===e.path.length)throw new Error("[confedit] Patch path must be a non-empty array.");if("add"!==e.op&&"replace"!==e.op&&"remove"!==e.op)throw new Error(`[confedit] Unsupported patch operation: ${String(e.op)}.`)}(t);const r=t.path,o=function(e,t){if(0===t.length)throw new Error("[confedit] Replacing the YAML document root is not supported.");if(1===t.length){if(null===e.contents)throw new Error("[confedit] Cannot patch an empty YAML document without a root container.");return e.contents}const r=t.slice(0,-1),o=e.getIn(r,!0);if(null==o)throw new Error(`[confedit] Missing parent path: ${formatPath2(r)}.`);if(!(0,c.isMap)(o)&&!(0,c.isSeq)(o))throw new Error(`[confedit] Parent at ${formatPath2(r)} is not a YAML map or sequence.`);return o}(e,r),n=r[r.length-1];if((0,c.isMap)(o))!function(e,t,r,o){if("string"!=typeof r)throw new Error(`[confedit] YAML map keys must be strings at ${formatPath2(o.path)}.`);const n=t.has(r);switch(o.op){case"add":return void t.set(r,e.createNode(o.value));case"replace":if(!n)throw new Error(`[confedit] Cannot replace missing value at ${formatPath2(o.path)}.`);return void t.set(r,e.createNode(o.value));case"remove":if(!n)throw new Error(`[confedit] Cannot remove missing value at ${formatPath2(o.path)}.`);return void t.delete(r);default:throw new Error(`[confedit] Unsupported patch operation: ${String(o.op)}.`)}}(e,o,n,t);else{if(!(0,c.isSeq)(o))throw new Error(`[confedit] Cannot apply patch at ${formatPath2(r)} because its parent is not a YAML map or sequence.`);!function(e,t,r,o){if("number"!=typeof r||!Number.isSafeInteger(r)||r<0)throw new Error(`[confedit] YAML sequence indexes must be non-negative integers at ${formatPath2(o.path)}.`);const n=t.items.length;switch(o.op){case"add":if(r>n)throw new Error(`[confedit] Cannot insert at index ${r}; sequence length is ${n}.`);return void t.items.splice(r,0,e.createNode(o.value));case"replace":if(r>=n)throw new Error(`[confedit] Cannot replace index ${r}; sequence length is ${n}.`);return void(t.items[r]=e.createNode(o.value));case"remove":if(r>=n)throw new Error(`[confedit] Cannot remove index ${r}; sequence length is ${n}.`);return void t.items.splice(r,1);default:throw new Error(`[confedit] Unsupported patch operation: ${String(o.op)}.`)}}(e,o,n,t)}}function formatPath2(e){return`[${e.map(e=>JSON.stringify(e)).join(", ")}]`}function assertNonEmptyString(e,t){if("string"!=typeof e||0===e.length)throw new TypeError(`[confedit] ${t} must be a non-empty string.`)}function assertPatchPath(e,t="path"){if(!Array.isArray(e)||0===e.length)throw new TypeError(`[confedit] ${t} must be a non-empty array.`);for(const[r,o]of e.entries())if("string"!=typeof o){if("number"!=typeof o||!Number.isSafeInteger(o)||o<0)throw new TypeError(`[confedit] ${t}[${r}] must be a non-empty string or a non-negative integer.`)}else if(0===o.length)throw new TypeError(`[confedit] ${t}[${r}] must not be an empty string.`)}function assertPatchOperations(e){if(!Array.isArray(e))throw new TypeError("[confedit] ops must be an array.");for(const[t,r]of e.entries()){if(null===r||"object"!=typeof r)throw new TypeError(`[confedit] Patch operation at index ${t} must be an object.`);if("add"!==r.op&&"replace"!==r.op&&"remove"!==r.op)throw new Error(`[confedit] Unsupported patch operation at index ${t}: ${String(r.op)}.`);if(assertPatchPath(r.path,`ops[${t}].path`),("add"===r.op||"replace"===r.op)&&!Object.prototype.hasOwnProperty.call(r,"value"))throw new TypeError(`[confedit] Patch operation at index ${t} requires a value.`)}}function assertConfigFormat(e){if("json"!==e&&"jsonc"!==e&&"yaml"!==e)throw new Error(`[confedit] Unsupported configuration format: ${String(e)}.`)}function getErrorMessage2(e){return e instanceof Error?e.message:String(e)}function createError2(e,t){const r=new Error(e);try{Object.defineProperty(r,"cause",{configurable:!0,enumerable:!1,value:t,writable:!0})}catch{}return r}function patchContent(e,t,r,o={}){if("string"!=typeof e)throw new TypeError("[confedit] content must be a string.");if(assertPatchOperations(t),assertConfigFormat(r),0===t.length)return e;const n=o.strict??!0;switch(r){case"json":case"jsonc":return function(e,t,r=!0){if("string"!=typeof e)throw new TypeError("[confedit] sourceText must be a string.");if(!Array.isArray(t))throw new TypeError("[confedit] ops must be an array.");let o=e;for(const e of t)try{validateOperation(e);const t=normalizePath(e.path);switch(e.op){case"add":o=applyAdd(o,t,e.value);break;case"replace":o=applyReplace(o,t,e.value);break;case"remove":o=applyRemove(o,t);break;default:throw new Error(`[confedit] Unsupported JSON patch operation: ${String(e.op)}`)}}catch(t){const o=`[confedit] Failed to apply JSON patch ${safeStringify(e)}: ${getErrorMessage(t)}`;if(r)throw createError(o,t);console.warn(o)}return o}(e,t,n);case"yaml":return function(e,t,r=!0){const o=(0,c.parseDocument)(e,{prettyErrors:!0,strict:!0});if(o.errors.length>0)throw new Error(`[confedit] Invalid YAML source: ${o.errors.map(e=>e.message).join("; ")}`);for(const e of t)try{applyYamlOperation(o,e)}catch(t){if(r)throw t;console.warn(`[confedit yaml patch warn] Skip operation ${JSON.stringify(e)}`,t)}return o.toString()}(e,t,n)}}function setContentValue(e,t,r,o){return assertPatchPath(t),patchContent(e,[{op:"add",path:[...t],value:r}],o)}function deleteContentValue(e,t,r){return assertPatchPath(t),patchContent(e,[{op:"remove",path:[...t]}],r)}var l=require("fs/promises"),u=require("path"),f=require("url");function normalizeFilePath(e){if("string"!=typeof e||0===e.length)throw new TypeError("[confedit] filePath must be a non-empty string.");if(e.startsWith("file:"))try{return(0,f.fileURLToPath)(e)}catch(t){throw function(e,t){const r=new Error(e);try{Object.defineProperty(r,"cause",{configurable:!0,enumerable:!1,value:t,writable:!0})}catch{}return r}(`[confedit] Invalid file URL "${e}": ${function(e){return e instanceof Error?e.message:String(e)}(t)}`,t)}return(0,u.isAbsolute)(e)?e:(0,u.resolve)(e)}async function readConfigFile(e){assertNonEmptyString(e,"filePath");const t=normalizeFilePath(e);try{return await(0,l.readFile)(t,"utf8")}catch(t){throw createError2(`[confedit] Failed to read "${e}": ${getErrorMessage2(t)}`,t)}}var p=require("fs/promises"),h=require("path"),d=require("crypto"),m=require("fs/promises"),w=require("path");async function atomicWrite(e,t){if(function(e,t){if("string"!=typeof e||0===e.length)throw new TypeError(`[confedit] ${t} must be a non-empty string.`)}(e,"filePath"),"string"!=typeof t)throw new TypeError("[confedit] content must be a string.");const r=normalizeFilePath(e),o=(0,w.dirname)(r),n=(0,w.basename)(r),a=`${process.pid}.${Date.now()}.${(0,d.randomBytes)(12).toString("hex")}`,i=(0,w.join)(o,`.${n}.${a}.tmp`),s=(0,w.join)(o,`.${n}.${a}.bak`);let c,l=!1,u=!1;try{await(0,m.mkdir)(o,{recursive:!0});const e=await async function(e){try{return 511&(await(0,m.stat)(e)).mode}catch(e){if("ENOENT"===getErrorCode(e))return;throw e}}(r);c=await(0,m.open)(i,"wx",e??384);try{await c.writeFile(t,"utf8"),await c.sync()}finally{await c.close(),c=void 0}void 0!==e&&await(0,m.chmod)(i,e);try{await(0,m.rename)(i,r),u=!0}catch(e){if(!function(e){if("win32"!==process.platform)return!1;const t=getErrorCode(e);return"EEXIST"===t||"EPERM"===t||"EACCES"===t}(e))throw e;await(0,m.rename)(r,s),l=!0;try{await(0,m.rename)(i,r),u=!0}catch(e){const t=await async function(e,t){try{return await(0,m.unlink)(e).catch(e=>{if("ENOENT"!==getErrorCode(e))throw e}),await(0,m.rename)(t,e),!0}catch{return!1}}(r,s);throw t&&(l=!1),createError4(t?`[confedit] Failed to replace "${r}", but the original file was restored.`:`[confedit] Failed to replace "${r}". The backup was retained at "${s}".`,e)}}await syncDirectory(o),l&&(await(0,m.unlink)(s),l=!1,await syncDirectory(o))}catch(t){throw void 0!==c&&await c.close().catch(()=>{}),createError4(`[confedit] Failed to atomically write "${e}": ${function(e){return e instanceof Error?e.message:String(e)}(t)}`,t)}finally{await(0,m.unlink)(i).catch(()=>{}),u&&l&&await(0,m.unlink)(s).catch(()=>{})}}async function syncDirectory(e){let t;try{t=await(0,m.open)(e,"r"),await t.sync()}catch(e){const t=getErrorCode(e);if("EINVAL"!==t&&"EPERM"!==t&&"EISDIR"!==t&&"ENOSYS"!==t&&"ENOTSUP"!==t)throw e}finally{await(t?.close().catch(()=>{}))}}function getErrorCode(e){if(null!==e&&"object"==typeof e&&"code"in e&&"string"==typeof e.code)return e.code}function createError4(e,t){const r=new Error(e);try{Object.defineProperty(r,"cause",{configurable:!0,enumerable:!1,value:t,writable:!0})}catch{}return r}var y=require("crypto"),g=require("fs/promises"),E=require("os"),b=1e4,v=25,P=1e3,O=6e4,$=new Map,M=new Set;async function withFileLock(e,t,r={}){const o=normalizeFilePath(e);return function(e){if(void 0!==e.timeoutMs&&(!Number.isFinite(e.timeoutMs)||e.timeoutMs<0))throw new TypeError("[confedit] lock timeoutMs must be a non-negative finite number.");if(void 0!==e.retryDelayMs&&(!Number.isFinite(e.retryDelayMs)||e.retryDelayMs<=0))throw new TypeError("[confedit] lock retryDelayMs must be a positive finite number.");if(void 0!==e.staleThresholdMs&&(!Number.isFinite(e.staleThresholdMs)||e.staleThresholdMs<=0))throw new TypeError("[confedit] lock staleThresholdMs must be a positive finite number.")}(r),function(e,t){const r=$.get(e)??Promise.resolve();let o;const n=new Promise(e=>{o=e}),a=r.catch(()=>{}).then(()=>n);return $.set(e,a),r.catch(()=>{}).then(t).finally(()=>{o(),$.get(e)===a&&$.delete(e)})}(o,async()=>{const e=await async function(e,t){const r=t.timeoutMs??b,o=t.retryDelayMs??v,n=t.staleThresholdMs??Math.max(2*r,O),a=t.allowStaleRecovery??!1,i=`${e}.confedit.lock`,s=Date.now();let c=o;const l=createToken(),u={version:1,pid:process.pid,hostname:(0,E.hostname)(),createdAt:(new Date).toISOString(),token:l};for(;;)try{const e=await(0,g.open)(i,"wx",384);try{await(0,g.writeFile)(e,`${JSON.stringify(u)}\n`,"utf8"),await e.sync()}finally{await e.close()}return M.add(i),createReleaseHandler(i,l)}catch(t){if("EEXIST"!==getErrorCode2(t))throw createError5(`[confedit] Failed to acquire lock "${i}": ${getErrorMessage5(t)}`,t);if(a&&await tryRecoverStaleLock(i,n),Date.now()-s>=r)throw new Error(`[confedit] Timed out waiting for lock on "${e}" after ${r}ms.`);await sleep(c),c=Math.min(Math.ceil(1.5*c),P)}}(o,r);try{return await t()}finally{await e()}})}async function releaseAllLocalLocks(){const e=Array.from(M).map(e=>(0,g.unlink)(e).catch(()=>{}));await Promise.allSettled(e),M.clear()}function createReleaseHandler(e,t){return async()=>{try{const r=await readLockData(e);r?.token===t&&(await(0,g.unlink)(e).catch(()=>{}),M.delete(e))}catch{}}}async function tryRecoverStaleLock(e,t){const r=await readLockData(e);if(void 0===r||!isExpiredLock(r,t))return;const o=`${e}.stale.${createToken()}`;try{await(0,g.rename)(e,o)}catch(e){return void getErrorCode2(e)}try{const n=await readLockData(o);if(n?.token===r.token&&isExpiredLock(n,t))return void await(0,g.unlink)(o).catch(()=>{});await(0,g.rename)(o,e).catch(()=>{})}catch{}}function isExpiredLock(e,t){const r=Date.parse(e.createdAt);return Number.isFinite(r)&&Date.now()-r>t}async function readLockData(e){try{return function(e){try{const t=JSON.parse(e);if(1!==t.version||"number"!=typeof t.pid||!Number.isSafeInteger(t.pid)||t.pid<=0||"string"!=typeof t.hostname||"string"!=typeof t.createdAt||!Number.isFinite(Date.parse(t.createdAt))||"string"!=typeof t.token||t.token.length<16)return;return{version:1,pid:t.pid,hostname:t.hostname,createdAt:t.createdAt,token:t.token}}catch{return}}(await(0,g.readFile)(e,"utf8"))}catch{return}}function createToken(){return`${process.pid}-${Date.now()}-${(0,y.randomBytes)(16).toString("hex")}`}function sleep(e){return new Promise(t=>setTimeout(t,e))}function getErrorCode2(e){if(null!==e&&"object"==typeof e&&"code"in e&&"string"==typeof e.code)return e.code}function getErrorMessage5(e){return e instanceof Error?e.message:String(e)}function createError5(e,t){const r=new Error(e);try{Object.defineProperty(r,"cause",{configurable:!0,enumerable:!1,value:t,writable:!0})}catch{}return r}async function writeConfigFile(e,t,r={}){if(assertNonEmptyString(e,"filePath"),"string"!=typeof t)throw new TypeError("[confedit] content must be a string.");const o=normalizeFilePath(e),writeTransaction=async()=>{try{await atomicWrite(o,t)}catch(t){throw createError2(`[confedit] Failed to write "${e}": ${getErrorMessage2(t)}`,t)}};r.lock??!0?(await(0,p.mkdir)((0,h.dirname)(o),{recursive:!0}),await withFileLock(o,writeTransaction,{timeoutMs:r.lockTimeoutMs,retryDelayMs:r.lockRetryDelayMs,staleThresholdMs:r.lockStaleThresholdMs,allowStaleRecovery:r.allowStaleRecovery})):await writeTransaction()}var T=require("path");function detectFormat(e){const t=normalizeFilePath(e);switch((0,T.extname)(t).toLowerCase()){case".json":return"json";case".jsonc":return"jsonc";case".yaml":case".yml":return"yaml";default:throw new Error(`[confedit] Cannot detect a supported configuration format for "${e}". Expected .json, .jsonc, .yaml, or .yml.`)}}async function patchConfigFile(e,t,r={}){if("string"!=typeof e||0===e.length)throw new TypeError("[confedit] filePath must be a non-empty string.");if(assertPatchOperations(t),0===t.length)return;const o=normalizeFilePath(e),n=r.format??detectFormat(o);assertConfigFormat(n),function(e){if(void 0!==e.lockTimeoutMs&&(!Number.isFinite(e.lockTimeoutMs)||e.lockTimeoutMs<0))throw new TypeError("[confedit] lockTimeoutMs must be a non-negative finite number.");if(void 0!==e.lockRetryDelayMs&&(!Number.isFinite(e.lockRetryDelayMs)||e.lockRetryDelayMs<=0))throw new TypeError("[confedit] lockRetryDelayMs must be a positive finite number.");if(void 0!==e.lockStaleThresholdMs&&(!Number.isFinite(e.lockStaleThresholdMs)||e.lockStaleThresholdMs<=0))throw new TypeError("[confedit] lockStaleThresholdMs must be a positive finite number.")}(r);const a=r.strict??!0,patchTransaction=async()=>{const r=await readConfigFile(o),i=patchContent(r,t,n,{strict:a});if(i!==r)try{await atomicWrite(o,i)}catch(t){throw createError2(`[confedit] Failed to write "${e}": ${getErrorMessage2(t)}`,t)}};r.lock??!0?await withFileLock(o,patchTransaction,{timeoutMs:r.lockTimeoutMs,retryDelayMs:r.lockRetryDelayMs,staleThresholdMs:r.lockStaleThresholdMs,allowStaleRecovery:r.allowStaleRecovery}):await patchTransaction()}async function setConfigValue(e,t,r,o={}){await patchConfigFile(e,[{op:"add",path:[...t],value:r}],o)}async function deleteConfigValue(e,t,r={}){await patchConfigFile(e,[{op:"remove",path:[...t]}],r)}var D,N=require("fs/promises"),S=require("path"),A=require("yaml"),I=class extends Error{constructor(e,t,r){super(t),this.name="OpenApiValidationError",this.code=e,this.cause=r}},F={inputKind:"content",timeoutMs:15e3,maxInputBytes:5242880,maxDocumentNodes:1e5,maxDocumentDepth:100,maxValidationErrors:50,maxErrorMessageLength:1e3};async function validateOpenAPISpec(e,t={}){!function(e,t){if("string"!=typeof e||0===e.length)throw new TypeError(`[confedit] ${t} must be a non-empty string.`)}(e,"input");const r=function(e){const t={inputKind:e.inputKind??F.inputKind,baseFilePath:e.baseFilePath,allowedRootDirectory:e.allowedRootDirectory,timeoutMs:e.timeoutMs??F.timeoutMs,maxInputBytes:e.maxInputBytes??F.maxInputBytes,maxDocumentNodes:e.maxDocumentNodes??F.maxDocumentNodes,maxDocumentDepth:e.maxDocumentDepth??F.maxDocumentDepth,maxValidationErrors:e.maxValidationErrors??F.maxValidationErrors,maxErrorMessageLength:e.maxErrorMessageLength??F.maxErrorMessageLength,signal:e.signal};if("content"!==t.inputKind&&"file"!==t.inputKind)throw new I("INVALID_OPTION",`inputKind must be "content" or "file", got: ${String(t.inputKind)}.`);return assertPositiveFiniteNumber(t.timeoutMs,"timeoutMs"),assertPositiveFiniteNumber(t.maxInputBytes,"maxInputBytes"),assertPositiveFiniteNumber(t.maxDocumentNodes,"maxDocumentNodes"),assertPositiveFiniteNumber(t.maxDocumentDepth,"maxDocumentDepth"),assertPositiveFiniteNumber(t.maxValidationErrors,"maxValidationErrors"),assertPositiveFiniteNumber(t.maxErrorMessageLength,"maxErrorMessageLength"),t}(t),o=function(e){const t=new AbortController;if(e){if(!e.aborted){const onAbort=()=>t.abort();return e.addEventListener("abort",onAbort,{once:!0}),{controller:t,dispose:()=>e.removeEventListener("abort",onAbort)}}t.abort()}return{controller:t,dispose:()=>{}}}(r.signal),n={options:r,controller:o.controller,deadline:Date.now()+r.timeoutMs};try{return await runWithDeadline(n,async()=>{if("file"===r.inputKind){const t=await async function(e,t){const r=normalizeFilePath(e);if(!t.options.allowedRootDirectory)throw new I("FILE_INPUT_FORBIDDEN","File input requires allowedRootDirectory.");return async function(e,t){const r=(0,S.isAbsolute)(e)?e:(0,S.resolve)(t,e),o=await(0,N.realpath)(r),n=(0,S.relative)(t,o);if(n.startsWith("..")||""===n||"\\"===S.sep&&/^[a-zA-Z]:/.test(n))throw new I("PATH_OUTSIDE_ROOT",`File path is outside the allowed root directory: ${e}.`);return o}(r,await async function(e){if(e.rootDirectory)return e.rootDirectory;const t=e.options.allowedRootDirectory;if(!t)throw new I("INVALID_OPTION","allowedRootDirectory is required for file operations.");const r=(0,S.resolve)(t),o=await(0,N.realpath)(r);if(!(await(0,N.stat)(o)).isDirectory())throw new I("INVALID_OPTION",`allowedRootDirectory is not a directory: ${t}.`);return e.rootDirectory=o,o}(t))}(e,n),o=await async function(e,t,r,o){throwIfCancelled(r);const n=await(0,N.open)(e,"r");try{const r=await n.stat();if(r.size>t)throw new I(o,`File exceeds maximum allowed size of ${t} bytes: ${e}.`);const a=Buffer.alloc(r.size);return await n.read(a,0,r.size,0),a.toString("utf8")}finally{await n.close()}}(t,r.maxInputBytes,n,"INPUT_FILE_TOO_LARGE");return validateRawContent(o,{...n,options:{...r,baseFilePath:t}})}return assertByteLength(e,r.maxInputBytes,"INPUT_TOO_LARGE"),validateRawContent(e,n)})}catch(e){throw function(e){if(e instanceof I)return e;return new I("UNKNOWN_ERROR",`OpenAPI validation failed: ${getErrorMessage6(e)}.`,e)}(e)}finally{o.dispose(),n.controller.abort()}}async function validateOpenAPIFile(e,t={}){return validateOpenAPISpec(e,{...t,inputKind:"file",baseFilePath:e})}async function validateRawContent(e,t){throwIfCancelled(t),assertByteLength(e,t.options.maxInputBytes,"INPUT_TOO_LARGE");const r=function(e){try{const t=(0,A.parse)(e);if(null===t||"object"!=typeof t||Array.isArray(t))throw new I("INVALID_DOCUMENT_SHAPE","OpenAPI document must be a JSON object.");return t}catch(e){if(e instanceof I)throw e;throw new I("PARSE_ERROR",`Failed to parse OpenAPI document: ${getErrorMessage6(e)}.`,e)}}(e);!function(e,t){let r=0;const o=[{value:e,depth:0}];for(;o.length>0;){const{value:e,depth:n}=o.pop();if(n>t.maxDocumentDepth)throw new I("DOCUMENT_TOO_DEEP",`Document exceeds maximum nesting depth of ${t.maxDocumentDepth}.`);if(r++,r>t.maxDocumentNodes)throw new I("DOCUMENT_TOO_LARGE",`Document exceeds maximum node count of ${t.maxDocumentNodes}.`);if(Array.isArray(e))for(const t of e)o.push({value:t,depth:n+1});else if(null!==e&&"object"==typeof e)for(const t of Object.values(e))o.push({value:t,depth:n+1})}}(r,t.options),function(e){const t=e.openapi??e.swagger;if("string"!=typeof t||0===t.length)throw new I("UNSUPPORTED_VERSION","Document must declare an openapi or swagger version.");const r=Number.parseInt(t.split(".")[0]??"",10);if(!Number.isFinite(r)||2!==r&&3!==r)throw new I("UNSUPPORTED_VERSION",`Unsupported OpenAPI/Swagger version: ${t}. Supported: 2.x, 3.x.`)}(r);const o=await runWithDeadline(t,()=>async function(){return D??=import("@powerduck/openapi-parser").then(({validate:e})=>e),D}()),n=await runWithDeadline(t,()=>o(r,{throwOnError:!1}));if(!n.valid)throw new I("SPEC_VALIDATION_FAILED",`OpenAPI validation failed: ${function(e,t,r){const o=e.slice(0,t).map(e=>{const t=e.instancePath??"",o=e.message??"Unknown error",n=t?`${t}: ${o}`:o;return n.length>r?`${n.slice(0,r)}...`:n});e.length>t&&o.push(`... and ${e.length-t} more errors`);return o.join("; ")}(n.errors??[],t.options.maxValidationErrors,t.options.maxErrorMessageLength)}`);return n.specification}function assertPositiveFiniteNumber(e,t){if(!Number.isFinite(e)||e<=0)throw new I("INVALID_OPTION",`${t} must be a positive finite number, got: ${String(e)}.`)}async function runWithDeadline(e,t){throwIfCancelled(e);const r=await Promise.race([t(),createDeadlinePromise(e)]);return throwIfCancelled(e),r}function createDeadlinePromise(e){return new Promise((t,r)=>{const o=e.deadline-Date.now(),n=Math.max(0,Math.min(o,2147483647)),a=setTimeout(()=>{r(new I("OPERATION_TIMEOUT",`OpenAPI validation operation timed out after ${e.options.timeoutMs}ms.`))},n);e.controller.signal.addEventListener("abort",()=>{clearTimeout(a),r(new I("OPERATION_ABORTED","OpenAPI validation operation was aborted."))},{once:!0})})}function throwIfCancelled(e){if(e.controller.signal.aborted)throw new I("OPERATION_ABORTED","OpenAPI validation operation was aborted.");if(Date.now()>e.deadline)throw new I("OPERATION_TIMEOUT",`OpenAPI validation operation timed out after ${e.options.timeoutMs}ms.`)}function assertByteLength(e,t,r){const o=Buffer.byteLength(e,"utf8");if(o>t)throw new I(r,`Input exceeds maximum allowed size of ${t} bytes (actual: ${o} bytes).`)}function getErrorMessage6(e){return e instanceof Error?e.message:String(e)}
1
+ "use strict";Object.create;var e,t=Object.defineProperty,r=Object.getOwnPropertyDescriptor,o=Object.getOwnPropertyNames,n=(Object.getPrototypeOf,Object.prototype.hasOwnProperty),__copyProps=(e,a,i,s)=>{if(a&&"object"==typeof a||"function"==typeof a)for(let c of o(a))n.call(e,c)||c===i||t(e,c,{get:()=>a[c],enumerable:!(s=r(a,c))||s.enumerable});return e},a={};((e,r)=>{for(var o in r)t(e,o,{get:r[o],enumerable:!0})})(a,{OpenApiValidationError:()=>I,assertConfigFormat:()=>assertConfigFormat,assertNonEmptyString:()=>assertNonEmptyString,assertPatchOperations:()=>assertPatchOperations,assertPatchPath:()=>assertPatchPath,createError:()=>createError2,deleteConfigValue:()=>deleteConfigValue,deleteContentValue:()=>deleteContentValue,detectFormat:()=>detectFormat,getErrorMessage:()=>getErrorMessage2,normalizeFilePath:()=>normalizeFilePath,patchConfigFile:()=>patchConfigFile,patchContent:()=>patchContent,readConfigFile:()=>readConfigFile,releaseAllLocalLocks:()=>releaseAllLocalLocks,setConfigValue:()=>setConfigValue,setContentValue:()=>setContentValue,validateOpenAPIFile:()=>validateOpenAPIFile,validateOpenAPISpec:()=>validateOpenAPISpec,withFileLock:()=>withFileLock,writeConfigFile:()=>writeConfigFile}),module.exports=(e=a,__copyProps(t({},"__esModule",{value:!0}),e));var i=require("jsonc-parser"),s={insertSpaces:!0,tabSize:2,eol:"\n"};function validateOperation(e){if(null===e||"object"!=typeof e)throw new TypeError("Patch operation must be an object.");if(!Array.isArray(e.path)||0===e.path.length)throw new Error("Patch operation path must be a non-empty array.");if("add"!==e.op&&"replace"!==e.op&&"remove"!==e.op)throw new Error(`Unsupported JSON patch operation: ${String(e.op)}`);if(("add"===e.op||"replace"===e.op)&&!Object.prototype.hasOwnProperty.call(e,"value"))throw new Error(`Patch operation "${e.op}" requires a value.`)}function normalizePath(e){return e.map(e=>{if("number"==typeof e){if(!Number.isSafeInteger(e)||e<0)throw new Error(`Invalid array index: ${e}`);return e}if("string"!=typeof e)throw new TypeError(`Patch path segments must be strings or numbers; received ${typeof e}.`);return e})}function applyAdd(e,t,r){const o=function(e,t){if(1===t.length){if("object"!==e.type&&"array"!==e.type)throw new Error("Cannot add a root child to a scalar JSON value.");return e}const r=t.slice(0,-1),o=(0,i.findNodeAtLocation)(e,r);if(void 0===o)throw new Error(`Cannot add value because its parent does not exist at path: ${formatPath(r)}`);if("object"!==o.type&&"array"!==o.type)throw new Error(`Cannot add value because its parent is not an object or array at path: ${formatPath(r)}`);return o}(getTree(e),t),n=t[t.length-1];if("array"===o.type){const a=function(e,t){if("number"!=typeof e)throw new Error(`Array index must be a number at path: ${formatPath(t)}`);if(!Number.isSafeInteger(e)||e<0)throw new Error(`Invalid array index ${e} at path: ${formatPath(t)}`);return e}(n,t),i=o.children?.length??0;if(a>i)throw new Error(`Cannot add at array index ${a}; array length is ${i} at path: ${formatPath(t.slice(0,-1))}`);return applyModify(e,t,r,!0)}if("object"===o.type){if("string"!=typeof n)throw new Error(`Object property path segment must be a string at path: ${formatPath(t)}`);return applyModify(e,t,r,!1)}throw new Error(`Cannot add a child to non-container value at path: ${formatPath(t.slice(0,-1))}`)}function applyReplace(e,t,r){const o=getTree(e);if(void 0===(0,i.findNodeAtLocation)(o,t))throw new Error(`Cannot replace a value that does not exist at path: ${formatPath(t)}`);return applyModify(e,t,r,!1)}function applyRemove(e,t){const r=getTree(e);if(void 0===(0,i.findNodeAtLocation)(r,t))throw new Error(`Cannot remove a value that does not exist at path: ${formatPath(t)}`);return applyModify(e,t,void 0,!1)}function applyModify(e,t,r,o){const n=(0,i.modify)(e,t,r,{formattingOptions:s,isArrayInsertion:o});if(0===n.length)throw new Error(`No JSONC edit was generated for path: ${formatPath(t)}`);return(0,i.applyEdits)(e,n)}function getTree(e){const t=[],r=(0,i.parseTree)(e,t,{allowTrailingComma:!0,disallowComments:!1});if(void 0===r||t.length>0)throw new Error(`The source text is not valid JSON or JSONC${function(e){if(0===e.length)return"";return` (parse errors: ${e.map(e=>`code=${e.error}, offset=${e.offset}`).join("; ")})`}(t)}.`);return r}function formatPath(e){return`[${e.map(e=>JSON.stringify(e)).join(", ")}]`}function safeStringify(e){try{return JSON.stringify(e)}catch{return"[unserializable patch operation]"}}function getErrorMessage(e){return e instanceof Error?e.message:String(e)}function createError(e,t){const r=new Error(e);try{Object.defineProperty(r,"cause",{configurable:!0,enumerable:!1,value:t,writable:!0})}catch{}return r}var c=require("yaml");function applyYamlOperation(e,t){!function(e){if(!Array.isArray(e.path)||0===e.path.length)throw new Error("[confedit] Patch path must be a non-empty array.");if("add"!==e.op&&"replace"!==e.op&&"remove"!==e.op)throw new Error(`[confedit] Unsupported patch operation: ${String(e.op)}.`)}(t);const r=t.path,o=function(e,t){if(0===t.length)throw new Error("[confedit] Replacing the YAML document root is not supported.");if(1===t.length){if(null===e.contents)throw new Error("[confedit] Cannot patch an empty YAML document without a root container.");return e.contents}const r=t.slice(0,-1),o=e.getIn(r,!0);if(null==o)throw new Error(`[confedit] Missing parent path: ${formatPath2(r)}.`);if(!(0,c.isMap)(o)&&!(0,c.isSeq)(o))throw new Error(`[confedit] Parent at ${formatPath2(r)} is not a YAML map or sequence.`);return o}(e,r),n=r[r.length-1];if((0,c.isMap)(o))!function(e,t,r,o){if("string"!=typeof r)throw new Error(`[confedit] YAML map keys must be strings at ${formatPath2(o.path)}.`);const n=t.has(r);switch(o.op){case"add":return void t.set(r,e.createNode(o.value));case"replace":if(!n)throw new Error(`[confedit] Cannot replace missing value at ${formatPath2(o.path)}.`);return void t.set(r,e.createNode(o.value));case"remove":if(!n)throw new Error(`[confedit] Cannot remove missing value at ${formatPath2(o.path)}.`);return void t.delete(r);default:throw new Error(`[confedit] Unsupported patch operation: ${String(o.op)}.`)}}(e,o,n,t);else{if(!(0,c.isSeq)(o))throw new Error(`[confedit] Cannot apply patch at ${formatPath2(r)} because its parent is not a YAML map or sequence.`);!function(e,t,r,o){if("number"!=typeof r||!Number.isSafeInteger(r)||r<0)throw new Error(`[confedit] YAML sequence indexes must be non-negative integers at ${formatPath2(o.path)}.`);const n=t.items.length;switch(o.op){case"add":if(r>n)throw new Error(`[confedit] Cannot insert at index ${r}; sequence length is ${n}.`);return void t.items.splice(r,0,e.createNode(o.value));case"replace":if(r>=n)throw new Error(`[confedit] Cannot replace index ${r}; sequence length is ${n}.`);return void(t.items[r]=e.createNode(o.value));case"remove":if(r>=n)throw new Error(`[confedit] Cannot remove index ${r}; sequence length is ${n}.`);return void t.items.splice(r,1);default:throw new Error(`[confedit] Unsupported patch operation: ${String(o.op)}.`)}}(e,o,n,t)}}function formatPath2(e){return`[${e.map(e=>JSON.stringify(e)).join(", ")}]`}function assertNonEmptyString(e,t){if("string"!=typeof e||0===e.length)throw new TypeError(`[confedit] ${t} must be a non-empty string.`)}function assertPatchPath(e,t="path"){if(!Array.isArray(e)||0===e.length)throw new TypeError(`[confedit] ${t} must be a non-empty array.`);for(const[r,o]of e.entries())if("string"!=typeof o){if("number"!=typeof o||!Number.isSafeInteger(o)||o<0)throw new TypeError(`[confedit] ${t}[${r}] must be a non-empty string or a non-negative integer.`)}else if(0===o.length)throw new TypeError(`[confedit] ${t}[${r}] must not be an empty string.`)}function assertPatchOperations(e){if(!Array.isArray(e))throw new TypeError("[confedit] ops must be an array.");for(const[t,r]of e.entries()){if(null===r||"object"!=typeof r)throw new TypeError(`[confedit] Patch operation at index ${t} must be an object.`);if("add"!==r.op&&"replace"!==r.op&&"remove"!==r.op)throw new Error(`[confedit] Unsupported patch operation at index ${t}: ${String(r.op)}.`);if(assertPatchPath(r.path,`ops[${t}].path`),("add"===r.op||"replace"===r.op)&&!Object.prototype.hasOwnProperty.call(r,"value"))throw new TypeError(`[confedit] Patch operation at index ${t} requires a value.`)}}function assertConfigFormat(e){if("json"!==e&&"jsonc"!==e&&"yaml"!==e)throw new Error(`[confedit] Unsupported configuration format: ${String(e)}.`)}function getErrorMessage2(e){return e instanceof Error?e.message:String(e)}function createError2(e,t){const r=new Error(e);try{Object.defineProperty(r,"cause",{configurable:!0,enumerable:!1,value:t,writable:!0})}catch{}return r}function patchContent(e,t,r,o={}){if("string"!=typeof e)throw new TypeError("[confedit] content must be a string.");if(assertPatchOperations(t),assertConfigFormat(r),0===t.length)return e;const n=o.strict??!0;switch(r){case"json":case"jsonc":return function(e,t,r=!0){if("string"!=typeof e)throw new TypeError("[confedit] sourceText must be a string.");if(!Array.isArray(t))throw new TypeError("[confedit] ops must be an array.");let o=e;for(const e of t)try{validateOperation(e);const t=normalizePath(e.path);switch(e.op){case"add":o=applyAdd(o,t,e.value);break;case"replace":o=applyReplace(o,t,e.value);break;case"remove":o=applyRemove(o,t);break;default:throw new Error(`[confedit] Unsupported JSON patch operation: ${String(e.op)}`)}}catch(t){const o=`[confedit] Failed to apply JSON patch ${safeStringify(e)}: ${getErrorMessage(t)}`;if(r)throw createError(o,t);console.warn(o)}return o}(e,t,n);case"yaml":return function(e,t,r=!0){const o=(0,c.parseDocument)(e,{prettyErrors:!0,strict:!0});if(o.errors.length>0)throw new Error(`[confedit] Invalid YAML source: ${o.errors.map(e=>e.message).join("; ")}`);for(const e of t)try{applyYamlOperation(o,e)}catch(t){if(r)throw t;console.warn(`[confedit yaml patch warn] Skip operation ${JSON.stringify(e)}`,t)}return o.toString()}(e,t,n)}}function setContentValue(e,t,r,o){return assertPatchPath(t),patchContent(e,[{op:"add",path:[...t],value:r}],o)}function deleteContentValue(e,t,r){return assertPatchPath(t),patchContent(e,[{op:"remove",path:[...t]}],r)}var l=require("fs/promises"),u=require("path"),f=require("url");function normalizeFilePath(e){if("string"!=typeof e||0===e.length)throw new TypeError("[confedit] filePath must be a non-empty string.");if(e.startsWith("file:"))try{return(0,f.fileURLToPath)(e)}catch(t){throw function(e,t){const r=new Error(e);try{Object.defineProperty(r,"cause",{configurable:!0,enumerable:!1,value:t,writable:!0})}catch{}return r}(`[confedit] Invalid file URL "${e}": ${function(e){return e instanceof Error?e.message:String(e)}(t)}`,t)}return(0,u.isAbsolute)(e)?e:(0,u.resolve)(e)}async function readConfigFile(e){assertNonEmptyString(e,"filePath");const t=normalizeFilePath(e);try{return await(0,l.readFile)(t,"utf8")}catch(t){throw createError2(`[confedit] Failed to read "${e}": ${getErrorMessage2(t)}`,t)}}var p=require("fs/promises"),h=require("path"),d=require("crypto"),m=require("fs/promises"),w=require("path");async function atomicWrite(e,t){if(function(e,t){if("string"!=typeof e||0===e.length)throw new TypeError(`[confedit] ${t} must be a non-empty string.`)}(e,"filePath"),"string"!=typeof t)throw new TypeError("[confedit] content must be a string.");const r=normalizeFilePath(e),o=(0,w.dirname)(r),n=(0,w.basename)(r),a=`${process.pid}.${Date.now()}.${(0,d.randomBytes)(12).toString("hex")}`,i=(0,w.join)(o,`.${n}.${a}.tmp`),s=(0,w.join)(o,`.${n}.${a}.bak`);let c,l=!1,u=!1;try{await(0,m.mkdir)(o,{recursive:!0});const e=await async function(e){try{return 511&(await(0,m.stat)(e)).mode}catch(e){if("ENOENT"===getErrorCode(e))return;throw e}}(r);c=await(0,m.open)(i,"wx",e??384);try{await c.writeFile(t,"utf8"),await c.sync()}finally{await c.close(),c=void 0}void 0!==e&&await(0,m.chmod)(i,e);try{await(0,m.rename)(i,r),u=!0}catch(e){if(!function(e){if("win32"!==process.platform)return!1;const t=getErrorCode(e);return"EEXIST"===t||"EPERM"===t||"EACCES"===t}(e))throw e;await(0,m.rename)(r,s),l=!0;try{await(0,m.rename)(i,r),u=!0}catch(e){const t=await async function(e,t){try{return await(0,m.unlink)(e).catch(e=>{if("ENOENT"!==getErrorCode(e))throw e}),await(0,m.rename)(t,e),!0}catch{return!1}}(r,s);throw t&&(l=!1),createError4(t?`[confedit] Failed to replace "${r}", but the original file was restored.`:`[confedit] Failed to replace "${r}". The backup was retained at "${s}".`,e)}}await syncDirectory(o),l&&(await(0,m.unlink)(s),l=!1,await syncDirectory(o))}catch(t){throw void 0!==c&&await c.close().catch(()=>{}),createError4(`[confedit] Failed to atomically write "${e}": ${function(e){return e instanceof Error?e.message:String(e)}(t)}`,t)}finally{await(0,m.unlink)(i).catch(()=>{}),u&&l&&await(0,m.unlink)(s).catch(()=>{})}}async function syncDirectory(e){let t;try{t=await(0,m.open)(e,"r"),await t.sync()}catch(e){const t=getErrorCode(e);if("EINVAL"!==t&&"EPERM"!==t&&"EISDIR"!==t&&"ENOSYS"!==t&&"ENOTSUP"!==t)throw e}finally{await(t?.close().catch(()=>{}))}}function getErrorCode(e){if(null!==e&&"object"==typeof e&&"code"in e&&"string"==typeof e.code)return e.code}function createError4(e,t){const r=new Error(e);try{Object.defineProperty(r,"cause",{configurable:!0,enumerable:!1,value:t,writable:!0})}catch{}return r}var y=require("crypto"),g=require("fs/promises"),E=require("os"),b=1e4,v=25,P=1e3,O=6e4,$=new Map,M=new Set;async function withFileLock(e,t,r={}){const o=normalizeFilePath(e);return function(e){if(void 0!==e.timeoutMs&&(!Number.isFinite(e.timeoutMs)||e.timeoutMs<0))throw new TypeError("[confedit] lock timeoutMs must be a non-negative finite number.");if(void 0!==e.retryDelayMs&&(!Number.isFinite(e.retryDelayMs)||e.retryDelayMs<=0))throw new TypeError("[confedit] lock retryDelayMs must be a positive finite number.");if(void 0!==e.staleThresholdMs&&(!Number.isFinite(e.staleThresholdMs)||e.staleThresholdMs<=0))throw new TypeError("[confedit] lock staleThresholdMs must be a positive finite number.")}(r),function(e,t){const r=$.get(e)??Promise.resolve();let o;const n=new Promise(e=>{o=e}),a=r.catch(()=>{}).then(()=>n);return $.set(e,a),r.catch(()=>{}).then(t).finally(()=>{o(),$.get(e)===a&&$.delete(e)})}(o,async()=>{const e=await async function(e,t){const r=t.timeoutMs??b,o=t.retryDelayMs??v,n=t.staleThresholdMs??Math.max(2*r,O),a=t.allowStaleRecovery??!1,i=`${e}.confedit.lock`,s=Date.now();let c=o;const l=createToken(),u={version:1,pid:process.pid,hostname:(0,E.hostname)(),createdAt:(new Date).toISOString(),token:l};for(;;)try{const e=await(0,g.open)(i,"wx",384);try{await(0,g.writeFile)(e,`${JSON.stringify(u)}\n`,"utf8"),await e.sync()}finally{await e.close()}return M.add(i),createReleaseHandler(i,l)}catch(t){if("EEXIST"!==getErrorCode2(t))throw createError5(`[confedit] Failed to acquire lock "${i}": ${getErrorMessage5(t)}`,t);if(a&&await tryRecoverStaleLock(i,n),Date.now()-s>=r)throw new Error(`[confedit] Timed out waiting for lock on "${e}" after ${r}ms.`);await sleep(c),c=Math.min(Math.ceil(1.5*c),P)}}(o,r);try{return await t()}finally{await e()}})}async function releaseAllLocalLocks(){const e=Array.from(M).map(e=>(0,g.unlink)(e).catch(()=>{}));await Promise.allSettled(e),M.clear()}function createReleaseHandler(e,t){return async()=>{try{const r=await readLockData(e);r?.token===t&&(await(0,g.unlink)(e).catch(()=>{}),M.delete(e))}catch{}}}async function tryRecoverStaleLock(e,t){const r=await readLockData(e);if(void 0===r||!isExpiredLock(r,t))return;const o=`${e}.stale.${createToken()}`;try{await(0,g.rename)(e,o)}catch(e){return void getErrorCode2(e)}try{const n=await readLockData(o);if(n?.token===r.token&&isExpiredLock(n,t))return void await(0,g.unlink)(o).catch(()=>{});await(0,g.rename)(o,e).catch(()=>{})}catch{}}function isExpiredLock(e,t){const r=Date.parse(e.createdAt);return Number.isFinite(r)&&Date.now()-r>t}async function readLockData(e){try{return function(e){try{const t=JSON.parse(e);if(1!==t.version||"number"!=typeof t.pid||!Number.isSafeInteger(t.pid)||t.pid<=0||"string"!=typeof t.hostname||"string"!=typeof t.createdAt||!Number.isFinite(Date.parse(t.createdAt))||"string"!=typeof t.token||t.token.length<16)return;return{version:1,pid:t.pid,hostname:t.hostname,createdAt:t.createdAt,token:t.token}}catch{return}}(await(0,g.readFile)(e,"utf8"))}catch{return}}function createToken(){return`${process.pid}-${Date.now()}-${(0,y.randomBytes)(16).toString("hex")}`}function sleep(e){return new Promise(t=>setTimeout(t,e))}function getErrorCode2(e){if(null!==e&&"object"==typeof e&&"code"in e&&"string"==typeof e.code)return e.code}function getErrorMessage5(e){return e instanceof Error?e.message:String(e)}function createError5(e,t){const r=new Error(e);try{Object.defineProperty(r,"cause",{configurable:!0,enumerable:!1,value:t,writable:!0})}catch{}return r}async function writeConfigFile(e,t,r={}){if(assertNonEmptyString(e,"filePath"),"string"!=typeof t)throw new TypeError("[confedit] content must be a string.");const o=normalizeFilePath(e),writeTransaction=async()=>{try{await atomicWrite(o,t)}catch(t){throw createError2(`[confedit] Failed to write "${e}": ${getErrorMessage2(t)}`,t)}};r.lock??!0?(await(0,p.mkdir)((0,h.dirname)(o),{recursive:!0}),await withFileLock(o,writeTransaction,{timeoutMs:r.lockTimeoutMs,retryDelayMs:r.lockRetryDelayMs,staleThresholdMs:r.lockStaleThresholdMs,allowStaleRecovery:r.allowStaleRecovery})):await writeTransaction()}var T=require("path");function detectFormat(e){const t=normalizeFilePath(e);switch((0,T.extname)(t).toLowerCase()){case".json":return"json";case".jsonc":return"jsonc";case".yaml":case".yml":return"yaml";default:throw new Error(`[confedit] Cannot detect a supported configuration format for "${e}". Expected .json, .jsonc, .yaml, or .yml.`)}}async function patchConfigFile(e,t,r={}){if("string"!=typeof e||0===e.length)throw new TypeError("[confedit] filePath must be a non-empty string.");if(assertPatchOperations(t),0===t.length)return;const o=normalizeFilePath(e),n=r.format??detectFormat(o);assertConfigFormat(n),function(e){if(void 0!==e.lockTimeoutMs&&(!Number.isFinite(e.lockTimeoutMs)||e.lockTimeoutMs<0))throw new TypeError("[confedit] lockTimeoutMs must be a non-negative finite number.");if(void 0!==e.lockRetryDelayMs&&(!Number.isFinite(e.lockRetryDelayMs)||e.lockRetryDelayMs<=0))throw new TypeError("[confedit] lockRetryDelayMs must be a positive finite number.");if(void 0!==e.lockStaleThresholdMs&&(!Number.isFinite(e.lockStaleThresholdMs)||e.lockStaleThresholdMs<=0))throw new TypeError("[confedit] lockStaleThresholdMs must be a positive finite number.")}(r);const a=r.strict??!0,patchTransaction=async()=>{const r=await readConfigFile(o),i=patchContent(r,t,n,{strict:a});if(i!==r)try{await atomicWrite(o,i)}catch(t){throw createError2(`[confedit] Failed to write "${e}": ${getErrorMessage2(t)}`,t)}};r.lock??!0?await withFileLock(o,patchTransaction,{timeoutMs:r.lockTimeoutMs,retryDelayMs:r.lockRetryDelayMs,staleThresholdMs:r.lockStaleThresholdMs,allowStaleRecovery:r.allowStaleRecovery}):await patchTransaction()}async function setConfigValue(e,t,r,o={}){await patchConfigFile(e,[{op:"add",path:[...t],value:r}],o)}async function deleteConfigValue(e,t,r={}){await patchConfigFile(e,[{op:"remove",path:[...t]}],r)}var D,N=require("fs/promises"),S=require("path"),A=require("yaml"),I=class extends Error{constructor(e,t,r){super(t),this.name="OpenApiValidationError",this.code=e,this.cause=r}},F={inputKind:"content",timeoutMs:15e3,maxInputBytes:5242880,maxDocumentNodes:1e5,maxDocumentDepth:100,maxValidationErrors:50,maxErrorMessageLength:1e3};async function validateOpenAPISpec(e,t={}){!function(e,t){if("string"!=typeof e||0===e.length)throw new TypeError(`[confedit] ${t} must be a non-empty string.`)}(e,"input");const r=function(e){const t={inputKind:e.inputKind??F.inputKind,baseFilePath:e.baseFilePath,allowedRootDirectory:e.allowedRootDirectory,timeoutMs:e.timeoutMs??F.timeoutMs,maxInputBytes:e.maxInputBytes??F.maxInputBytes,maxDocumentNodes:e.maxDocumentNodes??F.maxDocumentNodes,maxDocumentDepth:e.maxDocumentDepth??F.maxDocumentDepth,maxValidationErrors:e.maxValidationErrors??F.maxValidationErrors,maxErrorMessageLength:e.maxErrorMessageLength??F.maxErrorMessageLength,signal:e.signal};if("content"!==t.inputKind&&"file"!==t.inputKind)throw new I("INVALID_OPTION",`inputKind must be "content" or "file", got: ${String(t.inputKind)}.`);return assertPositiveFiniteNumber(t.timeoutMs,"timeoutMs"),assertPositiveFiniteNumber(t.maxInputBytes,"maxInputBytes"),assertPositiveFiniteNumber(t.maxDocumentNodes,"maxDocumentNodes"),assertPositiveFiniteNumber(t.maxDocumentDepth,"maxDocumentDepth"),assertPositiveFiniteNumber(t.maxValidationErrors,"maxValidationErrors"),assertPositiveFiniteNumber(t.maxErrorMessageLength,"maxErrorMessageLength"),t}(t),o=function(e){const t=new AbortController;if(e){if(!e.aborted){const onAbort=()=>t.abort();return e.addEventListener("abort",onAbort,{once:!0}),{controller:t,dispose:()=>e.removeEventListener("abort",onAbort)}}t.abort()}return{controller:t,dispose:()=>{}}}(r.signal),n={options:r,controller:o.controller,deadline:Date.now()+r.timeoutMs};try{return await runWithDeadline(n,async()=>{if("file"===r.inputKind){const t=await async function(e,t){const r=normalizeFilePath(e);if(!t.options.allowedRootDirectory)throw new I("FILE_INPUT_FORBIDDEN","File input requires allowedRootDirectory.");return async function(e,t){const r=(0,S.isAbsolute)(e)?e:(0,S.resolve)(t,e),o=await(0,N.realpath)(r),n=(0,S.relative)(t,o);if(n.startsWith("..")||""===n||"\\"===S.sep&&/^[a-zA-Z]:/.test(n))throw new I("PATH_OUTSIDE_ROOT",`File path is outside the allowed root directory: ${e}.`);return o}(r,await async function(e){if(e.rootDirectory)return e.rootDirectory;const t=e.options.allowedRootDirectory;if(!t)throw new I("INVALID_OPTION","allowedRootDirectory is required for file operations.");const r=(0,S.resolve)(t),o=await(0,N.realpath)(r);if(!(await(0,N.stat)(o)).isDirectory())throw new I("INVALID_OPTION",`allowedRootDirectory is not a directory: ${t}.`);return e.rootDirectory=o,o}(t))}(e,n),o=await async function(e,t,r,o){throwIfCancelled(r);const n=await(0,N.open)(e,"r");try{const r=await n.stat();if(r.size>t)throw new I(o,`File exceeds maximum allowed size of ${t} bytes: ${e}.`);const a=Buffer.alloc(r.size);return await n.read(a,0,r.size,0),a.toString("utf8")}finally{await n.close()}}(t,r.maxInputBytes,n,"INPUT_FILE_TOO_LARGE");return validateRawContent(o,{...n,options:{...r,baseFilePath:t}})}return assertByteLength(e,r.maxInputBytes,"INPUT_TOO_LARGE"),validateRawContent(e,n)})}catch(e){throw function(e){if(e instanceof I)return e;return new I("UNKNOWN_ERROR",`OpenAPI validation failed: ${getErrorMessage6(e)}.`,e)}(e)}finally{o.dispose(),n.controller.abort()}}async function validateOpenAPIFile(e,t={}){return validateOpenAPISpec(e,{...t,inputKind:"file",baseFilePath:e})}async function validateRawContent(e,t){throwIfCancelled(t),assertByteLength(e,t.options.maxInputBytes,"INPUT_TOO_LARGE");const r=function(e){try{const t=(0,A.parse)(e);if(null===t||"object"!=typeof t||Array.isArray(t))throw new I("INVALID_DOCUMENT_SHAPE","OpenAPI document must be a JSON object.");return t}catch(e){if(e instanceof I)throw e;throw new I("PARSE_ERROR",`Failed to parse OpenAPI document: ${getErrorMessage6(e)}.`,e)}}(e);!function(e,t){let r=0;const o=[{value:e,depth:0}];for(;o.length>0;){const{value:e,depth:n}=o.pop();if(n>t.maxDocumentDepth)throw new I("DOCUMENT_TOO_DEEP",`Document exceeds maximum nesting depth of ${t.maxDocumentDepth}.`);if(r++,r>t.maxDocumentNodes)throw new I("DOCUMENT_TOO_LARGE",`Document exceeds maximum node count of ${t.maxDocumentNodes}.`);if(Array.isArray(e))for(const t of e)o.push({value:t,depth:n+1});else if(null!==e&&"object"==typeof e)for(const t of Object.values(e))o.push({value:t,depth:n+1})}}(r,t.options),function(e){const t=e.openapi??e.swagger;if("string"!=typeof t||0===t.length)throw new I("UNSUPPORTED_VERSION","Document must declare an openapi or swagger version.");const r=Number.parseInt(t.split(".")[0]??"",10);if(!Number.isFinite(r)||2!==r&&3!==r)throw new I("UNSUPPORTED_VERSION",`Unsupported OpenAPI/Swagger version: ${t}. Supported: 2.x, 3.x.`)}(r);const o=await runWithDeadline(t,()=>async function(){return D??=import("@powerduck/openapi-parser").then(({validate:e})=>e),D}()),n=await runWithDeadline(t,()=>o(r,{throwOnError:!1}));if(!n.valid)throw new I("SPEC_VALIDATION_FAILED",`OpenAPI validation failed: ${function(e,t,r){const o=e.slice(0,t).map(e=>{const t=e.instancePath??"",o=e.message??"Unknown error",n=t?`${t}: ${o}`:o;return n.length>r?`${n.slice(0,r)}...`:n});e.length>t&&o.push(`... and ${e.length-t} more errors`);return o.join("; ")}(n.errors??[],t.options.maxValidationErrors,t.options.maxErrorMessageLength)}`);return n.specification}function assertPositiveFiniteNumber(e,t){if(!Number.isFinite(e)||e<=0)throw new I("INVALID_OPTION",`${t} must be a positive finite number, got: ${String(e)}.`)}async function runWithDeadline(e,t){throwIfCancelled(e);const r=await Promise.race([t(),createDeadlinePromise(e)]);return throwIfCancelled(e),r}function createDeadlinePromise(e){return new Promise((t,r)=>{const o=e.deadline-Date.now(),n=Math.max(0,Math.min(o,2147483647)),a=setTimeout(()=>{r(new I("OPERATION_TIMEOUT",`OpenAPI validation operation timed out after ${e.options.timeoutMs}ms.`))},n);e.controller.signal.addEventListener("abort",()=>{clearTimeout(a),r(new I("OPERATION_ABORTED","OpenAPI validation operation was aborted."))},{once:!0})})}function throwIfCancelled(e){if(e.controller.signal.aborted)throw new I("OPERATION_ABORTED","OpenAPI validation operation was aborted.");if(Date.now()>e.deadline)throw new I("OPERATION_TIMEOUT",`OpenAPI validation operation timed out after ${e.options.timeoutMs}ms.`)}function assertByteLength(e,t,r){const o=Buffer.byteLength(e,"utf8");if(o>t)throw new I(r,`Input exceeds maximum allowed size of ${t} bytes (actual: ${o} bytes).`)}function getErrorMessage6(e){return e instanceof Error?e.message:String(e)}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@powerduck/conf-patch",
3
- "version": "0.3.1",
3
+ "version": "0.3.2",
4
4
  "description": "Two-layer configuration editor: pure core for patching JSON/JSONC/YAML strings (browser-safe), plus file layer with atomic writes and locking for Node.js/Electron. RFC 6902 JSON Patch, comment and formatting preservation, OpenAPI validation.",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",