securequ 1.1.2 → 1.1.4

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/client/Base.d.ts CHANGED
@@ -5,6 +5,7 @@ declare class Base {
5
5
  protected loadingHandshake: boolean;
6
6
  protected secret_length: number;
7
7
  protected handshakeInfo: HandshakeInfo | null;
8
+ readonly CONTENT_TYPE = "application/octet-stream";
8
9
  constructor(config: SecurequClientConfig);
9
10
  protected hooksCall(hook: keyof NonNullable<SecurequClientConfig['hooks']>, ...args: any[]): any;
10
11
  protected getSecret(): Promise<{
package/client/Base.js CHANGED
@@ -1 +1 @@
1
- "use strict";Object.defineProperty(exports,"__esModule",{value:!0});var t=require("../include/crypto.js"),e=require("xanfetch");const s=new Map;exports.default=class{constructor(t){this.loadingHandshake=!1,this.secret_length=0,this.handshakeInfo=null,this.config=Object.assign({},t);const e=new URL(t.url);if(e.search||e.hash)throw new Error(`Invalid config url ${t.url}. Search params or Hash url is not supported in config.url`);if(t.url=`${e.origin}${e.pathname}`,s.has(t.url))throw new Error("Client is Blocked!")}hooksCall(t,...e){if(this.config.hooks&&this.config.hooks[t])return this.config.hooks[t](...e)}async getSecret(){let e=this.config.secret,s=e.substring(0,this.secret_length);return{full:e,secret:s,hash:(await t.default.hash(s)).substring(0,this.secret_length)}}async url(t){const e=await this.getSecret(),s=this.config.url;return"/"===t&&(t=""),(t=(t=(t=t.trim()).startsWith("/")?t.substring(1):t).endsWith("/")?t.substring(0,t.length-1):t)&&(t=`/${t}`),new URL(`${s}/${e.hash}${t}`)}async getHeaders(e,s){var a,n,i;const r=await this.url(e),h=await this.getSecret();let o={};return this.handshakeInfo&&(o["X-SIGNETURE"]=await t.default.encrypt({signeture:null===(a=this.handshakeInfo)||void 0===a?void 0:a.signeture,expire:Date.now()+this.handshakeInfo.timeDiffarenc+1e4},h.secret)||""),Object.assign(Object.assign(Object.assign(Object.assign({},null===(i=null===(n=this.config)||void 0===n?void 0:n.defaultOptions)||void 0===i?void 0:i.headers),null==s?void 0:s.headers),o),{"Content-Type":"application/octet-stream","X-ORIGIN":r.origin})}async awaitForHandshake(){this.loadingHandshake&&await new Promise(t=>{const e=setInterval(()=>{this.loadingHandshake||(clearInterval(e),t(null))},100)}),this.handshakeInfo||await this.handshake()}async handshake(){await this.hooksCall("beforeHandshake"),this.handshakeInfo=null,this.loadingHandshake=!0;let t=this.config.secret.length,e=3*Math.floor(t/4);this.secret_length=Math.floor(Math.random()*(t-e+1))+e;const s=await this.getSecret(),a=await this.fetch("/",{method:"POST",body:{hash:s.hash,clientTime:(new Date).toISOString(),secret:s.secret}});this.handshakeInfo=a.data,this.loadingHandshake=!1,await this.hooksCall("afterHandshake",this.handshakeInfo)}async fetch(s,a){var n,i;const r="/"!==s&&(null===(n=this.handshakeInfo)||void 0===n?void 0:n.dev),h=await this.getSecret(),o=await this.url(s);let c=Object.fromEntries(o.searchParams.entries());const l=Object.assign({},a);let d=Object.assign({},c);if(Object.keys(c).length>0)for(let t in c)o.searchParams.delete(t);if(null==l?void 0:l.params){for(let t in l.params)d[t]=l.params[t];delete l.params}if(Object.keys(d).length>0)if(r)l.params=d;else{const e=await t.default.encrypt(d,h.secret);o.href=o.href+"?"+encodeURIComponent(e)}const u=Object.assign(Object.assign(Object.assign({method:"GET"},null===(i=this.config)||void 0===i?void 0:i.defaultOptions),l),{headers:await this.getHeaders(s,a)});(null==u?void 0:u.body)&&(u.body=r?JSON.stringify(u.body):await t.default.encryptBuffer(u.body,h.secret));const f=await e(o.href,u);if(r){const t=await f.text(),e=JSON.parse(t);return{success:f.ok,message:f.ok?f.statusText:e,data:f.ok?e:null,code:f.status}}const g=await f.arrayBuffer(),k=await t.default.decryptBuffer(new Uint8Array(g),h.secret);return{success:f.ok,message:f.ok?f.statusText:k,data:f.ok?k:null,code:f.status}}};//# sourceMappingURL=Base.js.map
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:!0});var t=require("../include/crypto.js"),e=require("xanfetch");const s=new Map;exports.default=class{constructor(t){this.loadingHandshake=!1,this.secret_length=0,this.handshakeInfo=null,this.CONTENT_TYPE="application/octet-stream",this.config=Object.assign({},t);const e=new URL(t.url);if(e.search||e.hash)throw new Error(`Invalid config url ${t.url}. Search params or Hash url is not supported in config.url`);if(t.url=`${e.origin}${e.pathname}`,s.has(t.url))throw new Error("Client is Blocked!")}hooksCall(t,...e){if(this.config.hooks&&this.config.hooks[t])return this.config.hooks[t](...e)}async getSecret(){let e=this.config.secret,s=e.substring(0,this.secret_length);return{full:e,secret:s,hash:(await t.default.hash(s)).substring(0,this.secret_length)}}async url(t){const e=await this.getSecret(),s=this.config.url;return"/"===t&&(t=""),(t=(t=(t=t.trim()).startsWith("/")?t.substring(1):t).endsWith("/")?t.substring(0,t.length-1):t)&&(t=`/${t}`),new URL(`${s}/${e.hash}${t}`)}async getHeaders(e,s){var a,n,i;const r=await this.url(e),h=await this.getSecret();let o={};return this.handshakeInfo&&(o["X-SIGNETURE"]=await t.default.encrypt({signeture:null===(a=this.handshakeInfo)||void 0===a?void 0:a.signeture,expire:Date.now()+this.handshakeInfo.timeDiffarenc+1e4},h.secret)||""),o=Object.assign(Object.assign(Object.assign(Object.assign({},null===(i=null===(n=this.config)||void 0===n?void 0:n.defaultOptions)||void 0===i?void 0:i.headers),null==s?void 0:s.headers),o),{"Content-Type":this.CONTENT_TYPE,"X-ORIGIN":r.origin,"X-METHOD":((null==s?void 0:s.method)||"GET").toUpperCase()}),o}async awaitForHandshake(){this.loadingHandshake&&await new Promise(t=>{const e=setInterval(()=>{this.loadingHandshake||(clearInterval(e),t(null))},100)}),this.handshakeInfo||await this.handshake()}async handshake(){await this.hooksCall("beforeHandshake"),this.handshakeInfo=null,this.loadingHandshake=!0;let t=this.config.secret.length,e=3*Math.floor(t/4);this.secret_length=Math.floor(Math.random()*(t-e+1))+e;const s=await this.getSecret(),a=await this.fetch("/",{method:"POST",body:{hash:s.hash,clientTime:(new Date).toISOString(),secret:s.secret}});this.handshakeInfo=a.data,this.loadingHandshake=!1,await this.hooksCall("afterHandshake",this.handshakeInfo)}async fetch(s,a){var n,i;const r="/"!==s&&(null===(n=this.handshakeInfo)||void 0===n?void 0:n.dev),h=await this.getSecret(),o=await this.url(s);let c=Object.fromEntries(o.searchParams.entries());const l=Object.assign({},a);let d=Object.assign({},c);if(Object.keys(c).length>0)for(let t in c)o.searchParams.delete(t);if(null==l?void 0:l.params){for(let t in l.params)d[t]=l.params[t];delete l.params}if(Object.keys(d).length>0)if(r)l.params=d;else{const e=await t.default.encrypt(d,h.secret);o.href=o.href+"?"+encodeURIComponent(e)}const u=Object.assign(Object.assign(Object.assign({method:"GET"},null===(i=this.config)||void 0===i?void 0:i.defaultOptions),l),{headers:await this.getHeaders(s,l)});(null==u?void 0:u.body)&&(u.body=r?JSON.stringify(u.body):await t.default.encryptBuffer(u.body,h.secret));const f=await e(o.href,u);if(r){const t=await f.text(),e=JSON.parse(t);return{success:f.ok,message:f.ok?f.statusText:e,data:f.ok?e:null,code:f.status}}const g=await f.arrayBuffer(),k=await t.default.decryptBuffer(new Uint8Array(g),h.secret);return{success:f.ok,message:f.ok?f.statusText:k||f.statusText,data:f.ok?k:null,code:f.status}}};//# sourceMappingURL=Base.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"Base.js","sources":["../../src/client/Base.ts"],"sourcesContent":["import crypto from \"../include/crypto\";\nimport { HandshakeInfo, HttpRequestInit, SecurequClientConfig, SecurequClientResponse } from \"./types\";\nimport xanFetch from 'xanfetch'\n\n\nconst Clients = new Map<string, Base>()\n\nclass Base {\n protected config: SecurequClientConfig;\n protected loadingHandshake: boolean = false;\n protected secret_length: number = 0;\n protected handshakeInfo: HandshakeInfo | null = null;\n\n constructor(config: SecurequClientConfig) {\n this.config = { ...config }\n const url = new URL(config.url)\n if (url.search || url.hash) throw new Error(`Invalid config url ${config.url}. Search params or Hash url is not supported in config.url`)\n config.url = `${url.origin}${url.pathname}`\n\n if (Clients.has(config.url)) {\n throw new Error(`Client is Blocked!`);\n }\n }\n\n protected hooksCall(hook: keyof NonNullable<SecurequClientConfig['hooks']>, ...args: any[]) {\n if (this.config.hooks && this.config.hooks[hook]) {\n return (this.config.hooks[hook] as Function)(...args)\n }\n }\n\n protected async getSecret() {\n let full = this.config.secret\n let secret = full.substring(0, this.secret_length)\n let hash = (await crypto.hash(secret)).substring(0, this.secret_length)\n return { full, secret, hash }\n }\n\n protected async url(path: string) {\n const secret = await this.getSecret()\n const base = this.config.url;\n if (path === '/') path = ''\n path = path.trim();\n path = path.startsWith('/') ? path.substring(1) : path\n path = path.endsWith('/') ? path.substring(0, path.length - 1) : path\n if (path) path = `/${path}`\n return new URL(`${base}/${secret.hash}${path}`);\n }\n\n protected async getHeaders(path: string, init?: HttpRequestInit) {\n const url = await this.url(path)\n const secret = await this.getSecret()\n let headers: any = {};\n if (this.handshakeInfo) {\n headers[\"X-SIGNETURE\"] = await crypto.encrypt({\n signeture: this.handshakeInfo?.signeture,\n expire: Date.now() + this.handshakeInfo!.timeDiffarenc + 10000 // 10 seconds\n }, secret.secret) || '';\n }\n return {\n ...this.config?.defaultOptions?.headers,\n ...init?.headers,\n ...headers,\n 'Content-Type': 'application/octet-stream',\n \"X-ORIGIN\": url.origin\n }\n }\n\n protected async awaitForHandshake() {\n if (this.loadingHandshake) {\n await new Promise((resolve) => {\n const interval = setInterval(() => {\n if (!this.loadingHandshake) {\n clearInterval(interval);\n resolve(null);\n }\n }, 100);\n })\n }\n if (!this.handshakeInfo) {\n await this.handshake();\n }\n }\n\n async handshake() {\n await this.hooksCall('beforeHandshake');\n this.handshakeInfo = null;\n this.loadingHandshake = true;\n\n let max = this.config.secret.length\n let min = Math.floor(max / 4) * 3\n this.secret_length = Math.floor(Math.random() * (max - min + 1)) + min\n\n const secret = await this.getSecret()\n const res = await this.fetch('/', {\n method: 'POST',\n body: {\n hash: secret.hash,\n clientTime: new Date().toISOString(),\n secret: secret.secret,\n }\n })\n this.handshakeInfo = res.data\n this.loadingHandshake = false;\n await this.hooksCall('afterHandshake', this.handshakeInfo);\n }\n\n protected async fetch(path: string, init?: HttpRequestInit): Promise<SecurequClientResponse> {\n const isDev = path !== '/' && this.handshakeInfo?.dev\n const secret = await this.getSecret()\n const url = await this.url(path)\n let sparams = Object.fromEntries(url.searchParams.entries())\n const _init = { ...init }\n let params: any = {\n ...sparams,\n }\n\n if (Object.keys(sparams).length > 0) {\n for (let key in sparams) {\n url.searchParams.delete(key)\n }\n }\n\n if (_init?.params) {\n for (let key in _init.params) {\n params[key] = _init.params[key]\n }\n delete _init.params\n }\n\n if (Object.keys(params).length > 0) {\n if (isDev) {\n _init.params = params\n } else {\n const enc = await crypto.encrypt(params, secret.secret)\n url.href = url.href + \"?\" + encodeURIComponent(enc)\n }\n }\n\n const httpOption: any = {\n method: \"GET\",\n ...this.config?.defaultOptions,\n ..._init,\n headers: await this.getHeaders(path, init)\n }\n\n if (httpOption?.body) {\n if (isDev) {\n httpOption.body = JSON.stringify(httpOption.body)\n } else {\n httpOption.body = await crypto.encryptBuffer(httpOption.body, secret.secret);\n }\n }\n const res = await xanFetch(url.href, httpOption)\n if (isDev) {\n const value = await res.text()\n const val = JSON.parse(value)\n return {\n success: res.ok,\n message: res.ok ? res.statusText : val,\n data: res.ok ? val : null,\n code: res.status\n }\n }\n const value = await res.arrayBuffer()\n const val = await crypto.decryptBuffer(new Uint8Array(value), secret.secret) as any\n return {\n success: res.ok,\n message: res.ok ? res.statusText : val,\n data: res.ok ? val : null,\n code: res.status\n }\n }\n\n}\n\nexport default Base;\n"],"names":["Object","defineProperty","exports","value","crypto","require","xanFetch","Clients","Map","default","constructor","config","this","loadingHandshake","secret_length","handshakeInfo","assign","url","URL","search","hash","Error","origin","pathname","has","hooksCall","hook","args","hooks","getSecret","full","secret","substring","path","base","trim","startsWith","endsWith","length","getHeaders","init","headers","encrypt","signeture","_a","expire","Date","now","timeDiffarenc","_c","_b","defaultOptions","awaitForHandshake","Promise","resolve","interval","setInterval","clearInterval","handshake","max","min","Math","floor","random","res","fetch","method","body","clientTime","toISOString","data","isDev","dev","sparams","fromEntries","searchParams","entries","_init","params","keys","key","delete","enc","href","encodeURIComponent","httpOption","JSON","stringify","encryptBuffer","text","val","parse","success","ok","message","statusText","code","status","arrayBuffer","decryptBuffer","Uint8Array"],"mappings":"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"}
1
+ {"version":3,"file":"Base.js","sources":["../../src/client/Base.ts"],"sourcesContent":["import crypto from \"../include/crypto\";\nimport { HandshakeInfo, HttpRequestInit, SecurequClientConfig, SecurequClientResponse } from \"./types\";\nimport xanFetch from 'xanfetch'\n\n\nconst Clients = new Map<string, Base>()\n\nclass Base {\n protected config: SecurequClientConfig;\n protected loadingHandshake: boolean = false;\n protected secret_length: number = 0;\n protected handshakeInfo: HandshakeInfo | null = null;\n readonly CONTENT_TYPE = \"application/octet-stream\";\n\n constructor(config: SecurequClientConfig) {\n this.config = { ...config }\n const url = new URL(config.url)\n if (url.search || url.hash) throw new Error(`Invalid config url ${config.url}. Search params or Hash url is not supported in config.url`)\n config.url = `${url.origin}${url.pathname}`\n\n if (Clients.has(config.url)) {\n throw new Error(`Client is Blocked!`);\n }\n }\n\n protected hooksCall(hook: keyof NonNullable<SecurequClientConfig['hooks']>, ...args: any[]) {\n if (this.config.hooks && this.config.hooks[hook]) {\n return (this.config.hooks[hook] as Function)(...args)\n }\n }\n\n protected async getSecret() {\n let full = this.config.secret\n let secret = full.substring(0, this.secret_length)\n let hash = (await crypto.hash(secret)).substring(0, this.secret_length)\n return { full, secret, hash }\n }\n\n protected async url(path: string) {\n const secret = await this.getSecret()\n const base = this.config.url;\n if (path === '/') path = ''\n path = path.trim();\n path = path.startsWith('/') ? path.substring(1) : path\n path = path.endsWith('/') ? path.substring(0, path.length - 1) : path\n if (path) path = `/${path}`\n return new URL(`${base}/${secret.hash}${path}`);\n }\n\n protected async getHeaders(path: string, init?: HttpRequestInit) {\n const url = await this.url(path)\n const secret = await this.getSecret()\n let headers: any = {};\n if (this.handshakeInfo) {\n headers[\"X-SIGNETURE\"] = await crypto.encrypt({\n signeture: this.handshakeInfo?.signeture,\n expire: Date.now() + this.handshakeInfo!.timeDiffarenc + 10000 // 10 seconds\n }, secret.secret) || '';\n }\n\n headers = {\n ...this.config?.defaultOptions?.headers,\n ...init?.headers,\n ...headers,\n 'Content-Type': this.CONTENT_TYPE,\n \"X-ORIGIN\": url.origin,\n \"X-METHOD\": (init?.method || 'GET').toUpperCase()\n }\n\n return headers;\n }\n\n protected async awaitForHandshake() {\n if (this.loadingHandshake) {\n await new Promise((resolve) => {\n const interval = setInterval(() => {\n if (!this.loadingHandshake) {\n clearInterval(interval);\n resolve(null);\n }\n }, 100);\n })\n }\n if (!this.handshakeInfo) {\n await this.handshake();\n }\n }\n\n async handshake() {\n await this.hooksCall('beforeHandshake');\n this.handshakeInfo = null;\n this.loadingHandshake = true;\n\n let max = this.config.secret.length\n let min = Math.floor(max / 4) * 3\n this.secret_length = Math.floor(Math.random() * (max - min + 1)) + min\n\n const secret = await this.getSecret()\n const res = await this.fetch('/', {\n method: 'POST',\n body: {\n hash: secret.hash,\n clientTime: new Date().toISOString(),\n secret: secret.secret,\n }\n })\n this.handshakeInfo = res.data\n this.loadingHandshake = false;\n await this.hooksCall('afterHandshake', this.handshakeInfo);\n }\n\n protected async fetch(path: string, init?: HttpRequestInit): Promise<SecurequClientResponse> {\n const isDev = path !== '/' && this.handshakeInfo?.dev\n const secret = await this.getSecret()\n const url = await this.url(path)\n let sparams = Object.fromEntries(url.searchParams.entries())\n const _init = { ...init }\n let params: any = {\n ...sparams,\n }\n\n if (Object.keys(sparams).length > 0) {\n for (let key in sparams) {\n url.searchParams.delete(key)\n }\n }\n\n if (_init?.params) {\n for (let key in _init.params) {\n params[key] = _init.params[key]\n }\n delete _init.params\n }\n\n if (Object.keys(params).length > 0) {\n if (isDev) {\n _init.params = params\n } else {\n const enc = await crypto.encrypt(params, secret.secret)\n url.href = url.href + \"?\" + encodeURIComponent(enc)\n }\n }\n\n const httpOption: any = {\n method: \"GET\",\n ...this.config?.defaultOptions,\n ..._init,\n headers: await this.getHeaders(path, _init)\n }\n\n if (httpOption?.body) {\n if (isDev) {\n httpOption.body = JSON.stringify(httpOption.body)\n } else {\n httpOption.body = await crypto.encryptBuffer(httpOption.body, secret.secret);\n }\n }\n const res = await xanFetch(url.href, httpOption)\n if (isDev) {\n const value = await res.text()\n const val = JSON.parse(value)\n return {\n success: res.ok,\n message: res.ok ? res.statusText : val,\n data: res.ok ? val : null,\n code: res.status\n }\n }\n const value = await res.arrayBuffer()\n const val = await crypto.decryptBuffer(new Uint8Array(value), secret.secret) as any\n\n return {\n success: res.ok,\n message: res.ok ? res.statusText : (val || res.statusText),\n data: res.ok ? val : null,\n code: res.status\n }\n }\n\n}\n\nexport default Base;\n"],"names":["Object","defineProperty","exports","value","crypto","require","xanFetch","Clients","Map","default","constructor","config","this","loadingHandshake","secret_length","handshakeInfo","CONTENT_TYPE","assign","url","URL","search","hash","Error","origin","pathname","has","hooksCall","hook","args","hooks","getSecret","full","secret","substring","path","base","trim","startsWith","endsWith","length","getHeaders","init","headers","encrypt","signeture","_a","expire","Date","now","timeDiffarenc","_b","defaultOptions","_c","method","toUpperCase","awaitForHandshake","Promise","resolve","interval","setInterval","clearInterval","handshake","max","min","Math","floor","random","res","fetch","body","clientTime","toISOString","data","isDev","dev","sparams","fromEntries","searchParams","entries","_init","params","keys","key","delete","enc","href","encodeURIComponent","httpOption","JSON","stringify","encryptBuffer","text","val","parse","success","ok","message","statusText","code","status","arrayBuffer","decryptBuffer","Uint8Array"],"mappings":"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"}
package/client/Base.mjs CHANGED
@@ -1 +1 @@
1
- import t from"../include/crypto.mjs";import e from"xanfetch";const s=new Map;class a{constructor(t){this.loadingHandshake=!1,this.secret_length=0,this.handshakeInfo=null,this.config=Object.assign({},t);const e=new URL(t.url);if(e.search||e.hash)throw new Error(`Invalid config url ${t.url}. Search params or Hash url is not supported in config.url`);if(t.url=`${e.origin}${e.pathname}`,s.has(t.url))throw new Error("Client is Blocked!")}hooksCall(t,...e){if(this.config.hooks&&this.config.hooks[t])return this.config.hooks[t](...e)}async getSecret(){let e=this.config.secret,s=e.substring(0,this.secret_length);return{full:e,secret:s,hash:(await t.hash(s)).substring(0,this.secret_length)}}async url(t){const e=await this.getSecret(),s=this.config.url;return"/"===t&&(t=""),(t=(t=(t=t.trim()).startsWith("/")?t.substring(1):t).endsWith("/")?t.substring(0,t.length-1):t)&&(t=`/${t}`),new URL(`${s}/${e.hash}${t}`)}async getHeaders(e,s){var a,n,i;const r=await this.url(e),h=await this.getSecret();let o={};return this.handshakeInfo&&(o["X-SIGNETURE"]=await t.encrypt({signeture:null===(a=this.handshakeInfo)||void 0===a?void 0:a.signeture,expire:Date.now()+this.handshakeInfo.timeDiffarenc+1e4},h.secret)||""),Object.assign(Object.assign(Object.assign(Object.assign({},null===(i=null===(n=this.config)||void 0===n?void 0:n.defaultOptions)||void 0===i?void 0:i.headers),null==s?void 0:s.headers),o),{"Content-Type":"application/octet-stream","X-ORIGIN":r.origin})}async awaitForHandshake(){this.loadingHandshake&&await new Promise(t=>{const e=setInterval(()=>{this.loadingHandshake||(clearInterval(e),t(null))},100)}),this.handshakeInfo||await this.handshake()}async handshake(){await this.hooksCall("beforeHandshake"),this.handshakeInfo=null,this.loadingHandshake=!0;let t=this.config.secret.length,e=3*Math.floor(t/4);this.secret_length=Math.floor(Math.random()*(t-e+1))+e;const s=await this.getSecret(),a=await this.fetch("/",{method:"POST",body:{hash:s.hash,clientTime:(new Date).toISOString(),secret:s.secret}});this.handshakeInfo=a.data,this.loadingHandshake=!1,await this.hooksCall("afterHandshake",this.handshakeInfo)}async fetch(s,a){var n,i;const r="/"!==s&&(null===(n=this.handshakeInfo)||void 0===n?void 0:n.dev),h=await this.getSecret(),o=await this.url(s);let c=Object.fromEntries(o.searchParams.entries());const l=Object.assign({},a);let d=Object.assign({},c);if(Object.keys(c).length>0)for(let t in c)o.searchParams.delete(t);if(null==l?void 0:l.params){for(let t in l.params)d[t]=l.params[t];delete l.params}if(Object.keys(d).length>0)if(r)l.params=d;else{const e=await t.encrypt(d,h.secret);o.href=o.href+"?"+encodeURIComponent(e)}const f=Object.assign(Object.assign(Object.assign({method:"GET"},null===(i=this.config)||void 0===i?void 0:i.defaultOptions),l),{headers:await this.getHeaders(s,a)});(null==f?void 0:f.body)&&(f.body=r?JSON.stringify(f.body):await t.encryptBuffer(f.body,h.secret));const g=await e(o.href,f);if(r){const t=await g.text(),e=JSON.parse(t);return{success:g.ok,message:g.ok?g.statusText:e,data:g.ok?e:null,code:g.status}}const u=await g.arrayBuffer(),k=await t.decryptBuffer(new Uint8Array(u),h.secret);return{success:g.ok,message:g.ok?g.statusText:k,data:g.ok?k:null,code:g.status}}}export{a as default};//# sourceMappingURL=Base.mjs.map
1
+ import t from"../include/crypto.mjs";import e from"xanfetch";const s=new Map;class a{constructor(t){this.loadingHandshake=!1,this.secret_length=0,this.handshakeInfo=null,this.CONTENT_TYPE="application/octet-stream",this.config=Object.assign({},t);const e=new URL(t.url);if(e.search||e.hash)throw new Error(`Invalid config url ${t.url}. Search params or Hash url is not supported in config.url`);if(t.url=`${e.origin}${e.pathname}`,s.has(t.url))throw new Error("Client is Blocked!")}hooksCall(t,...e){if(this.config.hooks&&this.config.hooks[t])return this.config.hooks[t](...e)}async getSecret(){let e=this.config.secret,s=e.substring(0,this.secret_length);return{full:e,secret:s,hash:(await t.hash(s)).substring(0,this.secret_length)}}async url(t){const e=await this.getSecret(),s=this.config.url;return"/"===t&&(t=""),(t=(t=(t=t.trim()).startsWith("/")?t.substring(1):t).endsWith("/")?t.substring(0,t.length-1):t)&&(t=`/${t}`),new URL(`${s}/${e.hash}${t}`)}async getHeaders(e,s){var a,n,i;const r=await this.url(e),h=await this.getSecret();let o={};return this.handshakeInfo&&(o["X-SIGNETURE"]=await t.encrypt({signeture:null===(a=this.handshakeInfo)||void 0===a?void 0:a.signeture,expire:Date.now()+this.handshakeInfo.timeDiffarenc+1e4},h.secret)||""),o=Object.assign(Object.assign(Object.assign(Object.assign({},null===(i=null===(n=this.config)||void 0===n?void 0:n.defaultOptions)||void 0===i?void 0:i.headers),null==s?void 0:s.headers),o),{"Content-Type":this.CONTENT_TYPE,"X-ORIGIN":r.origin,"X-METHOD":((null==s?void 0:s.method)||"GET").toUpperCase()}),o}async awaitForHandshake(){this.loadingHandshake&&await new Promise(t=>{const e=setInterval(()=>{this.loadingHandshake||(clearInterval(e),t(null))},100)}),this.handshakeInfo||await this.handshake()}async handshake(){await this.hooksCall("beforeHandshake"),this.handshakeInfo=null,this.loadingHandshake=!0;let t=this.config.secret.length,e=3*Math.floor(t/4);this.secret_length=Math.floor(Math.random()*(t-e+1))+e;const s=await this.getSecret(),a=await this.fetch("/",{method:"POST",body:{hash:s.hash,clientTime:(new Date).toISOString(),secret:s.secret}});this.handshakeInfo=a.data,this.loadingHandshake=!1,await this.hooksCall("afterHandshake",this.handshakeInfo)}async fetch(s,a){var n,i;const r="/"!==s&&(null===(n=this.handshakeInfo)||void 0===n?void 0:n.dev),h=await this.getSecret(),o=await this.url(s);let c=Object.fromEntries(o.searchParams.entries());const l=Object.assign({},a);let d=Object.assign({},c);if(Object.keys(c).length>0)for(let t in c)o.searchParams.delete(t);if(null==l?void 0:l.params){for(let t in l.params)d[t]=l.params[t];delete l.params}if(Object.keys(d).length>0)if(r)l.params=d;else{const e=await t.encrypt(d,h.secret);o.href=o.href+"?"+encodeURIComponent(e)}const f=Object.assign(Object.assign(Object.assign({method:"GET"},null===(i=this.config)||void 0===i?void 0:i.defaultOptions),l),{headers:await this.getHeaders(s,l)});(null==f?void 0:f.body)&&(f.body=r?JSON.stringify(f.body):await t.encryptBuffer(f.body,h.secret));const u=await e(o.href,f);if(r){const t=await u.text(),e=JSON.parse(t);return{success:u.ok,message:u.ok?u.statusText:e,data:u.ok?e:null,code:u.status}}const g=await u.arrayBuffer(),k=await t.decryptBuffer(new Uint8Array(g),h.secret);return{success:u.ok,message:u.ok?u.statusText:k||u.statusText,data:u.ok?k:null,code:u.status}}}export{a as default};//# sourceMappingURL=Base.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"Base.mjs","sources":["../../src/client/Base.ts"],"sourcesContent":["import crypto from \"../include/crypto\";\nimport { HandshakeInfo, HttpRequestInit, SecurequClientConfig, SecurequClientResponse } from \"./types\";\nimport xanFetch from 'xanfetch'\n\n\nconst Clients = new Map<string, Base>()\n\nclass Base {\n protected config: SecurequClientConfig;\n protected loadingHandshake: boolean = false;\n protected secret_length: number = 0;\n protected handshakeInfo: HandshakeInfo | null = null;\n\n constructor(config: SecurequClientConfig) {\n this.config = { ...config }\n const url = new URL(config.url)\n if (url.search || url.hash) throw new Error(`Invalid config url ${config.url}. Search params or Hash url is not supported in config.url`)\n config.url = `${url.origin}${url.pathname}`\n\n if (Clients.has(config.url)) {\n throw new Error(`Client is Blocked!`);\n }\n }\n\n protected hooksCall(hook: keyof NonNullable<SecurequClientConfig['hooks']>, ...args: any[]) {\n if (this.config.hooks && this.config.hooks[hook]) {\n return (this.config.hooks[hook] as Function)(...args)\n }\n }\n\n protected async getSecret() {\n let full = this.config.secret\n let secret = full.substring(0, this.secret_length)\n let hash = (await crypto.hash(secret)).substring(0, this.secret_length)\n return { full, secret, hash }\n }\n\n protected async url(path: string) {\n const secret = await this.getSecret()\n const base = this.config.url;\n if (path === '/') path = ''\n path = path.trim();\n path = path.startsWith('/') ? path.substring(1) : path\n path = path.endsWith('/') ? path.substring(0, path.length - 1) : path\n if (path) path = `/${path}`\n return new URL(`${base}/${secret.hash}${path}`);\n }\n\n protected async getHeaders(path: string, init?: HttpRequestInit) {\n const url = await this.url(path)\n const secret = await this.getSecret()\n let headers: any = {};\n if (this.handshakeInfo) {\n headers[\"X-SIGNETURE\"] = await crypto.encrypt({\n signeture: this.handshakeInfo?.signeture,\n expire: Date.now() + this.handshakeInfo!.timeDiffarenc + 10000 // 10 seconds\n }, secret.secret) || '';\n }\n return {\n ...this.config?.defaultOptions?.headers,\n ...init?.headers,\n ...headers,\n 'Content-Type': 'application/octet-stream',\n \"X-ORIGIN\": url.origin\n }\n }\n\n protected async awaitForHandshake() {\n if (this.loadingHandshake) {\n await new Promise((resolve) => {\n const interval = setInterval(() => {\n if (!this.loadingHandshake) {\n clearInterval(interval);\n resolve(null);\n }\n }, 100);\n })\n }\n if (!this.handshakeInfo) {\n await this.handshake();\n }\n }\n\n async handshake() {\n await this.hooksCall('beforeHandshake');\n this.handshakeInfo = null;\n this.loadingHandshake = true;\n\n let max = this.config.secret.length\n let min = Math.floor(max / 4) * 3\n this.secret_length = Math.floor(Math.random() * (max - min + 1)) + min\n\n const secret = await this.getSecret()\n const res = await this.fetch('/', {\n method: 'POST',\n body: {\n hash: secret.hash,\n clientTime: new Date().toISOString(),\n secret: secret.secret,\n }\n })\n this.handshakeInfo = res.data\n this.loadingHandshake = false;\n await this.hooksCall('afterHandshake', this.handshakeInfo);\n }\n\n protected async fetch(path: string, init?: HttpRequestInit): Promise<SecurequClientResponse> {\n const isDev = path !== '/' && this.handshakeInfo?.dev\n const secret = await this.getSecret()\n const url = await this.url(path)\n let sparams = Object.fromEntries(url.searchParams.entries())\n const _init = { ...init }\n let params: any = {\n ...sparams,\n }\n\n if (Object.keys(sparams).length > 0) {\n for (let key in sparams) {\n url.searchParams.delete(key)\n }\n }\n\n if (_init?.params) {\n for (let key in _init.params) {\n params[key] = _init.params[key]\n }\n delete _init.params\n }\n\n if (Object.keys(params).length > 0) {\n if (isDev) {\n _init.params = params\n } else {\n const enc = await crypto.encrypt(params, secret.secret)\n url.href = url.href + \"?\" + encodeURIComponent(enc)\n }\n }\n\n const httpOption: any = {\n method: \"GET\",\n ...this.config?.defaultOptions,\n ..._init,\n headers: await this.getHeaders(path, init)\n }\n\n if (httpOption?.body) {\n if (isDev) {\n httpOption.body = JSON.stringify(httpOption.body)\n } else {\n httpOption.body = await crypto.encryptBuffer(httpOption.body, secret.secret);\n }\n }\n const res = await xanFetch(url.href, httpOption)\n if (isDev) {\n const value = await res.text()\n const val = JSON.parse(value)\n return {\n success: res.ok,\n message: res.ok ? res.statusText : val,\n data: res.ok ? val : null,\n code: res.status\n }\n }\n const value = await res.arrayBuffer()\n const val = await crypto.decryptBuffer(new Uint8Array(value), secret.secret) as any\n return {\n success: res.ok,\n message: res.ok ? res.statusText : val,\n data: res.ok ? val : null,\n code: res.status\n }\n }\n\n}\n\nexport default Base;\n"],"names":["crypto","xanFetch","Clients","Map","Base","constructor","config","this","loadingHandshake","secret_length","handshakeInfo","Object","assign","url","URL","search","hash","Error","origin","pathname","has","hooksCall","hook","args","hooks","getSecret","full","secret","substring","path","base","trim","startsWith","endsWith","length","getHeaders","init","headers","encrypt","signeture","_a","expire","Date","now","timeDiffarenc","_c","_b","defaultOptions","awaitForHandshake","Promise","resolve","interval","setInterval","clearInterval","handshake","max","min","Math","floor","random","res","fetch","method","body","clientTime","toISOString","data","isDev","dev","sparams","fromEntries","searchParams","entries","_init","params","keys","key","delete","enc","href","encodeURIComponent","httpOption","JSON","stringify","encryptBuffer","value","text","val","parse","success","ok","message","statusText","code","status","arrayBuffer","decryptBuffer","Uint8Array"],"mappings":"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"}
1
+ {"version":3,"file":"Base.mjs","sources":["../../src/client/Base.ts"],"sourcesContent":["import crypto from \"../include/crypto\";\nimport { HandshakeInfo, HttpRequestInit, SecurequClientConfig, SecurequClientResponse } from \"./types\";\nimport xanFetch from 'xanfetch'\n\n\nconst Clients = new Map<string, Base>()\n\nclass Base {\n protected config: SecurequClientConfig;\n protected loadingHandshake: boolean = false;\n protected secret_length: number = 0;\n protected handshakeInfo: HandshakeInfo | null = null;\n readonly CONTENT_TYPE = \"application/octet-stream\";\n\n constructor(config: SecurequClientConfig) {\n this.config = { ...config }\n const url = new URL(config.url)\n if (url.search || url.hash) throw new Error(`Invalid config url ${config.url}. Search params or Hash url is not supported in config.url`)\n config.url = `${url.origin}${url.pathname}`\n\n if (Clients.has(config.url)) {\n throw new Error(`Client is Blocked!`);\n }\n }\n\n protected hooksCall(hook: keyof NonNullable<SecurequClientConfig['hooks']>, ...args: any[]) {\n if (this.config.hooks && this.config.hooks[hook]) {\n return (this.config.hooks[hook] as Function)(...args)\n }\n }\n\n protected async getSecret() {\n let full = this.config.secret\n let secret = full.substring(0, this.secret_length)\n let hash = (await crypto.hash(secret)).substring(0, this.secret_length)\n return { full, secret, hash }\n }\n\n protected async url(path: string) {\n const secret = await this.getSecret()\n const base = this.config.url;\n if (path === '/') path = ''\n path = path.trim();\n path = path.startsWith('/') ? path.substring(1) : path\n path = path.endsWith('/') ? path.substring(0, path.length - 1) : path\n if (path) path = `/${path}`\n return new URL(`${base}/${secret.hash}${path}`);\n }\n\n protected async getHeaders(path: string, init?: HttpRequestInit) {\n const url = await this.url(path)\n const secret = await this.getSecret()\n let headers: any = {};\n if (this.handshakeInfo) {\n headers[\"X-SIGNETURE\"] = await crypto.encrypt({\n signeture: this.handshakeInfo?.signeture,\n expire: Date.now() + this.handshakeInfo!.timeDiffarenc + 10000 // 10 seconds\n }, secret.secret) || '';\n }\n\n headers = {\n ...this.config?.defaultOptions?.headers,\n ...init?.headers,\n ...headers,\n 'Content-Type': this.CONTENT_TYPE,\n \"X-ORIGIN\": url.origin,\n \"X-METHOD\": (init?.method || 'GET').toUpperCase()\n }\n\n return headers;\n }\n\n protected async awaitForHandshake() {\n if (this.loadingHandshake) {\n await new Promise((resolve) => {\n const interval = setInterval(() => {\n if (!this.loadingHandshake) {\n clearInterval(interval);\n resolve(null);\n }\n }, 100);\n })\n }\n if (!this.handshakeInfo) {\n await this.handshake();\n }\n }\n\n async handshake() {\n await this.hooksCall('beforeHandshake');\n this.handshakeInfo = null;\n this.loadingHandshake = true;\n\n let max = this.config.secret.length\n let min = Math.floor(max / 4) * 3\n this.secret_length = Math.floor(Math.random() * (max - min + 1)) + min\n\n const secret = await this.getSecret()\n const res = await this.fetch('/', {\n method: 'POST',\n body: {\n hash: secret.hash,\n clientTime: new Date().toISOString(),\n secret: secret.secret,\n }\n })\n this.handshakeInfo = res.data\n this.loadingHandshake = false;\n await this.hooksCall('afterHandshake', this.handshakeInfo);\n }\n\n protected async fetch(path: string, init?: HttpRequestInit): Promise<SecurequClientResponse> {\n const isDev = path !== '/' && this.handshakeInfo?.dev\n const secret = await this.getSecret()\n const url = await this.url(path)\n let sparams = Object.fromEntries(url.searchParams.entries())\n const _init = { ...init }\n let params: any = {\n ...sparams,\n }\n\n if (Object.keys(sparams).length > 0) {\n for (let key in sparams) {\n url.searchParams.delete(key)\n }\n }\n\n if (_init?.params) {\n for (let key in _init.params) {\n params[key] = _init.params[key]\n }\n delete _init.params\n }\n\n if (Object.keys(params).length > 0) {\n if (isDev) {\n _init.params = params\n } else {\n const enc = await crypto.encrypt(params, secret.secret)\n url.href = url.href + \"?\" + encodeURIComponent(enc)\n }\n }\n\n const httpOption: any = {\n method: \"GET\",\n ...this.config?.defaultOptions,\n ..._init,\n headers: await this.getHeaders(path, _init)\n }\n\n if (httpOption?.body) {\n if (isDev) {\n httpOption.body = JSON.stringify(httpOption.body)\n } else {\n httpOption.body = await crypto.encryptBuffer(httpOption.body, secret.secret);\n }\n }\n const res = await xanFetch(url.href, httpOption)\n if (isDev) {\n const value = await res.text()\n const val = JSON.parse(value)\n return {\n success: res.ok,\n message: res.ok ? res.statusText : val,\n data: res.ok ? val : null,\n code: res.status\n }\n }\n const value = await res.arrayBuffer()\n const val = await crypto.decryptBuffer(new Uint8Array(value), secret.secret) as any\n\n return {\n success: res.ok,\n message: res.ok ? res.statusText : (val || res.statusText),\n data: res.ok ? val : null,\n code: res.status\n }\n }\n\n}\n\nexport default Base;\n"],"names":["crypto","xanFetch","Clients","Map","Base","constructor","config","this","loadingHandshake","secret_length","handshakeInfo","CONTENT_TYPE","Object","assign","url","URL","search","hash","Error","origin","pathname","has","hooksCall","hook","args","hooks","getSecret","full","secret","substring","path","base","trim","startsWith","endsWith","length","getHeaders","init","headers","encrypt","signeture","_a","expire","Date","now","timeDiffarenc","_b","defaultOptions","_c","method","toUpperCase","awaitForHandshake","Promise","resolve","interval","setInterval","clearInterval","handshake","max","min","Math","floor","random","res","fetch","body","clientTime","toISOString","data","isDev","dev","sparams","fromEntries","searchParams","entries","_init","params","keys","key","delete","enc","href","encodeURIComponent","httpOption","JSON","stringify","encryptBuffer","value","text","val","parse","success","ok","message","statusText","code","status","arrayBuffer","decryptBuffer","Uint8Array"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../../src/client/index.ts"],"sourcesContent":["import { fileTypeFromBuffer } from 'file-type';\nimport { HttpRequestInit, SecurequClientResponse } from \"./types\";\nimport { chunkFile, getFileId, totalChunks } from \"../include/File\";\nimport Base from \"./Base\";\nimport fileScaner from '../include/FileScaner';\n\nclass SecurequClient extends Base {\n\n async send(path: string, init?: HttpRequestInit): Promise<SecurequClientResponse> {\n await this.awaitForHandshake();\n init = await this.hooksCall('beforeRequest', path, init) || init;\n const url = await this.url(path)\n if (url.pathname === '/') throw new Error(\"Path is not allowed\")\n\n for (let key in init?.body) {\n if (init?.body[key] instanceof File) {\n init.body[key] = await this.upload(init.body[key], init?.onProgress)\n }\n }\n\n const res = await this.fetch(path, init);\n if ([\"Signeture expired\", \"Request expired\"].includes(res.message)) {\n await this.handshake();\n return await this.send(path, init);\n }\n await this.hooksCall('afterResponse', res);\n return res;\n }\n\n async upload(file: File, onProgress?: (p: number) => void): Promise<SecurequClientResponse> {\n await this.awaitForHandshake();\n const fileId = await getFileId(file);\n const chunkSize = this.config.chunkSize\n const controller = new AbortController();\n let _file = await this.hooksCall('beforeUpload', file, fileId) || file;\n const maxFileSize = this.handshakeInfo?.maxFileSize\n if (maxFileSize && _file.size > maxFileSize * 1024) {\n throw new Error(`File size exceeds the limit of ${maxFileSize / 1024} MB`)\n }\n // send metadata\n const meta = {\n filename: file.name,\n filesize: file.size,\n filetype: file.type,\n fileid: fileId,\n totalChunks: totalChunks(file, chunkSize),\n }\n\n const abort = async () => {\n await this.fetch('/', {\n method: 'PUT',\n body: { ...meta, type: 'failed' },\n })\n controller.abort();\n window.removeEventListener(\"pagehide\", abort);\n }\n window.addEventListener(\"pagehide\", abort);\n\n const metares = await this.fetch('/', {\n method: 'PUT',\n body: { ...meta, type: 'meta' }\n })\n\n\n if (!metares.success) {\n if ([\"Signeture expired\", \"Request expired\"].includes(metares.message)) {\n await this.handshake();\n return await this.upload(file, onProgress);\n }\n await abort()\n return metares\n }\n\n\n for await (let { chunk, chunkIndex } of chunkFile(_file, chunkSize)) {\n\n if (this.handshakeInfo?.checkFileType && chunkIndex === 0) {\n let fileType = fileScaner(chunk);\n if (!fileType) {\n await abort()\n return {\n success: false,\n message: \"Unknown or unsupported file type\",\n data: null,\n code: 0\n }\n }\n }\n\n await this.hooksCall('beforeUploadChunk', chunk, chunkIndex, meta.totalChunks);\n const info: any = {\n method: 'PUT',\n signal: controller.signal,\n body: { chunk, chunkIndex, fileId },\n onProgress: (p: number) => {\n if (onProgress) {\n const totalProgress = Math.floor(((chunkIndex + 1) / meta.totalChunks) * 100)\n const currentProgress = Math.floor((p / 100) / meta.totalChunks * 100)\n onProgress(Math.min(totalProgress + currentProgress, 100))\n }\n }\n }\n\n let res = await this.fetch('/', info)\n\n if (!res.success) {\n if ([\"Signeture expired\", \"Request expired\"].includes(metares.message)) {\n await this.handshake();\n res = await this.fetch('/', info)\n } else {\n await abort()\n return res\n }\n }\n await this.hooksCall('afterUploadChunk', res, chunkIndex, meta.totalChunks);\n\n if (chunkIndex + 1 === meta.totalChunks) {\n const info = {\n success: true,\n message: 'File uploaded successfully',\n data: res.data,\n code: res.code\n }\n await this.hooksCall('afterUpload', info, _file);\n return info\n }\n }\n return {\n success: false,\n message: 'File upload failed',\n data: null,\n code: 0\n }\n }\n\n async get(path: string, init?: Omit<HttpRequestInit, 'body' | 'method'>) {\n return await this.send(path, init);\n }\n\n async post(path: string, init?: Omit<HttpRequestInit, 'method'>) {\n return await this.send(path, { ...init, method: \"POST\" });\n }\n\n async put(path: string, init?: Omit<HttpRequestInit, 'method'>) {\n return await this.send(path, { ...init, method: \"PUT\" });\n }\n\n async delete(path: string, init?: Omit<HttpRequestInit, 'method'>) {\n return await this.send(path, { ...init, method: \"DELETE\" });\n }\n\n}\n\nexport default SecurequClient;\n"],"names":["SecurequClient","Base","send","path","init","this","awaitForHandshake","hooksCall","url","pathname","Error","key","body","File","upload","onProgress","res","fetch","includes","message","handshake","file","fileId","getFileId","chunkSize","config","controller","AbortController","_file","maxFileSize","_d","handshakeInfo","size","meta","filename","name","filesize","filetype","type","fileid","totalChunks","abort","async","method","window","removeEventListener","addEventListener","metares","success","_h","_f","_g","__asyncValues","chunkFile","_a","next","done","_c","value","chunk","chunkIndex","_e","checkFileType","fileScaner","data","code","info","signal","p","totalProgress","Math","floor","currentProgress","min","get","post","Object","assign","put","exports","default"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sources":["../../src/client/index.ts"],"sourcesContent":["import { HttpRequestInit, SecurequClientResponse } from \"./types\";\nimport { chunkFile, getFileId, totalChunks } from \"../include/File\";\nimport Base from \"./Base\";\nimport fileScaner from '../include/FileScaner';\n\nclass SecurequClient extends Base {\n\n async send(path: string, init?: HttpRequestInit): Promise<SecurequClientResponse> {\n await this.awaitForHandshake();\n init = await this.hooksCall('beforeRequest', path, init) || init;\n const url = await this.url(path)\n if (url.pathname === '/') throw new Error(\"Path is not allowed\")\n\n for (let key in init?.body) {\n if (init?.body[key] instanceof File) {\n init.body[key] = await this.upload(init.body[key], init?.onProgress)\n }\n }\n\n const res = await this.fetch(path, init);\n if ([\"Signeture expired\", \"Request expired\"].includes(res.message)) {\n await this.handshake();\n return await this.send(path, init);\n }\n await this.hooksCall('afterResponse', res);\n return res;\n }\n\n async upload(file: File, onProgress?: (p: number) => void): Promise<SecurequClientResponse> {\n await this.awaitForHandshake();\n const fileId = await getFileId(file);\n const chunkSize = this.config.chunkSize\n const controller = new AbortController();\n let _file = await this.hooksCall('beforeUpload', file, fileId) || file;\n const maxFileSize = this.handshakeInfo?.maxFileSize\n if (maxFileSize && _file.size > maxFileSize * 1024) {\n throw new Error(`File size exceeds the limit of ${maxFileSize / 1024} MB`)\n }\n // send metadata\n const meta = {\n filename: file.name,\n filesize: file.size,\n filetype: file.type,\n fileid: fileId,\n totalChunks: totalChunks(file, chunkSize),\n }\n\n const abort = async () => {\n await this.fetch('/', {\n method: 'PUT',\n body: { ...meta, type: 'failed' },\n })\n controller.abort();\n window.removeEventListener(\"pagehide\", abort);\n }\n window.addEventListener(\"pagehide\", abort);\n\n const metares = await this.fetch('/', {\n method: 'PUT',\n body: { ...meta, type: 'meta' }\n })\n\n\n if (!metares.success) {\n if ([\"Signeture expired\", \"Request expired\"].includes(metares.message)) {\n await this.handshake();\n return await this.upload(file, onProgress);\n }\n await abort()\n return metares\n }\n\n\n for await (let { chunk, chunkIndex } of chunkFile(_file, chunkSize)) {\n\n if (this.handshakeInfo?.checkFileType && chunkIndex === 0) {\n let fileType = fileScaner(chunk);\n if (!fileType) {\n await abort()\n return {\n success: false,\n message: \"Unknown or unsupported file type\",\n data: null,\n code: 0\n }\n }\n }\n\n await this.hooksCall('beforeUploadChunk', chunk, chunkIndex, meta.totalChunks);\n const info: any = {\n method: 'PUT',\n signal: controller.signal,\n body: { chunk, chunkIndex, fileId },\n onProgress: (p: number) => {\n if (onProgress) {\n const totalProgress = Math.floor(((chunkIndex + 1) / meta.totalChunks) * 100)\n const currentProgress = Math.floor((p / 100) / meta.totalChunks * 100)\n onProgress(Math.min(totalProgress + currentProgress, 100))\n }\n }\n }\n\n let res = await this.fetch('/', info)\n\n if (!res.success) {\n if ([\"Signeture expired\", \"Request expired\"].includes(metares.message)) {\n await this.handshake();\n res = await this.fetch('/', info)\n } else {\n await abort()\n return res\n }\n }\n await this.hooksCall('afterUploadChunk', res, chunkIndex, meta.totalChunks);\n\n if (chunkIndex + 1 === meta.totalChunks) {\n const info = {\n success: true,\n message: 'File uploaded successfully',\n data: res.data,\n code: res.code\n }\n await this.hooksCall('afterUpload', info, _file);\n return info\n }\n }\n return {\n success: false,\n message: 'File upload failed',\n data: null,\n code: 0\n }\n }\n\n async get(path: string, init?: Omit<HttpRequestInit, 'body' | 'method'>) {\n return await this.send(path, init);\n }\n\n async post(path: string, init?: Omit<HttpRequestInit, 'method'>) {\n return await this.send(path, { ...init, method: \"POST\" });\n }\n\n async put(path: string, init?: Omit<HttpRequestInit, 'method'>) {\n return await this.send(path, { ...init, method: \"PUT\" });\n }\n\n async delete(path: string, init?: Omit<HttpRequestInit, 'method'>) {\n return await this.send(path, { ...init, method: \"DELETE\" });\n }\n\n}\n\nexport default SecurequClient;\n"],"names":["SecurequClient","Base","send","path","init","this","awaitForHandshake","hooksCall","url","pathname","Error","key","body","File","upload","onProgress","res","fetch","includes","message","handshake","file","fileId","getFileId","chunkSize","config","controller","AbortController","_file","maxFileSize","_d","handshakeInfo","size","meta","filename","name","filesize","filetype","type","fileid","totalChunks","abort","async","method","window","removeEventListener","addEventListener","metares","success","_h","_f","_g","__asyncValues","chunkFile","_a","next","done","_c","value","chunk","chunkIndex","_e","checkFileType","fileScaner","data","code","info","signal","p","totalProgress","Math","floor","currentProgress","min","get","post","Object","assign","put","exports","default"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","sources":["../../src/client/index.ts"],"sourcesContent":["import { fileTypeFromBuffer } from 'file-type';\nimport { HttpRequestInit, SecurequClientResponse } from \"./types\";\nimport { chunkFile, getFileId, totalChunks } from \"../include/File\";\nimport Base from \"./Base\";\nimport fileScaner from '../include/FileScaner';\n\nclass SecurequClient extends Base {\n\n async send(path: string, init?: HttpRequestInit): Promise<SecurequClientResponse> {\n await this.awaitForHandshake();\n init = await this.hooksCall('beforeRequest', path, init) || init;\n const url = await this.url(path)\n if (url.pathname === '/') throw new Error(\"Path is not allowed\")\n\n for (let key in init?.body) {\n if (init?.body[key] instanceof File) {\n init.body[key] = await this.upload(init.body[key], init?.onProgress)\n }\n }\n\n const res = await this.fetch(path, init);\n if ([\"Signeture expired\", \"Request expired\"].includes(res.message)) {\n await this.handshake();\n return await this.send(path, init);\n }\n await this.hooksCall('afterResponse', res);\n return res;\n }\n\n async upload(file: File, onProgress?: (p: number) => void): Promise<SecurequClientResponse> {\n await this.awaitForHandshake();\n const fileId = await getFileId(file);\n const chunkSize = this.config.chunkSize\n const controller = new AbortController();\n let _file = await this.hooksCall('beforeUpload', file, fileId) || file;\n const maxFileSize = this.handshakeInfo?.maxFileSize\n if (maxFileSize && _file.size > maxFileSize * 1024) {\n throw new Error(`File size exceeds the limit of ${maxFileSize / 1024} MB`)\n }\n // send metadata\n const meta = {\n filename: file.name,\n filesize: file.size,\n filetype: file.type,\n fileid: fileId,\n totalChunks: totalChunks(file, chunkSize),\n }\n\n const abort = async () => {\n await this.fetch('/', {\n method: 'PUT',\n body: { ...meta, type: 'failed' },\n })\n controller.abort();\n window.removeEventListener(\"pagehide\", abort);\n }\n window.addEventListener(\"pagehide\", abort);\n\n const metares = await this.fetch('/', {\n method: 'PUT',\n body: { ...meta, type: 'meta' }\n })\n\n\n if (!metares.success) {\n if ([\"Signeture expired\", \"Request expired\"].includes(metares.message)) {\n await this.handshake();\n return await this.upload(file, onProgress);\n }\n await abort()\n return metares\n }\n\n\n for await (let { chunk, chunkIndex } of chunkFile(_file, chunkSize)) {\n\n if (this.handshakeInfo?.checkFileType && chunkIndex === 0) {\n let fileType = fileScaner(chunk);\n if (!fileType) {\n await abort()\n return {\n success: false,\n message: \"Unknown or unsupported file type\",\n data: null,\n code: 0\n }\n }\n }\n\n await this.hooksCall('beforeUploadChunk', chunk, chunkIndex, meta.totalChunks);\n const info: any = {\n method: 'PUT',\n signal: controller.signal,\n body: { chunk, chunkIndex, fileId },\n onProgress: (p: number) => {\n if (onProgress) {\n const totalProgress = Math.floor(((chunkIndex + 1) / meta.totalChunks) * 100)\n const currentProgress = Math.floor((p / 100) / meta.totalChunks * 100)\n onProgress(Math.min(totalProgress + currentProgress, 100))\n }\n }\n }\n\n let res = await this.fetch('/', info)\n\n if (!res.success) {\n if ([\"Signeture expired\", \"Request expired\"].includes(metares.message)) {\n await this.handshake();\n res = await this.fetch('/', info)\n } else {\n await abort()\n return res\n }\n }\n await this.hooksCall('afterUploadChunk', res, chunkIndex, meta.totalChunks);\n\n if (chunkIndex + 1 === meta.totalChunks) {\n const info = {\n success: true,\n message: 'File uploaded successfully',\n data: res.data,\n code: res.code\n }\n await this.hooksCall('afterUpload', info, _file);\n return info\n }\n }\n return {\n success: false,\n message: 'File upload failed',\n data: null,\n code: 0\n }\n }\n\n async get(path: string, init?: Omit<HttpRequestInit, 'body' | 'method'>) {\n return await this.send(path, init);\n }\n\n async post(path: string, init?: Omit<HttpRequestInit, 'method'>) {\n return await this.send(path, { ...init, method: \"POST\" });\n }\n\n async put(path: string, init?: Omit<HttpRequestInit, 'method'>) {\n return await this.send(path, { ...init, method: \"PUT\" });\n }\n\n async delete(path: string, init?: Omit<HttpRequestInit, 'method'>) {\n return await this.send(path, { ...init, method: \"DELETE\" });\n }\n\n}\n\nexport default SecurequClient;\n"],"names":["SecurequClient","Base","send","path","init","this","awaitForHandshake","hooksCall","url","pathname","Error","key","body","File","upload","onProgress","res","fetch","includes","message","handshake","file","fileId","getFileId","chunkSize","config","controller","AbortController","_file","maxFileSize","_d","handshakeInfo","size","meta","filename","name","filesize","filetype","type","fileid","totalChunks","abort","async","method","window","removeEventListener","addEventListener","metares","success","_h","_f","_g","__asyncValues","chunkFile","_a","next","done","_c","value","chunk","chunkIndex","_e","checkFileType","fileScaner","data","code","info","signal","p","totalProgress","Math","floor","currentProgress","min","get","post","Object","assign","put"],"mappings":"uMAMA,MAAMA,UAAuBC,EAE1B,UAAMC,CAAKC,EAAcC,SAChBC,KAAKC,oBACXF,QAAaC,KAAKE,UAAU,gBAAiBJ,EAAMC,IAASA,EAE5D,GAAqB,aADHC,KAAKG,IAAIL,IACnBM,SAAkB,MAAM,IAAIC,MAAM,uBAE1C,IAAK,IAAIC,KAAOP,aAAI,EAAJA,EAAMQ,MACfR,aAAI,EAAJA,EAAMQ,KAAKD,cAAgBE,OAC5BT,EAAKQ,KAAKD,SAAaN,KAAKS,OAAOV,EAAKQ,KAAKD,GAAMP,aAAI,EAAJA,EAAMW,aAI/D,MAAMC,QAAYX,KAAKY,MAAMd,EAAMC,GACnC,MAAI,CAAC,oBAAqB,mBAAmBc,SAASF,EAAIG,gBACjDd,KAAKe,kBACEf,KAAKH,KAAKC,EAAMC,WAE1BC,KAAKE,UAAU,gBAAiBS,GAC/BA,EACV,CAEA,YAAMF,CAAOO,EAAYN,yBAChBV,KAAKC,oBACX,MAAMgB,QAAeC,EAAUF,GACzBG,EAAYnB,KAAKoB,OAAOD,UACxBE,EAAa,IAAIC,gBACvB,IAAIC,QAAcvB,KAAKE,UAAU,eAAgBc,EAAMC,IAAWD,EAClE,MAAMQ,EAAgC,QAAlBC,EAAAzB,KAAK0B,qBAAa,IAAAD,OAAA,EAAAA,EAAED,YACxC,GAAIA,GAAeD,EAAMI,KAAqB,KAAdH,EAC7B,MAAM,IAAInB,MAAM,kCAAkCmB,EAAc,WAGnE,MAAMI,EAAO,CACVC,SAAUb,EAAKc,KACfC,SAAUf,EAAKW,KACfK,SAAUhB,EAAKiB,KACfC,OAAQjB,EACRkB,YAAaA,EAAYnB,EAAMG,IAG5BiB,EAAQC,gBACLrC,KAAKY,MAAM,IAAK,CACnB0B,OAAQ,MACR/B,oCAAWqB,GAAI,CAAEK,KAAM,aAE1BZ,EAAWe,QACXG,OAAOC,oBAAoB,WAAYJ,IAE1CG,OAAOE,iBAAiB,WAAYL,GAEpC,MAAMM,QAAgB1C,KAAKY,MAAM,IAAK,CACnC0B,OAAQ,MACR/B,oCAAWqB,GAAI,CAAEK,KAAM,WAI1B,IAAKS,EAAQC,QACV,MAAI,CAAC,oBAAqB,mBAAmB9B,SAAS6B,EAAQ5B,gBACrDd,KAAKe,kBACEf,KAAKS,OAAOO,EAAMN,WAE5B0B,IACCM,OAIV,IAAwC,IAA2BE,EAA3BC,GAAA,EAAAC,EAAAC,EAAAC,EAAUzB,EAAOJ,MAAU8B,GAAAL,QAAAE,EAAAI,QAAAC,OAAA,CAA3BC,EAAAR,EAAAS,MAAAR,GAAA,MAA7B,IAAIS,MAAEA,EAAKC,WAAEA,KAErB,IAAsB,QAAlBC,EAAAxD,KAAK0B,qBAAa,IAAA8B,OAAA,EAAAA,EAAEC,gBAAgC,IAAfF,EAAkB,CAExD,IADeG,EAAWJ,GAGvB,aADMlB,IACC,CACJO,SAAS,EACT7B,QAAS,mCACT6C,KAAM,KACNC,KAAM,EAGd,OAEK5D,KAAKE,UAAU,oBAAqBoD,EAAOC,EAAY3B,EAAKO,aAClE,MAAM0B,EAAY,CACfvB,OAAQ,MACRwB,OAAQzC,EAAWyC,OACnBvD,KAAM,CAAE+C,QAAOC,aAAYtC,UAC3BP,WAAaqD,IACV,GAAIrD,EAAY,CACb,MAAMsD,EAAgBC,KAAKC,OAAQX,EAAa,GAAK3B,EAAKO,YAAe,KACnEgC,EAAkBF,KAAKC,MAAOH,EAAI,IAAOnC,EAAKO,YAAc,KAClEzB,EAAWuD,KAAKG,IAAIJ,EAAgBG,EAAiB,KACvD,IAIP,IAAIxD,QAAYX,KAAKY,MAAM,IAAKiD,GAEhC,IAAKlD,EAAIgC,QAAS,CACf,IAAI,CAAC,oBAAqB,mBAAmB9B,SAAS6B,EAAQ5B,SAK3D,aADMsB,IACCzB,QAJDX,KAAKe,YACXJ,QAAYX,KAAKY,MAAM,IAAKiD,EAKjC,CAGD,SAFM7D,KAAKE,UAAU,mBAAoBS,EAAK4C,EAAY3B,EAAKO,aAE3DoB,EAAa,IAAM3B,EAAKO,YAAa,CACtC,MAAM0B,EAAO,CACVlB,SAAS,EACT7B,QAAS,6BACT6C,KAAMhD,EAAIgD,KACVC,KAAMjD,EAAIiD,MAGb,aADM5D,KAAKE,UAAU,cAAe2D,EAAMtC,GACnCsC,CACT,eACH,oGACD,MAAO,CACJlB,SAAS,EACT7B,QAAS,qBACT6C,KAAM,KACNC,KAAM,EAEZ,CAEA,SAAMS,CAAIvE,EAAcC,GACrB,aAAaC,KAAKH,KAAKC,EAAMC,EAChC,CAEA,UAAMuE,CAAKxE,EAAcC,GACtB,aAAaC,KAAKH,KAAKC,EAAIyE,OAAAC,OAAAD,OAAAC,OAAA,CAAA,EAAOzE,GAAI,CAAEuC,OAAQ,SACnD,CAEA,SAAMmC,CAAI3E,EAAcC,GACrB,aAAaC,KAAKH,KAAKC,EAAIyE,OAAAC,OAAAD,OAAAC,OAAA,CAAA,EAAOzE,GAAI,CAAEuC,OAAQ,QACnD,CAEA,YAAM,CAAOxC,EAAcC,GACxB,aAAaC,KAAKH,KAAKC,EAAIyE,OAAAC,OAAAD,OAAAC,OAAA,CAAA,EAAOzE,GAAI,CAAEuC,OAAQ,WACnD,SAEF3C"}
1
+ {"version":3,"file":"index.mjs","sources":["../../src/client/index.ts"],"sourcesContent":["import { HttpRequestInit, SecurequClientResponse } from \"./types\";\nimport { chunkFile, getFileId, totalChunks } from \"../include/File\";\nimport Base from \"./Base\";\nimport fileScaner from '../include/FileScaner';\n\nclass SecurequClient extends Base {\n\n async send(path: string, init?: HttpRequestInit): Promise<SecurequClientResponse> {\n await this.awaitForHandshake();\n init = await this.hooksCall('beforeRequest', path, init) || init;\n const url = await this.url(path)\n if (url.pathname === '/') throw new Error(\"Path is not allowed\")\n\n for (let key in init?.body) {\n if (init?.body[key] instanceof File) {\n init.body[key] = await this.upload(init.body[key], init?.onProgress)\n }\n }\n\n const res = await this.fetch(path, init);\n if ([\"Signeture expired\", \"Request expired\"].includes(res.message)) {\n await this.handshake();\n return await this.send(path, init);\n }\n await this.hooksCall('afterResponse', res);\n return res;\n }\n\n async upload(file: File, onProgress?: (p: number) => void): Promise<SecurequClientResponse> {\n await this.awaitForHandshake();\n const fileId = await getFileId(file);\n const chunkSize = this.config.chunkSize\n const controller = new AbortController();\n let _file = await this.hooksCall('beforeUpload', file, fileId) || file;\n const maxFileSize = this.handshakeInfo?.maxFileSize\n if (maxFileSize && _file.size > maxFileSize * 1024) {\n throw new Error(`File size exceeds the limit of ${maxFileSize / 1024} MB`)\n }\n // send metadata\n const meta = {\n filename: file.name,\n filesize: file.size,\n filetype: file.type,\n fileid: fileId,\n totalChunks: totalChunks(file, chunkSize),\n }\n\n const abort = async () => {\n await this.fetch('/', {\n method: 'PUT',\n body: { ...meta, type: 'failed' },\n })\n controller.abort();\n window.removeEventListener(\"pagehide\", abort);\n }\n window.addEventListener(\"pagehide\", abort);\n\n const metares = await this.fetch('/', {\n method: 'PUT',\n body: { ...meta, type: 'meta' }\n })\n\n\n if (!metares.success) {\n if ([\"Signeture expired\", \"Request expired\"].includes(metares.message)) {\n await this.handshake();\n return await this.upload(file, onProgress);\n }\n await abort()\n return metares\n }\n\n\n for await (let { chunk, chunkIndex } of chunkFile(_file, chunkSize)) {\n\n if (this.handshakeInfo?.checkFileType && chunkIndex === 0) {\n let fileType = fileScaner(chunk);\n if (!fileType) {\n await abort()\n return {\n success: false,\n message: \"Unknown or unsupported file type\",\n data: null,\n code: 0\n }\n }\n }\n\n await this.hooksCall('beforeUploadChunk', chunk, chunkIndex, meta.totalChunks);\n const info: any = {\n method: 'PUT',\n signal: controller.signal,\n body: { chunk, chunkIndex, fileId },\n onProgress: (p: number) => {\n if (onProgress) {\n const totalProgress = Math.floor(((chunkIndex + 1) / meta.totalChunks) * 100)\n const currentProgress = Math.floor((p / 100) / meta.totalChunks * 100)\n onProgress(Math.min(totalProgress + currentProgress, 100))\n }\n }\n }\n\n let res = await this.fetch('/', info)\n\n if (!res.success) {\n if ([\"Signeture expired\", \"Request expired\"].includes(metares.message)) {\n await this.handshake();\n res = await this.fetch('/', info)\n } else {\n await abort()\n return res\n }\n }\n await this.hooksCall('afterUploadChunk', res, chunkIndex, meta.totalChunks);\n\n if (chunkIndex + 1 === meta.totalChunks) {\n const info = {\n success: true,\n message: 'File uploaded successfully',\n data: res.data,\n code: res.code\n }\n await this.hooksCall('afterUpload', info, _file);\n return info\n }\n }\n return {\n success: false,\n message: 'File upload failed',\n data: null,\n code: 0\n }\n }\n\n async get(path: string, init?: Omit<HttpRequestInit, 'body' | 'method'>) {\n return await this.send(path, init);\n }\n\n async post(path: string, init?: Omit<HttpRequestInit, 'method'>) {\n return await this.send(path, { ...init, method: \"POST\" });\n }\n\n async put(path: string, init?: Omit<HttpRequestInit, 'method'>) {\n return await this.send(path, { ...init, method: \"PUT\" });\n }\n\n async delete(path: string, init?: Omit<HttpRequestInit, 'method'>) {\n return await this.send(path, { ...init, method: \"DELETE\" });\n }\n\n}\n\nexport default SecurequClient;\n"],"names":["SecurequClient","Base","send","path","init","this","awaitForHandshake","hooksCall","url","pathname","Error","key","body","File","upload","onProgress","res","fetch","includes","message","handshake","file","fileId","getFileId","chunkSize","config","controller","AbortController","_file","maxFileSize","_d","handshakeInfo","size","meta","filename","name","filesize","filetype","type","fileid","totalChunks","abort","async","method","window","removeEventListener","addEventListener","metares","success","_h","_f","_g","__asyncValues","chunkFile","_a","next","done","_c","value","chunk","chunkIndex","_e","checkFileType","fileScaner","data","code","info","signal","p","totalProgress","Math","floor","currentProgress","min","get","post","Object","assign","put"],"mappings":"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"}
package/index.d.ts CHANGED
@@ -2,5 +2,5 @@ export { default as SecurequServer } from './server/index.js';
2
2
  export { default as SecurequClient } from './client/index.js';
