nodelistparser 1.2.1 → 1.3.1

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.
@@ -35,6 +35,12 @@ interface ShadowSocksConfig extends SharedConfigBase {
35
35
  obfsUri?: string;
36
36
  /** udp-port */
37
37
  udpPort?: number;
38
+ /** Shadow TLS Version */
39
+ shadowTlsVersion?: 1 | 2 | 3;
40
+ /** Shadow TLS Password */
41
+ shadowTlsPassword?: string;
42
+ /** Shadow TLS SNI */
43
+ shadowTlsSni?: string | undefined;
38
44
  }
39
45
  interface TrojanConfig extends SharedConfigBase, TlsSharedConfig {
40
46
  type: 'trojan';
@@ -107,6 +113,9 @@ declare namespace index$4 {
107
113
 
108
114
  declare function decode(config: Record<string, any>): SupportedConfig;
109
115
  declare function encode(config: SupportedConfig): {
116
+ name: string;
117
+ server: string;
118
+ port: number;
110
119
  tfo: boolean | undefined;
111
120
  'dialer-proxy': string | undefined;
112
121
  plugin?: string | undefined;
@@ -114,149 +123,89 @@ declare function encode(config: SupportedConfig): {
114
123
  mode: "http" | "tls";
115
124
  host: string | undefined;
116
125
  uri: string | undefined;
126
+ password?: undefined;
127
+ version?: undefined;
128
+ } | {
129
+ host: string | undefined;
130
+ password: string;
131
+ version: 1 | 2 | 3 | undefined;
132
+ mode?: undefined;
133
+ uri?: undefined;
117
134
  } | undefined;
118
- name: string;
119
135
  type: string;
120
- server: string;
121
- port: number;
122
136
  cipher: string;
123
137
  password: string;
124
138
  udp: boolean;
125
- alterId?: undefined;
126
- tls?: undefined;
127
- uuid?: undefined;
128
- servername?: undefined;
129
- 'ws-path'?: undefined;
130
- 'ws-headers'?: undefined;
131
- 'ws-opts'?: undefined;
132
- network?: undefined;
133
- ports?: undefined;
134
- down?: undefined;
135
- 'skip-cert-verify'?: undefined;
136
139
  } | {
137
- tfo: boolean | undefined;
138
- 'dialer-proxy': string | undefined;
139
140
  name: string;
140
- type: string;
141
141
  server: string;
142
142
  port: number;
143
+ tfo: boolean | undefined;
144
+ 'dialer-proxy': string | undefined;
145
+ type: string;
143
146
  password: string;
144
147
  sni: string | undefined;
145
148
  'skip-cert-verify': boolean;
146
149
  udp: boolean;
147
- alterId?: undefined;
148
- tls?: undefined;
149
- uuid?: undefined;
150
- servername?: undefined;
151
- 'ws-path'?: undefined;
152
- 'ws-headers'?: undefined;
153
- cipher?: undefined;
154
- 'ws-opts'?: undefined;
155
- network?: undefined;
156
- ports?: undefined;
157
- down?: undefined;
158
150
  } | {
151
+ name: string;
152
+ server: string;
153
+ port: number;
159
154
  tfo: boolean | undefined;
160
155
  'dialer-proxy': string | undefined;
161
156
  'skip-cert-verify': boolean;
162
157
  udp: boolean;
163
158
  version: number;
164
159
  token: string;
165
- name: string;
166
160
  type: string;
167
- server: string;
168
- port: number;
169
161
  sni: string | undefined;
170
162
  uuid: string;
171
163
  alpn: string[];
172
- alterId?: undefined;
173
- tls?: undefined;
174
- servername?: undefined;
175
- 'ws-path'?: undefined;
176
- 'ws-headers'?: undefined;
177
- cipher?: undefined;
178
- 'ws-opts'?: undefined;
179
- network?: undefined;
180
- ports?: undefined;
181
- password?: undefined;
182
- down?: undefined;
183
164
  } | {
165
+ name: string;
166
+ server: string;
167
+ port: number;
184
168
  tfo: boolean | undefined;
185
169
  'dialer-proxy': string | undefined;
186
170
  'skip-cert-verify': boolean;
187
171
  udp: boolean;
188
172
  version: number;
189
173
  password: string;
190
- name: string;
191
174
  type: string;
192
- server: string;
193
- port: number;
194
175
  sni: string | undefined;
195
176
  uuid: string;
196
177
  alpn: string[];
197
- alterId?: undefined;
198
- tls?: undefined;
199
- servername?: undefined;
200
- 'ws-path'?: undefined;
201
- 'ws-headers'?: undefined;
202
- cipher?: undefined;
203
- 'ws-opts'?: undefined;
204
- network?: undefined;
205
- ports?: undefined;
206
- down?: undefined;
207
178
  } | {
208
- tfo: boolean | undefined;
209
- 'dialer-proxy': string | undefined;
210
179
  name: string;
211
- type: string;
212
180
  server: string;
213
181
  port: number;
182
+ tfo: boolean | undefined;
183
+ 'dialer-proxy': string | undefined;
184
+ type: string;
214
185
  username: string;
215
186
  password: string;
216
187
  udp: boolean;
217
- alterId?: undefined;
218
- tls?: undefined;
219
- uuid?: undefined;
220
- servername?: undefined;
221
- 'ws-path'?: undefined;
222
- 'ws-headers'?: undefined;
223
- cipher?: undefined;
224
- 'ws-opts'?: undefined;
225
- network?: undefined;
226
- ports?: undefined;
227
- down?: undefined;
228
- 'skip-cert-verify'?: undefined;
229
188
  } | {
230
- tfo: boolean | undefined;
231
- 'dialer-proxy': string | undefined;
232
189
  name: string;
233
- type: string;
234
190
  server: string;
235
191
  port: number;
192
+ tfo: boolean | undefined;
193
+ 'dialer-proxy': string | undefined;
194
+ type: string;
236
195
  username: string;
237
196
  password: string;
238
- alterId?: undefined;
239
- tls?: undefined;
240
- udp?: undefined;
241
- uuid?: undefined;
242
- servername?: undefined;
243
- 'ws-path'?: undefined;
244
- 'ws-headers'?: undefined;
245
- cipher?: undefined;
246
- 'ws-opts'?: undefined;
247
- network?: undefined;
248
- ports?: undefined;
249
- down?: undefined;
250
- 'skip-cert-verify'?: undefined;
251
197
  } | {
198
+ name: string;
199
+ server: string;
200
+ port: number;
201
+ tfo: boolean | undefined;
202
+ 'dialer-proxy': string | undefined;
252
203
  alterId: number | undefined;
253
204
  tls: boolean;
254
205
  udp: boolean;
255
206
  uuid: string;
256
- name: string;
257
207
  servername: string | undefined;
258
208
  'ws-path': string | undefined;
259
- server: string;
260
209
  'ws-headers': Record<string, string> | undefined;
261
210
  cipher: string;
262
211
  'ws-opts': {
@@ -264,31 +213,18 @@ declare function encode(config: SupportedConfig): {
264
213
  headers: Record<string, string> | undefined;
265
214
  };
266
215
  type: string;
267
- port: number;
268
216
  network: string;
269
- ports?: undefined;
270
- password?: undefined;
271
- down?: undefined;
272
- 'skip-cert-verify'?: undefined;
273
217
  } | {
274
218
  name: string;
275
- type: string;
276
219
  server: string;
277
220
  port: number;
278
- ports: string | undefined;
221
+ tfo: boolean | undefined;
222
+ 'dialer-proxy': string | undefined;
223
+ type: string;
224
+ ports: string;
279
225
  password: string;
280
226
  down: string;
281
227
  'skip-cert-verify': boolean;
282
- alterId?: undefined;
283
- tls?: undefined;
284
- udp?: undefined;
285
- uuid?: undefined;
286
- servername?: undefined;
287
- 'ws-path'?: undefined;
288
- 'ws-headers'?: undefined;
289
- cipher?: undefined;
290
- 'ws-opts'?: undefined;
291
- network?: undefined;
292
228
  };
293
229
 
294
230
  declare const index$3_decode: typeof decode;
package/dist/cjs/index.js CHANGED
@@ -1 +1 @@
1
- var e=require("foxts/guard"),r=require("foxts/string-join"),s=require("node:buffer");const t=Number,o=e=>e.split(",").map(e=>e.trim());function p(e){let r=e.indexOf("=");return -1===r?["",""]:[e.slice(0,r).trim(),e.slice(r+1).trim()]}const n=new Set(["udp-relay","tfo","reuse","skip-cert-verify","tls","vmess-aead","ws"]),a=new Set(["version","download-bandwidth","port-hopping-interval","udp-port"]),i=new Set([]),d=new Set(["username","password","sni","encrypt-method","psk","obfs","obfs-host","uuid","alpn","block-quic","ws-path","ws-headers","port-hopping","token","underlying-proxy"]),u=Symbol("unsupported");function l(e){return e.split(",").reduce((e,r)=>{let[s,t]=r.split(":");return e[s.trim()]=t.trim(),e},{})}function c(e){let r,s,[o,p]=e.split("://");if("ss"!==o)throw Error(`[ss.decodeOne] Unsupported type: ${o}`);let[n,a]=p.split("@");n.includes(":")?[r,s]=n.split(":"):[r,s]=atob(n).split(":");let[i,d]=a.split(":"),[u,l]=d.split("#"),[c,y]=u.split("/"),w=null;if(y)try{w=new URLSearchParams(y).get("plugin")}catch(r){let e=Error(`[ss.decodeOne] Invalid plugins: ${y}`);throw e.cause=r,e}let m=(w?.split(";")??[]).reduce((e,r)=>{let[s,t]=r.split("=");return e[s]=t,e},{});return{raw:e,type:"ss",name:decodeURIComponent(l),server:i,port:t(c),cipher:r,password:s,udp:!0,obfs:"obfs-local"in m&&"obfs"in m&&("http"===m.obfs||"tls"===m.obfs)?m.obfs:void 0,obfsHost:"obfs-host"in m?m["obfs-host"]:void 0}}function y(e){return atob(e).replaceAll("\r\n","\n").split("\n").filter(Boolean)}const w=new TextDecoder;exports.clash={__proto__:null,decode:function(e){if(!("type"in e)||"string"!=typeof e.type)throw TypeError("Missing or invalid type field");let r=JSON.stringify(e);switch(e.type){case"http":return{type:"http",name:e.name,server:e.server,port:Number(e.port),username:e.username,password:e.password,underlyingProxy:e["dialer-proxy"],raw:r};case"ss":return{type:"ss",name:e.name,server:e.server,port:Number(e.port),cipher:e.cipher,password:e.password,udp:e.udp||!1,obfs:"obfs"===e.plugin?e["plugin-opts"].mode:void 0,underlyingProxy:e["dialer-proxy"],raw:r};case"socks5":return{type:"socks5",name:e.name,server:e.server,port:Number(e.port),username:e.username,password:e.password,udp:e.udp||!1,underlyingProxy:e["dialer-proxy"],raw:r};case"trojan":return{type:"trojan",name:e.name,server:e.server,port:Number(e.port),password:e.password,sni:e.sni,skipCertVerify:e["skip-cert-verify"]||!1,udp:e.udp||!1,underlyingProxy:e["dialer-proxy"],raw:r};case"vmess":return{type:"vmess",name:e.name,server:e.server,port:Number(e.port),username:e.uuid,vmessAead:1===e.alterId||"1"===e.alterId,sni:e.servername,ws:"ws"===e.network,wsPath:e["ws-path"],wsHeaders:e["ws-headers"]?Object.entries(e["ws-headers"]).map(([e,r])=>`${e}:${r}`).join(", "):void 0,tls:e.tls||!1,udp:e.udp??!0,underlyingProxy:e["dialer-proxy"],raw:r,skipCertVerify:e["skip-cert-verify"]||!1};default:throw TypeError(`Unsupported type: ${e.type} (clash decode)`)}},encode:function(r){let s={tfo:r.tfo,"dialer-proxy":r.underlyingProxy};switch(r.type){case"ss":return{name:r.name,type:"ss",server:r.server,port:r.port,cipher:r.cipher,password:r.password,udp:r.udp,...r.obfs?{plugin:"obfs","plugin-opts":{mode:r.obfs,host:r.obfsHost,uri:r.obfsUri}}:{},...s};case"trojan":return{name:r.name,type:"trojan",server:r.server,port:r.port,password:r.password,sni:r.sni,"skip-cert-verify":r.skipCertVerify,udp:r.udp,...s};case"tuic":case"tuic-v5":return{name:r.name,type:"tuic",server:r.server,port:r.port,sni:r.sni,uuid:r.uuid,alpn:r.alpn.split(",").map(e=>e.trim()),..."tuic"===r.type?{token:r.token}:{password:r.password},"skip-cert-verify":r.skipCertVerify,udp:!0,version:"tuic"===r.type?4:"tuic-v5"===r.type?5:e.never(r),...s};case"socks5":return{name:r.name,type:"socks5",server:r.server,port:r.port,username:r.username,password:r.password,udp:r.udp,...s};case"http":return{name:r.name,type:"http",server:r.server,port:r.port,username:r.username,password:r.password,...s};case"vmess":return{alterId:r.vmessAead?0:void 0,tls:r.tls,udp:r.udp,uuid:r.username,name:r.name,servername:r.sni,"ws-path":r.wsPath,server:r.server,"ws-headers":r.wsHeaders?l(r.wsHeaders):void 0,cipher:"auto","ws-opts":{path:r.wsPath,headers:r.wsHeaders?l(r.wsHeaders):void 0},type:"vmess",port:r.port,network:r.ws?"ws":"tcp"};case"hysteria2":return{name:r.name,type:"hysteria2",server:r.server,port:r.port,ports:r.portHopping,password:r.password,down:r.downloadBandwidth+" Mbps","skip-cert-verify":r.skipCertVerify};default:throw TypeError(`Unsupported type: ${r.type} (clash encode)`)}}},exports.ss={__proto__:null,decodeBase64Multiline:y,decodeMultiline:function(e){return y(e).map(e=>c(e))},decodeOne:c},exports.surge={__proto__:null,decode:function(e){let[r,s]=p(e),[l,c,y,...w]=o(s),m=t(y),f=Object.fromEntries(w.map(e=>{let[r,s]=p(e);return n.has(r)?[r,"true"===s]:a.has(r)?[r,t(s)]:i.has(r)?[r,o(s)]:d.has(r)?'"'===s[0]&&s.endsWith('"')||"'"===s[0]&&s.endsWith("'")?[r,s.slice(1,-1)]:[r,s]:[r,u]})),v={raw:e,name:r,server:c,port:m,tfo:f.tfo,blockQuic:f["block-quic"],underlyingProxy:f["underlying-proxy"]},h={sni:f.sni,skipCertVerify:f["skip-cert-verify"]};switch(l){case"snell":return{type:"snell",psk:f.psk,version:f.version,reuse:f.reuse,...v};case"ss":return{type:"ss",cipher:f["encrypt-method"],password:f.password,udp:f["udp-relay"],obfs:f.obfs,obfsHost:f["obfs-host"],obfsUri:f["obfs-uri"],udpPort:f["udp-port"],...v};case"trojan":return{type:"trojan",password:f.password,udp:f["udp-relay"],...h,...v};case"tuic":return{type:"tuic",uuid:f.uuid,alpn:f.alpn,token:f.token,...h,...v};case"tuic-v5":return{type:"tuic-v5",uuid:f.uuid,alpn:f.alpn,password:f.password,...h,...v};case"socks5":return{type:"socks5",username:w[0],password:w[1],udp:f["udp-relay"],...v};case"http":return{type:"http",username:w[0],password:w[1],...v};case"vmess":return{type:"vmess",username:f.username,tls:f.tls,vmessAead:f["vmess-aead"],ws:f.ws,wsPath:f["ws-path"],wsHeaders:f["ws-headers"],udp:f["udp-relay"],...h,...v};case"hysteria2":return{type:"hysteria2",password:f.password,skipCertVerify:f["skip-cert-verify"],downloadBandwidth:f["download-bandwidth"],portHopping:f["port-hopping"],portHoppingInterval:f["port-hopping-interval"],...v};default:throw TypeError(`Unsupported type: ${l} (surge decode)`)}},encode:function(s){let t=[s.tfo&&"tfo=true",s.blockQuic&&`block-quic=${s.blockQuic}`,s.underlyingProxy&&`underlying-proxy=${s.underlyingProxy}`];switch(s.type){case"snell":return r.stringJoin([`${s.name} = snell, ${s.server}, ${s.port}, psk=${s.psk}, version=${s.version}, reuse=${s.reuse}`,...t],", ");case"ss":return r.stringJoin([`${s.name} = ss, ${s.server}, ${s.port}, encrypt-method=${s.cipher}, password=${s.password}`,s.udp&&"udp-relay=true",s.udpPort&&`udp-port=${s.udpPort}`,s.obfs&&`obfs=${s.obfs}`,s.obfsHost&&`obfs-host=${s.obfsHost}`,s.obfsUri&&`obfs-uri=${s.obfsUri}`,...t],", ");case"trojan":return r.stringJoin([`${s.name} = trojan, ${s.server}, ${s.port}, password=${s.password}`,s.sni&&`sni=${s.sni}`,s.skipCertVerify&&"skip-cert-verify=true",...t,s.udp&&"udp-relay=true"],", ");case"tuic":return r.stringJoin([`${s.name} = tuic, ${s.server}, ${s.port}, sni=${s.sni}, uuid=${s.uuid}, alpn=${s.alpn}, token=${s.token}`,...t],", ");case"socks5":return r.stringJoin([`${s.name} = socks5, ${s.server}, ${s.port}, ${s.username}, ${s.password}`,s.udp&&"udp-relay=true",...t],", ");case"http":return r.stringJoin([`${s.name} = http, ${s.server}, ${s.port}, ${s.username}, ${s.password}`,...t],", ");case"vmess":return r.stringJoin([`${s.name} = vmess, ${s.server}, ${s.port}`,`username=${s.username}`,`tls=${s.tls}`,`vmess-aead=${s.vmessAead}`,"ws=true",s.wsPath&&`ws-path=${"/"===s.wsPath[0]?s.wsPath:`/${s.wsPath}`}`,s.wsHeaders&&`ws-headers=${s.wsHeaders}`,`skip-cert-verify=${s.skipCertVerify}`,`tfo=${s.tfo}`,`udp-relay=${s.udp}`],", ");case"hysteria2":return r.stringJoin([`${s.name} = hysteria2, ${s.server}, ${s.port}`,`password=${s.password}`,`download-bandwidth=${s.downloadBandwidth}`,s.portHopping&&`port-hopping="${s.portHopping}"`,s.portHoppingInterval&&`port-hopping-interval=${s.portHoppingInterval}`,`skip-cert-verify=${s.skipCertVerify}`,...t],", ");case"tuic-v5":return r.stringJoin([`${s.name} = tuic-v5, ${s.server}, ${s.port}`,`password=${s.password}`,`uuid=${s.uuid}`,`alpn=${s.alpn}`,`skip-cert-verify=${s.skipCertVerify}`,`sni=${s.sni}`,...t],", ");default:e.never(s,"type (surge encode)")}}},exports.trojan={__proto__:null,parse:function(e){let r=new URL(e),s=r.username,t=r.hostname,o=Number.parseInt(r.port,10);return{raw:e,name:decodeURIComponent(r.hash.slice(1)),type:"trojan",server:t,port:o,password:s,udp:!0,sni:r.searchParams.get("sni")??t,skipCertVerify:!0}}},exports.vmess={__proto__:null,parse:function(e){let r=JSON.parse(w.decode(s.Buffer.from(e.slice(8),"base64"))),t=r.ps,o=r.path;return{raw:e,name:t,server:r.add,port:Number.parseInt(r.port,10),type:"vmess",username:r.id,tls:r.tls,vmessAead:"0"===r.aid,sni:r.sni,ws:"ws"===r.net,wsPath:"/"===o[0]?o:`/${o}`,wsHeaders:r.sni||r.host?`Host:${r.sni||r.host}`:r.add,skipCertVerify:!0,udp:!0}}};
1
+ var s=require("foxts/guard"),e=require("foxts/string-join"),r=require("node:buffer");const t=Number,o=s=>s.split(",").map(s=>s.trim());function p(s){let e=s.indexOf("=");return -1===e?["",""]:[s.slice(0,e).trim(),s.slice(e+1).trim()]}const n=new Set(["udp-relay","tfo","reuse","skip-cert-verify","tls","vmess-aead","ws"]),a=new Set(["version","download-bandwidth","port-hopping-interval","udp-port","shadow-tls-version"]),i=new Set([]),d=new Set(["username","password","sni","encrypt-method","psk","obfs","obfs-host","uuid","alpn","block-quic","ws-path","ws-headers","port-hopping","token","underlying-proxy","shadow-tls-password","shadow-tls-sni"]),u=Symbol("unsupported");function l(s){return s.split(",").reduce((s,e)=>{let[r,t]=e.split(":");return s[r.trim()]=t.trim(),s},{})}function w(s){let e,r,[o,p]=s.split("://");if("ss"!==o)throw Error(`[ss.decodeOne] Unsupported type: ${o}`);let[n,a]=p.split("@");n.includes(":")?[e,r]=n.split(":"):[e,r]=atob(n).split(":");let[i,d]=a.split(":"),[u,l]=d.split("#"),[w,c]=u.split("/"),h=null;if(c)try{h=new URLSearchParams(c).get("plugin")}catch(e){let s=Error(`[ss.decodeOne] Invalid plugins: ${c}`);throw s.cause=e,s}let y=(h?.split(";")??[]).reduce((s,e)=>{let[r,t]=e.split("=");return s[r]=t,s},{});return{raw:s,type:"ss",name:decodeURIComponent(l),server:i,port:t(w),cipher:e,password:r,udp:!0,obfs:"obfs-local"in y&&"obfs"in y&&("http"===y.obfs||"tls"===y.obfs)?y.obfs:void 0,obfsHost:"obfs-host"in y?y["obfs-host"]:void 0}}function c(s){return atob(s).replaceAll("\r\n","\n").split("\n").filter(Boolean)}const h=new TextDecoder;exports.clash={__proto__:null,decode:function(s){if(!("type"in s)||"string"!=typeof s.type)throw TypeError("Missing or invalid type field");let e=JSON.stringify(s);switch(s.type){case"http":return{type:"http",name:s.name,server:s.server,port:Number(s.port),username:s.username,password:s.password,underlyingProxy:s["dialer-proxy"],raw:e};case"ss":return{type:"ss",name:s.name,server:s.server,port:Number(s.port),cipher:s.cipher,password:s.password,udp:s.udp||!1,obfs:"obfs"===s.plugin?s["plugin-opts"].mode:void 0,underlyingProxy:s["dialer-proxy"],shadowTlsSni:"shadow-tls"===s.plugin?s["plugin-opts"].host:void 0,shadowTlsPassword:"shadow-tls"===s.plugin?s["plugin-opts"].password:void 0,shadowTlsVersion:"shadow-tls"===s.plugin?s["plugin-opts"].version:void 0,raw:e};case"socks5":return{type:"socks5",name:s.name,server:s.server,port:Number(s.port),username:s.username,password:s.password,udp:s.udp||!1,underlyingProxy:s["dialer-proxy"],raw:e};case"trojan":return{type:"trojan",name:s.name,server:s.server,port:Number(s.port),password:s.password,sni:s.sni,skipCertVerify:s["skip-cert-verify"]||!1,udp:s.udp||!1,underlyingProxy:s["dialer-proxy"],raw:e};case"vmess":return{type:"vmess",name:s.name,server:s.server,port:Number(s.port),username:s.uuid,vmessAead:1===s.alterId||"1"===s.alterId,sni:s.servername,ws:"ws"===s.network,wsPath:s["ws-path"],wsHeaders:s["ws-headers"]?Object.entries(s["ws-headers"]).map(([s,e])=>`${s}:${e}`).join(", "):void 0,tls:s.tls||!1,udp:s.udp??!0,underlyingProxy:s["dialer-proxy"],raw:e,skipCertVerify:s["skip-cert-verify"]||!1};default:throw TypeError(`Unsupported type: ${s.type} (clash decode)`)}},encode:function(e){let r={name:e.name,server:e.server,port:e.port,tfo:e.tfo,"dialer-proxy":e.underlyingProxy};switch(e.type){case"ss":if(e.shadowTlsPassword&&(e.udp||e.udpPort))throw Error("Clash doesn't support plain UDP for Shadow TLS (clash encode)");return{type:"ss",cipher:e.cipher,password:e.password,udp:e.udp,...e.obfs?{plugin:"obfs","plugin-opts":{mode:e.obfs,host:e.obfsHost,uri:e.obfsUri}}:{},...e.shadowTlsPassword?{plugin:"shadow-tls","plugin-opts":{host:e.shadowTlsSni,password:e.shadowTlsPassword,version:e.shadowTlsVersion}}:{},...r};case"trojan":return{type:"trojan",password:e.password,sni:e.sni,"skip-cert-verify":e.skipCertVerify,udp:e.udp,...r};case"tuic":case"tuic-v5":return{type:"tuic",sni:e.sni,uuid:e.uuid,alpn:e.alpn.split(",").map(s=>s.trim()),..."tuic"===e.type?{token:e.token}:{password:e.password},"skip-cert-verify":e.skipCertVerify,udp:!0,version:"tuic"===e.type?4:"tuic-v5"===e.type?5:s.never(e),...r};case"socks5":return{type:"socks5",username:e.username,password:e.password,udp:e.udp,...r};case"http":return{type:"http",username:e.username,password:e.password,...r};case"vmess":return{alterId:e.vmessAead?0:void 0,tls:e.tls,udp:e.udp,uuid:e.username,servername:e.sni,"ws-path":e.wsPath,"ws-headers":e.wsHeaders?l(e.wsHeaders):void 0,cipher:"auto","ws-opts":{path:e.wsPath,headers:e.wsHeaders?l(e.wsHeaders):void 0},type:"vmess",network:e.ws?"ws":"tcp",...r};case"hysteria2":return{type:"hysteria2",ports:e.port+","+e.portHopping,password:e.password,down:e.downloadBandwidth+" Mbps","skip-cert-verify":e.skipCertVerify,...r};default:throw TypeError(`Unsupported type: ${e.type} (clash encode)`)}}},exports.ss={__proto__:null,decodeBase64Multiline:c,decodeMultiline:function(s){return c(s).map(s=>w(s))},decodeOne:w},exports.surge={__proto__:null,decode:function(s){let[e,r]=p(s),[l,w,c,...h]=o(r),y=t(c),f=Object.fromEntries(h.map(s=>{let[e,r]=p(s);return n.has(e)?[e,"true"===r]:a.has(e)?[e,t(r)]:i.has(e)?[e,o(r)]:d.has(e)?'"'===r[0]&&r.endsWith('"')||"'"===r[0]&&r.endsWith("'")?[e,r.slice(1,-1)]:[e,r]:[e,u]})),m={raw:s,name:e,server:w,port:y,tfo:f.tfo,blockQuic:f["block-quic"],underlyingProxy:f["underlying-proxy"]},v={sni:f.sni,skipCertVerify:f["skip-cert-verify"]};switch(l){case"snell":return{type:"snell",psk:f.psk,version:f.version,reuse:f.reuse,...m};case"ss":{let s=f["shadow-tls-password"],e=f["shadow-tls-sni"],r=f["shadow-tls-version"];return{type:"ss",cipher:f["encrypt-method"],password:f.password,udp:f["udp-relay"],obfs:f.obfs,obfsHost:f["obfs-host"],obfsUri:f["obfs-uri"],udpPort:f["udp-port"],shadowTlsPassword:s,shadowTlsSni:e,shadowTlsVersion:r,...m}}case"trojan":return{type:"trojan",password:f.password,udp:f["udp-relay"],...v,...m};case"tuic":return{type:"tuic",uuid:f.uuid,alpn:f.alpn,token:f.token,...v,...m};case"tuic-v5":return{type:"tuic-v5",uuid:f.uuid,alpn:f.alpn,password:f.password,...v,...m};case"socks5":return{type:"socks5",username:h[0],password:h[1],udp:f["udp-relay"],...m};case"http":return{type:"http",username:h[0],password:h[1],...m};case"vmess":return{type:"vmess",username:f.username,tls:f.tls,vmessAead:f["vmess-aead"],ws:f.ws,wsPath:f["ws-path"],wsHeaders:f["ws-headers"],udp:f["udp-relay"],...v,...m};case"hysteria2":return{type:"hysteria2",password:f.password,skipCertVerify:f["skip-cert-verify"],downloadBandwidth:f["download-bandwidth"],portHopping:f["port-hopping"],portHoppingInterval:f["port-hopping-interval"],...m};default:throw TypeError(`Unsupported type: ${l} (surge decode)`)}},encode:function(r){let t=[r.tfo&&"tfo=true",r.blockQuic&&`block-quic=${r.blockQuic}`,r.underlyingProxy&&`underlying-proxy=${r.underlyingProxy}`];switch(r.type){case"snell":return e.stringJoin([`${r.name} = snell, ${r.server}, ${r.port}, psk=${r.psk}, version=${r.version}, reuse=${r.reuse}`,...t],", ");case"ss":return e.stringJoin([`${r.name} = ss, ${r.server}, ${r.port}, encrypt-method=${r.cipher}, password=${r.password}`,r.shadowTlsPassword&&`shadow-tls-password=${r.shadowTlsPassword}`,r.shadowTlsSni&&`shadow-tls-sni=${r.shadowTlsSni}`,r.shadowTlsVersion&&`shadow-tls-version=${r.shadowTlsVersion}`,r.udp&&"udp-relay=true",r.udpPort&&`udp-port=${r.udpPort}`,r.obfs&&`obfs=${r.obfs}`,r.obfsHost&&`obfs-host=${r.obfsHost}`,r.obfsUri&&`obfs-uri=${r.obfsUri}`,...t],", ");case"trojan":return e.stringJoin([`${r.name} = trojan, ${r.server}, ${r.port}, password=${r.password}`,r.sni&&`sni=${r.sni}`,r.skipCertVerify&&"skip-cert-verify=true",...t,r.udp&&"udp-relay=true"],", ");case"tuic":return e.stringJoin([`${r.name} = tuic, ${r.server}, ${r.port}, sni=${r.sni}, uuid=${r.uuid}, alpn=${r.alpn}, token=${r.token}`,...t],", ");case"socks5":return e.stringJoin([`${r.name} = socks5, ${r.server}, ${r.port}, ${r.username}, ${r.password}`,r.udp&&"udp-relay=true",...t],", ");case"http":return e.stringJoin([`${r.name} = http, ${r.server}, ${r.port}, ${r.username}, ${r.password}`,...t],", ");case"vmess":return e.stringJoin([`${r.name} = vmess, ${r.server}, ${r.port}`,`username=${r.username}`,`tls=${r.tls}`,`vmess-aead=${r.vmessAead}`,"ws=true",r.wsPath&&`ws-path=${"/"===r.wsPath[0]?r.wsPath:`/${r.wsPath}`}`,r.wsHeaders&&`ws-headers=${r.wsHeaders}`,`skip-cert-verify=${r.skipCertVerify}`,`tfo=${r.tfo}`,`udp-relay=${r.udp}`],", ");case"hysteria2":return e.stringJoin([`${r.name} = hysteria2, ${r.server}, ${r.port}`,`password=${r.password}`,`download-bandwidth=${r.downloadBandwidth}`,r.portHopping&&`port-hopping="${r.portHopping}"`,r.portHoppingInterval&&`port-hopping-interval=${r.portHoppingInterval}`,`skip-cert-verify=${r.skipCertVerify}`,...t],", ");case"tuic-v5":return e.stringJoin([`${r.name} = tuic-v5, ${r.server}, ${r.port}`,`password=${r.password}`,`uuid=${r.uuid}`,`alpn=${r.alpn}`,`skip-cert-verify=${r.skipCertVerify}`,`sni=${r.sni}`,...t],", ");default:s.never(r,"type (surge encode)")}}},exports.trojan={__proto__:null,parse:function(s){let e=new URL(s),r=e.username,t=e.hostname,o=Number.parseInt(e.port,10);return{raw:s,name:decodeURIComponent(e.hash.slice(1)),type:"trojan",server:t,port:o,password:r,udp:!0,sni:e.searchParams.get("sni")??t,skipCertVerify:!0}}},exports.vmess={__proto__:null,parse:function(s){let e=JSON.parse(h.decode(r.Buffer.from(s.slice(8),"base64"))),t=e.ps,o=e.path;return{raw:s,name:t,server:e.add,port:Number.parseInt(e.port,10),type:"vmess",username:e.id,tls:e.tls,vmessAead:"0"===e.aid,sni:e.sni,ws:"ws"===e.net,wsPath:"/"===o[0]?o:`/${o}`,wsHeaders:e.sni||e.host?`Host:${e.sni||e.host}`:e.add,skipCertVerify:!0,udp:!0}}};
@@ -35,6 +35,12 @@ interface ShadowSocksConfig extends SharedConfigBase {
35
35
  obfsUri?: string;
36
36
  /** udp-port */
37
37
  udpPort?: number;
38
+ /** Shadow TLS Version */
39
+ shadowTlsVersion?: 1 | 2 | 3;
40
+ /** Shadow TLS Password */
41
+ shadowTlsPassword?: string;
42
+ /** Shadow TLS SNI */
43
+ shadowTlsSni?: string | undefined;
38
44
  }
39
45
  interface TrojanConfig extends SharedConfigBase, TlsSharedConfig {
40
46
  type: 'trojan';
@@ -107,6 +113,9 @@ declare namespace index$4 {
107
113
 
108
114
  declare function decode(config: Record<string, any>): SupportedConfig;
109
115
  declare function encode(config: SupportedConfig): {
116
+ name: string;
117
+ server: string;
118
+ port: number;
110
119
  tfo: boolean | undefined;
111
120
  'dialer-proxy': string | undefined;
112
121
  plugin?: string | undefined;
@@ -114,149 +123,89 @@ declare function encode(config: SupportedConfig): {
114
123
  mode: "http" | "tls";
115
124
  host: string | undefined;
116
125
  uri: string | undefined;
126
+ password?: undefined;
127
+ version?: undefined;
128
+ } | {
129
+ host: string | undefined;
130
+ password: string;
131
+ version: 1 | 2 | 3 | undefined;
132
+ mode?: undefined;
133
+ uri?: undefined;
117
134
  } | undefined;
118
- name: string;
119
135
  type: string;
120
- server: string;
121
- port: number;
122
136
  cipher: string;
123
137
  password: string;
124
138
  udp: boolean;
125
- alterId?: undefined;
126
- tls?: undefined;
127
- uuid?: undefined;
128
- servername?: undefined;
129
- 'ws-path'?: undefined;
130
- 'ws-headers'?: undefined;
131
- 'ws-opts'?: undefined;
132
- network?: undefined;
133
- ports?: undefined;
134
- down?: undefined;
135
- 'skip-cert-verify'?: undefined;
136
139
  } | {
137
- tfo: boolean | undefined;
138
- 'dialer-proxy': string | undefined;
139
140
  name: string;
140
- type: string;
141
141
  server: string;
142
142
  port: number;
143
+ tfo: boolean | undefined;
144
+ 'dialer-proxy': string | undefined;
145
+ type: string;
143
146
  password: string;
144
147
  sni: string | undefined;
145
148
  'skip-cert-verify': boolean;
146
149
  udp: boolean;
147
- alterId?: undefined;
148
- tls?: undefined;
149
- uuid?: undefined;
150
- servername?: undefined;
151
- 'ws-path'?: undefined;
152
- 'ws-headers'?: undefined;
153
- cipher?: undefined;
154
- 'ws-opts'?: undefined;
155
- network?: undefined;
156
- ports?: undefined;
157
- down?: undefined;
158
150
  } | {
151
+ name: string;
152
+ server: string;
153
+ port: number;
159
154
  tfo: boolean | undefined;
160
155
  'dialer-proxy': string | undefined;
161
156
  'skip-cert-verify': boolean;
162
157
  udp: boolean;
163
158
  version: number;
164
159
  token: string;
165
- name: string;
166
160
  type: string;
167
- server: string;
168
- port: number;
169
161
  sni: string | undefined;
170
162
  uuid: string;
171
163
  alpn: string[];
172
- alterId?: undefined;
173
- tls?: undefined;
174
- servername?: undefined;
175
- 'ws-path'?: undefined;
176
- 'ws-headers'?: undefined;
177
- cipher?: undefined;
178
- 'ws-opts'?: undefined;
179
- network?: undefined;
180
- ports?: undefined;
181
- password?: undefined;
182
- down?: undefined;
183
164
  } | {
165
+ name: string;
166
+ server: string;
167
+ port: number;
184
168
  tfo: boolean | undefined;
185
169
  'dialer-proxy': string | undefined;
186
170
  'skip-cert-verify': boolean;
187
171
  udp: boolean;
188
172
  version: number;
189
173
  password: string;
190
- name: string;
191
174
  type: string;
192
- server: string;
193
- port: number;
194
175
  sni: string | undefined;
195
176
  uuid: string;
196
177
  alpn: string[];
197
- alterId?: undefined;
198
- tls?: undefined;
199
- servername?: undefined;
200
- 'ws-path'?: undefined;
201
- 'ws-headers'?: undefined;
202
- cipher?: undefined;
203
- 'ws-opts'?: undefined;
204
- network?: undefined;
205
- ports?: undefined;
206
- down?: undefined;
207
178
  } | {
208
- tfo: boolean | undefined;
209
- 'dialer-proxy': string | undefined;
210
179
  name: string;
211
- type: string;
212
180
  server: string;
213
181
  port: number;
182
+ tfo: boolean | undefined;
183
+ 'dialer-proxy': string | undefined;
184
+ type: string;
214
185
  username: string;
215
186
  password: string;
216
187
  udp: boolean;
217
- alterId?: undefined;
218
- tls?: undefined;
219
- uuid?: undefined;
220
- servername?: undefined;
221
- 'ws-path'?: undefined;
222
- 'ws-headers'?: undefined;
223
- cipher?: undefined;
224
- 'ws-opts'?: undefined;
225
- network?: undefined;
226
- ports?: undefined;
227
- down?: undefined;
228
- 'skip-cert-verify'?: undefined;
229
188
  } | {
230
- tfo: boolean | undefined;
231
- 'dialer-proxy': string | undefined;
232
189
  name: string;
233
- type: string;
234
190
  server: string;
235
191
  port: number;
192
+ tfo: boolean | undefined;
193
+ 'dialer-proxy': string | undefined;
194
+ type: string;
236
195
  username: string;
237
196
  password: string;
238
- alterId?: undefined;
239
- tls?: undefined;
240
- udp?: undefined;
241
- uuid?: undefined;
242
- servername?: undefined;
243
- 'ws-path'?: undefined;
244
- 'ws-headers'?: undefined;
245
- cipher?: undefined;
246
- 'ws-opts'?: undefined;
247
- network?: undefined;
248
- ports?: undefined;
249
- down?: undefined;
250
- 'skip-cert-verify'?: undefined;
251
197
  } | {
198
+ name: string;
199
+ server: string;
200
+ port: number;
201
+ tfo: boolean | undefined;
202
+ 'dialer-proxy': string | undefined;
252
203
  alterId: number | undefined;
253
204
  tls: boolean;
254
205
  udp: boolean;
255
206
  uuid: string;
256
- name: string;
257
207
  servername: string | undefined;
258
208
  'ws-path': string | undefined;
259
- server: string;
260
209
  'ws-headers': Record<string, string> | undefined;
261
210
  cipher: string;
262
211
  'ws-opts': {
@@ -264,31 +213,18 @@ declare function encode(config: SupportedConfig): {
264
213
  headers: Record<string, string> | undefined;
265
214
  };
266
215
  type: string;
267
- port: number;
268
216
  network: string;
269
- ports?: undefined;
270
- password?: undefined;
271
- down?: undefined;
272
- 'skip-cert-verify'?: undefined;
273
217
  } | {
274
218
  name: string;
275
- type: string;
276
219
  server: string;
277
220
  port: number;
278
- ports: string | undefined;
221
+ tfo: boolean | undefined;
222
+ 'dialer-proxy': string | undefined;
223
+ type: string;
224
+ ports: string;
279
225
  password: string;
280
226
  down: string;
281
227
  'skip-cert-verify': boolean;
282
- alterId?: undefined;
283
- tls?: undefined;
284
- udp?: undefined;
285
- uuid?: undefined;
286
- servername?: undefined;
287
- 'ws-path'?: undefined;
288
- 'ws-headers'?: undefined;
289
- cipher?: undefined;
290
- 'ws-opts'?: undefined;
291
- network?: undefined;
292
228
  };
293
229
 
294
230
  declare const index$3_decode: typeof decode;
package/dist/es/index.mjs CHANGED
@@ -1 +1 @@
1
- import{never as e}from"foxts/guard";import{stringJoin as r}from"foxts/string-join";import{Buffer as s}from"node:buffer";let t=Number,p=e=>e.split(",").map(e=>e.trim());function o(e){let r=e.indexOf("=");return -1===r?["",""]:[e.slice(0,r).trim(),e.slice(r+1).trim()]}let n=new Set(["udp-relay","tfo","reuse","skip-cert-verify","tls","vmess-aead","ws"]),a=new Set(["version","download-bandwidth","port-hopping-interval","udp-port"]),i=new Set([]),d=new Set(["username","password","sni","encrypt-method","psk","obfs","obfs-host","uuid","alpn","block-quic","ws-path","ws-headers","port-hopping","token","underlying-proxy"]),u=Symbol("unsupported");var l={__proto__:null,decode:function(e){let[r,s]=o(e),[l,c,y,...w]=p(s),m=t(y),f=Object.fromEntries(w.map(e=>{let[r,s]=o(e);return n.has(r)?[r,"true"===s]:a.has(r)?[r,t(s)]:i.has(r)?[r,p(s)]:d.has(r)?'"'===s[0]&&s.endsWith('"')||"'"===s[0]&&s.endsWith("'")?[r,s.slice(1,-1)]:[r,s]:[r,u]})),v={raw:e,name:r,server:c,port:m,tfo:f.tfo,blockQuic:f["block-quic"],underlyingProxy:f["underlying-proxy"]},h={sni:f.sni,skipCertVerify:f["skip-cert-verify"]};switch(l){case"snell":return{type:"snell",psk:f.psk,version:f.version,reuse:f.reuse,...v};case"ss":return{type:"ss",cipher:f["encrypt-method"],password:f.password,udp:f["udp-relay"],obfs:f.obfs,obfsHost:f["obfs-host"],obfsUri:f["obfs-uri"],udpPort:f["udp-port"],...v};case"trojan":return{type:"trojan",password:f.password,udp:f["udp-relay"],...h,...v};case"tuic":return{type:"tuic",uuid:f.uuid,alpn:f.alpn,token:f.token,...h,...v};case"tuic-v5":return{type:"tuic-v5",uuid:f.uuid,alpn:f.alpn,password:f.password,...h,...v};case"socks5":return{type:"socks5",username:w[0],password:w[1],udp:f["udp-relay"],...v};case"http":return{type:"http",username:w[0],password:w[1],...v};case"vmess":return{type:"vmess",username:f.username,tls:f.tls,vmessAead:f["vmess-aead"],ws:f.ws,wsPath:f["ws-path"],wsHeaders:f["ws-headers"],udp:f["udp-relay"],...h,...v};case"hysteria2":return{type:"hysteria2",password:f.password,skipCertVerify:f["skip-cert-verify"],downloadBandwidth:f["download-bandwidth"],portHopping:f["port-hopping"],portHoppingInterval:f["port-hopping-interval"],...v};default:throw TypeError(`Unsupported type: ${l} (surge decode)`)}},encode:function(s){let t=[s.tfo&&"tfo=true",s.blockQuic&&`block-quic=${s.blockQuic}`,s.underlyingProxy&&`underlying-proxy=${s.underlyingProxy}`];switch(s.type){case"snell":return r([`${s.name} = snell, ${s.server}, ${s.port}, psk=${s.psk}, version=${s.version}, reuse=${s.reuse}`,...t],", ");case"ss":return r([`${s.name} = ss, ${s.server}, ${s.port}, encrypt-method=${s.cipher}, password=${s.password}`,s.udp&&"udp-relay=true",s.udpPort&&`udp-port=${s.udpPort}`,s.obfs&&`obfs=${s.obfs}`,s.obfsHost&&`obfs-host=${s.obfsHost}`,s.obfsUri&&`obfs-uri=${s.obfsUri}`,...t],", ");case"trojan":return r([`${s.name} = trojan, ${s.server}, ${s.port}, password=${s.password}`,s.sni&&`sni=${s.sni}`,s.skipCertVerify&&"skip-cert-verify=true",...t,s.udp&&"udp-relay=true"],", ");case"tuic":return r([`${s.name} = tuic, ${s.server}, ${s.port}, sni=${s.sni}, uuid=${s.uuid}, alpn=${s.alpn}, token=${s.token}`,...t],", ");case"socks5":return r([`${s.name} = socks5, ${s.server}, ${s.port}, ${s.username}, ${s.password}`,s.udp&&"udp-relay=true",...t],", ");case"http":return r([`${s.name} = http, ${s.server}, ${s.port}, ${s.username}, ${s.password}`,...t],", ");case"vmess":return r([`${s.name} = vmess, ${s.server}, ${s.port}`,`username=${s.username}`,`tls=${s.tls}`,`vmess-aead=${s.vmessAead}`,"ws=true",s.wsPath&&`ws-path=${"/"===s.wsPath[0]?s.wsPath:`/${s.wsPath}`}`,s.wsHeaders&&`ws-headers=${s.wsHeaders}`,`skip-cert-verify=${s.skipCertVerify}`,`tfo=${s.tfo}`,`udp-relay=${s.udp}`],", ");case"hysteria2":return r([`${s.name} = hysteria2, ${s.server}, ${s.port}`,`password=${s.password}`,`download-bandwidth=${s.downloadBandwidth}`,s.portHopping&&`port-hopping="${s.portHopping}"`,s.portHoppingInterval&&`port-hopping-interval=${s.portHoppingInterval}`,`skip-cert-verify=${s.skipCertVerify}`,...t],", ");case"tuic-v5":return r([`${s.name} = tuic-v5, ${s.server}, ${s.port}`,`password=${s.password}`,`uuid=${s.uuid}`,`alpn=${s.alpn}`,`skip-cert-verify=${s.skipCertVerify}`,`sni=${s.sni}`,...t],", ");default:e(s,"type (surge encode)")}}};function c(e){return e.split(",").reduce((e,r)=>{let[s,t]=r.split(":");return e[s.trim()]=t.trim(),e},{})}var y={__proto__:null,decode:function(e){if(!("type"in e)||"string"!=typeof e.type)throw TypeError("Missing or invalid type field");let r=JSON.stringify(e);switch(e.type){case"http":return{type:"http",name:e.name,server:e.server,port:Number(e.port),username:e.username,password:e.password,underlyingProxy:e["dialer-proxy"],raw:r};case"ss":return{type:"ss",name:e.name,server:e.server,port:Number(e.port),cipher:e.cipher,password:e.password,udp:e.udp||!1,obfs:"obfs"===e.plugin?e["plugin-opts"].mode:void 0,underlyingProxy:e["dialer-proxy"],raw:r};case"socks5":return{type:"socks5",name:e.name,server:e.server,port:Number(e.port),username:e.username,password:e.password,udp:e.udp||!1,underlyingProxy:e["dialer-proxy"],raw:r};case"trojan":return{type:"trojan",name:e.name,server:e.server,port:Number(e.port),password:e.password,sni:e.sni,skipCertVerify:e["skip-cert-verify"]||!1,udp:e.udp||!1,underlyingProxy:e["dialer-proxy"],raw:r};case"vmess":return{type:"vmess",name:e.name,server:e.server,port:Number(e.port),username:e.uuid,vmessAead:1===e.alterId||"1"===e.alterId,sni:e.servername,ws:"ws"===e.network,wsPath:e["ws-path"],wsHeaders:e["ws-headers"]?Object.entries(e["ws-headers"]).map(([e,r])=>`${e}:${r}`).join(", "):void 0,tls:e.tls||!1,udp:e.udp??!0,underlyingProxy:e["dialer-proxy"],raw:r,skipCertVerify:e["skip-cert-verify"]||!1};default:throw TypeError(`Unsupported type: ${e.type} (clash decode)`)}},encode:function(r){let s={tfo:r.tfo,"dialer-proxy":r.underlyingProxy};switch(r.type){case"ss":return{name:r.name,type:"ss",server:r.server,port:r.port,cipher:r.cipher,password:r.password,udp:r.udp,...r.obfs?{plugin:"obfs","plugin-opts":{mode:r.obfs,host:r.obfsHost,uri:r.obfsUri}}:{},...s};case"trojan":return{name:r.name,type:"trojan",server:r.server,port:r.port,password:r.password,sni:r.sni,"skip-cert-verify":r.skipCertVerify,udp:r.udp,...s};case"tuic":case"tuic-v5":return{name:r.name,type:"tuic",server:r.server,port:r.port,sni:r.sni,uuid:r.uuid,alpn:r.alpn.split(",").map(e=>e.trim()),..."tuic"===r.type?{token:r.token}:{password:r.password},"skip-cert-verify":r.skipCertVerify,udp:!0,version:"tuic"===r.type?4:"tuic-v5"===r.type?5:e(r),...s};case"socks5":return{name:r.name,type:"socks5",server:r.server,port:r.port,username:r.username,password:r.password,udp:r.udp,...s};case"http":return{name:r.name,type:"http",server:r.server,port:r.port,username:r.username,password:r.password,...s};case"vmess":return{alterId:r.vmessAead?0:void 0,tls:r.tls,udp:r.udp,uuid:r.username,name:r.name,servername:r.sni,"ws-path":r.wsPath,server:r.server,"ws-headers":r.wsHeaders?c(r.wsHeaders):void 0,cipher:"auto","ws-opts":{path:r.wsPath,headers:r.wsHeaders?c(r.wsHeaders):void 0},type:"vmess",port:r.port,network:r.ws?"ws":"tcp"};case"hysteria2":return{name:r.name,type:"hysteria2",server:r.server,port:r.port,ports:r.portHopping,password:r.password,down:r.downloadBandwidth+" Mbps","skip-cert-verify":r.skipCertVerify};default:throw TypeError(`Unsupported type: ${r.type} (clash encode)`)}}};function w(e){let r,s,[p,o]=e.split("://");if("ss"!==p)throw Error(`[ss.decodeOne] Unsupported type: ${p}`);let[n,a]=o.split("@");n.includes(":")?[r,s]=n.split(":"):[r,s]=atob(n).split(":");let[i,d]=a.split(":"),[u,l]=d.split("#"),[c,y]=u.split("/"),w=null;if(y)try{w=new URLSearchParams(y).get("plugin")}catch(r){let e=Error(`[ss.decodeOne] Invalid plugins: ${y}`);throw e.cause=r,e}let m=(w?.split(";")??[]).reduce((e,r)=>{let[s,t]=r.split("=");return e[s]=t,e},{});return{raw:e,type:"ss",name:decodeURIComponent(l),server:i,port:t(c),cipher:r,password:s,udp:!0,obfs:"obfs-local"in m&&"obfs"in m&&("http"===m.obfs||"tls"===m.obfs)?m.obfs:void 0,obfsHost:"obfs-host"in m?m["obfs-host"]:void 0}}function m(e){return atob(e).replaceAll("\r\n","\n").split("\n").filter(Boolean)}var f={__proto__:null,decodeBase64Multiline:m,decodeMultiline:function(e){return m(e).map(e=>w(e))},decodeOne:w},v={__proto__:null,parse:function(e){let r=new URL(e),s=r.username,t=r.hostname,p=Number.parseInt(r.port,10);return{raw:e,name:decodeURIComponent(r.hash.slice(1)),type:"trojan",server:t,port:p,password:s,udp:!0,sni:r.searchParams.get("sni")??t,skipCertVerify:!0}}};let h=new TextDecoder;var $={__proto__:null,parse:function(e){let r=JSON.parse(h.decode(s.from(e.slice(8),"base64"))),t=r.ps,p=r.path;return{raw:e,name:t,server:r.add,port:Number.parseInt(r.port,10),type:"vmess",username:r.id,tls:r.tls,vmessAead:"0"===r.aid,sni:r.sni,ws:"ws"===r.net,wsPath:"/"===p[0]?p:`/${p}`,wsHeaders:r.sni||r.host?`Host:${r.sni||r.host}`:r.add,skipCertVerify:!0,udp:!0}}};export{y as clash,f as ss,l as surge,v as trojan,$ as vmess};
1
+ import{never as s}from"foxts/guard";import{stringJoin as e}from"foxts/string-join";import{Buffer as r}from"node:buffer";let t=Number,o=s=>s.split(",").map(s=>s.trim());function p(s){let e=s.indexOf("=");return -1===e?["",""]:[s.slice(0,e).trim(),s.slice(e+1).trim()]}let n=new Set(["udp-relay","tfo","reuse","skip-cert-verify","tls","vmess-aead","ws"]),a=new Set(["version","download-bandwidth","port-hopping-interval","udp-port","shadow-tls-version"]),i=new Set([]),d=new Set(["username","password","sni","encrypt-method","psk","obfs","obfs-host","uuid","alpn","block-quic","ws-path","ws-headers","port-hopping","token","underlying-proxy","shadow-tls-password","shadow-tls-sni"]),u=Symbol("unsupported");var l={__proto__:null,decode:function(s){let[e,r]=p(s),[l,w,c,...h]=o(r),y=t(c),m=Object.fromEntries(h.map(s=>{let[e,r]=p(s);return n.has(e)?[e,"true"===r]:a.has(e)?[e,t(r)]:i.has(e)?[e,o(r)]:d.has(e)?'"'===r[0]&&r.endsWith('"')||"'"===r[0]&&r.endsWith("'")?[e,r.slice(1,-1)]:[e,r]:[e,u]})),f={raw:s,name:e,server:w,port:y,tfo:m.tfo,blockQuic:m["block-quic"],underlyingProxy:m["underlying-proxy"]},v={sni:m.sni,skipCertVerify:m["skip-cert-verify"]};switch(l){case"snell":return{type:"snell",psk:m.psk,version:m.version,reuse:m.reuse,...f};case"ss":{let s=m["shadow-tls-password"],e=m["shadow-tls-sni"],r=m["shadow-tls-version"];return{type:"ss",cipher:m["encrypt-method"],password:m.password,udp:m["udp-relay"],obfs:m.obfs,obfsHost:m["obfs-host"],obfsUri:m["obfs-uri"],udpPort:m["udp-port"],shadowTlsPassword:s,shadowTlsSni:e,shadowTlsVersion:r,...f}}case"trojan":return{type:"trojan",password:m.password,udp:m["udp-relay"],...v,...f};case"tuic":return{type:"tuic",uuid:m.uuid,alpn:m.alpn,token:m.token,...v,...f};case"tuic-v5":return{type:"tuic-v5",uuid:m.uuid,alpn:m.alpn,password:m.password,...v,...f};case"socks5":return{type:"socks5",username:h[0],password:h[1],udp:m["udp-relay"],...f};case"http":return{type:"http",username:h[0],password:h[1],...f};case"vmess":return{type:"vmess",username:m.username,tls:m.tls,vmessAead:m["vmess-aead"],ws:m.ws,wsPath:m["ws-path"],wsHeaders:m["ws-headers"],udp:m["udp-relay"],...v,...f};case"hysteria2":return{type:"hysteria2",password:m.password,skipCertVerify:m["skip-cert-verify"],downloadBandwidth:m["download-bandwidth"],portHopping:m["port-hopping"],portHoppingInterval:m["port-hopping-interval"],...f};default:throw TypeError(`Unsupported type: ${l} (surge decode)`)}},encode:function(r){let t=[r.tfo&&"tfo=true",r.blockQuic&&`block-quic=${r.blockQuic}`,r.underlyingProxy&&`underlying-proxy=${r.underlyingProxy}`];switch(r.type){case"snell":return e([`${r.name} = snell, ${r.server}, ${r.port}, psk=${r.psk}, version=${r.version}, reuse=${r.reuse}`,...t],", ");case"ss":return e([`${r.name} = ss, ${r.server}, ${r.port}, encrypt-method=${r.cipher}, password=${r.password}`,r.shadowTlsPassword&&`shadow-tls-password=${r.shadowTlsPassword}`,r.shadowTlsSni&&`shadow-tls-sni=${r.shadowTlsSni}`,r.shadowTlsVersion&&`shadow-tls-version=${r.shadowTlsVersion}`,r.udp&&"udp-relay=true",r.udpPort&&`udp-port=${r.udpPort}`,r.obfs&&`obfs=${r.obfs}`,r.obfsHost&&`obfs-host=${r.obfsHost}`,r.obfsUri&&`obfs-uri=${r.obfsUri}`,...t],", ");case"trojan":return e([`${r.name} = trojan, ${r.server}, ${r.port}, password=${r.password}`,r.sni&&`sni=${r.sni}`,r.skipCertVerify&&"skip-cert-verify=true",...t,r.udp&&"udp-relay=true"],", ");case"tuic":return e([`${r.name} = tuic, ${r.server}, ${r.port}, sni=${r.sni}, uuid=${r.uuid}, alpn=${r.alpn}, token=${r.token}`,...t],", ");case"socks5":return e([`${r.name} = socks5, ${r.server}, ${r.port}, ${r.username}, ${r.password}`,r.udp&&"udp-relay=true",...t],", ");case"http":return e([`${r.name} = http, ${r.server}, ${r.port}, ${r.username}, ${r.password}`,...t],", ");case"vmess":return e([`${r.name} = vmess, ${r.server}, ${r.port}`,`username=${r.username}`,`tls=${r.tls}`,`vmess-aead=${r.vmessAead}`,"ws=true",r.wsPath&&`ws-path=${"/"===r.wsPath[0]?r.wsPath:`/${r.wsPath}`}`,r.wsHeaders&&`ws-headers=${r.wsHeaders}`,`skip-cert-verify=${r.skipCertVerify}`,`tfo=${r.tfo}`,`udp-relay=${r.udp}`],", ");case"hysteria2":return e([`${r.name} = hysteria2, ${r.server}, ${r.port}`,`password=${r.password}`,`download-bandwidth=${r.downloadBandwidth}`,r.portHopping&&`port-hopping="${r.portHopping}"`,r.portHoppingInterval&&`port-hopping-interval=${r.portHoppingInterval}`,`skip-cert-verify=${r.skipCertVerify}`,...t],", ");case"tuic-v5":return e([`${r.name} = tuic-v5, ${r.server}, ${r.port}`,`password=${r.password}`,`uuid=${r.uuid}`,`alpn=${r.alpn}`,`skip-cert-verify=${r.skipCertVerify}`,`sni=${r.sni}`,...t],", ");default:s(r,"type (surge encode)")}}};function w(s){return s.split(",").reduce((s,e)=>{let[r,t]=e.split(":");return s[r.trim()]=t.trim(),s},{})}var c={__proto__:null,decode:function(s){if(!("type"in s)||"string"!=typeof s.type)throw TypeError("Missing or invalid type field");let e=JSON.stringify(s);switch(s.type){case"http":return{type:"http",name:s.name,server:s.server,port:Number(s.port),username:s.username,password:s.password,underlyingProxy:s["dialer-proxy"],raw:e};case"ss":return{type:"ss",name:s.name,server:s.server,port:Number(s.port),cipher:s.cipher,password:s.password,udp:s.udp||!1,obfs:"obfs"===s.plugin?s["plugin-opts"].mode:void 0,underlyingProxy:s["dialer-proxy"],shadowTlsSni:"shadow-tls"===s.plugin?s["plugin-opts"].host:void 0,shadowTlsPassword:"shadow-tls"===s.plugin?s["plugin-opts"].password:void 0,shadowTlsVersion:"shadow-tls"===s.plugin?s["plugin-opts"].version:void 0,raw:e};case"socks5":return{type:"socks5",name:s.name,server:s.server,port:Number(s.port),username:s.username,password:s.password,udp:s.udp||!1,underlyingProxy:s["dialer-proxy"],raw:e};case"trojan":return{type:"trojan",name:s.name,server:s.server,port:Number(s.port),password:s.password,sni:s.sni,skipCertVerify:s["skip-cert-verify"]||!1,udp:s.udp||!1,underlyingProxy:s["dialer-proxy"],raw:e};case"vmess":return{type:"vmess",name:s.name,server:s.server,port:Number(s.port),username:s.uuid,vmessAead:1===s.alterId||"1"===s.alterId,sni:s.servername,ws:"ws"===s.network,wsPath:s["ws-path"],wsHeaders:s["ws-headers"]?Object.entries(s["ws-headers"]).map(([s,e])=>`${s}:${e}`).join(", "):void 0,tls:s.tls||!1,udp:s.udp??!0,underlyingProxy:s["dialer-proxy"],raw:e,skipCertVerify:s["skip-cert-verify"]||!1};default:throw TypeError(`Unsupported type: ${s.type} (clash decode)`)}},encode:function(e){let r={name:e.name,server:e.server,port:e.port,tfo:e.tfo,"dialer-proxy":e.underlyingProxy};switch(e.type){case"ss":if(e.shadowTlsPassword&&(e.udp||e.udpPort))throw Error("Clash doesn't support plain UDP for Shadow TLS (clash encode)");return{type:"ss",cipher:e.cipher,password:e.password,udp:e.udp,...e.obfs?{plugin:"obfs","plugin-opts":{mode:e.obfs,host:e.obfsHost,uri:e.obfsUri}}:{},...e.shadowTlsPassword?{plugin:"shadow-tls","plugin-opts":{host:e.shadowTlsSni,password:e.shadowTlsPassword,version:e.shadowTlsVersion}}:{},...r};case"trojan":return{type:"trojan",password:e.password,sni:e.sni,"skip-cert-verify":e.skipCertVerify,udp:e.udp,...r};case"tuic":case"tuic-v5":return{type:"tuic",sni:e.sni,uuid:e.uuid,alpn:e.alpn.split(",").map(s=>s.trim()),..."tuic"===e.type?{token:e.token}:{password:e.password},"skip-cert-verify":e.skipCertVerify,udp:!0,version:"tuic"===e.type?4:"tuic-v5"===e.type?5:s(e),...r};case"socks5":return{type:"socks5",username:e.username,password:e.password,udp:e.udp,...r};case"http":return{type:"http",username:e.username,password:e.password,...r};case"vmess":return{alterId:e.vmessAead?0:void 0,tls:e.tls,udp:e.udp,uuid:e.username,servername:e.sni,"ws-path":e.wsPath,"ws-headers":e.wsHeaders?w(e.wsHeaders):void 0,cipher:"auto","ws-opts":{path:e.wsPath,headers:e.wsHeaders?w(e.wsHeaders):void 0},type:"vmess",network:e.ws?"ws":"tcp",...r};case"hysteria2":return{type:"hysteria2",ports:e.port+","+e.portHopping,password:e.password,down:e.downloadBandwidth+" Mbps","skip-cert-verify":e.skipCertVerify,...r};default:throw TypeError(`Unsupported type: ${e.type} (clash encode)`)}}};function h(s){let e,r,[o,p]=s.split("://");if("ss"!==o)throw Error(`[ss.decodeOne] Unsupported type: ${o}`);let[n,a]=p.split("@");n.includes(":")?[e,r]=n.split(":"):[e,r]=atob(n).split(":");let[i,d]=a.split(":"),[u,l]=d.split("#"),[w,c]=u.split("/"),h=null;if(c)try{h=new URLSearchParams(c).get("plugin")}catch(e){let s=Error(`[ss.decodeOne] Invalid plugins: ${c}`);throw s.cause=e,s}let y=(h?.split(";")??[]).reduce((s,e)=>{let[r,t]=e.split("=");return s[r]=t,s},{});return{raw:s,type:"ss",name:decodeURIComponent(l),server:i,port:t(w),cipher:e,password:r,udp:!0,obfs:"obfs-local"in y&&"obfs"in y&&("http"===y.obfs||"tls"===y.obfs)?y.obfs:void 0,obfsHost:"obfs-host"in y?y["obfs-host"]:void 0}}function y(s){return atob(s).replaceAll("\r\n","\n").split("\n").filter(Boolean)}var m={__proto__:null,decodeBase64Multiline:y,decodeMultiline:function(s){return y(s).map(s=>h(s))},decodeOne:h},f={__proto__:null,parse:function(s){let e=new URL(s),r=e.username,t=e.hostname,o=Number.parseInt(e.port,10);return{raw:s,name:decodeURIComponent(e.hash.slice(1)),type:"trojan",server:t,port:o,password:r,udp:!0,sni:e.searchParams.get("sni")??t,skipCertVerify:!0}}};let v=new TextDecoder;var $={__proto__:null,parse:function(s){let e=JSON.parse(v.decode(r.from(s.slice(8),"base64"))),t=e.ps,o=e.path;return{raw:s,name:t,server:e.add,port:Number.parseInt(e.port,10),type:"vmess",username:e.id,tls:e.tls,vmessAead:"0"===e.aid,sni:e.sni,ws:"ws"===e.net,wsPath:"/"===o[0]?o:`/${o}`,wsHeaders:e.sni||e.host?`Host:${e.sni||e.host}`:e.add,skipCertVerify:!0,udp:!0}}};export{c as clash,m as ss,l as surge,f as trojan,$ as vmess};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nodelistparser",
3
- "version": "1.2.1",
3
+ "version": "1.3.1",
4
4
  "description": "Surge / Mihomo (Clash.Meta) nodelist / proxy provider parser and generator.",
5
5
  "repository": {
6
6
  "type": "git",
@@ -34,21 +34,21 @@
34
34
  "author": "Sukka <https://skk.moe>",
35
35
  "license": "MIT",
36
36
  "dependencies": {
37
- "foxts": "^3.10.1"
37
+ "foxts": "^3.13.0"
38
38
  },
39
39
  "devDependencies": {
40
- "@eslint-sukka/node": "^6.23.1",
41
- "@swc-node/register": "^1.10.10",
42
- "@swc/core": "^1.13.3",
40
+ "@eslint-sukka/node": "^7.1.1",
41
+ "@swc-node/register": "^1.11.1",
42
+ "@swc/core": "^1.13.5",
43
43
  "@types/mocha": "^10.0.10",
44
- "@types/node": "^22.17.1",
44
+ "@types/node": "^24.5.2",
45
45
  "bumpp": "^10.2.3",
46
46
  "bunchee": "^6.6.0",
47
- "eslint": "^9.33.0",
48
- "eslint-config-sukka": "^6.23.1",
49
- "eslint-formatter-sukka": "^6.23.1",
50
- "expect": "^30.0.5",
51
- "mocha": "^11.7.1",
47
+ "eslint": "^9.36.0",
48
+ "eslint-config-sukka": "^7.1.1",
49
+ "eslint-formatter-sukka": "^7.1.1",
50
+ "expect": "^30.1.2",
51
+ "mocha": "^11.7.2",
52
52
  "typescript": "^5.9.2"
53
53
  },
54
54
  "scripts": {