Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 32 additions & 27 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -201,35 +201,40 @@
"description": "Use local IP as host"
},
"liveServer.settings.proxy": {
"type": "object",
"default": {
"enable": false,
"baseUri": "/",
"proxyUri": "http://127.0.0.1:80"
},
"properties": {
"enable": {
"type": "boolean",
"default": false,
"description": "Make it true to enable the feature."
},
"baseUri": {
"type": "string",
"default": "/",
"pattern": ""
},
"proxyUri": {
"type": "string",
"default": "http://127.0.0.1:80",
"pattern": "(^http[s]?://)(.[^(\\|\\s)]+)$"
"type": "array",
"default": [
{
"enable": false,
"baseUri": "/",
"proxyUri": "http://127.0.0.1:80"
}
},
"required": [
"enable",
"baseUri",
"proxyUri"
],
"additionalProperties": false,
"items": {
"type": "object",
"properties": {
"enable": {
"type": "boolean",
"default": false,
"description": "Make it true to enable the feature."
},
"baseUri": {
"type": "string",
"default": "/",
"pattern": ""
},
"proxyUri": {
"type": "string",
"default": "http://127.0.0.1:80",
"pattern": "(^http[s]?://)(.[^(\\|\\s)]+)$"
}
},
"required": [
"enable",
"baseUri",
"proxyUri"
],
"additionalProperties": false
Comment on lines +204 to +236

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[NITPICK] You changed the settings schema from an object to an array (breaking). Update any user-facing documentation and examples to reflect the new array form (docs/settings.md still shows the old single-object example). Also add a clear migration note in README/CHANGELOG describing the breaking change and example of the new shape so users know how to update their settings.

### Breaking change: `liveServer.settings.proxy`

The `liveServer.settings.proxy` configuration has changed from a single object to an array of proxy definitions.

**Before (single proxy object):**

```jsonc
"liveServer.settings.proxy": {
  "enable": true,
  "baseUri": "/api",
  "proxyUri": "http://127.0.0.1:3000"
}

After (multiple proxy objects):

"liveServer.settings.proxy": [
  {
    "enable": true,
    "baseUri": "/api",
    "proxyUri": "http://127.0.0.1:3000"
  },
  {
    "enable": true,
    "baseUri": "/auth",
    "proxyUri": "http://127.0.0.1:4000"
  }
]

Existing users must wrap their previous single proxy object in an array to avoid breakage.

Also update docs/settings.md to show the new array format under liveServer.settings.proxy.

},
"description": "To Setup Proxy"
},
"liveServer.settings.useWebExt": {
Expand Down
8 changes: 6 additions & 2 deletions src/Config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -89,8 +89,12 @@ export class Config {
return Config.getSettings<boolean>('useWebExt') || false;
}

public static get getProxy(): IProxy {
return Config.getSettings<IProxy>('proxy');
public static get getProxy(): IProxy[] {
const val = Config.getSettings<IProxy | IProxy[]>('proxy');
if (!val) {
return [];
}
return Array.isArray(val) ? val : [val];
Comment on lines +92 to +97

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[VALIDATION] getProxy now returns IProxy[] and wraps single-object values into an array which is good for backward compatibility. However, you're trusting the value from configuration without validating its shape. Add a runtime guard that validates each array element (ensure enable is boolean, baseUri and proxyUri are strings and proxyUri matches the expected protocol pattern) before returning it. This prevents later code from throwing if users set an invalid custom config.

public static get getProxy(): IProxy[] {
    const raw = Config.getSettings<unknown>('proxy');

    if (!raw) {
        return [];
    }

    const toArray = Array.isArray(raw) ? raw : [raw];

    const proxies: IProxy[] = [];
    for (const item of toArray) {
        if (!item || typeof item !== 'object') {
            continue;
        }

        const { enable, baseUri, proxyUri } = item as Partial<IProxy>;

        if (typeof enable !== 'boolean') {
            continue;
        }
        if (typeof baseUri !== 'string') {
            continue;
        }
        if (typeof proxyUri !== 'string') {
            continue;
        }
        if (!/^https?:\/\/.+$/i.test(proxyUri)) {
            continue;
        }

        proxies.push({ enable, baseUri, proxyUri } as IProxy);
    }

    return proxies;
}

}
Comment thread
GHLandy marked this conversation as resolved.

public static get getHttps(): IHttps {
Expand Down
25 changes: 19 additions & 6 deletions src/Helper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -144,15 +144,28 @@ export class Helper {
}

static getProxySetup() {
const proxySetup = Config.getProxy;
let proxy = [[]];
if (proxySetup.enable === true) {
proxy[0].push(proxySetup.baseUri, proxySetup.proxyUri);
let proxySetup = Config.getProxy;

// Handle missing/undefined config
if (!proxySetup) {
return null;
}
else {
proxy = null; // required to change the type [[]] to black array [].

// Backward compatibility: old single-object config
if (!Array.isArray(proxySetup)) {
proxySetup = [proxySetup];
}

const validProxy = proxySetup.filter(item => item && typeof item === 'object' && item.enable);

if (!validProxy.length) {
return null;
}

const proxy = validProxy.map(item => {
return [item.baseUri, item.proxyUri];
});

Comment thread
GHLandy marked this conversation as resolved.
return proxy;
Comment on lines 146 to 169

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[REFACTORING] This compatibility logic can be simplified and made safer: Config.getProxy already returns an array (empty if missing). Remove the redundant if (!proxySetup) return null; and the !Array.isArray branch (it will never run with current Config.getProxy). Also validate/normalize each proxy entry before mapping (ensure baseUri starts with '/' or normalize it, ensure proxyUri is a valid http(s) URL). Finally, handle the case of duplicate or overlapping baseUri rules (either document behavior or deduplicate) so consumers of the returned array won't get unexpected routing conflicts.

static getProxySetup() {
    const proxies = Config.getProxy; // always an array

    const validProxy = proxies
        .filter((item) => item && typeof item === 'object' && item.enable)
        .map((item) => {
            let baseUri = item.baseUri || '/';
            if (!baseUri.startsWith('/')) {
                baseUri = `/${baseUri}`;
            }

            // Basic normalization: trim spaces
            const proxyUri = (item.proxyUri || '').trim();

            return { ...item, baseUri, proxyUri };
        });

    if (!validProxy.length) {
        return null;
    }

    // Optional: dedupe by baseUri, keep first occurrence
    const seen = new Set<string>();
    const deduped = validProxy.filter((item) => {
        if (seen.has(item.baseUri)) {
            return false;
        }
        seen.add(item.baseUri);
        return true;
    });

    return deduped.map((item) => [item.baseUri, item.proxyUri]);
}

}
}