3
3
  export { default as crypto } from './include/crypto.js';
4
4
  export { default as compresor } from './include/compress.js';
5
- export { ArgsInfo, HandlerFunction, HandlerInfo, ListenerInfo, RouteFactory, SecurequServerConfig, ServerClient, ServerClientInfo, ServerClientOrigin, ServerClientSecret, ServerResponse, UploadFileMeta, UploadFilePath } from './server/types.js';
5
+ export { HandlerFunction, HandlerInfo, ListenerInfo, Metadata, RouteFactory, SecurequServerConfig, ServerClient, ServerClientInfo, ServerClientOrigin, ServerClientSecret, ServerResponse, UploadFileMeta, UploadFilePath } from './server/types.js';
6
6
  export { HTTPMethods, HandshakeInfo, HttpRequestInit, SecurequClientConfig, SecurequClientResponse } from './client/types.js';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "securequ",
3
- "version": "1.1.2",
3
+ "version": "1.1.4",
4
4
  "description": "",
5
5
  "keywords": [],
6
6
  "sideEffects": false,
package/readme.md CHANGED
@@ -1,54 +1,312 @@
1
+ <div align="center">
2
+
1
3
  # securequ
2
4
 
3
- [![npm version](https://img.shields.io/npm/v/securequ.svg)](https://www.npmjs.com/package/securequ)
4
- [![License](https://img.shields.io/npm/l/securequ.svg)](https://github.com/your-username/securequ/blob/main/LICENSE)
5
- [![Downloads](https://img.shields.io/npm/dt/securequ.svg)](https://www.npmjs.com/package/securequ)
5
+ High‑level encrypted & compressed HTTP request + chunked upload toolkit for browser ↔ server applications.
6
+
7
+ </div>
8
+
9
+ > Provides an additional application‑layer privacy/integrity envelope. Always deploy behind HTTPS.
10
+
11
+ <p align="center">
12
+ <a href="https://www.npmjs.com/package/securequ"><img src="https://img.shields.io/npm/v/securequ.svg" alt="npm version" /></a>
13
+ <a href="#"><img src="https://img.shields.io/badge/status-active-green" alt="status" /></a>
14
+ <a href="#security"><img src="https://img.shields.io/badge/focus-security-blue" alt="focus" /></a>
15
+ </p>
16
+
17
+ ## Table of Contents
18
+
19
+ - [securequ](#securequ)
20
+ - [Table of Contents](#table-of-contents)
21
+ - [Overview](#overview)
22
+ - [Why securequ?](#why-securequ)
23
+ - [Core Concepts (Abstracted)](#core-concepts-abstracted)
24
+ - [Security (Summary)](#security-summary)
25
+ - [Performance Snapshot](#performance-snapshot)
26
+ - [Install](#install)
27
+ - [Minimal Server (Express)](#minimal-server-express)
28
+ - [Minimal Client](#minimal-client)
29
+ - [Client Hooks (Selected)](#client-hooks-selected)
30
+ - [API Surface (High Level)](#api-surface-high-level)
31
+ - [Server Response Model](#server-response-model)
32
+ - [File Upload Overview](#file-upload-overview)
33
+ - [Configuration (Essentials)](#configuration-essentials)
34
+ - [Error Semantics](#error-semantics)
35
+ - [Performance Guidance](#performance-guidance)
36
+ - [Troubleshooting](#troubleshooting)
37
+ - [FAQ](#faq)
38
+ - [Versioning \& Stability](#versioning--stability)
39
+ - [Contributing](#contributing)
40
+ - [Security Reporting](#security-reporting)
41
+ - [Disclaimer](#disclaimer)
42
+ - [License](#license)
43
+
44
+ ## Overview
45
+
46
+ securequ places a compact, binary, encrypted envelope around HTTP request/response bodies and coordinates secure, chunked file uploads. A lightweight, ephemeral token (internally named `signeture`) is established via a handshake per client origin and renewed automatically when necessary. Development mode keeps the ergonomics of plain JSON while production mode obfuscates both payload bodies and (optionally) query parameters.
47
+
48
+ Key capabilities:
49
+ - Application‑layer confidentiality & integrity (in addition to transport‑layer TLS)
50
+ - Binary serialization + compression for efficient payload transfer
51
+ - Short‑lived opaque token automatically refreshed
52
+ - File uploads with controlled chunk sizing, size limits, optional first‑chunk file‑type validation, and progress events
53
+ - Minimal routing utilities and lifecycle hooks—framework agnostic
54
+ - Consistent TypeScript surface
55
+
56
+ ## Why securequ?
57
+
58
+ | Need | Plain fetch + JSON | securequ |
59
+ | --------------------------------------------- | -------------------- | ---------------------- |
60
+ | Hide request structure from casual inspection | ✗ | ✓ (encrypted envelope) |
61
+ | Automatic compression + binary serialization | Partial (manual) | ✓ built‑in |
62
+ | Short‑lived opaque request token | Custom work | ✓ baked in |
63
+ | Client lifecycle hooks | Manual wiring | ✓ hooks API |
64
+ | Validated chunked uploads + progress | Manual / library mix | ✓ integrated |
65
+
66
+ Use it when you want an extra (opaque) layer plus structured uploads without re‑inventing crypto + binary packing. If HTTPS + standard auth covers all your needs and you prefer transparency, you may not need this.
67
+
68
+ ## Core Concepts (Abstracted)
69
+
70
+ | Concept | Summary |
71
+ | ------------------ | --------------------------------------------------------------------------------------- |
72
+ | Pre‑shared secret | Static value per allowed origin (server‑side registration) |
73
+ | Handshake | Lightweight exchange producing a short‑lived opaque token (auto refreshed) |
74
+ | Encrypted envelope | Bodies (and in production, query params) serialized → compressed → encrypted |
75
+ | Development mode | Skips encryption for non‑handshake application requests to aid debugging |
76
+ | Hooks | Extensibility points for request & upload lifecycle events |
77
+ | Chunked upload | Deterministic splitting + metadata negotiation + ordered transfer + completion callback |
78
+
79
+ ## Security (Summary)
80
+
81
+ Implemented (High Level):
82
+ - Symmetric encryption with authenticated integrity (AEAD style)
83
+ - Short token lifetime, minimizing replay viability
84
+ - Payload and (production) query obfuscation
85
+ - Optional file‑type validation via first‑chunk signature scanning
6
86
 
7
- A brief description of what your package does and its purpose.
87
+ Operator Responsibilities:
88
+ - Enforce HTTPS and standard secure headers
89
+ - Generate long, random client secrets and rotate periodically
90
+ - Layer proper authentication/authorization (sessions, tokens, etc.)
91
+ - Validate and sanitize business data in handlers
8
92
 
9
- ## Installation
93
+ Out of Scope:
94
+ - Forward secrecy / per‑message key rotation
95
+ - Fine‑grained end‑user authentication
96
+ - True streaming (payloads are presently buffered)
97
+ - Built‑in rate limiting / abuse controls
10
98
 
11
- ```sh
99
+ ## Performance Snapshot
100
+
101
+ - Compression + binary encoding reduce large structured bodies vs raw JSON
102
+ - Overhead is minimal for medium/large payloads; for tiny payloads (< 200B) you may prefer plain requests
103
+ - Chunk size is adaptive (you can override) to balance memory and progress smoothness
104
+ - File type detection (if enabled) inspects only the first chunk
105
+
106
+ ## Install
107
+
108
+ ```bash
12
109
  npm install securequ
13
110
  ```
14
111
 
15
- or with yarn:
112
+ Peer/runtime deps are installed automatically (libsodium, fflate, msgpackr, path-to-regexp, xanfetch).
113
+
114
+ ## Minimal Server (Express)
115
+
116
+ ```ts
117
+ import express from 'express';
118
+ import { SecurequServer } from 'securequ';
119
+
120
+ const api = new SecurequServer({
121
+ mode: 'production',
122
+ basepath: '/api',
123
+ clients: [{ origin: 'https://app.example.com' | "*", secret: process.env.APP_CLIENT_SECRET! }],
124
+ upload: {
125
+ chunk: async (chunk, meta) => { /* store chunk */ return true; },
126
+ complete: async (meta) => { /* stitch & persist */ return `/files/${meta.fileid}`; },
127
+ failed: async (meta) => boolean
128
+ }
129
+ });
130
+
131
+ api.post('/echo', ({ body }) => { throw { ok: true, body }; });
132
+
133
+ const app = express();
134
+ app.use('/api/*', express.raw({ type: 'application/octet-stream', limit: '20mb' }), async (req, res) => {
135
+ const r = await api.listen(req.originalUrl, {
136
+ body: req.body,
137
+ headers: req.headers,
138
+ }, req);
139
+ res.status(r.status).end(r.content);
140
+ });
141
+ app.listen(4000);
142
+ ```
143
+
144
+ ## Minimal Client
145
+
146
+ ```ts
147
+ import { SecurequClient } from 'securequ';
148
+
149
+ const client = new SecurequClient({
150
+ url: 'https://api.example.com/api',
151
+ secret: '<client-secret>'
152
+ });
153
+
154
+ // Simple request
155
+ const res = await client.post('echo', { body: { hello: 'world' } });
156
+ console.log(res);
157
+
158
+ // File upload with progress
159
+ async function uploadFile(file: File) {
160
+ const result = await client.upload(file, p => console.log('progress %', p));
161
+ console.log(result);
162
+ }
163
+ ```
164
+
165
+ ## Client Hooks (Selected)
166
+
167
+ ```ts
168
+ hooks: {
169
+ beforeRequest: (path, init) => init,
170
+ afterResponse: (resp) => {},
171
+ beforeUpload: (file, fileId) => file,
172
+ afterUpload: (response, file) => {},
173
+ beforeUploadChunk: (chunk, idx, total) => {},
174
+ afterUploadChunk: (resp, idx, total) => {},
175
+ }
176
+ ```
177
+
178
+ ## API Surface (High Level)
16
179
 
17
- ```sh
18
- yarn add securequ
180
+ ```ts
181
+ // Client
182
+ client.get(path, init?)
183
+ client.post(path, init?)
184
+ client.put(path, init?)
185
+ client.delete(path, init?)
186
+ client.upload(file, onProgress?)
187
+
188
+ // Server
189
+ server.get(path, handler)
190
+ server.post(path, handler)
191
+ server.put(path, handler)
192
+ server.delete(path, handler)
193
+ server.listen(url, listenerInfo)
194
+
195
+ // Utilities (optional direct use)
196
+ import { crypto, compresor } from 'securequ';
19
197
  ```
20
198
 
21
- ## Usage
199
+ ### Server Response Model
200
+
201
+ Handlers conclude by `throw`ing:
202
+ - Plain object / primitive → serialized (dev) or encrypted (prod) with 200 status
203
+ - `Response` instance → its status/body is used (still wrapped if necessary)
204
+ - `Error` → message returned with a not‑found style status (configurable via customization if you wrap upstream)
205
+
206
+ This pattern deliberately short‑circuits route evaluation and keeps handler code linear.
22
207
 
23
- ```js
24
- import { feature } from "securequ";
208
+ ## File Upload Overview
25
209
 
26
- const result = feature("example");
27
- console.log(result);
210
+ - Client sends metadata first
211
+ - Server accepts and tracks state
212
+ - Client streams fixed‑size chunks sequentially
213
+ - Final chunk triggers assembly + returned path / identifier
214
+ - A failure notification allows cleanup
215
+
216
+ ## Configuration (Essentials)
217
+
218
+ ```ts
219
+ // Server
220
+ new SecurequServer({
221
+ mode: 'production' | 'development',
222
+ basepath: '/api',
223
+ clients: [{ origin, secret }],
224
+ upload?: { maxFilesize?, checkFileType?, chunk(), complete(), failed? },
225
+ accept?: (info: HandlerInfo, metadata?: Metadata) => boolean | Promise<boolean>
226
+ });
227
+
228
+ // Client
229
+ new SecurequClient({
230
+ url: 'https://host/api',
231
+ secret: '<pre-shared>',
232
+ chunkSize?: number,
233
+ hooks?: { ... }
234
+ });
28
235
  ```
29
236
 
30
- ## API
237
+ ## Error Semantics
238
+
239
+ - Success: `success: true`, `data` contains decrypted payload
240
+ - Expired token is auto‑recovered (one retry) by re-handshaking
241
+ - Server thrown `Error` surfaces message (wrapped) to client
242
+
243
+ ## Performance Guidance
244
+
245
+ - Use production mode for real benchmarking (encryption path active)
246
+ - Keep secrets long & random (>= 32 chars)
247
+ - Tune `chunkSize` only if you need very granular progress events
248
+
249
+ ## Troubleshooting
250
+
251
+ | Symptom | Possible Cause | Suggested Fix |
252
+ | -------------------------------- | ------------------------------------ | ----------------------------------------------------------------- |
253
+ | `Signeture expired` loops | Clock skew or token window too short | Ensure system clocks are synced; minimize artificial delays |
254
+ | Always 404 / Not found | Route not registered before `listen` | Register handlers before attaching middleware |
255
+ | Plain text visible in production | App running in development mode | Set `mode: 'production'` in server config |
256
+ | Upload stops mid‑way | Page navigation / tab close | Use `beforeunload` UI warning or resume strategy (future roadmap) |
257
+ | File type rejected | Magic bytes not recognized | Disable `checkFileType` or extend scanner if needed |
258
+ | High CPU for tiny payloads | Compression/encryption overhead | Bypass securequ for very small trivial requests |
31
259
 
32
- ### `feature(input: string): string`
33
- Description of the function and its parameters.
260
+ If an issue isn’t listed: enable development mode locally to inspect raw (unencrypted) bodies for debugging, then switch back.
34
261
 
35
- ## Configuration (if applicable)
36
- Explain any configuration options if your package requires setup.
262
+ ## FAQ
37
263
 
38
- ## Examples
39
- Provide additional usage examples for clarity.
264
+ **Does this replace TLS?**
265
+ No. It layers *on top* of TLS.
266
+
267
+ **Can I plug into another HTTP framework?**
268
+ Yes—adapt the raw body + headers and call `server.listen()`.
269
+
270
+ **How do I add auth?**
271
+ Put your auth tokens/data *inside* the encrypted body or add middleware before calling `listen`.
272
+
273
+ **TypeScript support?**
274
+ Fully typed. Route handlers get a typed `info` object; client responses are typed with a generic shape (`SecurequClientResponse`).
275
+
276
+ **Can I inspect payloads in production?**
277
+ Not without decrypting. Use development mode locally when introspection is needed.
278
+
279
+ **Is there resume upload support?**
280
+ Not yet; planned. You can implement partial detection using hooks + server state.
281
+
282
+ **How big can files be?**
283
+ Limited by your configured `maxFilesize` (KB) and infrastructure memory / timeout constraints.
284
+
285
+ ## Versioning & Stability
286
+
287
+ The project follows semantic versioning principles as features mature. Prior to a formal `1.x` stability declaration, minor releases may introduce carefully documented adjustments. Pin exact versions in sensitive production environments.
40
288
 
41
289
  ## Contributing
42
- Contributions are welcome! Please follow the guidelines in [CONTRIBUTING.md](./CONTRIBUTING.md).
43
290
 
44
- ## License
291
+ 1. Fork & create a feature branch
292
+ 2. Add or adjust tests where behavior changes
293
+ 3. Ensure TypeScript builds without errors
294
+ 4. Open a PR with a concise rationale
295
+
296
+ Please avoid including sensitive implementation details in public issue titles (describe at a high level instead).
297
+
298
+ ## Security Reporting
299
+
300
+ If you believe you have discovered a vulnerability, please refrain from opening a public issue. Instead contact the maintainer privately (add a SECURITY.md for formal process if publishing broadly). Provide a minimal, reproducible scenario.
45
301
 
46
- This project is licensed under the MIT License - see the [LICENSE](./LICENSE) file for details.
302
+ ## Disclaimer
303
+
304
+ securequ provides an additional obfuscation + encryption layer. It is not a substitute for robust authentication, authorization, or transport security practices. Combine with TLS, secret rotation, and standard security controls.
305
+
306
+ ## License
47
307
 
48
- ## Links
49
- - [GitHub Repository](https://github.com/your-username/securequ)
50
- - [NPM Package](https://www.npmjs.com/package/securequ)
308
+ No license file included. Add one (e.g., MIT) before publishing publicly.
51
309
 
52
310
  ---
311
+ Issues & contributions welcome.
53
312
 
54
- Feel free to modify this template based on your package's specific needs.
package/server/Base.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import Router from './Router.js';
2
- import { SecurequServerConfig, UploadFileMeta, HandlerInfo, ArgsInfo } from './types.js';
2
+ import { SecurequServerConfig, UploadFileMeta, HandlerInfo, Metadata } from './types.js';
3
3
 
4
4
  declare class SecurequServerBase extends Router {
5
5
  protected config: SecurequServerConfig;
@@ -8,6 +8,7 @@ declare class SecurequServerBase extends Router {
8
8
  protected uploadMeta: Map<string, UploadFileMeta & {
9
9
  expire: number;
10
10
  }>;
11
+ readonly CONTENT_TYPE = "application/octet-stream";
11
12
  constructor(config: SecurequServerConfig);
12
13
  protected getSecret(): Promise<string>;
13
14
  protected clientInfo(path: string, origin: string): Promise<{
@@ -17,9 +18,9 @@ declare class SecurequServerBase extends Router {
17
18
  searchParams: {
18
19
  [key: string]: any;
19
20
  };
20
- }>;
21
+ } | null>;
21
22
  protected isValidSigneture(signeture: string | undefined, hash: string): Promise<void>;
22
- handleRequest(info: HandlerInfo, args?: ArgsInfo): Promise<void>;
23
+ handleRequest(info: HandlerInfo, metadata?: Metadata): Promise<void>;
23
24
  }
24
25
 
25
26
  export { SecurequServerBase as default };
package/server/Base.js CHANGED
@@ -1 +1 @@
1
- "use strict";Object.defineProperty(exports,"__esModule",{value:!0});var e=require("../include/crypto.js"),t=require("./Router.js");class s extends t.default{constructor(e){if(super(),this.secret=null,this.clients=new Map,this.uploadMeta=new Map,!e.basepath)throw new Error("Basepath is required");if(!e.clients||0===Object.keys(e.clients).length)throw new Error("Atleast one client is required");e.basepath.startsWith("/")||(e.basepath=`/${e.basepath}`),e.basepath.endsWith("/")&&(e.basepath=e.basepath.substring(0,e.basepath.length-1)),e.upload&&(e.upload.maxFilesize=e.upload.maxFilesize||51200,e.upload.checkFileType=e.upload.checkFileType||!0),this.config=e;for(let e of this.config.clients)this.clients.set(e.origin,e.secret)}async getSecret(){return this.secret||(this.secret=await e.default.hash(Math.random().toString(36).substring(2,15)+Math.random().toString(36).substring(2,15))),this.secret}async clientInfo(t,s){const a="/"!==t&&"development"===this.config.mode;let i=t.split("?");const n=(t=(t=(t=(t=i[0]).replace(this.config.basepath+"/","")).endsWith("/")?t.substring(0,t.length-1):t).startsWith("/")?t.substring(1):t).split("/"),r=n.shift();if(!(null==r?void 0:r.length)||!this.clients.has(s))throw new Response("Client not allowed",{status:403});let o=this.clients.get(s).substring(0,r.length),h={};return i.length>1&&(h=a?Object.fromEntries(new URLSearchParams(decodeURIComponent(i[1]))):await e.default.decrypt(decodeURIComponent(i[1]),o)),{path:"/"+n.join("/"),secret:o,hash:r,searchParams:h}}async isValidSigneture(t,s){const a=await this.getSecret();if(this.secret&&t){let i=await e.default.decrypt(t,a),n=i.hash===s,r=i.expire>Date.now();if(!n)throw new Response("Invalid Signeture",{status:403});if(!r)throw new Response("Signeture expired",{status:403})}}async handleRequest(e,t){if(this.config.accept){if(!await this.config.accept(e,t))throw new Response("Request not accepted",{status:403})}const{path:s,method:a}=e;let i=Object.values(this.routes[a]);for(let{test:a,handler:n}of i){const i=a(s);i&&await n(Object.assign(Object.assign({},e),{params:i.params}),t)}}}exports.default=s;//# sourceMappingURL=Base.js.map
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:!0});var e=require("../include/crypto.js"),t=require("./Router.js");class s extends t.default{constructor(e){if(super(),this.secret=null,this.clients=new Map,this.uploadMeta=new Map,this.CONTENT_TYPE="application/octet-stream",!e.basepath)throw new Error("Basepath is required");if(!e.clients||0===Object.keys(e.clients).length)throw new Error("Atleast one client is required");e.basepath.startsWith("/")||(e.basepath=`/${e.basepath}`),e.basepath.endsWith("/")&&(e.basepath=e.basepath.substring(0,e.basepath.length-1)),e.upload&&(e.upload.maxFilesize=e.upload.maxFilesize||51200,e.upload.checkFileType=e.upload.checkFileType||!0),e.mode=["production","development"].includes(e.mode||"")?e.mode:"production",this.config=e;for(let e of this.config.clients)this.clients.set(e.origin,e.secret)}async getSecret(){return this.secret||(this.secret=await e.default.hash(Math.random().toString(36).substring(2,15)+Math.random().toString(36).substring(2,15))),this.secret}async clientInfo(t,s){const i="/"!==t&&"development"===this.config.mode;let a=t.split("?");const n=(t=(t=(t=(t=a[0]).replace(this.config.basepath+"/","")).endsWith("/")?t.substring(0,t.length-1):t).startsWith("/")?t.substring(1):t).split("/"),r=n.shift();let o=this.clients.get(s);if(o||(o=this.clients.get("*")),!(null==r?void 0:r.length)||!o)return null;let c=o.substring(0,r.length),h={};return a.length>1&&(h=i?Object.fromEntries(new URLSearchParams(decodeURIComponent(a[1]))):await e.default.decrypt(decodeURIComponent(a[1]),c)),{path:"/"+n.join("/"),secret:c,hash:r,searchParams:h}}async isValidSigneture(t,s){const i=await this.getSecret();if(this.secret&&t){let a=await e.default.decrypt(t,i),n=a.hash===s,r=a.expire>Date.now();if(!n)throw new Response("Invalid Signeture",{status:403});if(!r)throw new Response("Signeture expired",{status:403})}}async handleRequest(e,t){if(this.config.accept){if(!await this.config.accept(e,t))throw new Response("Request not accepted",{status:403})}const{path:s,method:i}=e;let a=Object.values(this.routes[i]);for(let{test:i,handler:n}of a){const a=i(s);a&&await n(Object.assign(Object.assign({},e),{params:a.params}),t)}}}exports.default=s;//# sourceMappingURL=Base.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"Base.js","sources":["../../src/server/Base.ts"],"sourcesContent":["import crypto from \"../include/crypto\";\nimport Router from \"./Router\";\nimport { HandlerInfo, SecurequServerConfig, ServerClientSecret, ServerClientOrigin, UploadFileMeta, ArgsInfo } from \"./types\";\n\nclass SecurequServerBase extends Router {\n protected config: SecurequServerConfig;\n protected secret: string | null = null\n protected clients = new Map<ServerClientOrigin, ServerClientSecret>();\n protected uploadMeta = new Map<string, UploadFileMeta & { expire: number }>();\n\n constructor(config: SecurequServerConfig) {\n super()\n if (!config.basepath) throw new Error(\"Basepath is required\");\n if (!config.clients || Object.keys(config.clients).length === 0) throw new Error(\"Atleast one client is required\");\n if (!config.basepath.startsWith(\"/\")) config.basepath = `/${config.basepath}`;\n if (config.basepath.endsWith(\"/\")) config.basepath = config.basepath.substring(0, config.basepath.length - 1);\n if (config.upload) {\n config.upload.maxFilesize = config.upload.maxFilesize || 50 * 1024 // 50MB default\n config.upload.checkFileType = config.upload.checkFileType || true\n }\n this.config = config\n for (let client of this.config.clients) {\n this.clients.set(client.origin, client.secret)\n }\n }\n\n protected async getSecret() {\n if (!this.secret) {\n this.secret = await crypto.hash(Math.random().toString(36).substring(2, 15) + Math.random().toString(36).substring(2, 15))\n }\n return this.secret\n }\n\n protected async clientInfo(path: string, origin: string) {\n const isDev = path !== '/' && this.config.mode === 'development'\n let splitUrl = path.split(\"?\")\n path = splitUrl[0]\n path = path.replace(this.config.basepath + \"/\", \"\")\n path = path.endsWith('/') ? path.substring(0, path.length - 1) : path\n path = path.startsWith('/') ? path.substring(1) : path\n\n const split = path.split(\"/\")\n const hash = split.shift()\n if (!hash?.length || !this.clients.has(origin)) throw new Response(\"Client not allowed\", { status: 403 });\n let client = this.clients.get(origin as string) as string;\n let secret = client.substring(0, hash.length as number);\n let searchParams: { [key: string]: any } = {}\n if (splitUrl.length > 1) {\n if (isDev) {\n searchParams = Object.fromEntries(new URLSearchParams(decodeURIComponent(splitUrl[1])))\n } else {\n searchParams = await crypto.decrypt(decodeURIComponent(splitUrl[1]), secret) as any\n }\n }\n return {\n path: \"/\" + split.join('/'),\n secret,\n hash,\n searchParams\n }\n }\n\n protected async isValidSigneture(signeture: string | undefined, hash: string) {\n const serverSecret = await this.getSecret()\n if (this.secret && signeture) {\n let info: any = await crypto.decrypt(signeture, serverSecret)\n let isHashValid = info.hash === hash\n let isNotExpired = info.expire > Date.now()\n if (!isHashValid) throw new Response(\"Invalid Signeture\", { status: 403 });\n if (!isNotExpired) throw new Response(\"Signeture expired\", { status: 403 });\n }\n }\n\n async handleRequest(info: HandlerInfo, args?: ArgsInfo) {\n if (this.config.accept) {\n const is = await this.config.accept(info, args)\n if (!is) throw new Response(\"Request not accepted\", { status: 403 })\n }\n\n const { path, method } = info;\n let values: any = Object.values(this.routes[method]);\n for (let { test, handler } of values) {\n const match = test(path)\n if (match) {\n await handler({ ...info, params: match.params }, args)\n }\n }\n }\n\n}\n\nexport default SecurequServerBase;"],"names":["SecurequServerBase","Router","constructor","config","super","this","secret","clients","Map","uploadMeta","basepath","Error","Object","keys","length","startsWith","endsWith","substring","upload","maxFilesize","checkFileType","client","set","origin","getSecret","crypto","hash","Math","random","toString","clientInfo","path","isDev","mode","splitUrl","split","replace","shift","has","Response","status","get","searchParams","fromEntries","URLSearchParams","decodeURIComponent","decrypt","join","isValidSigneture","signeture","serverSecret","info","isHashValid","isNotExpired","expire","Date","now","handleRequest","args","accept","method","values","routes","test","handler","match","assign","params","exports","default"],"mappings":"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"}
1
+ {"version":3,"file":"Base.js","sources":["../../src/server/Base.ts"],"sourcesContent":["import crypto from \"../include/crypto\";\nimport Router from \"./Router\";\nimport { HandlerInfo, SecurequServerConfig, ServerClientSecret, ServerClientOrigin, UploadFileMeta, Metadata } from \"./types\";\n\nclass SecurequServerBase extends Router {\n protected config: SecurequServerConfig;\n protected secret: string | null = null\n protected clients = new Map<ServerClientOrigin, ServerClientSecret>();\n protected uploadMeta = new Map<string, UploadFileMeta & { expire: number }>();\n readonly CONTENT_TYPE = \"application/octet-stream\";\n\n constructor(config: SecurequServerConfig) {\n super()\n if (!config.basepath) throw new Error(\"Basepath is required\");\n if (!config.clients || Object.keys(config.clients).length === 0) throw new Error(\"Atleast one client is required\");\n if (!config.basepath.startsWith(\"/\")) config.basepath = `/${config.basepath}`;\n if (config.basepath.endsWith(\"/\")) config.basepath = config.basepath.substring(0, config.basepath.length - 1);\n if (config.upload) {\n config.upload.maxFilesize = config.upload.maxFilesize || 50 * 1024 // 50MB default\n config.upload.checkFileType = config.upload.checkFileType || true\n }\n config.mode = [\"production\", 'development'].includes(config.mode || \"\") ? config.mode : \"production\"\n this.config = config\n for (let client of this.config.clients) {\n this.clients.set(client.origin, client.secret)\n }\n }\n\n protected async getSecret() {\n if (!this.secret) {\n this.secret = await crypto.hash(Math.random().toString(36).substring(2, 15) + Math.random().toString(36).substring(2, 15))\n }\n return this.secret\n }\n\n protected async clientInfo(path: string, origin: string) {\n const isDev = path !== '/' && this.config.mode === 'development'\n let splitUrl = path.split(\"?\")\n path = splitUrl[0]\n path = path.replace(this.config.basepath + \"/\", \"\")\n path = path.endsWith('/') ? path.substring(0, path.length - 1) : path\n path = path.startsWith('/') ? path.substring(1) : path\n\n const split = path.split(\"/\")\n const hash = split.shift()\n let client = this.clients.get(origin)\n if (!client) {\n client = this.clients.get(\"*\")\n }\n\n if (!hash?.length || !client) return null\n let secret = client.substring(0, hash.length as number);\n let searchParams: { [key: string]: any } = {}\n if (splitUrl.length > 1) {\n if (isDev) {\n searchParams = Object.fromEntries(new URLSearchParams(decodeURIComponent(splitUrl[1])))\n } else {\n searchParams = await crypto.decrypt(decodeURIComponent(splitUrl[1]), secret) as any\n }\n }\n return {\n path: \"/\" + split.join('/'),\n secret,\n hash,\n searchParams\n }\n }\n\n protected async isValidSigneture(signeture: string | undefined, hash: string) {\n const serverSecret = await this.getSecret()\n if (this.secret && signeture) {\n let info: any = await crypto.decrypt(signeture, serverSecret)\n let isHashValid = info.hash === hash\n let isNotExpired = info.expire > Date.now()\n if (!isHashValid) throw new Response(\"Invalid Signeture\", { status: 403 });\n if (!isNotExpired) throw new Response(\"Signeture expired\", { status: 403 });\n }\n }\n\n async handleRequest(info: HandlerInfo, metadata?: Metadata) {\n if (this.config.accept) {\n const is = await this.config.accept(info, metadata)\n if (!is) throw new Response(\"Request not accepted\", { status: 403 })\n }\n\n const { path, method } = info;\n let values: any = Object.values(this.routes[method]);\n for (let { test, handler } of values) {\n const match = test(path)\n if (match) {\n await handler({ ...info, params: match.params }, metadata)\n }\n }\n }\n\n}\n\nexport default SecurequServerBase;"],"names":["SecurequServerBase","Router","constructor","config","super","this","secret","clients","Map","uploadMeta","CONTENT_TYPE","basepath","Error","Object","keys","length","startsWith","endsWith","substring","upload","maxFilesize","checkFileType","mode","includes","client","set","origin","getSecret","crypto","hash","Math","random","toString","clientInfo","path","isDev","splitUrl","split","replace","shift","get","searchParams","fromEntries","URLSearchParams","decodeURIComponent","decrypt","join","isValidSigneture","signeture","serverSecret","info","isHashValid","isNotExpired","expire","Date","now","Response","status","handleRequest","metadata","accept","method","values","routes","test","handler","match","assign","params","exports","default"],"mappings":"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"}
package/server/Base.mjs CHANGED
@@ -1 +1 @@
1
- import t from"../include/crypto.mjs";import e from"./Router.mjs";class s extends e{constructor(t){if(super(),this.secret=null,this.clients=new Map,this.uploadMeta=new Map,!t.basepath)throw new Error("Basepath is required");if(!t.clients||0===Object.keys(t.clients).length)throw new Error("Atleast one client is required");t.basepath.startsWith("/")||(t.basepath=`/${t.basepath}`),t.basepath.endsWith("/")&&(t.basepath=t.basepath.substring(0,t.basepath.length-1)),t.upload&&(t.upload.maxFilesize=t.upload.maxFilesize||51200,t.upload.checkFileType=t.upload.checkFileType||!0),this.config=t;for(let t of this.config.clients)this.clients.set(t.origin,t.secret)}async getSecret(){return this.secret||(this.secret=await t.hash(Math.random().toString(36).substring(2,15)+Math.random().toString(36).substring(2,15))),this.secret}async clientInfo(e,s){const i="/"!==e&&"development"===this.config.mode;let a=e.split("?");const n=(e=(e=(e=(e=a[0]).replace(this.config.basepath+"/","")).endsWith("/")?e.substring(0,e.length-1):e).startsWith("/")?e.substring(1):e).split("/"),r=n.shift();if(!(null==r?void 0:r.length)||!this.clients.has(s))throw new Response("Client not allowed",{status:403});let o=this.clients.get(s).substring(0,r.length),h={};return a.length>1&&(h=i?Object.fromEntries(new URLSearchParams(decodeURIComponent(a[1]))):await t.decrypt(decodeURIComponent(a[1]),o)),{path:"/"+n.join("/"),secret:o,hash:r,searchParams:h}}async isValidSigneture(e,s){const i=await this.getSecret();if(this.secret&&e){let a=await t.decrypt(e,i),n=a.hash===s,r=a.expire>Date.now();if(!n)throw new Response("Invalid Signeture",{status:403});if(!r)throw new Response("Signeture expired",{status:403})}}async handleRequest(t,e){if(this.config.accept){if(!await this.config.accept(t,e))throw new Response("Request not accepted",{status:403})}const{path:s,method:i}=t;let a=Object.values(this.routes[i]);for(let{test:i,handler:n}of a){const a=i(s);a&&await n(Object.assign(Object.assign({},t),{params:a.params}),e)}}}export{s as default};//# sourceMappingURL=Base.mjs.map
1
+ import t from"../include/crypto.mjs";import e from"./Router.mjs";class s extends e{constructor(t){if(super(),this.secret=null,this.clients=new Map,this.uploadMeta=new Map,this.CONTENT_TYPE="application/octet-stream",!t.basepath)throw new Error("Basepath is required");if(!t.clients||0===Object.keys(t.clients).length)throw new Error("Atleast one client is required");t.basepath.startsWith("/")||(t.basepath=`/${t.basepath}`),t.basepath.endsWith("/")&&(t.basepath=t.basepath.substring(0,t.basepath.length-1)),t.upload&&(t.upload.maxFilesize=t.upload.maxFilesize||51200,t.upload.checkFileType=t.upload.checkFileType||!0),t.mode=["production","development"].includes(t.mode||"")?t.mode:"production",this.config=t;for(let t of this.config.clients)this.clients.set(t.origin,t.secret)}async getSecret(){return this.secret||(this.secret=await t.hash(Math.random().toString(36).substring(2,15)+Math.random().toString(36).substring(2,15))),this.secret}async clientInfo(e,s){const i="/"!==e&&"development"===this.config.mode;let a=e.split("?");const n=(e=(e=(e=(e=a[0]).replace(this.config.basepath+"/","")).endsWith("/")?e.substring(0,e.length-1):e).startsWith("/")?e.substring(1):e).split("/"),r=n.shift();let o=this.clients.get(s);if(o||(o=this.clients.get("*")),!(null==r?void 0:r.length)||!o)return null;let c=o.substring(0,r.length),h={};return a.length>1&&(h=i?Object.fromEntries(new URLSearchParams(decodeURIComponent(a[1]))):await t.decrypt(decodeURIComponent(a[1]),c)),{path:"/"+n.join("/"),secret:c,hash:r,searchParams:h}}async isValidSigneture(e,s){const i=await this.getSecret();if(this.secret&&e){let a=await t.decrypt(e,i),n=a.hash===s,r=a.expire>Date.now();if(!n)throw new Response("Invalid Signeture",{status:403});if(!r)throw new Response("Signeture expired",{status:403})}}async handleRequest(t,e){if(this.config.accept){if(!await this.config.accept(t,e))throw new Response("Request not accepted",{status:403})}const{path:s,method:i}=t;let a=Object.values(this.routes[i]);for(let{test:i,handler:n}of a){const a=i(s);a&&await n(Object.assign(Object.assign({},t),{params:a.params}),e)}}}export{s as default};//# sourceMappingURL=Base.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"Base.mjs","sources":["../../src/server/Base.ts"],"sourcesContent":["import crypto from \"../include/crypto\";\nimport Router from \"./Router\";\nimport { HandlerInfo, SecurequServerConfig, ServerClientSecret, ServerClientOrigin, UploadFileMeta, ArgsInfo } from \"./types\";\n\nclass SecurequServerBase extends Router {\n protected config: SecurequServerConfig;\n protected secret: string | null = null\n protected clients = new Map<ServerClientOrigin, ServerClientSecret>();\n protected uploadMeta = new Map<string, UploadFileMeta & { expire: number }>();\n\n constructor(config: SecurequServerConfig) {\n super()\n if (!config.basepath) throw new Error(\"Basepath is required\");\n if (!config.clients || Object.keys(config.clients).length === 0) throw new Error(\"Atleast one client is required\");\n if (!config.basepath.startsWith(\"/\")) config.basepath = `/${config.basepath}`;\n if (config.basepath.endsWith(\"/\")) config.basepath = config.basepath.substring(0, config.basepath.length - 1);\n if (config.upload) {\n config.upload.maxFilesize = config.upload.maxFilesize || 50 * 1024 // 50MB default\n config.upload.checkFileType = config.upload.checkFileType || true\n }\n this.config = config\n for (let client of this.config.clients) {\n this.clients.set(client.origin, client.secret)\n }\n }\n\n protected async getSecret() {\n if (!this.secret) {\n this.secret = await crypto.hash(Math.random().toString(36).substring(2, 15) + Math.random().toString(36).substring(2, 15))\n }\n return this.secret\n }\n\n protected async clientInfo(path: string, origin: string) {\n const isDev = path !== '/' && this.config.mode === 'development'\n let splitUrl = path.split(\"?\")\n path = splitUrl[0]\n path = path.replace(this.config.basepath + \"/\", \"\")\n path = path.endsWith('/') ? path.substring(0, path.length - 1) : path\n path = path.startsWith('/') ? path.substring(1) : path\n\n const split = path.split(\"/\")\n const hash = split.shift()\n if (!hash?.length || !this.clients.has(origin)) throw new Response(\"Client not allowed\", { status: 403 });\n let client = this.clients.get(origin as string) as string;\n let secret = client.substring(0, hash.length as number);\n let searchParams: { [key: string]: any } = {}\n if (splitUrl.length > 1) {\n if (isDev) {\n searchParams = Object.fromEntries(new URLSearchParams(decodeURIComponent(splitUrl[1])))\n } else {\n searchParams = await crypto.decrypt(decodeURIComponent(splitUrl[1]), secret) as any\n }\n }\n return {\n path: \"/\" + split.join('/'),\n secret,\n hash,\n searchParams\n }\n }\n\n protected async isValidSigneture(signeture: string | undefined, hash: string) {\n const serverSecret = await this.getSecret()\n if (this.secret && signeture) {\n let info: any = await crypto.decrypt(signeture, serverSecret)\n let isHashValid = info.hash === hash\n let isNotExpired = info.expire > Date.now()\n if (!isHashValid) throw new Response(\"Invalid Signeture\", { status: 403 });\n if (!isNotExpired) throw new Response(\"Signeture expired\", { status: 403 });\n }\n }\n\n async handleRequest(info: HandlerInfo, args?: ArgsInfo) {\n if (this.config.accept) {\n const is = await this.config.accept(info, args)\n if (!is) throw new Response(\"Request not accepted\", { status: 403 })\n }\n\n const { path, method } = info;\n let values: any = Object.values(this.routes[method]);\n for (let { test, handler } of values) {\n const match = test(path)\n if (match) {\n await handler({ ...info, params: match.params }, args)\n }\n }\n }\n\n}\n\nexport default SecurequServerBase;"],"names":["SecurequServerBase","Router","constructor","config","super","this","secret","clients","Map","uploadMeta","basepath","Error","Object","keys","length","startsWith","endsWith","substring","upload","maxFilesize","checkFileType","client","set","origin","getSecret","crypto","hash","Math","random","toString","clientInfo","path","isDev","mode","splitUrl","split","replace","shift","has","Response","status","get","searchParams","fromEntries","URLSearchParams","decodeURIComponent","decrypt","join","isValidSigneture","signeture","serverSecret","info","isHashValid","isNotExpired","expire","Date","now","handleRequest","args","accept","method","values","routes","test","handler","match","assign","params"],"mappings":"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"}
1
+ {"version":3,"file":"Base.mjs","sources":["../../src/server/Base.ts"],"sourcesContent":["import crypto from \"../include/crypto\";\nimport Router from \"./Router\";\nimport { HandlerInfo, SecurequServerConfig, ServerClientSecret, ServerClientOrigin, UploadFileMeta, Metadata } from \"./types\";\n\nclass SecurequServerBase extends Router {\n protected config: SecurequServerConfig;\n protected secret: string | null = null\n protected clients = new Map<ServerClientOrigin, ServerClientSecret>();\n protected uploadMeta = new Map<string, UploadFileMeta & { expire: number }>();\n readonly CONTENT_TYPE = \"application/octet-stream\";\n\n constructor(config: SecurequServerConfig) {\n super()\n if (!config.basepath) throw new Error(\"Basepath is required\");\n if (!config.clients || Object.keys(config.clients).length === 0) throw new Error(\"Atleast one client is required\");\n if (!config.basepath.startsWith(\"/\")) config.basepath = `/${config.basepath}`;\n if (config.basepath.endsWith(\"/\")) config.basepath = config.basepath.substring(0, config.basepath.length - 1);\n if (config.upload) {\n config.upload.maxFilesize = config.upload.maxFilesize || 50 * 1024 // 50MB default\n config.upload.checkFileType = config.upload.checkFileType || true\n }\n config.mode = [\"production\", 'development'].includes(config.mode || \"\") ? config.mode : \"production\"\n this.config = config\n for (let client of this.config.clients) {\n this.clients.set(client.origin, client.secret)\n }\n }\n\n protected async getSecret() {\n if (!this.secret) {\n this.secret = await crypto.hash(Math.random().toString(36).substring(2, 15) + Math.random().toString(36).substring(2, 15))\n }\n return this.secret\n }\n\n protected async clientInfo(path: string, origin: string) {\n const isDev = path !== '/' && this.config.mode === 'development'\n let splitUrl = path.split(\"?\")\n path = splitUrl[0]\n path = path.replace(this.config.basepath + \"/\", \"\")\n path = path.endsWith('/') ? path.substring(0, path.length - 1) : path\n path = path.startsWith('/') ? path.substring(1) : path\n\n const split = path.split(\"/\")\n const hash = split.shift()\n let client = this.clients.get(origin)\n if (!client) {\n client = this.clients.get(\"*\")\n }\n\n if (!hash?.length || !client) return null\n let secret = client.substring(0, hash.length as number);\n let searchParams: { [key: string]: any } = {}\n if (splitUrl.length > 1) {\n if (isDev) {\n searchParams = Object.fromEntries(new URLSearchParams(decodeURIComponent(splitUrl[1])))\n } else {\n searchParams = await crypto.decrypt(decodeURIComponent(splitUrl[1]), secret) as any\n }\n }\n return {\n path: \"/\" + split.join('/'),\n secret,\n hash,\n searchParams\n }\n }\n\n protected async isValidSigneture(signeture: string | undefined, hash: string) {\n const serverSecret = await this.getSecret()\n if (this.secret && signeture) {\n let info: any = await crypto.decrypt(signeture, serverSecret)\n let isHashValid = info.hash === hash\n let isNotExpired = info.expire > Date.now()\n if (!isHashValid) throw new Response(\"Invalid Signeture\", { status: 403 });\n if (!isNotExpired) throw new Response(\"Signeture expired\", { status: 403 });\n }\n }\n\n async handleRequest(info: HandlerInfo, metadata?: Metadata) {\n if (this.config.accept) {\n const is = await this.config.accept(info, metadata)\n if (!is) throw new Response(\"Request not accepted\", { status: 403 })\n }\n\n const { path, method } = info;\n let values: any = Object.values(this.routes[method]);\n for (let { test, handler } of values) {\n const match = test(path)\n if (match) {\n await handler({ ...info, params: match.params }, metadata)\n }\n }\n }\n\n}\n\nexport default SecurequServerBase;"],"names":["SecurequServerBase","Router","constructor","config","super","this","secret","clients","Map","uploadMeta","CONTENT_TYPE","basepath","Error","Object","keys","length","startsWith","endsWith","substring","upload","maxFilesize","checkFileType","mode","includes","client","set","origin","getSecret","crypto","hash","Math","random","toString","clientInfo","path","isDev","splitUrl","split","replace","shift","get","searchParams","fromEntries","URLSearchParams","decodeURIComponent","decrypt","join","isValidSigneture","signeture","serverSecret","info","isHashValid","isNotExpired","expire","Date","now","Response","status","handleRequest","metadata","accept","method","values","routes","test","handler","match","assign","params"],"mappings":"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"}
package/server/index.d.ts CHANGED
@@ -1,10 +1,10 @@
1
- import { ArgsInfo, ListenerInfo, ServerResponse } from './types.js';
1
+ import { Metadata, ListenerInfo, ServerResponse } from './types.js';
2
2
  import SecurequServerBase from './Base.js';
3
3
 
4
4
  declare class SecurequServer extends SecurequServerBase {
5
5
  handshake(body: any, clientInfo: any): Promise<void>;
6
- upload(body: any, clientInfo: any, signeture: string, args?: ArgsInfo): Promise<void>;
7
- listen({ path, body, method, origin, signeture }: ListenerInfo, args?: ArgsInfo): Promise<ServerResponse>;
6
+ upload(body: any, clientInfo: any, signeture: string, metadata?: Metadata): Promise<void>;
7
+ listen(url: string, { body, headers, metadata }: ListenerInfo): Promise<ServerResponse>;
8
8
  }
9
9
 
10
10
  export { SecurequServer as default };
package/server/index.js CHANGED
@@ -1 +1 @@
1
- "use strict";Object.defineProperty(exports,"__esModule",{value:!0});var e=require("../include/crypto.js"),t=require("./Base.js"),i=require("../include/FileScaner.js");class a extends t.default{async handshake(t,i){var a,s;const n=await e.default.decryptBuffer(t,i.secret),o=await this.getSecret();if(!n)throw new Error("Invalid handshake data");if(n.hash!==i.hash)throw new Error("Invalid handshake");if(n.secret!==i.secret)throw new Error("Invalid handshake secret");if(Date.now()-n.clientTime>3e4)throw new Error("Handshake expired");const l=new Date;throw{timeDiffarenc:new Date(n.clientTime).getTime()-l.getTime(),maxFileSize:(null===(a=this.config.upload)||void 0===a?void 0:a.maxFilesize)||null,dev:"development"===this.config.mode,checkFileType:(null===(s=this.config.upload)||void 0===s?void 0:s.checkFileType)||!1,signeture:await e.default.encrypt({expire:Date.now()+3e4,hash:i.hash},o)}}async upload(t,a,s,n){var o;const l=await e.default.decryptBuffer(t,a.secret),r=await e.default.decrypt(s,a.secret);await this.isValidSigneture(r.signeture,a.hash);const d=this.config.upload;if(!(null==d?void 0:d.chunk)||!(null==d?void 0:d.complete))throw new Response("Upload not supported",{status:403});if("failed"===(null==l?void 0:l.type)){const e=this.uploadMeta.get(l.fileid);throw e&&d.failed?(await d.failed(e,n),this.uploadMeta.delete(l.fileid),{success:!0}):new Response("Invalid upload",{status:400})}if("meta"===l.type){if((null==d?void 0:d.maxFilesize)&&l.filesize>1024*d.maxFilesize)throw new Response(`File size exceeds the limit of ${d.maxFilesize} KB`,{status:413});throw this.uploadMeta.set(l.fileid,Object.assign(Object.assign({},l),{expire:Date.now()+36e5})),this.uploadMeta.forEach((e,t)=>{e.expire<Date.now()&&this.uploadMeta.delete(t)}),l}{const{chunk:e,fileId:t,chunkIndex:a}=l,s=this.uploadMeta.get(t);if(!s)throw new Response("Invalid upload meta",{status:400});if(d.checkFileType&&0===a){if(!i.fileScaner(e))throw new Error("Unknown or unsupported file type")}if((null===(o=this.config.upload)||void 0===o?void 0:o.maxFilesize)&&l.filesize>1024*this.config.upload.maxFilesize)throw new Response(`File size exceeds the limit of ${this.config.upload.maxFilesize/1024} MB`,{status:413});if(await d.chunk(e,{filename:s.filename,filesize:s.filesize,filetype:s.filetype,fileid:s.fileid,totalChunks:s.totalChunks,chunkIndex:a},n),a+1===s.totalChunks){const e=await d.complete(s,n);throw this.uploadMeta.delete(t),e}throw l}}async listen({path:t,body:i,method:a,origin:s,signeture:n},o){let l=await this.clientInfo(t,s);const r="/"!==(t=l.path)&&"development"===this.config.mode;try{if("/"===t){if(!["POST","PUT"].includes(a))throw new Response("Invalid method",{status:405});"POST"===a?await this.handshake(i,l):await this.upload(i,l,n,o)}const s=await e.default.decrypt(n,l.secret);if(await this.isValidSigneture(s.signeture,l.hash),s.expire<Date.now())throw new Response("Request expired",{status:403});let d=null;if(i)if(r){const e=(new TextDecoder).decode(i);d=JSON.parse(e)}else d=await e.default.decryptBuffer(i,l.secret);await this.handleRequest({method:a,path:t,body:d,searchParams:l.searchParams,params:{}},o)}catch(t){const i=t instanceof Error,a=t instanceof Response;let s=i?t.message:a?await t.text():t;return r?{status:i?404:(null==t?void 0:t.status)||200,content:JSON.stringify(s)}:{status:i?404:(null==t?void 0:t.status)||200,content:await e.default.encryptBuffer(s,l.secret)}}return r?{status:404,content:"Not found"}:{status:404,content:await e.default.encryptBuffer("Not found",l.secret)}}}exports.default=a;//# sourceMappingURL=index.js.map
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:!0});var e=require("../include/crypto.js"),t=require("./Base.js"),i=require("../include/FileScaner.js");class a extends t.default{async handshake(t,i){var a,s;const n=await e.default.decryptBuffer(t,i.secret),o=await this.getSecret();if(!n)throw new Error("Invalid handshake data");if(n.hash!==i.hash)throw new Error("Invalid handshake");if(n.secret!==i.secret)throw new Error("Invalid handshake secret");if(Date.now()-n.clientTime>3e4)throw new Error("Handshake expired");const l=new Date;throw{timeDiffarenc:new Date(n.clientTime).getTime()-l.getTime(),maxFileSize:(null===(a=this.config.upload)||void 0===a?void 0:a.maxFilesize)||null,dev:"development"===this.config.mode,checkFileType:(null===(s=this.config.upload)||void 0===s?void 0:s.checkFileType)||!1,signeture:await e.default.encrypt({expire:Date.now()+3e4,hash:i.hash},o)}}async upload(t,a,s,n){var o;const l=await e.default.decryptBuffer(t,a.secret),r=await e.default.decrypt(s,a.secret);await this.isValidSigneture(r.signeture,a.hash);const d=this.config.upload;if(!(null==d?void 0:d.chunk)||!(null==d?void 0:d.complete))throw new Response("Upload not supported",{status:403});if("failed"===(null==l?void 0:l.type)){const e=this.uploadMeta.get(l.fileid);throw e&&d.failed?(await d.failed(e,n),this.uploadMeta.delete(l.fileid),{success:!0}):new Response("Invalid upload",{status:400})}if("meta"===l.type){if((null==d?void 0:d.maxFilesize)&&l.filesize>1024*d.maxFilesize)throw new Response(`File size exceeds the limit of ${d.maxFilesize} KB`,{status:413});throw this.uploadMeta.set(l.fileid,Object.assign(Object.assign({},l),{expire:Date.now()+36e5})),this.uploadMeta.forEach((e,t)=>{e.expire<Date.now()&&this.uploadMeta.delete(t)}),l}{const{chunk:e,fileId:t,chunkIndex:a}=l,s=this.uploadMeta.get(t);if(!s)throw new Response("Invalid upload meta",{status:400});if(d.checkFileType&&0===a){if(!i.fileScaner(e))throw new Error("Unknown or unsupported file type")}if((null===(o=this.config.upload)||void 0===o?void 0:o.maxFilesize)&&l.filesize>1024*this.config.upload.maxFilesize)throw new Response(`File size exceeds the limit of ${this.config.upload.maxFilesize/1024} MB`,{status:413});if(await d.chunk(e,{filename:s.filename,filesize:s.filesize,filetype:s.filetype,fileid:s.fileid,totalChunks:s.totalChunks,chunkIndex:a},n),a+1===s.totalChunks){const e=await d.complete(s,n);throw this.uploadMeta.delete(t),e}throw l}}async listen(t,{body:i,headers:a,metadata:s}){const n=a["x-signeture"]||"",o=a["x-origin"]||"",l=a["x-method"]||"POST";let r=await this.clientInfo(t,o);if(!r)return{status:403,content:"Client not allowed"};let d=r.path;const u="/"!==d&&"development"===this.config.mode;try{if("/"===d){if(!["POST","PUT"].includes(l))throw new Response("Invalid method",{status:405});"POST"===l?await this.handshake(i,r):await this.upload(i,r,n,s)}const t=await e.default.decrypt(n,r.secret);if(await this.isValidSigneture(t.signeture,r.hash),t.expire<Date.now())throw new Response("Request expired",{status:403});let a=null;if(i)if(u){const e=(new TextDecoder).decode(i);a=JSON.parse(e)}else a=await e.default.decryptBuffer(i,r.secret);await this.handleRequest({method:l,path:d,body:a,searchParams:r.searchParams,params:{}},s)}catch(t){const i=t instanceof Error,a=t instanceof Response;let s=i?t.message:a?await t.text():t;return u?{status:i?404:(null==t?void 0:t.status)||200,content:JSON.stringify(s)}:{status:i?404:(null==t?void 0:t.status)||200,content:await e.default.encryptBuffer(s,r.secret)}}return u?{status:404,content:"Not found"}:{status:404,content:await e.default.encryptBuffer("Not found",r.secret)}}}exports.default=a;//# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../../src/server/index.ts"],"sourcesContent":["import crypto from \"../include/crypto\";\nimport { ArgsInfo, ListenerInfo, ServerResponse } from \"./types\";\nimport SecurequServerBase from \"./Base\";\nimport fileScaner from \"../include/FileScaner\";\n\nclass SecurequServer extends SecurequServerBase {\n\n async handshake(body: any, clientInfo: any) {\n const data: any = await crypto.decryptBuffer(body, clientInfo.secret)\n const serverSecret = await this.getSecret()\n if (!data) throw new Error(\"Invalid handshake data\");\n if (data.hash !== clientInfo.hash) {\n throw new Error(\"Invalid handshake\");\n } else if (data.secret !== clientInfo.secret) {\n throw new Error(\"Invalid handshake secret\");\n } else if (Date.now() - data.clientTime > 30000) { // 30 seconds\n throw new Error(\"Handshake expired\");\n }\n\n const serverTime = new Date();\n const clientDate = new Date(data.clientTime);\n const offsetMs = clientDate.getTime() - serverTime.getTime();\n\n let info = {\n timeDiffarenc: offsetMs,\n maxFileSize: this.config.upload?.maxFilesize || null,\n dev: this.config.mode === 'development',\n checkFileType: this.config.upload?.checkFileType || false,\n signeture: await crypto.encrypt({\n expire: Date.now() + 30000, // 30 seconds\n hash: clientInfo.hash\n }, serverSecret)\n }\n throw info\n }\n\n async upload(body: any, clientInfo: any, signeture: string, args?: ArgsInfo) {\n const data: any = await crypto.decryptBuffer(body, clientInfo.secret)\n const decryptSigneture = await crypto.decrypt(signeture, clientInfo.secret) as any\n await this.isValidSigneture(decryptSigneture.signeture, clientInfo.hash)\n const upload = this.config.upload\n\n if (!upload?.chunk || !upload?.complete) {\n throw new Response(\"Upload not supported\", { status: 403 })\n }\n\n if (data?.type === 'failed') {\n const meta = this.uploadMeta.get(data.fileid)\n if (meta && upload.failed) {\n await upload.failed(meta, args)\n this.uploadMeta.delete(data.fileid)\n throw { success: true }\n } else {\n throw new Response(\"Invalid upload\", { status: 400 })\n }\n } else if (data.type === 'meta') {\n if (upload?.maxFilesize && data.filesize > upload.maxFilesize * 1024) {\n throw new Response(`File size exceeds the limit of ${upload.maxFilesize} KB`, { status: 413 })\n }\n this.uploadMeta.set(data.fileid, {\n ...data,\n expire: Date.now() + 3600000 // 1 hour\n })\n this.uploadMeta.forEach((meta, key) => {\n if (meta.expire < Date.now()) {\n this.uploadMeta.delete(key)\n }\n })\n\n throw data\n } else {\n const { chunk, fileId, chunkIndex } = data;\n const meta = this.uploadMeta.get(fileId)\n if (!meta) {\n throw new Response(\"Invalid upload meta\", { status: 400 })\n }\n if (upload.checkFileType && chunkIndex === 0) {\n let fileType = fileScaner(chunk);\n if (!fileType) {\n throw new Error(\"Unknown or unsupported file type\");\n }\n }\n\n if (this.config.upload?.maxFilesize && data.filesize > this.config.upload.maxFilesize * 1024) {\n throw new Response(`File size exceeds the limit of ${this.config.upload.maxFilesize / 1024} MB`, { status: 413 })\n }\n await upload.chunk(chunk, {\n filename: meta.filename,\n filesize: meta.filesize,\n filetype: meta.filetype,\n fileid: meta.fileid,\n totalChunks: meta.totalChunks,\n chunkIndex,\n }, args)\n if (chunkIndex + 1 === meta.totalChunks) {\n const filepath = await upload.complete(meta, args)\n this.uploadMeta.delete(fileId)\n throw filepath\n }\n throw data\n }\n }\n\n async listen({ path, body, method, origin, signeture }: ListenerInfo, args?: ArgsInfo): Promise<ServerResponse> {\n let clientInfo = await this.clientInfo(path, origin)\n path = clientInfo.path\n const isDev = path !== '/' && this.config.mode === 'development'\n try {\n if (path === '/') {\n if (!['POST', 'PUT'].includes(method)) throw new Response(\"Invalid method\", { status: 405 });\n method === \"POST\"\n ? await this.handshake(body, clientInfo)\n : await this.upload(body, clientInfo, signeture, args);\n }\n\n const decryptSigneture = await crypto.decrypt(signeture, clientInfo.secret) as any\n await this.isValidSigneture(decryptSigneture.signeture, clientInfo.hash)\n\n // if reques is expired\n if (decryptSigneture.expire < Date.now()) throw new Response(\"Request expired\", { status: 403 });\n let data: any = null\n if (body) {\n if (isDev) {\n const decoder = new TextDecoder();\n const text = decoder.decode(body);\n data = JSON.parse(text)\n } else {\n data = await crypto.decryptBuffer(body, clientInfo.secret)\n }\n }\n\n await this.handleRequest({\n method,\n path,\n body: data,\n searchParams: clientInfo.searchParams,\n params: {}\n }, args);\n } catch (info: any) {\n const isError = info instanceof Error\n const isResponse = info instanceof Response\n let content = isError ? info.message : (isResponse ? await info.text() : info);\n if (path === '/') {\n\n }\n if (isDev) {\n return {\n status: isError ? 404 : (info?.status || 200),\n content: JSON.stringify(content)\n };\n }\n return {\n status: isError ? 404 : (info?.status || 200),\n content: await crypto.encryptBuffer(content, clientInfo.secret)\n };\n }\n\n if (isDev) {\n return {\n status: 404,\n content: \"Not found\"\n };\n }\n\n return {\n status: 404,\n content: await crypto.encryptBuffer(\"Not found\", clientInfo.secret)\n };\n }\n\n}\n\nexport default SecurequServer;"],"names":["SecurequServer","SecurequServerBase","handshake","body","clientInfo","data","crypto","decryptBuffer","secret","serverSecret","this","getSecret","Error","hash","Date","now","clientTime","serverTime","timeDiffarenc","getTime","maxFileSize","_a","config","upload","maxFilesize","dev","mode","checkFileType","_b","signeture","encrypt","expire","args","decryptSigneture","decrypt","isValidSigneture","chunk","complete","Response","status","type","meta","uploadMeta","get","fileid","failed","delete","success","filesize","set","Object","assign","forEach","key","fileId","chunkIndex","fileScaner","filename","filetype","totalChunks","filepath","listen","path","method","origin","isDev","includes","text","TextDecoder","decode","JSON","parse","handleRequest","searchParams","params","info","isError","isResponse","content","message","stringify","encryptBuffer","exports","default"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sources":["../../src/server/index.ts"],"sourcesContent":["import crypto from \"../include/crypto\";\nimport { Metadata, ListenerInfo, ServerResponse } from \"./types\";\nimport SecurequServerBase from \"./Base\";\nimport fileScaner from \"../include/FileScaner\";\nimport { HTTPMethods } from \"../client/types\";\n\nclass SecurequServer extends SecurequServerBase {\n\n async handshake(body: any, clientInfo: any) {\n const data: any = await crypto.decryptBuffer(body, clientInfo.secret)\n const serverSecret = await this.getSecret()\n if (!data) throw new Error(\"Invalid handshake data\");\n if (data.hash !== clientInfo.hash) {\n throw new Error(\"Invalid handshake\");\n } else if (data.secret !== clientInfo.secret) {\n throw new Error(\"Invalid handshake secret\");\n } else if (Date.now() - data.clientTime > 30000) { // 30 seconds\n throw new Error(\"Handshake expired\");\n }\n\n const serverTime = new Date();\n const clientDate = new Date(data.clientTime);\n const offsetMs = clientDate.getTime() - serverTime.getTime();\n\n let info = {\n timeDiffarenc: offsetMs,\n maxFileSize: this.config.upload?.maxFilesize || null,\n dev: this.config.mode === 'development',\n checkFileType: this.config.upload?.checkFileType || false,\n signeture: await crypto.encrypt({\n expire: Date.now() + 30000, // 30 seconds\n hash: clientInfo.hash\n }, serverSecret)\n }\n throw info\n }\n\n async upload(body: any, clientInfo: any, signeture: string, metadata?: Metadata) {\n const data: any = await crypto.decryptBuffer(body, clientInfo.secret)\n const decryptSigneture = await crypto.decrypt(signeture, clientInfo.secret) as any\n await this.isValidSigneture(decryptSigneture.signeture, clientInfo.hash)\n const upload = this.config.upload\n\n if (!upload?.chunk || !upload?.complete) {\n throw new Response(\"Upload not supported\", { status: 403 })\n }\n\n if (data?.type === 'failed') {\n const meta = this.uploadMeta.get(data.fileid)\n if (meta && upload.failed) {\n await upload.failed(meta, metadata)\n this.uploadMeta.delete(data.fileid)\n throw { success: true }\n } else {\n throw new Response(\"Invalid upload\", { status: 400 })\n }\n } else if (data.type === 'meta') {\n if (upload?.maxFilesize && data.filesize > upload.maxFilesize * 1024) {\n throw new Response(`File size exceeds the limit of ${upload.maxFilesize} KB`, { status: 413 })\n }\n this.uploadMeta.set(data.fileid, {\n ...data,\n expire: Date.now() + 3600000 // 1 hour\n })\n this.uploadMeta.forEach((meta, key) => {\n if (meta.expire < Date.now()) {\n this.uploadMeta.delete(key)\n }\n })\n\n throw data\n } else {\n const { chunk, fileId, chunkIndex } = data;\n const meta = this.uploadMeta.get(fileId)\n if (!meta) {\n throw new Response(\"Invalid upload meta\", { status: 400 })\n }\n if (upload.checkFileType && chunkIndex === 0) {\n let fileType = fileScaner(chunk);\n if (!fileType) {\n throw new Error(\"Unknown or unsupported file type\");\n }\n }\n\n if (this.config.upload?.maxFilesize && data.filesize > this.config.upload.maxFilesize * 1024) {\n throw new Response(`File size exceeds the limit of ${this.config.upload.maxFilesize / 1024} MB`, { status: 413 })\n }\n await upload.chunk(chunk, {\n filename: meta.filename,\n filesize: meta.filesize,\n filetype: meta.filetype,\n fileid: meta.fileid,\n totalChunks: meta.totalChunks,\n chunkIndex,\n }, metadata)\n if (chunkIndex + 1 === meta.totalChunks) {\n const filepath = await upload.complete(meta, metadata)\n this.uploadMeta.delete(fileId)\n throw filepath\n }\n throw data\n }\n }\n\n async listen(url: string, { body, headers, metadata }: ListenerInfo): Promise<ServerResponse> {\n\n const signeture = headers['x-signeture'] || '';\n const origin = headers['x-origin'] || '';\n const method: HTTPMethods = headers['x-method'] || 'POST' as any\n\n let clientInfo = await this.clientInfo(url, origin)\n if (!clientInfo) {\n return {\n status: 403,\n content: \"Client not allowed\"\n }\n }\n let path = clientInfo.path\n const isDev = path !== '/' && this.config.mode === 'development'\n try {\n if (path === '/') {\n if (!['POST', 'PUT'].includes(method)) throw new Response(\"Invalid method\", { status: 405 });\n method === \"POST\"\n ? await this.handshake(body, clientInfo)\n : await this.upload(body, clientInfo, signeture, metadata);\n }\n\n const decryptSigneture = await crypto.decrypt(signeture, clientInfo.secret) as any\n await this.isValidSigneture(decryptSigneture.signeture, clientInfo.hash)\n\n // if reques is expired\n if (decryptSigneture.expire < Date.now()) throw new Response(\"Request expired\", { status: 403 });\n let data: any = null\n if (body) {\n if (isDev) {\n const decoder = new TextDecoder();\n const text = decoder.decode(body);\n data = JSON.parse(text)\n } else {\n data = await crypto.decryptBuffer(body, clientInfo.secret)\n }\n }\n\n await this.handleRequest({\n method,\n path,\n body: data,\n searchParams: clientInfo.searchParams,\n params: {}\n }, metadata);\n } catch (info: any) {\n const isError = info instanceof Error\n const isResponse = info instanceof Response\n let content = isError ? info.message : (isResponse ? await info.text() : info);\n if (isDev) {\n return {\n status: isError ? 404 : (info?.status || 200),\n content: JSON.stringify(content)\n };\n }\n return {\n status: isError ? 404 : (info?.status || 200),\n content: await crypto.encryptBuffer(content, clientInfo.secret)\n };\n }\n\n if (isDev) {\n return {\n status: 404,\n content: \"Not found\"\n };\n }\n\n return {\n status: 404,\n content: await crypto.encryptBuffer(\"Not found\", clientInfo.secret)\n };\n }\n\n}\n\nexport default SecurequServer;"],"names":["SecurequServer","SecurequServerBase","handshake","body","clientInfo","data","crypto","decryptBuffer","secret","serverSecret","this","getSecret","Error","hash","Date","now","clientTime","serverTime","timeDiffarenc","getTime","maxFileSize","_a","config","upload","maxFilesize","dev","mode","checkFileType","_b","signeture","encrypt","expire","metadata","decryptSigneture","decrypt","isValidSigneture","chunk","complete","Response","status","type","meta","uploadMeta","get","fileid","failed","delete","success","filesize","set","Object","assign","forEach","key","fileId","chunkIndex","fileScaner","filename","filetype","totalChunks","filepath","listen","url","headers","origin","method","content","path","isDev","includes","text","TextDecoder","decode","JSON","parse","handleRequest","searchParams","params","info","isError","isResponse","message","stringify","encryptBuffer","exports","default"],"mappings":"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"}
package/server/index.mjs CHANGED
@@ -1 +1 @@
1
- import e from"../include/crypto.mjs";import t from"./Base.mjs";import{fileScaner as i}from"../include/FileScaner.mjs";class a extends t{async handshake(t,i){var a,s;const n=await e.decryptBuffer(t,i.secret),o=await this.getSecret();if(!n)throw new Error("Invalid handshake data");if(n.hash!==i.hash)throw new Error("Invalid handshake");if(n.secret!==i.secret)throw new Error("Invalid handshake secret");if(Date.now()-n.clientTime>3e4)throw new Error("Handshake expired");const l=new Date;throw{timeDiffarenc:new Date(n.clientTime).getTime()-l.getTime(),maxFileSize:(null===(a=this.config.upload)||void 0===a?void 0:a.maxFilesize)||null,dev:"development"===this.config.mode,checkFileType:(null===(s=this.config.upload)||void 0===s?void 0:s.checkFileType)||!1,signeture:await e.encrypt({expire:Date.now()+3e4,hash:i.hash},o)}}async upload(t,a,s,n){var o;const l=await e.decryptBuffer(t,a.secret),r=await e.decrypt(s,a.secret);await this.isValidSigneture(r.signeture,a.hash);const d=this.config.upload;if(!(null==d?void 0:d.chunk)||!(null==d?void 0:d.complete))throw new Response("Upload not supported",{status:403});if("failed"===(null==l?void 0:l.type)){const e=this.uploadMeta.get(l.fileid);throw e&&d.failed?(await d.failed(e,n),this.uploadMeta.delete(l.fileid),{success:!0}):new Response("Invalid upload",{status:400})}if("meta"===l.type){if((null==d?void 0:d.maxFilesize)&&l.filesize>1024*d.maxFilesize)throw new Response(`File size exceeds the limit of ${d.maxFilesize} KB`,{status:413});throw this.uploadMeta.set(l.fileid,Object.assign(Object.assign({},l),{expire:Date.now()+36e5})),this.uploadMeta.forEach((e,t)=>{e.expire<Date.now()&&this.uploadMeta.delete(t)}),l}{const{chunk:e,fileId:t,chunkIndex:a}=l,s=this.uploadMeta.get(t);if(!s)throw new Response("Invalid upload meta",{status:400});if(d.checkFileType&&0===a){if(!i(e))throw new Error("Unknown or unsupported file type")}if((null===(o=this.config.upload)||void 0===o?void 0:o.maxFilesize)&&l.filesize>1024*this.config.upload.maxFilesize)throw new Response(`File size exceeds the limit of ${this.config.upload.maxFilesize/1024} MB`,{status:413});if(await d.chunk(e,{filename:s.filename,filesize:s.filesize,filetype:s.filetype,fileid:s.fileid,totalChunks:s.totalChunks,chunkIndex:a},n),a+1===s.totalChunks){const e=await d.complete(s,n);throw this.uploadMeta.delete(t),e}throw l}}async listen({path:t,body:i,method:a,origin:s,signeture:n},o){let l=await this.clientInfo(t,s);const r="/"!==(t=l.path)&&"development"===this.config.mode;try{if("/"===t){if(!["POST","PUT"].includes(a))throw new Response("Invalid method",{status:405});"POST"===a?await this.handshake(i,l):await this.upload(i,l,n,o)}const s=await e.decrypt(n,l.secret);if(await this.isValidSigneture(s.signeture,l.hash),s.expire<Date.now())throw new Response("Request expired",{status:403});let d=null;if(i)if(r){const e=(new TextDecoder).decode(i);d=JSON.parse(e)}else d=await e.decryptBuffer(i,l.secret);await this.handleRequest({method:a,path:t,body:d,searchParams:l.searchParams,params:{}},o)}catch(t){const i=t instanceof Error,a=t instanceof Response;let s=i?t.message:a?await t.text():t;return r?{status:i?404:(null==t?void 0:t.status)||200,content:JSON.stringify(s)}:{status:i?404:(null==t?void 0:t.status)||200,content:await e.encryptBuffer(s,l.secret)}}return r?{status:404,content:"Not found"}:{status:404,content:await e.encryptBuffer("Not found",l.secret)}}}export{a as default};//# sourceMappingURL=index.mjs.map
1
+ import e from"../include/crypto.mjs";import t from"./Base.mjs";import{fileScaner as i}from"../include/FileScaner.mjs";class a extends t{async handshake(t,i){var a,s;const n=await e.decryptBuffer(t,i.secret),o=await this.getSecret();if(!n)throw new Error("Invalid handshake data");if(n.hash!==i.hash)throw new Error("Invalid handshake");if(n.secret!==i.secret)throw new Error("Invalid handshake secret");if(Date.now()-n.clientTime>3e4)throw new Error("Handshake expired");const l=new Date;throw{timeDiffarenc:new Date(n.clientTime).getTime()-l.getTime(),maxFileSize:(null===(a=this.config.upload)||void 0===a?void 0:a.maxFilesize)||null,dev:"development"===this.config.mode,checkFileType:(null===(s=this.config.upload)||void 0===s?void 0:s.checkFileType)||!1,signeture:await e.encrypt({expire:Date.now()+3e4,hash:i.hash},o)}}async upload(t,a,s,n){var o;const l=await e.decryptBuffer(t,a.secret),r=await e.decrypt(s,a.secret);await this.isValidSigneture(r.signeture,a.hash);const d=this.config.upload;if(!(null==d?void 0:d.chunk)||!(null==d?void 0:d.complete))throw new Response("Upload not supported",{status:403});if("failed"===(null==l?void 0:l.type)){const e=this.uploadMeta.get(l.fileid);throw e&&d.failed?(await d.failed(e,n),this.uploadMeta.delete(l.fileid),{success:!0}):new Response("Invalid upload",{status:400})}if("meta"===l.type){if((null==d?void 0:d.maxFilesize)&&l.filesize>1024*d.maxFilesize)throw new Response(`File size exceeds the limit of ${d.maxFilesize} KB`,{status:413});throw this.uploadMeta.set(l.fileid,Object.assign(Object.assign({},l),{expire:Date.now()+36e5})),this.uploadMeta.forEach((e,t)=>{e.expire<Date.now()&&this.uploadMeta.delete(t)}),l}{const{chunk:e,fileId:t,chunkIndex:a}=l,s=this.uploadMeta.get(t);if(!s)throw new Response("Invalid upload meta",{status:400});if(d.checkFileType&&0===a){if(!i(e))throw new Error("Unknown or unsupported file type")}if((null===(o=this.config.upload)||void 0===o?void 0:o.maxFilesize)&&l.filesize>1024*this.config.upload.maxFilesize)throw new Response(`File size exceeds the limit of ${this.config.upload.maxFilesize/1024} MB`,{status:413});if(await d.chunk(e,{filename:s.filename,filesize:s.filesize,filetype:s.filetype,fileid:s.fileid,totalChunks:s.totalChunks,chunkIndex:a},n),a+1===s.totalChunks){const e=await d.complete(s,n);throw this.uploadMeta.delete(t),e}throw l}}async listen(t,{body:i,headers:a,metadata:s}){const n=a["x-signeture"]||"",o=a["x-origin"]||"",l=a["x-method"]||"POST";let r=await this.clientInfo(t,o);if(!r)return{status:403,content:"Client not allowed"};let d=r.path;const c="/"!==d&&"development"===this.config.mode;try{if("/"===d){if(!["POST","PUT"].includes(l))throw new Response("Invalid method",{status:405});"POST"===l?await this.handshake(i,r):await this.upload(i,r,n,s)}const t=await e.decrypt(n,r.secret);if(await this.isValidSigneture(t.signeture,r.hash),t.expire<Date.now())throw new Response("Request expired",{status:403});let a=null;if(i)if(c){const e=(new TextDecoder).decode(i);a=JSON.parse(e)}else a=await e.decryptBuffer(i,r.secret);await this.handleRequest({method:l,path:d,body:a,searchParams:r.searchParams,params:{}},s)}catch(t){const i=t instanceof Error,a=t instanceof Response;let s=i?t.message:a?await t.text():t;return c?{status:i?404:(null==t?void 0:t.status)||200,content:JSON.stringify(s)}:{status:i?404:(null==t?void 0:t.status)||200,content:await e.encryptBuffer(s,r.secret)}}return c?{status:404,content:"Not found"}:{status:404,content:await e.encryptBuffer("Not found",r.secret)}}}export{a as default};//# sourceMappingURL=index.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","sources":["../../src/server/index.ts"],"sourcesContent":["import crypto from \"../include/crypto\";\nimport { ArgsInfo, ListenerInfo, ServerResponse } from \"./types\";\nimport SecurequServerBase from \"./Base\";\nimport fileScaner from \"../include/FileScaner\";\n\nclass SecurequServer extends SecurequServerBase {\n\n async handshake(body: any, clientInfo: any) {\n const data: any = await crypto.decryptBuffer(body, clientInfo.secret)\n const serverSecret = await this.getSecret()\n if (!data) throw new Error(\"Invalid handshake data\");\n if (data.hash !== clientInfo.hash) {\n throw new Error(\"Invalid handshake\");\n } else if (data.secret !== clientInfo.secret) {\n throw new Error(\"Invalid handshake secret\");\n } else if (Date.now() - data.clientTime > 30000) { // 30 seconds\n throw new Error(\"Handshake expired\");\n }\n\n const serverTime = new Date();\n const clientDate = new Date(data.clientTime);\n const offsetMs = clientDate.getTime() - serverTime.getTime();\n\n let info = {\n timeDiffarenc: offsetMs,\n maxFileSize: this.config.upload?.maxFilesize || null,\n dev: this.config.mode === 'development',\n checkFileType: this.config.upload?.checkFileType || false,\n signeture: await crypto.encrypt({\n expire: Date.now() + 30000, // 30 seconds\n hash: clientInfo.hash\n }, serverSecret)\n }\n throw info\n }\n\n async upload(body: any, clientInfo: any, signeture: string, args?: ArgsInfo) {\n const data: any = await crypto.decryptBuffer(body, clientInfo.secret)\n const decryptSigneture = await crypto.decrypt(signeture, clientInfo.secret) as any\n await this.isValidSigneture(decryptSigneture.signeture, clientInfo.hash)\n const upload = this.config.upload\n\n if (!upload?.chunk || !upload?.complete) {\n throw new Response(\"Upload not supported\", { status: 403 })\n }\n\n if (data?.type === 'failed') {\n const meta = this.uploadMeta.get(data.fileid)\n if (meta && upload.failed) {\n await upload.failed(meta, args)\n this.uploadMeta.delete(data.fileid)\n throw { success: true }\n } else {\n throw new Response(\"Invalid upload\", { status: 400 })\n }\n } else if (data.type === 'meta') {\n if (upload?.maxFilesize && data.filesize > upload.maxFilesize * 1024) {\n throw new Response(`File size exceeds the limit of ${upload.maxFilesize} KB`, { status: 413 })\n }\n this.uploadMeta.set(data.fileid, {\n ...data,\n expire: Date.now() + 3600000 // 1 hour\n })\n this.uploadMeta.forEach((meta, key) => {\n if (meta.expire < Date.now()) {\n this.uploadMeta.delete(key)\n }\n })\n\n throw data\n } else {\n const { chunk, fileId, chunkIndex } = data;\n const meta = this.uploadMeta.get(fileId)\n if (!meta) {\n throw new Response(\"Invalid upload meta\", { status: 400 })\n }\n if (upload.checkFileType && chunkIndex === 0) {\n let fileType = fileScaner(chunk);\n if (!fileType) {\n throw new Error(\"Unknown or unsupported file type\");\n }\n }\n\n if (this.config.upload?.maxFilesize && data.filesize > this.config.upload.maxFilesize * 1024) {\n throw new Response(`File size exceeds the limit of ${this.config.upload.maxFilesize / 1024} MB`, { status: 413 })\n }\n await upload.chunk(chunk, {\n filename: meta.filename,\n filesize: meta.filesize,\n filetype: meta.filetype,\n fileid: meta.fileid,\n totalChunks: meta.totalChunks,\n chunkIndex,\n }, args)\n if (chunkIndex + 1 === meta.totalChunks) {\n const filepath = await upload.complete(meta, args)\n this.uploadMeta.delete(fileId)\n throw filepath\n }\n throw data\n }\n }\n\n async listen({ path, body, method, origin, signeture }: ListenerInfo, args?: ArgsInfo): Promise<ServerResponse> {\n let clientInfo = await this.clientInfo(path, origin)\n path = clientInfo.path\n const isDev = path !== '/' && this.config.mode === 'development'\n try {\n if (path === '/') {\n if (!['POST', 'PUT'].includes(method)) throw new Response(\"Invalid method\", { status: 405 });\n method === \"POST\"\n ? await this.handshake(body, clientInfo)\n : await this.upload(body, clientInfo, signeture, args);\n }\n\n const decryptSigneture = await crypto.decrypt(signeture, clientInfo.secret) as any\n await this.isValidSigneture(decryptSigneture.signeture, clientInfo.hash)\n\n // if reques is expired\n if (decryptSigneture.expire < Date.now()) throw new Response(\"Request expired\", { status: 403 });\n let data: any = null\n if (body) {\n if (isDev) {\n const decoder = new TextDecoder();\n const text = decoder.decode(body);\n data = JSON.parse(text)\n } else {\n data = await crypto.decryptBuffer(body, clientInfo.secret)\n }\n }\n\n await this.handleRequest({\n method,\n path,\n body: data,\n searchParams: clientInfo.searchParams,\n params: {}\n }, args);\n } catch (info: any) {\n const isError = info instanceof Error\n const isResponse = info instanceof Response\n let content = isError ? info.message : (isResponse ? await info.text() : info);\n if (path === '/') {\n\n }\n if (isDev) {\n return {\n status: isError ? 404 : (info?.status || 200),\n content: JSON.stringify(content)\n };\n }\n return {\n status: isError ? 404 : (info?.status || 200),\n content: await crypto.encryptBuffer(content, clientInfo.secret)\n };\n }\n\n if (isDev) {\n return {\n status: 404,\n content: \"Not found\"\n };\n }\n\n return {\n status: 404,\n content: await crypto.encryptBuffer(\"Not found\", clientInfo.secret)\n };\n }\n\n}\n\nexport default SecurequServer;"],"names":["SecurequServer","SecurequServerBase","handshake","body","clientInfo","data","crypto","decryptBuffer","secret","serverSecret","this","getSecret","Error","hash","Date","now","clientTime","serverTime","timeDiffarenc","getTime","maxFileSize","_a","config","upload","maxFilesize","dev","mode","checkFileType","_b","signeture","encrypt","expire","args","decryptSigneture","decrypt","isValidSigneture","chunk","complete","Response","status","type","meta","uploadMeta","get","fileid","failed","delete","success","filesize","set","Object","assign","forEach","key","fileId","chunkIndex","fileScaner","filename","filetype","totalChunks","filepath","listen","path","method","origin","isDev","includes","text","TextDecoder","decode","JSON","parse","handleRequest","searchParams","params","info","isError","isResponse","content","message","stringify","encryptBuffer"],"mappings":"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"}
1
+ {"version":3,"file":"index.mjs","sources":["../../src/server/index.ts"],"sourcesContent":["import crypto from \"../include/crypto\";\nimport { Metadata, ListenerInfo, ServerResponse } from \"./types\";\nimport SecurequServerBase from \"./Base\";\nimport fileScaner from \"../include/FileScaner\";\nimport { HTTPMethods } from \"../client/types\";\n\nclass SecurequServer extends SecurequServerBase {\n\n async handshake(body: any, clientInfo: any) {\n const data: any = await crypto.decryptBuffer(body, clientInfo.secret)\n const serverSecret = await this.getSecret()\n if (!data) throw new Error(\"Invalid handshake data\");\n if (data.hash !== clientInfo.hash) {\n throw new Error(\"Invalid handshake\");\n } else if (data.secret !== clientInfo.secret) {\n throw new Error(\"Invalid handshake secret\");\n } else if (Date.now() - data.clientTime > 30000) { // 30 seconds\n throw new Error(\"Handshake expired\");\n }\n\n const serverTime = new Date();\n const clientDate = new Date(data.clientTime);\n const offsetMs = clientDate.getTime() - serverTime.getTime();\n\n let info = {\n timeDiffarenc: offsetMs,\n maxFileSize: this.config.upload?.maxFilesize || null,\n dev: this.config.mode === 'development',\n checkFileType: this.config.upload?.checkFileType || false,\n signeture: await crypto.encrypt({\n expire: Date.now() + 30000, // 30 seconds\n hash: clientInfo.hash\n }, serverSecret)\n }\n throw info\n }\n\n async upload(body: any, clientInfo: any, signeture: string, metadata?: Metadata) {\n const data: any = await crypto.decryptBuffer(body, clientInfo.secret)\n const decryptSigneture = await crypto.decrypt(signeture, clientInfo.secret) as any\n await this.isValidSigneture(decryptSigneture.signeture, clientInfo.hash)\n const upload = this.config.upload\n\n if (!upload?.chunk || !upload?.complete) {\n throw new Response(\"Upload not supported\", { status: 403 })\n }\n\n if (data?.type === 'failed') {\n const meta = this.uploadMeta.get(data.fileid)\n if (meta && upload.failed) {\n await upload.failed(meta, metadata)\n this.uploadMeta.delete(data.fileid)\n throw { success: true }\n } else {\n throw new Response(\"Invalid upload\", { status: 400 })\n }\n } else if (data.type === 'meta') {\n if (upload?.maxFilesize && data.filesize > upload.maxFilesize * 1024) {\n throw new Response(`File size exceeds the limit of ${upload.maxFilesize} KB`, { status: 413 })\n }\n this.uploadMeta.set(data.fileid, {\n ...data,\n expire: Date.now() + 3600000 // 1 hour\n })\n this.uploadMeta.forEach((meta, key) => {\n if (meta.expire < Date.now()) {\n this.uploadMeta.delete(key)\n }\n })\n\n throw data\n } else {\n const { chunk, fileId, chunkIndex } = data;\n const meta = this.uploadMeta.get(fileId)\n if (!meta) {\n throw new Response(\"Invalid upload meta\", { status: 400 })\n }\n if (upload.checkFileType && chunkIndex === 0) {\n let fileType = fileScaner(chunk);\n if (!fileType) {\n throw new Error(\"Unknown or unsupported file type\");\n }\n }\n\n if (this.config.upload?.maxFilesize && data.filesize > this.config.upload.maxFilesize * 1024) {\n throw new Response(`File size exceeds the limit of ${this.config.upload.maxFilesize / 1024} MB`, { status: 413 })\n }\n await upload.chunk(chunk, {\n filename: meta.filename,\n filesize: meta.filesize,\n filetype: meta.filetype,\n fileid: meta.fileid,\n totalChunks: meta.totalChunks,\n chunkIndex,\n }, metadata)\n if (chunkIndex + 1 === meta.totalChunks) {\n const filepath = await upload.complete(meta, metadata)\n this.uploadMeta.delete(fileId)\n throw filepath\n }\n throw data\n }\n }\n\n async listen(url: string, { body, headers, metadata }: ListenerInfo): Promise<ServerResponse> {\n\n const signeture = headers['x-signeture'] || '';\n const origin = headers['x-origin'] || '';\n const method: HTTPMethods = headers['x-method'] || 'POST' as any\n\n let clientInfo = await this.clientInfo(url, origin)\n if (!clientInfo) {\n return {\n status: 403,\n content: \"Client not allowed\"\n }\n }\n let path = clientInfo.path\n const isDev = path !== '/' && this.config.mode === 'development'\n try {\n if (path === '/') {\n if (!['POST', 'PUT'].includes(method)) throw new Response(\"Invalid method\", { status: 405 });\n method === \"POST\"\n ? await this.handshake(body, clientInfo)\n : await this.upload(body, clientInfo, signeture, metadata);\n }\n\n const decryptSigneture = await crypto.decrypt(signeture, clientInfo.secret) as any\n await this.isValidSigneture(decryptSigneture.signeture, clientInfo.hash)\n\n // if reques is expired\n if (decryptSigneture.expire < Date.now()) throw new Response(\"Request expired\", { status: 403 });\n let data: any = null\n if (body) {\n if (isDev) {\n const decoder = new TextDecoder();\n const text = decoder.decode(body);\n data = JSON.parse(text)\n } else {\n data = await crypto.decryptBuffer(body, clientInfo.secret)\n }\n }\n\n await this.handleRequest({\n method,\n path,\n body: data,\n searchParams: clientInfo.searchParams,\n params: {}\n }, metadata);\n } catch (info: any) {\n const isError = info instanceof Error\n const isResponse = info instanceof Response\n let content = isError ? info.message : (isResponse ? await info.text() : info);\n if (isDev) {\n return {\n status: isError ? 404 : (info?.status || 200),\n content: JSON.stringify(content)\n };\n }\n return {\n status: isError ? 404 : (info?.status || 200),\n content: await crypto.encryptBuffer(content, clientInfo.secret)\n };\n }\n\n if (isDev) {\n return {\n status: 404,\n content: \"Not found\"\n };\n }\n\n return {\n status: 404,\n content: await crypto.encryptBuffer(\"Not found\", clientInfo.secret)\n };\n }\n\n}\n\nexport default SecurequServer;"],"names":["SecurequServer","SecurequServerBase","handshake","body","clientInfo","data","crypto","decryptBuffer","secret","serverSecret","this","getSecret","Error","hash","Date","now","clientTime","serverTime","timeDiffarenc","getTime","maxFileSize","_a","config","upload","maxFilesize","dev","mode","checkFileType","_b","signeture","encrypt","expire","metadata","decryptSigneture","decrypt","isValidSigneture","chunk","complete","Response","status","type","meta","uploadMeta","get","fileid","failed","delete","success","filesize","set","Object","assign","forEach","key","fileId","chunkIndex","fileScaner","filename","filetype","totalChunks","filepath","listen","url","headers","origin","method","content","path","isDev","includes","text","TextDecoder","decode","JSON","parse","handleRequest","searchParams","params","info","isError","isResponse","message","stringify","encryptBuffer"],"mappings":"sHAMA,MAAMA,UAAuBC,EAE1B,eAAMC,CAAUC,EAAWC,WACxB,MAAMC,QAAkBC,EAAOC,cAAcJ,EAAMC,EAAWI,QACxDC,QAAqBC,KAAKC,YAChC,IAAKN,EAAM,MAAM,IAAIO,MAAM,0BAC3B,GAAIP,EAAKQ,OAAST,EAAWS,KAC1B,MAAM,IAAID,MAAM,qBACZ,GAAIP,EAAKG,SAAWJ,EAAWI,OACnC,MAAM,IAAII,MAAM,4BACZ,GAAIE,KAAKC,MAAQV,EAAKW,WAAa,IACvC,MAAM,IAAIJ,MAAM,qBAGnB,MAAMK,EAAa,IAAIH,KAcvB,KAVW,CACRI,cAJgB,IAAIJ,KAAKT,EAAKW,YACLG,UAAYF,EAAWE,UAIhDC,aAA+B,QAAlBC,EAAAX,KAAKY,OAAOC,cAAM,IAAAF,OAAA,EAAAA,EAAEG,cAAe,KAChDC,IAA0B,gBAArBf,KAAKY,OAAOI,KACjBC,eAAiC,QAAlBC,EAAAlB,KAAKY,OAAOC,cAAM,IAAAK,OAAA,EAAAA,EAAED,iBAAiB,EACpDE,gBAAiBvB,EAAOwB,QAAQ,CAC7BC,OAAQjB,KAAKC,MAAQ,IACrBF,KAAMT,EAAWS,MACjBJ,GAGT,CAEA,YAAMc,CAAOpB,EAAWC,EAAiByB,EAAmBG,SACzD,MAAM3B,QAAkBC,EAAOC,cAAcJ,EAAMC,EAAWI,QACxDyB,QAAyB3B,EAAO4B,QAAQL,EAAWzB,EAAWI,cAC9DE,KAAKyB,iBAAiBF,EAAiBJ,UAAWzB,EAAWS,MACnE,MAAMU,EAASb,KAAKY,OAAOC,OAE3B,KAAKA,aAAM,EAANA,EAAQa,UAAUb,eAAAA,EAAQc,UAC5B,MAAM,IAAIC,SAAS,uBAAwB,CAAEC,OAAQ,MAGxD,GAAmB,YAAflC,aAAI,EAAJA,EAAMmC,MAAmB,CAC1B,MAAMC,EAAO/B,KAAKgC,WAAWC,IAAItC,EAAKuC,QACtC,MAAIH,GAAQlB,EAAOsB,cACVtB,EAAOsB,OAAOJ,EAAMT,GAC1BtB,KAAKgC,WAAWI,OAAOzC,EAAKuC,QACtB,CAAEG,SAAS,IAEX,IAAIT,SAAS,iBAAkB,CAAEC,OAAQ,KAEpD,CAAM,GAAkB,SAAdlC,EAAKmC,KAAiB,CAC9B,IAAIjB,aAAM,EAANA,EAAQC,cAAenB,EAAK2C,SAAgC,KAArBzB,EAAOC,YAC/C,MAAM,IAAIc,SAAS,kCAAkCf,EAAOC,iBAAkB,CAAEe,OAAQ,MAY3F,MAVA7B,KAAKgC,WAAWO,IAAI5C,EAAKuC,OAAMM,OAAAC,OAAAD,OAAAC,OAAA,CAAA,EACzB9C,IACH0B,OAAQjB,KAAKC,MAAQ,QAExBL,KAAKgC,WAAWU,QAAQ,CAACX,EAAMY,KACxBZ,EAAKV,OAASjB,KAAKC,OACpBL,KAAKgC,WAAWI,OAAOO,KAIvBhD,CACR,CAAM,CACJ,MAAM+B,MAAEA,EAAKkB,OAAEA,EAAMC,WAAEA,GAAelD,EAChCoC,EAAO/B,KAAKgC,WAAWC,IAAIW,GACjC,IAAKb,EACF,MAAM,IAAIH,SAAS,sBAAuB,CAAEC,OAAQ,MAEvD,GAAIhB,EAAOI,eAAgC,IAAf4B,EAAkB,CAE3C,IADeC,EAAWpB,GAEvB,MAAM,IAAIxB,MAAM,mCAErB,CAED,IAAsB,UAAlBF,KAAKY,OAAOC,cAAM,IAAAF,OAAA,EAAAA,EAAEG,cAAenB,EAAK2C,SAA4C,KAAjCtC,KAAKY,OAAOC,OAAOC,YACvE,MAAM,IAAIc,SAAS,kCAAkC5B,KAAKY,OAAOC,OAAOC,YAAc,UAAW,CAAEe,OAAQ,MAU9G,SARMhB,EAAOa,MAAMA,EAAO,CACvBqB,SAAUhB,EAAKgB,SACfT,SAAUP,EAAKO,SACfU,SAAUjB,EAAKiB,SACfd,OAAQH,EAAKG,OACbe,YAAalB,EAAKkB,YAClBJ,cACAvB,GACCuB,EAAa,IAAMd,EAAKkB,YAAa,CACtC,MAAMC,QAAiBrC,EAAOc,SAASI,EAAMT,GAE7C,MADAtB,KAAKgC,WAAWI,OAAOQ,GACjBM,CACR,CACD,MAAMvD,CACR,CACJ,CAEA,YAAMwD,CAAOC,GAAa3D,KAAEA,EAAI4D,QAAEA,EAAO/B,SAAEA,IAExC,MAAMH,EAAYkC,EAAQ,gBAAkB,GACtCC,EAASD,EAAQ,aAAe,GAChCE,EAAsBF,EAAQ,aAAe,OAEnD,IAAI3D,QAAmBM,KAAKN,WAAW0D,EAAKE,GAC5C,IAAK5D,EACF,MAAO,CACJmC,OAAQ,IACR2B,QAAS,sBAGf,IAAIC,EAAO/D,EAAW+D,KACtB,MAAMC,EAAiB,MAATD,GAAqC,gBAArBzD,KAAKY,OAAOI,KAC1C,IACG,GAAa,MAATyC,EAAc,CACf,IAAK,CAAC,OAAQ,OAAOE,SAASJ,GAAS,MAAM,IAAI3B,SAAS,iBAAkB,CAAEC,OAAQ,MAC3E,SAAX0B,QACWvD,KAAKR,UAAUC,EAAMC,SACrBM,KAAKa,OAAOpB,EAAMC,EAAYyB,EAAWG,EACtD,CAED,MAAMC,QAAyB3B,EAAO4B,QAAQL,EAAWzB,EAAWI,QAIpE,SAHME,KAAKyB,iBAAiBF,EAAiBJ,UAAWzB,EAAWS,MAG/DoB,EAAiBF,OAASjB,KAAKC,MAAO,MAAM,IAAIuB,SAAS,kBAAmB,CAAEC,OAAQ,MAC1F,IAAIlC,EAAY,KAChB,GAAIF,EACD,GAAIiE,EAAO,CACR,MACME,GADU,IAAIC,aACCC,OAAOrE,GAC5BE,EAAOoE,KAAKC,MAAMJ,EACpB,MACEjE,QAAaC,EAAOC,cAAcJ,EAAMC,EAAWI,cAInDE,KAAKiE,cAAc,CACtBV,SACAE,OACAhE,KAAME,EACNuE,aAAcxE,EAAWwE,aACzBC,OAAQ,CAAA,GACR7C,EACL,CAAC,MAAO8C,GACN,MAAMC,EAAUD,aAAgBlE,MAC1BoE,EAAaF,aAAgBxC,SACnC,IAAI4B,EAAUa,EAAUD,EAAKG,QAAWD,QAAmBF,EAAKR,OAASQ,EACzE,OAAIV,EACM,CACJ7B,OAAQwC,EAAU,KAAOD,aAAI,EAAJA,EAAMvC,SAAU,IACzC2B,QAASO,KAAKS,UAAUhB,IAGvB,CACJ3B,OAAQwC,EAAU,KAAOD,aAAI,EAAJA,EAAMvC,SAAU,IACzC2B,cAAe5D,EAAO6E,cAAcjB,EAAS9D,EAAWI,QAE7D,CAED,OAAI4D,EACM,CACJ7B,OAAQ,IACR2B,QAAS,aAIR,CACJ3B,OAAQ,IACR2B,cAAe5D,EAAO6E,cAAc,YAAa/E,EAAWI,QAElE,SAEFR"}
package/server/types.d.ts CHANGED
@@ -24,28 +24,28 @@ type UploadFileMeta = {
24
24
  totalChunks: number;
25
25
  };
26
26
  type UploadFilePath = string;
27
- type ArgsInfo = {
27
+ type Metadata = {
28
28
  [key: string]: any;
29
29
  };
30
30
  type SecurequServerConfig = {
31
- mode: "production" | "development";
31
+ mode?: "production" | "development";
32
32
  basepath: string;
33
33
  clients: ServerClient[];
34
34
  upload?: {
35
35
  maxFilesize?: number;
36
36
  checkFileType?: boolean;
37
- chunk: (chunk: Uint8Array, meta: UploadFileMeta, args?: ArgsInfo) => Promise<boolean>;
38
- complete: (meta: UploadFileMeta, args?: ArgsInfo) => Promise<UploadFilePath>;
39
- failed?: (meta: UploadFileMeta, args?: ArgsInfo) => Promise<boolean>;
37
+ chunk: (chunk: Uint8Array, uploadMeta: UploadFileMeta, metadata?: Metadata) => Promise<boolean>;
38
+ complete: (meta: UploadFileMeta, metadata?: Metadata) => Promise<UploadFilePath>;
39
+ failed?: (meta: UploadFileMeta, metadata?: Metadata) => Promise<boolean>;
40
40
  };
41
- accept?: (info: HandlerInfo, args?: ArgsInfo) => boolean | Promise<boolean>;
41
+ accept?: (info: HandlerInfo, metadata?: Metadata) => boolean | Promise<boolean>;
42
42
  };
43
43
  type ListenerInfo = {
44
- signeture: string;
45
- path: string;
46
44
  body: any;
47
- method: HTTPMethods;
48
- origin: string;
45
+ headers: {
46
+ [key: string]: string;
47
+ };
48
+ metadata?: Metadata;
49
49
  };
50
50
  type HandlerInfo = {
51
51
  path: string;
@@ -62,7 +62,7 @@ type ServerResponse = {
62
62
  content: Uint8Array | string;
63
63
  status: number;
64
64
  };
65
- type HandlerFunction = (info: HandlerInfo, args?: any) => (any | void) | Promise<Partial<any> | void>;
65
+ type HandlerFunction = (info: HandlerInfo, metadata?: Metadata) => (any | void) | Promise<Partial<any> | void>;
66
66
  type RouteFactory = {
67
67
  [key in HTTPMethods]: {
68
68
  [path: string]: {
@@ -74,4 +74,4 @@ type RouteFactory = {
74
74
  };
75
75
  };
76
76
 
77
- export type { ArgsInfo, HandlerFunction, HandlerInfo, ListenerInfo, RouteFactory, SecurequServerConfig, ServerClient, ServerClientInfo, ServerClientOrigin, ServerClientSecret, ServerResponse, UploadFileMeta, UploadFilePath };
77
+ export type { HandlerFunction, HandlerInfo, ListenerInfo, Metadata, RouteFactory, SecurequServerConfig, ServerClient, ServerClientInfo, ServerClientOrigin, ServerClientSecret, ServerResponse, UploadFileMeta, UploadFilePath };