@vbarbarosh/node-helpers 3.76.1 → 3.77.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/browser.js +1 -1
- package/package.json +1 -1
- package/src/assert_positive_integer.js +10 -0
- package/src/assert_positive_integer.md +8 -0
- package/src/fastdl.js +45 -4
- package/src/fastdl.md +8 -0
- package/src/http_get_file.js +15 -7
- package/src/http_get_file.md +7 -3
- package/src/http_get_stream_range.js +25 -7
- package/src/http_get_stream_range.md +10 -8
- package/src/http_stream_range.js +5 -0
- package/src/http_stream_range.md +4 -1
- package/src/mongo_stream_upsert.js +2 -0
- package/src/mongo_stream_upsert.md +1 -0
- package/src/mongo_stream_write.js +2 -0
- package/src/mongo_stream_write.md +1 -0
- package/src/parallel.js +2 -0
- package/src/parallel.md +1 -0
- package/src/pending.js +24 -0
- package/src/pending.md +22 -0
- package/src/redis_poll.js +2 -1
- package/src/redis_poll_zshift_callback_rpush.js +6 -5
- package/src/redis_poll_zshift_callback_rpush.md +3 -2
- package/src/redis_poll_zshift_spawn_rpush.js +5 -4
- package/src/redis_poll_zshift_spawn_rpush.md +3 -2
- package/src/redis_rpush.js +14 -0
- package/src/redis_rpush.md +12 -0
- package/src/stream_map_parallel.js +2 -0
- package/src/stream_map_parallel.md +2 -0
- package/src/stream_multiplex.js +5 -3
- package/src/stream_multiplex.md +2 -0
- package/src/stream_progress.js +10 -3
- package/src/stream_progress.md +1 -0
package/README.md
CHANGED
|
@@ -20,7 +20,7 @@ npm install @vbarbarosh/node-helpers
|
|
|
20
20
|
A subset of `@vbarbarosh/node-helpers` is available for browser:
|
|
21
21
|
|
|
22
22
|
```html
|
|
23
|
-
<script src="https://unpkg.com/@vbarbarosh/node-helpers@3.
|
|
23
|
+
<script src="https://unpkg.com/@vbarbarosh/node-helpers@3.77.0/dist/browser.js"></script>
|
|
24
24
|
```
|
|
25
25
|
|
|
26
26
|
⚠️ All browser functions are exposed globally.
|
package/dist/browser.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
(()=>{var t={932(t){t.exports=function(t){return"number"==typeof t&&isFinite(t)}},5392(t,e,n){const r=n(932);t.exports=function(t,e){return r(t)&&t>e}},4106(t,e){function n(t,e){var n=[],r=[];return null==e&&(e=function(t,e){return n[0]===e?"[Circular ~]":"[Circular ~."+r.slice(0,n.indexOf(e)).join(".")+"]"}),function(o,s){if(n.length>0){var u=n.indexOf(this);~u?n.splice(u+1):n.push(this),~u?r.splice(u,1/0,o):r.push(o),~n.indexOf(s)&&(s=e.call(this,o,s))}else n.push(s);return null==t?s:t.call(this,o,s)}}(t.exports=function(t,e,r,o){return JSON.stringify(t,n(e,o),r)}).getSerialize=n},6083(t){t.exports=function(t=[],e=1){if(e<1)throw new Error("Limit value should be at least 1");const n=[];for(let r=0,o=t.length;r<o;r+=e)n.push(t.slice(r,r+e));return n}},2458(t,e,n){const r=n(7727);t.exports=function(t=[],e=1,n=1){const o=r(1,e,Math.floor(t.length/n)),s=Math.floor(t.length/o);let u=t.length%o;const c=[];for(let e=0;e<t.length;){const n=s+(u?1:0);c.push(t.slice(e,e+n)),e+=n,u&&u--}return c}},353(t,e,n){const r=n(4476),o=1e-5;t.exports=function(t,e){const n=Math.floor(t*e);if(n<=1)return[0];const s=[];for(let e=0;e<n;++e)s.push(r(e/(n-1)*(t-o),o));return s}},6372(t,e,n){const r=n(6785);t.exports=function(t,e=Number){return t.map(t=>e(t)).reduce((t,e)=>r(t,e),0)}},3537(t){t.exports=function(t,e){const n=new Map;return t.forEach(function(t){const r=e(t);n.has(r)||n.set(r,{key:r,items:[]}),n.get(r).items.push(t)}),n.values().toArray()}},2976(t){t.exports=function(t,e){const n={};return t.forEach(function(t){const r=e(t);n[r]=n[r]||{key:r,items:[]},n[r].items.push(t)}),n}},2166(t,e,n){const r=n(956);t.exports=function(t,e=r){const n={};return t.forEach(t=>n[e(t)]=t),n}},7866(t,e,n){const r=n(7347);t.exports=function(t,e=Number){return t.map(t=>e(t)).reduce((t,e)=>r(t,e),1)}},6772(t,e,n){const r=n(956);t.exports=function(t,e=r){let n=null,o=null,s=!1;return t.forEach(function(t){const r=e(t);Number.isNaN(r)||(!s||o<r)&&(s=!0,o=r,n=t)}),n}},42(t,e,n){const r=n(956);t.exports=function(t,e=r){let n=null,o=null,s=!1;return t.forEach(function(t){const r=e(t);Number.isNaN(r)||(!s||o>r)&&(s=!0,o=r,n=t)}),n}},3685(t){t.exports=function t(e,n=e.length){if(n!==e.length)return function(e,n){if(0===n)return[[]];if(e.length<n)return[];const r=[];for(let o=0;o<e.length;o++){const s=e.slice(0,o).concat(e.slice(o+1));for(const u of t(s,n-1))r.push([e[o],...u])}return r}(e,n);let r,o,s=(e=e.slice()).length,u=[e.slice()],c=new Array(s).fill(0),a=1;for(;a<s;)c[a]<a?(r=a%2&&c[a],o=e[a],e[a]=e[r],e[r]=o,++c[a],a=1,u.push(e.slice())):(c[a]=0,++a);return u}},4943(t){t.exports=function(t){for(let e=t.length;--e>0;){const n=Math.floor(Math.random()*(e+1)),r=t[e];t[e]=t[n],t[n]=r}return t}},2356(t,e,n){const r=n(8310),o=n(4332);t.exports=function(t,e,n=r){const s=new Map;return t.sort(function(t,r){if(!s.has(t)){const n=e(t);s.set(t,Array.isArray(n)?n:[n])}if(!s.has(r)){const t=e(r);s.set(r,Array.isArray(t)?t:[t])}return o(s.get(t),s.get(r),n)})}},5181(t,e,n){const r=n(8310);t.exports=function(t,e,n,o=r){const s=Object.create(null);return n.forEach((t,e)=>s[t]=e+1),t.sort(function(t,n){const r=s[e(t)],u=s[e(n)];return r&&u?r-u:r?-1:u?1:o(t,n)})}},453(t){t.exports=function(t,e=Number){let n=0;return t.forEach(function(t){n+=e(t)}),n}},3523(t,e,n){const r=n(956);t.exports=function(t,e=r){const n=new Set;return t.filter(function(t){const r=e(t);return!n.has(r)&&(n.add(r),!0)})}},6382(t,e,n){const r=n(956);t.exports=function(t,e=r){const n=[],o=new Set;for(let r=t.length;--r>=0;){const s=t[r],u=e(s);o.has(u)||(o.add(u),n.push(s))}return n.reverse()}},7727(t){t.exports=function(t,e,n){return Math.max(t,Math.min(e,n))}},9870(t){t.exports=function(t,e){return t.setHours(t.getHours()+e),t}},5799(t){t.exports=function(t,e){return t.setMilliseconds(t.getMilliseconds()+e),t}},3160(t){t.exports=function(t,e){return t.setMinutes(t.getMinutes()+e),t}},1570(t){t.exports=function(t,e){if(!e)return t;const n=t.getDate();return t.setMonth(t.getMonth()+e),t.getDate()!==n&&t.setDate(0),t}},9296(t){t.exports=function(t,e){return t.setSeconds(t.getSeconds()+e),t}},5488(t){t.exports=function(t,e){return Math.floor((t.getTime()-e.getTime())/1e3)}},3752(t){t.exports=function(t){const e=t.getFullYear();return e%4==0&&e%100!=0||e%400==0}},3150(t){t.exports=function(t){return t=Math.trunc(Math.abs(t)),[Math.floor(t/36e5),Math.floor(t%36e5/6e4),Math.floor(t%6e4/1e3),t%1e3]}},2806(t){t.exports=function(t,e){return t.getTime()-e.getTime()}},8310(t,e,n){const r=n(7668);t.exports=function(t,e){return"string"==typeof t&&"string"==typeof e?r(t,e):t<e?-1:t>e?1:0}},2092(t,e,n){const r=n(8310);t.exports=function(t,e){return r(e,t)}},3553(t){function e(t){return"-"===t[0]?(t=t.slice(1),function(e,r){return n(r[t],e[t])}):function(e,r){return n(e[t],r[t])}}function n(t,e){return"string"==typeof t&&"string"==typeof e?t.localeCompare(e):t-e}t.exports=function(t){const n=t.map(e);switch(n.length){case 0:return()=>0;case 1:return n[0];case 2:return function(t,e){return n[0](t,e)||n[1](t,e)};case 3:return function(t,e){return n[0](t,e)||n[1](t,e)||n[2](t,e)};default:return function(t,e){for(let r=0;r<n.length;++r){const o=n[r](t,e);if(o)return o}return 0}}}},3129(t){t.exports=function(t,e){return t-e}},4332(t,e,n){const r=n(8310);t.exports=function(t,e,n=r){const o=Math.min(t.length,e.length);for(let r=0;r<o;++r){const o=n(t[r],e[r]);if(o)return o}return 0}},3106(t){t.exports=function(t,e){return t<e?-1:t>e?1:0}},2271(t){t.exports=function(t,e){return t.localeCompare(e,void 0,{sensitivity:"base"})}},4457(t){t.exports=function(t,e){return t.localeCompare(e,void 0,{sensitivity:"variant"})}},7668(t){function e(t,e){const r=t.replace(/^0+/,""),o=e.replace(/^0+/,"");return r.length-o.length||n(r,o)||t.length-e.length}function n(t,e){return t<e?-1:t>e?1:0}t.exports=function(t,r){const o=t.match(/\d+|\D+/g)||[],s=r.match(/\d+|\D+/g)||[],u=Math.min(o.length,s.length);for(let t=0;t<u;++t){const r=o[t][0]<="9"&&s[t][0]<="9"&&o[t][0]>="0"&&s[t][0]>="0"?e(o[t],s[t]):n(o[t],s[t]);if(r)return r}return o.length-s.length}},4385(t){t.exports=function(t,e){return t.localeCompare(e,void 0,{numeric:!0,sensitivity:"base"})}},8951(t){t.exports=function(t,e){return t.localeCompare(e,void 0,{numeric:!0,sensitivity:"variant"})}},4734(t,e,n){const r=n(8310),o=n(2092),s=n(956),u=Symbol("fcmpx.missing");function c(t){const{read:e,fcmp:n}=a(t);return function(t,r){return n(e(t),e(r))}}function a(t){if("function"==typeof t)return{read:i(t),fcmp:f(r)};if("string"==typeof t){const e=t.startsWith("-");return{read:i(e?t.slice(1):t),fcmp:f(e?o:r)}}const e=t.fcmp,n=i(t.read),s=f(t.desc?e?(t,n)=>e(n,t):o:e??r);if(Array.isArray(t.top)){const e=new Map(t.top.map((t,e)=>[t,e]));return{read:t=>e.get(n(t))??e.size,fcmp:s}}if(Array.isArray(t.bottom)){const e=new Map(t.bottom.map((t,e)=>[t,e]));return{read:t=>e.get(n(t))??-1,fcmp:s}}return{read:n,fcmp:s}}function i(t){if(void 0===t||""===t||"."===t)return s;if("function"==typeof t)return function(e){return t(e)??u};if("string"==typeof t){const e=t.split("."),[n,r,o,s,c]=e;switch(e.length){case 1:return t=>t?.[n]??u;case 2:return t=>t?.[n]?.[r]??u;case 3:return t=>t?.[n]?.[r]?.[o]??u;case 4:return t=>t?.[n]?.[r]?.[o]?.[s]??u;case 5:return t=>t?.[n]?.[r]?.[o]?.[s]?.[c]??u;default:return t=>e.reduce((t,e)=>t?.[e],t)??u}}return e=>e?.[t]??u}function f(t){return function(e,n){return e===u?n===u?0:1:n===u?-1:t(e,n)}}t.exports=function t(e){if("string"==typeof e)return e.includes(",")?t(e.split(",")):c(e);if(!Array.isArray(e))return c(e);const n=e.map(a);return function(t,e){const r=n.map(e=>e.read(t)),o=n.map(t=>t.read(e));for(let t=0;t<n.length;++t){const e=n[t].fcmp(r[t],o[t]);if(e)return e}return 0}}},7960(t){function e(t){let e,n,r;return e=t.replaceAll("^",""),n=e.length!==t.length,e=(t=e).replaceAll("$",""),r=e.length!==t.length,e=(t=e).replaceAll("!",""),(t.length-e.length)%2?n&&r?t=>!(t.startsWith(e)&&t.endsWith(e)):n?t=>!t.startsWith(e):r?t=>!t.endsWith(e):t=>!t.includes(e):n&&r?t=>t.startsWith(e)&&t.endsWith(e):n?t=>t.startsWith(e):r?t=>t.endsWith(e):t=>t.includes(e)}t.exports=function(t){let n,r,o,s;const u=function(t){return t.split("/").filter(t=>t).map(e)}(t);switch(u.length){case 0:return()=>!0;case 1:return u[0];case 2:return[n,r]=u,t=>n(t)&&r(t);case 3:return[n,r,o]=u,t=>n(t)&&r(t)&&o(t);case 4:return[n,r,o,s]=u,t=>n(t)&&r(t)&&o(t)&&s(t);default:return t=>u.every(e=>e(t))}}},6017(t){t.exports=function(t){if("number"!=typeof t||Number.isNaN(t))return"n/a";if(!t)return"0KB";if(t<1024)return"1KB";const e=Math.floor(Math.log(t)/Math.log(1024));return`${(t/1024**e).toFixed(t>1048576?2:0)}${["B","KB","MB","GB","TB","PB"][e]}`.replace(/\.00/,".0")}},1284(t){t.exports=function(t){return t.getFullYear()+`/0${t.getMonth()+1}/0${t.getDate()} 0${t.getHours()}:0${t.getMinutes()}:0${t.getSeconds()}`.replace(/0(\d\d)/g,"$1")}},5224(t){function e(t){return t>9?`${t}`:`0${t}`}t.exports=function(t){return t.getFullYear()+e(t.getMonth()+1)+e(t.getDate())+"_"+(e(t.getHours())+e(t.getMinutes())+e(t.getSeconds()))}},1690(t){function e(t){return t>9?`${t}`:`0${t}`}t.exports=function(t){return t.getFullYear()+"/"+e(t.getMonth()+1)+"/"+e(t.getDate())+" "+e(t.getHours())+":"+e(t.getMinutes())+":"+e(t.getSeconds())}},6997(t){t.exports=function(t){return t.getFullYear()+`/0${t.getMonth()+1}/0${t.getDate()}`.replace(/0(\d\d)/g,"$1")}},9009(t,e,n){const r=n(3332);t.exports=function(t){return t?t.response?.status&&t.response?.statusText&&t.response?.config?function(t){return`\n${t.message??"n/a"}\n\n--- REQUEST ---\n\n${(t.response.config.method||"").toUpperCase()} ${t.response.config.url}\n\n${JSON.stringify(t.response.config.headers||{},null,4).slice(1,-1).replace(/^\s+|,$/gm,"").trim()}\n\n--- RESPONSE ---\n\n${t.response.status} ${t.response.statusText}\n\n${String(t.response.data??"").slice(0,10240)||"n/a"}\n\n--- STACK ---\n\n${t.stack??"n/a"}\n`.trimStart()}(t):t.config?function(t){return`\n${t.message??"n/a"}\n\n--- REQUEST ---\n\n${(t.config.method||"").toUpperCase()} ${t.config.url}\n\n${JSON.stringify(t.config.headers||{},null,4).slice(1,-1).replace(/^\s+|,$/gm,"").trim()}\n\n--- STACK ---\n\n${t.stack??"n/a"}\n`.trimStart()}(t):r({code:t.code,name:t.name,message:t.message??"n/a",stack:t.stack&&t.stack.split(/\n\s*/)},null,4):r({error:void 0===t?"---undefined---":t})}},6015(t){t.exports=function(t,e=6){const[n,r]=t;return(n+r/1e9).toFixed(e)+"s"}},4153(t){t.exports=function(t){if("number"!=typeof t||Number.isNaN(t))return"n/a";if(!t)return"0";if(t<1e3)return t.toFixed(0);const e=parseInt(Math.floor(Math.log(t)/Math.log(1e3)),10);return`${(t/1e3**e).toFixed(2)}${["","K","M","G","T","P"][e]}`}},1120(t,e,n){const r=n(3150);t.exports=function(t){t||(t=0);const e=t<0?"-":"",[n,o,s]=r(t);return n?e+`0${n}:0${o}:0${s}`.replace(/0+(?=\d\d)/g,""):e+`0${o}:0${s}`.replace(/0+(?=\d\d)/g,"")}},7336(t,e,n){const r=n(3150);t.exports=function(t){t||(t=0);const e=t<0?"-":"",[n,o,s,u]=r(10*Math.round(Math.abs(t)/10));return n?e+`0${n}:0${o}:0${s}.0${u/10}`.replace(/0+(?=\d\d)/g,""):e+`0${o}:0${s}.0${u/10}`.replace(/0+(?=\d\d)/g,"")}},495(t,e,n){const r=n(3150);t.exports=function(t,e=!1){t||(t=0);const n=t<0?"-":"",[o,s,u,c]=r(t);return o||e?n+`0${o}:0${s}:0${u}.00${c}`.replace(/0+(?=\d\d+[:.]|\d\d\d)/g,""):n+`0${s}:0${u}.00${c}`.replace(/0+(?=\d\d+[:.]|\d\d\d)/g,"")}},7882(t){t.exports=function(t){return(100*t).toFixed(2).replace(/^(0|100).00$/,"$1")+"%"}},7111(t,e,n){const r=n(6017),o=n(7882),s=n(3527),u=n(5392);t.exports=function({percents:t,total:e,done:n,rate:c,eta:a,duration:i}){const f=u(c,0)?`${r(c)}/s`:"~";if(n>e)return`${r(n)} at ${f} duration=${s(i)}`;if(u(e,0)){const c=u(a,0)?s(a):"~";return`${o(t)} | ${r(n)} of ${r(e)} at ${f} ETA ${c} duration=${s(i)}`}return u(n,0)?`${r(n)} of ~ at ${f} duration=${s(i)}`:u(i,0)?`~ duration=${s(i)}`:"~"}},5051(t,e,n){const r=n(4153),o=n(7882),s=n(3527),u=n(5392);t.exports=function({percents:t,total:e,done:n,rate:c,eta:a,duration:i}){const f=u(c,0)?`${r(c)}/s`:"~";if(n>e)return`${r(n)} at ${f} duration=${s(i)}`;if(u(e,0)){const c=u(a,0)?s(a):"~";return`${o(t)} | ${r(n)} of ${r(e)} at ${f} ETA ${c} duration=${s(i)}`}return u(n,0)?`${r(n)} of ~ at ${f} duration=${s(i)}`:u(i,0)?`~ duration=${s(i)}`:"~"}},3527(t){t.exports=function(t){const e=Math.abs(Math.trunc(t)),n=`0${Math.floor(e/60/60)}:0${Math.floor(e/60)%60}:0${e%60}`.replace(/0(\d\d)/g,"$1");return t<=-1?"-"+n:n}},2677(t){t.exports=function(t){return t.toString().replace(/\B(?<!\.\d*)(?=(\d{3})+(?!\d))/g,",")}},4206(t,e,n){const r=n(3719);t.exports=function(t,e){return r.delete(t,{responseType:"json",...e}).then(t=>t.data)}},4131(t,e,n){const r=n(3719);t.exports=function(t,e){return r.get(t,{responseType:"blob",...e}).then(t=>t.data)}},706(t,e,n){const r=n(3719);t.exports=function(t,e){return r.get(t,{responseType:"arraybuffer",...e}).then(t=>t.data)}},3066(t,e,n){const r=n(3719);t.exports=function(t,e){return r.get(t,{responseType:"json",...e}).then(t=>t.data)}},3019(t,e,n){const r=n(3719);t.exports=function(t,e){return r.get(t,{responseType:"text",responseEncoding:"utf8",...e}).then(t=>t.data)}},7379(t,e,n){const r=n(3719);t.exports=function(t,e){return r.head(t,e).then(t=>t.request.res.headers)}},2552(t,e,n){const r=n(3719);t.exports=function(t,e,n){return r.patch(t,e,n).then(t=>t.data)}},7484(t,e,n){const r=n(3719);t.exports=function(t,e,n){return r.post(t,e,n).then(t=>t.data)}},5420(t,e,n){const r=n(8241),o=n(3719);t.exports=function(t,e,n){const s=new r;for(let t=0,n=e.length;t<n;++t){const n=e[t];n.options?s.append(n.name,n.body,n.options):s.append(n.name,n.body)}if(s.getHeaders){const e={...n};return e.headers={...e.headers,...s.getHeaders()},Promise.resolve(o.post(t,s,e)).then(t=>t.data)}return Promise.resolve(o.post(t,s,n)).then(t=>t.data)}},4605(t,e,n){const r=n(3719);t.exports=function(t,e,n){return r.put(t,e,n).then(t=>t.data)}},6357(t,e,n){const r=n(3719);t.exports=function(t,e,n){return r.put(t,e,n).then(t=>t.data)}},2380(t,e,n){const r=n(3719);t.exports=async function(t,e,n){return r.put(t,e,n).then(t=>t.data)}},956(t){t.exports=function(t){return t}},1828(t){t.exports=function(){}},3332(t,e,n){const r=n(4106);t.exports=r},6785(t){t.exports=function t(e,n){return n?t(n,e%n):Math.abs(e)}},7347(t,e,n){const r=n(6785);t.exports=function(t,e){return Math.abs(t*e)/r(t,e)}},792(t){t.exports=function(t,e,n,r){return 0===t&&"string"==typeof r?r:t%10==1&&t%100!=11?e.split("#").join(t):n.split("#").join(t)}},131(t){t.exports=function(t,e){return Math.floor(Math.random()*(e-t+1)+t)}},4476(t){t.exports=function(t,e=1){if(0===e)return t;const n=1/e,r=Math.sign(t),o=function(t){if(Math.floor(t)===t)return 0;const[e,n]=t.toExponential().split("e"),r=(e.split(".")[1]||"").length;return Math.max(0,r-parseInt(n,10))}(e),s=1e-12*r,u=Math.round(t*n+s)/n;return Number(u.toFixed(o))}},7233(t){t.exports=function(t,e){const n=String(t||""),r=Object.entries(e||{});if(!r.length)return n;const o=n.indexOf("#"),s=-1===o?"":n.slice(o),u=-1===o?n:n.slice(0,o),c=u.indexOf("?"),a=-1===c?u:u.slice(0,c),i=-1===c?"":u.slice(c+1),f=new URLSearchParams(i);r.forEach(function([t,e]){switch(e){case null:case void 0:f.delete(t);break;case!0:f.set(t,"1");break;case!1:f.set(t,"0");break;default:f.set(t,String(e))}});const p=f.toString();return a+(p?`?${p}`:"")+s}},6966(t,e,n){const r=n(2468);t.exports=function(t){return new r(function(e,n){t(function(t,r){t?n(t):e(r)})})}},7072(t,e,n){const r={"./array_chunk.js":6083,"./array_chunk_balanced.js":2458,"./array_fps.js":353,"./array_gcd.js":6372,"./array_group.js":3537,"./array_group_map.js":2976,"./array_index.js":2166,"./array_lcm.js":7866,"./array_max.js":6772,"./array_min.js":42,"./array_permutations.js":3685,"./array_shuffle.js":4943,"./array_sort.js":2356,"./array_sort_other.js":5181,"./array_sum.js":453,"./array_unique.js":3523,"./array_unique_last.js":6382,"./date_add_hours.js":9870,"./date_add_milliseconds.js":5799,"./date_add_minutes.js":3160,"./date_add_months.js":1570,"./date_add_seconds.js":9296,"./date_diff_seconds.js":5488,"./date_is_leap_year.js":3752,"./fcmp_dates.js":2806,"./fcmp_default.js":8310,"./fcmp_default_desc.js":2092,"./fcmp_from_spec.js":3553,"./fcmp_numbers.js":3129,"./fcmp_tuples.js":4332,"./fcmp_utf8_bin.js":3106,"./fcmp_utf8_ci.js":2271,"./fcmp_utf8_cs.js":4457,"./fcmp_utf8_natural_bin.js":7668,"./fcmp_utf8_natural_ci.js":4385,"./fcmp_utf8_natural_cs.js":8951,"./fcmpx.js":4734,"./filter1_from_spec.js":7960,"./format_bytes.js":6017,"./format_date.js":1284,"./format_date_fs.js":5224,"./format_date_human.js":1690,"./format_date_ymd.js":6997,"./format_error_report.js":9009,"./format_hrtime.js":6015,"./format_kilo.js":4153,"./format_ms.js":1120,"./format_ms2.js":7336,"./format_ms3.js":495,"./format_percents.js":7882,"./format_progress_bytes.js":7111,"./format_progress_kilo.js":5051,"./format_seconds.js":3527,"./format_thousands.js":2677,"./http_delete.js":4206,"./http_get_blob.js":4131,"./http_get_buffer.js":706,"./http_get_json.js":3066,"./http_get_utf8.js":3019,"./http_head.js":7379,"./http_patch_json.js":2552,"./http_post_json.js":7484,"./http_post_multipart.js":5420,"./http_put_buffer.js":4605,"./http_put_json.js":6357,"./http_put_utf8.js":2380,"./identity.js":956,"./ignore.js":1828,"./plural.js":792,"./random_int.js":131,"./urlmod.js":7233,"./waitcb.js":6966};function o(t){const e=s(t);return n(e)}function s(t){if(!n.o(r,t)){const e=new Error("Cannot find module '"+t+"'");throw e.code="MODULE_NOT_FOUND",e}return r[t]}o.keys=function(){return Object.keys(r)},o.resolve=s,t.exports=o,o.id=7072},8241(t){"use strict";t.exports=FormData},2468(t){"use strict";t.exports=Promise},3719(t){"use strict";t.exports=axios}};const e={};function n(r){const o=e[r];if(void 0!==o)return o.exports;const s=e[r]={exports:{}};return t[r](s,s.exports,n),s.exports}n.o=(t,e)=>Object.prototype.hasOwnProperty.call(t,e);const r=new URL(document.currentScript.src).searchParams.get("var")??"h";if(void 0!==window[r])console.log(`❌ @vbarbarosh/node-helpers@3.76.1 was not injected — window.${r} is already in use`);else{console.log(`🎉 @vbarbarosh/node-helpers@3.76.1 successfully exposed as window.${r}`),window[r]={};const t=n(7072);t.keys().forEach(function(e){const[,n]=e.match(/([^/]+)\.js$/);window[r][n]=t(e)})}})();
|
|
1
|
+
(()=>{var t={932(t){t.exports=function(t){return"number"==typeof t&&isFinite(t)}},5392(t,e,n){const r=n(932);t.exports=function(t,e){return r(t)&&t>e}},4106(t,e){function n(t,e){var n=[],r=[];return null==e&&(e=function(t,e){return n[0]===e?"[Circular ~]":"[Circular ~."+r.slice(0,n.indexOf(e)).join(".")+"]"}),function(o,s){if(n.length>0){var u=n.indexOf(this);~u?n.splice(u+1):n.push(this),~u?r.splice(u,1/0,o):r.push(o),~n.indexOf(s)&&(s=e.call(this,o,s))}else n.push(s);return null==t?s:t.call(this,o,s)}}(t.exports=function(t,e,r,o){return JSON.stringify(t,n(e,o),r)}).getSerialize=n},6083(t){t.exports=function(t=[],e=1){if(e<1)throw new Error("Limit value should be at least 1");const n=[];for(let r=0,o=t.length;r<o;r+=e)n.push(t.slice(r,r+e));return n}},2458(t,e,n){const r=n(7727);t.exports=function(t=[],e=1,n=1){const o=r(1,e,Math.floor(t.length/n)),s=Math.floor(t.length/o);let u=t.length%o;const c=[];for(let e=0;e<t.length;){const n=s+(u?1:0);c.push(t.slice(e,e+n)),e+=n,u&&u--}return c}},353(t,e,n){const r=n(4476),o=1e-5;t.exports=function(t,e){const n=Math.floor(t*e);if(n<=1)return[0];const s=[];for(let e=0;e<n;++e)s.push(r(e/(n-1)*(t-o),o));return s}},6372(t,e,n){const r=n(6785);t.exports=function(t,e=Number){return t.map(t=>e(t)).reduce((t,e)=>r(t,e),0)}},3537(t){t.exports=function(t,e){const n=new Map;return t.forEach(function(t){const r=e(t);n.has(r)||n.set(r,{key:r,items:[]}),n.get(r).items.push(t)}),n.values().toArray()}},2976(t){t.exports=function(t,e){const n={};return t.forEach(function(t){const r=e(t);n[r]=n[r]||{key:r,items:[]},n[r].items.push(t)}),n}},2166(t,e,n){const r=n(956);t.exports=function(t,e=r){const n={};return t.forEach(t=>n[e(t)]=t),n}},7866(t,e,n){const r=n(7347);t.exports=function(t,e=Number){return t.map(t=>e(t)).reduce((t,e)=>r(t,e),1)}},6772(t,e,n){const r=n(956);t.exports=function(t,e=r){let n=null,o=null,s=!1;return t.forEach(function(t){const r=e(t);Number.isNaN(r)||(!s||o<r)&&(s=!0,o=r,n=t)}),n}},42(t,e,n){const r=n(956);t.exports=function(t,e=r){let n=null,o=null,s=!1;return t.forEach(function(t){const r=e(t);Number.isNaN(r)||(!s||o>r)&&(s=!0,o=r,n=t)}),n}},3685(t){t.exports=function t(e,n=e.length){if(n!==e.length)return function(e,n){if(0===n)return[[]];if(e.length<n)return[];const r=[];for(let o=0;o<e.length;o++){const s=e.slice(0,o).concat(e.slice(o+1));for(const u of t(s,n-1))r.push([e[o],...u])}return r}(e,n);let r,o,s=(e=e.slice()).length,u=[e.slice()],c=new Array(s).fill(0),a=1;for(;a<s;)c[a]<a?(r=a%2&&c[a],o=e[a],e[a]=e[r],e[r]=o,++c[a],a=1,u.push(e.slice())):(c[a]=0,++a);return u}},4943(t){t.exports=function(t){for(let e=t.length;--e>0;){const n=Math.floor(Math.random()*(e+1)),r=t[e];t[e]=t[n],t[n]=r}return t}},2356(t,e,n){const r=n(8310),o=n(4332);t.exports=function(t,e,n=r){const s=new Map;return t.sort(function(t,r){if(!s.has(t)){const n=e(t);s.set(t,Array.isArray(n)?n:[n])}if(!s.has(r)){const t=e(r);s.set(r,Array.isArray(t)?t:[t])}return o(s.get(t),s.get(r),n)})}},5181(t,e,n){const r=n(8310);t.exports=function(t,e,n,o=r){const s=Object.create(null);return n.forEach((t,e)=>s[t]=e+1),t.sort(function(t,n){const r=s[e(t)],u=s[e(n)];return r&&u?r-u:r?-1:u?1:o(t,n)})}},453(t){t.exports=function(t,e=Number){let n=0;return t.forEach(function(t){n+=e(t)}),n}},3523(t,e,n){const r=n(956);t.exports=function(t,e=r){const n=new Set;return t.filter(function(t){const r=e(t);return!n.has(r)&&(n.add(r),!0)})}},6382(t,e,n){const r=n(956);t.exports=function(t,e=r){const n=[],o=new Set;for(let r=t.length;--r>=0;){const s=t[r],u=e(s);o.has(u)||(o.add(u),n.push(s))}return n.reverse()}},7727(t){t.exports=function(t,e,n){return Math.max(t,Math.min(e,n))}},9870(t){t.exports=function(t,e){return t.setHours(t.getHours()+e),t}},5799(t){t.exports=function(t,e){return t.setMilliseconds(t.getMilliseconds()+e),t}},3160(t){t.exports=function(t,e){return t.setMinutes(t.getMinutes()+e),t}},1570(t){t.exports=function(t,e){if(!e)return t;const n=t.getDate();return t.setMonth(t.getMonth()+e),t.getDate()!==n&&t.setDate(0),t}},9296(t){t.exports=function(t,e){return t.setSeconds(t.getSeconds()+e),t}},5488(t){t.exports=function(t,e){return Math.floor((t.getTime()-e.getTime())/1e3)}},3752(t){t.exports=function(t){const e=t.getFullYear();return e%4==0&&e%100!=0||e%400==0}},3150(t){t.exports=function(t){return t=Math.trunc(Math.abs(t)),[Math.floor(t/36e5),Math.floor(t%36e5/6e4),Math.floor(t%6e4/1e3),t%1e3]}},2806(t){t.exports=function(t,e){return t.getTime()-e.getTime()}},8310(t,e,n){const r=n(7668);t.exports=function(t,e){return"string"==typeof t&&"string"==typeof e?r(t,e):t<e?-1:t>e?1:0}},2092(t,e,n){const r=n(8310);t.exports=function(t,e){return r(e,t)}},3553(t){function e(t){return"-"===t[0]?(t=t.slice(1),function(e,r){return n(r[t],e[t])}):function(e,r){return n(e[t],r[t])}}function n(t,e){return"string"==typeof t&&"string"==typeof e?t.localeCompare(e):t-e}t.exports=function(t){const n=t.map(e);switch(n.length){case 0:return()=>0;case 1:return n[0];case 2:return function(t,e){return n[0](t,e)||n[1](t,e)};case 3:return function(t,e){return n[0](t,e)||n[1](t,e)||n[2](t,e)};default:return function(t,e){for(let r=0;r<n.length;++r){const o=n[r](t,e);if(o)return o}return 0}}}},3129(t){t.exports=function(t,e){return t-e}},4332(t,e,n){const r=n(8310);t.exports=function(t,e,n=r){const o=Math.min(t.length,e.length);for(let r=0;r<o;++r){const o=n(t[r],e[r]);if(o)return o}return 0}},3106(t){t.exports=function(t,e){return t<e?-1:t>e?1:0}},2271(t){t.exports=function(t,e){return t.localeCompare(e,void 0,{sensitivity:"base"})}},4457(t){t.exports=function(t,e){return t.localeCompare(e,void 0,{sensitivity:"variant"})}},7668(t){function e(t,e){const r=t.replace(/^0+/,""),o=e.replace(/^0+/,"");return r.length-o.length||n(r,o)||t.length-e.length}function n(t,e){return t<e?-1:t>e?1:0}t.exports=function(t,r){const o=t.match(/\d+|\D+/g)||[],s=r.match(/\d+|\D+/g)||[],u=Math.min(o.length,s.length);for(let t=0;t<u;++t){const r=o[t][0]<="9"&&s[t][0]<="9"&&o[t][0]>="0"&&s[t][0]>="0"?e(o[t],s[t]):n(o[t],s[t]);if(r)return r}return o.length-s.length}},4385(t){t.exports=function(t,e){return t.localeCompare(e,void 0,{numeric:!0,sensitivity:"base"})}},8951(t){t.exports=function(t,e){return t.localeCompare(e,void 0,{numeric:!0,sensitivity:"variant"})}},4734(t,e,n){const r=n(8310),o=n(2092),s=n(956),u=Symbol("fcmpx.missing");function c(t){const{read:e,fcmp:n}=a(t);return function(t,r){return n(e(t),e(r))}}function a(t){if("function"==typeof t)return{read:i(t),fcmp:f(r)};if("string"==typeof t){const e=t.startsWith("-");return{read:i(e?t.slice(1):t),fcmp:f(e?o:r)}}const e=t.fcmp,n=i(t.read),s=f(t.desc?e?(t,n)=>e(n,t):o:e??r);if(Array.isArray(t.top)){const e=new Map(t.top.map((t,e)=>[t,e]));return{read:t=>e.get(n(t))??e.size,fcmp:s}}if(Array.isArray(t.bottom)){const e=new Map(t.bottom.map((t,e)=>[t,e]));return{read:t=>e.get(n(t))??-1,fcmp:s}}return{read:n,fcmp:s}}function i(t){if(void 0===t||""===t||"."===t)return s;if("function"==typeof t)return function(e){return t(e)??u};if("string"==typeof t){const e=t.split("."),[n,r,o,s,c]=e;switch(e.length){case 1:return t=>t?.[n]??u;case 2:return t=>t?.[n]?.[r]??u;case 3:return t=>t?.[n]?.[r]?.[o]??u;case 4:return t=>t?.[n]?.[r]?.[o]?.[s]??u;case 5:return t=>t?.[n]?.[r]?.[o]?.[s]?.[c]??u;default:return t=>e.reduce((t,e)=>t?.[e],t)??u}}return e=>e?.[t]??u}function f(t){return function(e,n){return e===u?n===u?0:1:n===u?-1:t(e,n)}}t.exports=function t(e){if("string"==typeof e)return e.includes(",")?t(e.split(",")):c(e);if(!Array.isArray(e))return c(e);const n=e.map(a);return function(t,e){const r=n.map(e=>e.read(t)),o=n.map(t=>t.read(e));for(let t=0;t<n.length;++t){const e=n[t].fcmp(r[t],o[t]);if(e)return e}return 0}}},7960(t){function e(t){let e,n,r;return e=t.replaceAll("^",""),n=e.length!==t.length,e=(t=e).replaceAll("$",""),r=e.length!==t.length,e=(t=e).replaceAll("!",""),(t.length-e.length)%2?n&&r?t=>!(t.startsWith(e)&&t.endsWith(e)):n?t=>!t.startsWith(e):r?t=>!t.endsWith(e):t=>!t.includes(e):n&&r?t=>t.startsWith(e)&&t.endsWith(e):n?t=>t.startsWith(e):r?t=>t.endsWith(e):t=>t.includes(e)}t.exports=function(t){let n,r,o,s;const u=function(t){return t.split("/").filter(t=>t).map(e)}(t);switch(u.length){case 0:return()=>!0;case 1:return u[0];case 2:return[n,r]=u,t=>n(t)&&r(t);case 3:return[n,r,o]=u,t=>n(t)&&r(t)&&o(t);case 4:return[n,r,o,s]=u,t=>n(t)&&r(t)&&o(t)&&s(t);default:return t=>u.every(e=>e(t))}}},6017(t){t.exports=function(t){if("number"!=typeof t||Number.isNaN(t))return"n/a";if(!t)return"0KB";if(t<1024)return"1KB";const e=Math.floor(Math.log(t)/Math.log(1024));return`${(t/1024**e).toFixed(t>1048576?2:0)}${["B","KB","MB","GB","TB","PB"][e]}`.replace(/\.00/,".0")}},1284(t){t.exports=function(t){return t.getFullYear()+`/0${t.getMonth()+1}/0${t.getDate()} 0${t.getHours()}:0${t.getMinutes()}:0${t.getSeconds()}`.replace(/0(\d\d)/g,"$1")}},5224(t){function e(t){return t>9?`${t}`:`0${t}`}t.exports=function(t){return t.getFullYear()+e(t.getMonth()+1)+e(t.getDate())+"_"+(e(t.getHours())+e(t.getMinutes())+e(t.getSeconds()))}},1690(t){function e(t){return t>9?`${t}`:`0${t}`}t.exports=function(t){return t.getFullYear()+"/"+e(t.getMonth()+1)+"/"+e(t.getDate())+" "+e(t.getHours())+":"+e(t.getMinutes())+":"+e(t.getSeconds())}},6997(t){t.exports=function(t){return t.getFullYear()+`/0${t.getMonth()+1}/0${t.getDate()}`.replace(/0(\d\d)/g,"$1")}},9009(t,e,n){const r=n(3332);t.exports=function(t){return t?t.response?.status&&t.response?.statusText&&t.response?.config?function(t){return`\n${t.message??"n/a"}\n\n--- REQUEST ---\n\n${(t.response.config.method||"").toUpperCase()} ${t.response.config.url}\n\n${JSON.stringify(t.response.config.headers||{},null,4).slice(1,-1).replace(/^\s+|,$/gm,"").trim()}\n\n--- RESPONSE ---\n\n${t.response.status} ${t.response.statusText}\n\n${String(t.response.data??"").slice(0,10240)||"n/a"}\n\n--- STACK ---\n\n${t.stack??"n/a"}\n`.trimStart()}(t):t.config?function(t){return`\n${t.message??"n/a"}\n\n--- REQUEST ---\n\n${(t.config.method||"").toUpperCase()} ${t.config.url}\n\n${JSON.stringify(t.config.headers||{},null,4).slice(1,-1).replace(/^\s+|,$/gm,"").trim()}\n\n--- STACK ---\n\n${t.stack??"n/a"}\n`.trimStart()}(t):r({code:t.code,name:t.name,message:t.message??"n/a",stack:t.stack&&t.stack.split(/\n\s*/)},null,4):r({error:void 0===t?"---undefined---":t})}},6015(t){t.exports=function(t,e=6){const[n,r]=t;return(n+r/1e9).toFixed(e)+"s"}},4153(t){t.exports=function(t){if("number"!=typeof t||Number.isNaN(t))return"n/a";if(!t)return"0";if(t<1e3)return t.toFixed(0);const e=parseInt(Math.floor(Math.log(t)/Math.log(1e3)),10);return`${(t/1e3**e).toFixed(2)}${["","K","M","G","T","P"][e]}`}},1120(t,e,n){const r=n(3150);t.exports=function(t){t||(t=0);const e=t<0?"-":"",[n,o,s]=r(t);return n?e+`0${n}:0${o}:0${s}`.replace(/0+(?=\d\d)/g,""):e+`0${o}:0${s}`.replace(/0+(?=\d\d)/g,"")}},7336(t,e,n){const r=n(3150);t.exports=function(t){t||(t=0);const e=t<0?"-":"",[n,o,s,u]=r(10*Math.round(Math.abs(t)/10));return n?e+`0${n}:0${o}:0${s}.0${u/10}`.replace(/0+(?=\d\d)/g,""):e+`0${o}:0${s}.0${u/10}`.replace(/0+(?=\d\d)/g,"")}},495(t,e,n){const r=n(3150);t.exports=function(t,e=!1){t||(t=0);const n=t<0?"-":"",[o,s,u,c]=r(t);return o||e?n+`0${o}:0${s}:0${u}.00${c}`.replace(/0+(?=\d\d+[:.]|\d\d\d)/g,""):n+`0${s}:0${u}.00${c}`.replace(/0+(?=\d\d+[:.]|\d\d\d)/g,"")}},7882(t){t.exports=function(t){return(100*t).toFixed(2).replace(/^(0|100).00$/,"$1")+"%"}},7111(t,e,n){const r=n(6017),o=n(7882),s=n(3527),u=n(5392);t.exports=function({percents:t,total:e,done:n,rate:c,eta:a,duration:i}){const f=u(c,0)?`${r(c)}/s`:"~";if(n>e)return`${r(n)} at ${f} duration=${s(i)}`;if(u(e,0)){const c=u(a,0)?s(a):"~";return`${o(t)} | ${r(n)} of ${r(e)} at ${f} ETA ${c} duration=${s(i)}`}return u(n,0)?`${r(n)} of ~ at ${f} duration=${s(i)}`:u(i,0)?`~ duration=${s(i)}`:"~"}},5051(t,e,n){const r=n(4153),o=n(7882),s=n(3527),u=n(5392);t.exports=function({percents:t,total:e,done:n,rate:c,eta:a,duration:i}){const f=u(c,0)?`${r(c)}/s`:"~";if(n>e)return`${r(n)} at ${f} duration=${s(i)}`;if(u(e,0)){const c=u(a,0)?s(a):"~";return`${o(t)} | ${r(n)} of ${r(e)} at ${f} ETA ${c} duration=${s(i)}`}return u(n,0)?`${r(n)} of ~ at ${f} duration=${s(i)}`:u(i,0)?`~ duration=${s(i)}`:"~"}},3527(t){t.exports=function(t){const e=Math.abs(Math.trunc(t)),n=`0${Math.floor(e/60/60)}:0${Math.floor(e/60)%60}:0${e%60}`.replace(/0(\d\d)/g,"$1");return t<=-1?"-"+n:n}},2677(t){t.exports=function(t){return t.toString().replace(/\B(?<!\.\d*)(?=(\d{3})+(?!\d))/g,",")}},4206(t,e,n){const r=n(3719);t.exports=function(t,e){return r.delete(t,{responseType:"json",...e}).then(t=>t.data)}},4131(t,e,n){const r=n(3719);t.exports=function(t,e){return r.get(t,{responseType:"blob",...e}).then(t=>t.data)}},706(t,e,n){const r=n(3719);t.exports=function(t,e){return r.get(t,{responseType:"arraybuffer",...e}).then(t=>t.data)}},3066(t,e,n){const r=n(3719);t.exports=function(t,e){return r.get(t,{responseType:"json",...e}).then(t=>t.data)}},3019(t,e,n){const r=n(3719);t.exports=function(t,e){return r.get(t,{responseType:"text",responseEncoding:"utf8",...e}).then(t=>t.data)}},7379(t,e,n){const r=n(3719);t.exports=function(t,e){return r.head(t,e).then(t=>t.request.res.headers)}},2552(t,e,n){const r=n(3719);t.exports=function(t,e,n){return r.patch(t,e,n).then(t=>t.data)}},7484(t,e,n){const r=n(3719);t.exports=function(t,e,n){return r.post(t,e,n).then(t=>t.data)}},5420(t,e,n){const r=n(8241),o=n(3719);t.exports=function(t,e,n){const s=new r;for(let t=0,n=e.length;t<n;++t){const n=e[t];n.options?s.append(n.name,n.body,n.options):s.append(n.name,n.body)}if(s.getHeaders){const e={...n};return e.headers={...e.headers,...s.getHeaders()},Promise.resolve(o.post(t,s,e)).then(t=>t.data)}return Promise.resolve(o.post(t,s,n)).then(t=>t.data)}},4605(t,e,n){const r=n(3719);t.exports=function(t,e,n){return r.put(t,e,n).then(t=>t.data)}},6357(t,e,n){const r=n(3719);t.exports=function(t,e,n){return r.put(t,e,n).then(t=>t.data)}},2380(t,e,n){const r=n(3719);t.exports=async function(t,e,n){return r.put(t,e,n).then(t=>t.data)}},956(t){t.exports=function(t){return t}},1828(t){t.exports=function(){}},3332(t,e,n){const r=n(4106);t.exports=r},6785(t){t.exports=function t(e,n){return n?t(n,e%n):Math.abs(e)}},7347(t,e,n){const r=n(6785);t.exports=function(t,e){return Math.abs(t*e)/r(t,e)}},792(t){t.exports=function(t,e,n,r){return 0===t&&"string"==typeof r?r:t%10==1&&t%100!=11?e.split("#").join(t):n.split("#").join(t)}},131(t){t.exports=function(t,e){return Math.floor(Math.random()*(e-t+1)+t)}},4476(t){t.exports=function(t,e=1){if(0===e)return t;const n=1/e,r=Math.sign(t),o=function(t){if(Math.floor(t)===t)return 0;const[e,n]=t.toExponential().split("e"),r=(e.split(".")[1]||"").length;return Math.max(0,r-parseInt(n,10))}(e),s=1e-12*r,u=Math.round(t*n+s)/n;return Number(u.toFixed(o))}},7233(t){t.exports=function(t,e){const n=String(t||""),r=Object.entries(e||{});if(!r.length)return n;const o=n.indexOf("#"),s=-1===o?"":n.slice(o),u=-1===o?n:n.slice(0,o),c=u.indexOf("?"),a=-1===c?u:u.slice(0,c),i=-1===c?"":u.slice(c+1),f=new URLSearchParams(i);r.forEach(function([t,e]){switch(e){case null:case void 0:f.delete(t);break;case!0:f.set(t,"1");break;case!1:f.set(t,"0");break;default:f.set(t,String(e))}});const p=f.toString();return a+(p?`?${p}`:"")+s}},6966(t,e,n){const r=n(2468);t.exports=function(t){return new r(function(e,n){t(function(t,r){t?n(t):e(r)})})}},7072(t,e,n){const r={"./array_chunk.js":6083,"./array_chunk_balanced.js":2458,"./array_fps.js":353,"./array_gcd.js":6372,"./array_group.js":3537,"./array_group_map.js":2976,"./array_index.js":2166,"./array_lcm.js":7866,"./array_max.js":6772,"./array_min.js":42,"./array_permutations.js":3685,"./array_shuffle.js":4943,"./array_sort.js":2356,"./array_sort_other.js":5181,"./array_sum.js":453,"./array_unique.js":3523,"./array_unique_last.js":6382,"./date_add_hours.js":9870,"./date_add_milliseconds.js":5799,"./date_add_minutes.js":3160,"./date_add_months.js":1570,"./date_add_seconds.js":9296,"./date_diff_seconds.js":5488,"./date_is_leap_year.js":3752,"./fcmp_dates.js":2806,"./fcmp_default.js":8310,"./fcmp_default_desc.js":2092,"./fcmp_from_spec.js":3553,"./fcmp_numbers.js":3129,"./fcmp_tuples.js":4332,"./fcmp_utf8_bin.js":3106,"./fcmp_utf8_ci.js":2271,"./fcmp_utf8_cs.js":4457,"./fcmp_utf8_natural_bin.js":7668,"./fcmp_utf8_natural_ci.js":4385,"./fcmp_utf8_natural_cs.js":8951,"./fcmpx.js":4734,"./filter1_from_spec.js":7960,"./format_bytes.js":6017,"./format_date.js":1284,"./format_date_fs.js":5224,"./format_date_human.js":1690,"./format_date_ymd.js":6997,"./format_error_report.js":9009,"./format_hrtime.js":6015,"./format_kilo.js":4153,"./format_ms.js":1120,"./format_ms2.js":7336,"./format_ms3.js":495,"./format_percents.js":7882,"./format_progress_bytes.js":7111,"./format_progress_kilo.js":5051,"./format_seconds.js":3527,"./format_thousands.js":2677,"./http_delete.js":4206,"./http_get_blob.js":4131,"./http_get_buffer.js":706,"./http_get_json.js":3066,"./http_get_utf8.js":3019,"./http_head.js":7379,"./http_patch_json.js":2552,"./http_post_json.js":7484,"./http_post_multipart.js":5420,"./http_put_buffer.js":4605,"./http_put_json.js":6357,"./http_put_utf8.js":2380,"./identity.js":956,"./ignore.js":1828,"./plural.js":792,"./random_int.js":131,"./urlmod.js":7233,"./waitcb.js":6966};function o(t){const e=s(t);return n(e)}function s(t){if(!n.o(r,t)){const e=new Error("Cannot find module '"+t+"'");throw e.code="MODULE_NOT_FOUND",e}return r[t]}o.keys=function(){return Object.keys(r)},o.resolve=s,t.exports=o,o.id=7072},8241(t){"use strict";t.exports=FormData},2468(t){"use strict";t.exports=Promise},3719(t){"use strict";t.exports=axios}};const e={};function n(r){const o=e[r];if(void 0!==o)return o.exports;const s=e[r]={exports:{}};return t[r](s,s.exports,n),s.exports}n.o=(t,e)=>Object.prototype.hasOwnProperty.call(t,e);const r=new URL(document.currentScript.src).searchParams.get("var")??"h";if(void 0!==window[r])console.log(`❌ @vbarbarosh/node-helpers@3.77.0 was not injected — window.${r} is already in use`);else{console.log(`🎉 @vbarbarosh/node-helpers@3.77.0 successfully exposed as window.${r}`),window[r]={};const t=n(7072);t.keys().forEach(function(e){const[,n]=e.match(/([^/]+)\.js$/);window[r][n]=t(e)})}})();
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"author": "Vladimir Barbarosh <vladimir.barbarosh@gmail.com>",
|
|
3
3
|
"license": "MIT",
|
|
4
4
|
"name": "@vbarbarosh/node-helpers",
|
|
5
|
-
"version": "3.
|
|
5
|
+
"version": "3.77.0",
|
|
6
6
|
"description": "A set of helpers for JavaScript/Node.js",
|
|
7
7
|
"unpkg": "dist/browser.js",
|
|
8
8
|
"jsdelivr": "dist/browser.js",
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
const is_num_gt = require('@vbarbarosh/type-helpers/src/is_num_gt');
|
|
2
|
+
|
|
3
|
+
function assert_positive_integer(value, name = 'value')
|
|
4
|
+
{
|
|
5
|
+
if (!is_num_gt(value, 0) || !Number.isInteger(value)) {
|
|
6
|
+
throw new Error(`[${name}] should be a positive integer.`);
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
module.exports = assert_positive_integer;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
Asserts that `value` is a finite integer greater than or equal to `1`.
|
|
2
|
+
The optional `name` is included in the error message.
|
|
3
|
+
|
|
4
|
+
```js
|
|
5
|
+
assert_positive_integer(3, 'concurrency') // returns undefined
|
|
6
|
+
assert_positive_integer(0, 'concurrency') // throws Error
|
|
7
|
+
assert_positive_integer(1.5, 'concurrency') // throws Error
|
|
8
|
+
```
|
package/src/fastdl.js
CHANGED
|
@@ -1,12 +1,17 @@
|
|
|
1
1
|
const UserFriendlyError = require('./errors/UserFriendlyError');
|
|
2
|
+
const assert_positive_integer = require('./assert_positive_integer');
|
|
2
3
|
const format_bytes = require('./format_bytes');
|
|
3
4
|
const format_progress_bytes = require('./format_progress_bytes');
|
|
4
5
|
const format_thousands = require('./format_thousands');
|
|
5
6
|
const fs = require('fs');
|
|
6
7
|
const fs_path_basename = require('./fs_path_basename');
|
|
8
|
+
const fs_rename = require('./fs_rename');
|
|
9
|
+
const fs_rmf = require('./fs_rmf');
|
|
10
|
+
const fs_write = require('./fs_write');
|
|
7
11
|
const ignore = require('./ignore');
|
|
8
12
|
const make_progress = require('./make_progress');
|
|
9
13
|
const parallel = require('./parallel');
|
|
14
|
+
const random_hex = require('./random_hex');
|
|
10
15
|
const stream = require('stream');
|
|
11
16
|
|
|
12
17
|
/**
|
|
@@ -18,13 +23,32 @@ const stream = require('stream');
|
|
|
18
23
|
* });
|
|
19
24
|
*/
|
|
20
25
|
async function fastdl({file, read_stream_with_range, concurrency = 60, user_friendly_status = v => console.log(v)})
|
|
26
|
+
{
|
|
27
|
+
assert_positive_integer(concurrency, 'concurrency');
|
|
28
|
+
const tmp_file = `${file}.${process.pid}.${random_hex(8)}.tmp`;
|
|
29
|
+
try {
|
|
30
|
+
user_friendly_status(`Preparing destination file [${fs_path_basename(file)}]...`);
|
|
31
|
+
await fs_write(tmp_file, '', {flag: 'wx'});
|
|
32
|
+
await download({
|
|
33
|
+
concurrency,
|
|
34
|
+
file: tmp_file,
|
|
35
|
+
read_stream_with_range,
|
|
36
|
+
user_friendly_status,
|
|
37
|
+
});
|
|
38
|
+
await fs_rename(tmp_file, file);
|
|
39
|
+
}
|
|
40
|
+
finally {
|
|
41
|
+
await fs_rmf(tmp_file);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
async function download({file, read_stream_with_range, concurrency, user_friendly_status})
|
|
21
46
|
{
|
|
22
47
|
const M = 1024*1024;
|
|
23
48
|
const chunk_min_bytes = M;
|
|
24
49
|
const chunk_max_bytes = 50*M;
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
await fs.promises.writeFile(file, '');
|
|
50
|
+
const active_streams = new Set();
|
|
51
|
+
const writers = new Set();
|
|
28
52
|
|
|
29
53
|
user_friendly_status('Requesting first chunk to determine total size...');
|
|
30
54
|
const rs0 = await read_stream_with_range(0, chunk_min_bytes);
|
|
@@ -49,6 +73,11 @@ async function fastdl({file, read_stream_with_range, concurrency = 60, user_frie
|
|
|
49
73
|
try {
|
|
50
74
|
await parallel({concurrency, spawn});
|
|
51
75
|
}
|
|
76
|
+
catch (error) {
|
|
77
|
+
active_streams.forEach(v => v.destroy(error));
|
|
78
|
+
await Promise.all([...writers].map(v => v.catch(ignore)));
|
|
79
|
+
throw error;
|
|
80
|
+
}
|
|
52
81
|
finally {
|
|
53
82
|
tick();
|
|
54
83
|
clearInterval(timer);
|
|
@@ -66,7 +95,12 @@ async function fastdl({file, read_stream_with_range, concurrency = 60, user_frie
|
|
|
66
95
|
const last = Math.min(total - 1, first + (first === 0 ? rs0.content_range.last : chunk_size));
|
|
67
96
|
next_first = last + 1;
|
|
68
97
|
connections++;
|
|
69
|
-
|
|
98
|
+
const writer = Promise.resolve(run()).catch(run).catch(run).finally(function () {
|
|
99
|
+
connections--;
|
|
100
|
+
writers.delete(writer);
|
|
101
|
+
});
|
|
102
|
+
writers.add(writer);
|
|
103
|
+
return writer;
|
|
70
104
|
async function run() {
|
|
71
105
|
if (first > last) {
|
|
72
106
|
return;
|
|
@@ -89,8 +123,11 @@ async function fastdl({file, read_stream_with_range, concurrency = 60, user_frie
|
|
|
89
123
|
});
|
|
90
124
|
const ws = fs.createWriteStream(file, {
|
|
91
125
|
flags: fs.constants.O_WRONLY, // |fs.constants.O_CREAT,
|
|
126
|
+
flush: true,
|
|
92
127
|
start: first,
|
|
93
128
|
});
|
|
129
|
+
active_streams.add(rs);
|
|
130
|
+
active_streams.add(ws);
|
|
94
131
|
try {
|
|
95
132
|
await stream.promises.pipeline(rs, acc, ws);
|
|
96
133
|
}
|
|
@@ -100,6 +137,10 @@ async function fastdl({file, read_stream_with_range, concurrency = 60, user_frie
|
|
|
100
137
|
progress.add(-counted);
|
|
101
138
|
throw error;
|
|
102
139
|
}
|
|
140
|
+
finally {
|
|
141
|
+
active_streams.delete(rs);
|
|
142
|
+
active_streams.delete(ws);
|
|
143
|
+
}
|
|
103
144
|
}
|
|
104
145
|
}
|
|
105
146
|
}
|
package/src/fastdl.md
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
Download a file in several connections in parallel.
|
|
2
2
|
|
|
3
|
+
`concurrency` defaults to `60` and must be a positive integer.
|
|
4
|
+
|
|
5
|
+
All ranges are written to a unique temporary file beside `file`. After every
|
|
6
|
+
range completes and the final byte count is validated, the temporary file is
|
|
7
|
+
flushed, closed, and atomically renamed over `file`. A failed request, exhausted
|
|
8
|
+
retry, size mismatch, or write error removes the temporary file and preserves
|
|
9
|
+
an existing destination.
|
|
10
|
+
|
|
3
11
|
```js
|
|
4
12
|
await fastdl({
|
|
5
13
|
file: fs_path_basename(new URL(url).pathname),
|
package/src/http_get_file.js
CHANGED
|
@@ -1,17 +1,25 @@
|
|
|
1
1
|
const axios = require('axios');
|
|
2
2
|
const fs = require('fs');
|
|
3
|
+
const fs_rename = require('./fs_rename');
|
|
4
|
+
const fs_rmf = require('./fs_rmf');
|
|
5
|
+
const random_hex = require('./random_hex');
|
|
3
6
|
const stream = require('stream');
|
|
4
7
|
|
|
5
8
|
// https://stackoverflow.com/a/61269447
|
|
6
9
|
async function http_get_file(url, out_file, options)
|
|
7
10
|
{
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
11
|
+
const tmp_file = `${out_file}.${process.pid}.${random_hex(8)}.tmp`;
|
|
12
|
+
try {
|
|
13
|
+
const response = await axios.get(url, {responseType: 'stream', ...options});
|
|
14
|
+
await stream.promises.pipeline(response.data, fs.createWriteStream(tmp_file, {
|
|
15
|
+
flags: 'wx',
|
|
16
|
+
flush: true,
|
|
17
|
+
}));
|
|
18
|
+
await fs_rename(tmp_file, out_file);
|
|
19
|
+
}
|
|
20
|
+
finally {
|
|
21
|
+
await fs_rmf(tmp_file);
|
|
22
|
+
}
|
|
15
23
|
}
|
|
16
24
|
|
|
17
25
|
module.exports = http_get_file;
|
package/src/http_get_file.md
CHANGED
|
@@ -1,9 +1,13 @@
|
|
|
1
1
|
Downloads `url` into `out_file`.
|
|
2
2
|
|
|
3
|
-
-
|
|
4
|
-
|
|
3
|
+
- The response is written to a unique temporary file in the destination
|
|
4
|
+
directory, flushed, closed, and atomically renamed to `out_file` only after
|
|
5
|
+
the complete download succeeds.
|
|
6
|
+
- An HTTP error status (e.g. 404) rejects without creating `out_file`.
|
|
5
7
|
- Rejects when the server aborts the download mid-stream (no hanging) and
|
|
6
|
-
when `out_file` is not writable; both streams are destroyed
|
|
8
|
+
when `out_file` is not writable; both streams are destroyed and the
|
|
9
|
+
temporary file is removed on failure. An existing `out_file` remains
|
|
10
|
+
unchanged.
|
|
7
11
|
- `options` are passed through to `axios.get` (after
|
|
8
12
|
`responseType: 'stream'`).
|
|
9
13
|
|
|
@@ -2,12 +2,15 @@ const axios = require('axios');
|
|
|
2
2
|
const format_thousands = require('./format_thousands');
|
|
3
3
|
const parse_http_content_range = require('./parse_http_content_range');
|
|
4
4
|
|
|
5
|
-
async function http_get_stream_range(url, first, last)
|
|
5
|
+
async function http_get_stream_range(url, first, last, options)
|
|
6
6
|
{
|
|
7
7
|
const a = Number.isInteger(first) ? first : '';
|
|
8
8
|
const b = Number.isInteger(last) ? last : '';
|
|
9
|
-
const headers = {
|
|
10
|
-
|
|
9
|
+
const headers = {...options?.headers};
|
|
10
|
+
if (a !== '' || b !== '') {
|
|
11
|
+
headers.Range = `bytes=${a}-${b}`;
|
|
12
|
+
}
|
|
13
|
+
const res = await axios.get(url, {responseType: 'stream', ...options, headers});
|
|
11
14
|
const out = res.data;
|
|
12
15
|
out.headers = res.headers;
|
|
13
16
|
try {
|
|
@@ -27,15 +30,30 @@ async function http_get_stream_range(url, first, last)
|
|
|
27
30
|
out.destroy(); // release the socket; nobody will ever read this stream
|
|
28
31
|
throw error;
|
|
29
32
|
}
|
|
30
|
-
// A server reaching the end of the resource returns a shorter range than
|
|
31
|
-
// requested: `bytes=0-999999` of a 500-byte file is `bytes 0-499/500` (RFC 7233)
|
|
32
|
-
const expected_last = (b === '' || out.content_range.total === null) ? b : Math.min(b, out.content_range.total - 1);
|
|
33
33
|
if (a !== '' && out.content_range.first !== a) {
|
|
34
34
|
out.destroy(new Error(`First byte of a returned range (${fmt(out.content_range.first)}) is not as expected: [${fmt(a)}]`));
|
|
35
35
|
}
|
|
36
|
-
else if (
|
|
36
|
+
else if (a !== '' && b !== '') {
|
|
37
|
+
const expected_last = out.content_range.total === null ? b : Math.min(b, out.content_range.total - 1);
|
|
38
|
+
if (out.content_range.last !== expected_last) {
|
|
39
|
+
out.destroy(new Error(`Last byte of a returned range (${fmt(out.content_range.last)}) is not as expected: [${fmt(expected_last)}]`));
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
else if (a !== '' && out.content_range.total !== null && out.content_range.last !== out.content_range.total - 1) {
|
|
43
|
+
const expected_last = out.content_range.total - 1;
|
|
37
44
|
out.destroy(new Error(`Last byte of a returned range (${fmt(out.content_range.last)}) is not as expected: [${fmt(expected_last)}]`));
|
|
38
45
|
}
|
|
46
|
+
else if (b !== '') {
|
|
47
|
+
const actual_length = out.content_range.last - out.content_range.first + 1;
|
|
48
|
+
const expected_length = out.content_range.total === null ? Math.min(actual_length, b) : Math.min(out.content_range.total, b);
|
|
49
|
+
if (actual_length !== expected_length) {
|
|
50
|
+
out.destroy(new Error(`Length of a returned range (${fmt(actual_length)}) is not as expected: [${fmt(expected_length)}]`));
|
|
51
|
+
}
|
|
52
|
+
else if (out.content_range.total !== null && out.content_range.last !== out.content_range.total - 1) {
|
|
53
|
+
const expected_last = out.content_range.total - 1;
|
|
54
|
+
out.destroy(new Error(`Last byte of a returned range (${fmt(out.content_range.last)}) is not as expected: [${fmt(expected_last)}]`));
|
|
55
|
+
}
|
|
56
|
+
}
|
|
39
57
|
out.total = out.content_range.total;
|
|
40
58
|
return out;
|
|
41
59
|
}
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
GETs `url` with a `Range: bytes=first-last` header and returns the response
|
|
2
|
-
body as a readable stream.
|
|
3
|
-
|
|
4
|
-
a regular GET.
|
|
2
|
+
body as a readable stream. Omitting `last` requests `bytes=first-`; omitting
|
|
3
|
+
`first` requests the final `last` bytes with `bytes=-last`. When both are
|
|
4
|
+
omitted, the `Range` header is omitted and a regular GET is sent. Extra Axios
|
|
5
|
+
options are accepted as the fourth argument; caller headers are merged with
|
|
6
|
+
the computed `Range` header.
|
|
5
7
|
|
|
6
8
|
The stream gets extra properties attached: `headers` (raw response headers),
|
|
7
9
|
`content_range` (parsed `{type, first, last, total}`), and `total`. When the
|
|
@@ -9,11 +11,11 @@ server sends no `Content-Range`, it is synthesized from `Content-Length`; a
|
|
|
9
11
|
chunked 200 response (neither header) is accepted as
|
|
10
12
|
`{first: 0, last: null, total: null}` — body starts at byte 0, size unknown.
|
|
11
13
|
|
|
12
|
-
The returned range is validated
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
14
|
+
The returned range is validated according to the requested form. Closed ranges
|
|
15
|
+
accept a `last` clamped to the end of the resource; open-ended ranges must end
|
|
16
|
+
at the resource end when its size is known; suffix ranges validate their
|
|
17
|
+
length and resource end. A server that ignores a range and replies 200 is
|
|
18
|
+
rejected.
|
|
17
19
|
|
|
18
20
|
```js
|
|
19
21
|
const rs = await http_get_stream_range(url, 100, 199);
|
package/src/http_stream_range.js
CHANGED
|
@@ -86,6 +86,11 @@ async function http_stream_range(req, res, file)
|
|
|
86
86
|
|
|
87
87
|
for (let offset = first; offset <= last && !req_close; ) {
|
|
88
88
|
const chunk = await fs_fread(fp, buf, offset, Math.min(buf.length, last - offset + 1));
|
|
89
|
+
if (chunk.length === 0) {
|
|
90
|
+
const error = new Error(`File ended at byte ${offset} before the requested range ended at byte ${last}`);
|
|
91
|
+
error.code = 'ERR_HTTP_STREAM_RANGE_SHORT_READ';
|
|
92
|
+
throw error;
|
|
93
|
+
}
|
|
89
94
|
offset += chunk.length;
|
|
90
95
|
if (res.write(chunk)) {
|
|
91
96
|
// req.log(`[http_stream_range_write] ${chunk.length}`);
|
package/src/http_stream_range.md
CHANGED
|
@@ -22,7 +22,10 @@ http_stream_range(req, res, file) → Promise
|
|
|
22
22
|
`GET` and `HEAD` responses advertise `Accept-Ranges: bytes`.
|
|
23
23
|
|
|
24
24
|
Reads in 2 MiB chunks with an `fs_fread` loop, respecting backpressure
|
|
25
|
-
(`res.write` + `drain`) and stopping early when the client disconnects.
|
|
25
|
+
(`res.write` + `drain`) and stopping early when the client disconnects. If the
|
|
26
|
+
file becomes shorter than the size captured at the beginning of the request,
|
|
27
|
+
the handler rejects with code `ERR_HTTP_STREAM_RANGE_SHORT_READ` instead of
|
|
28
|
+
waiting indefinitely.
|
|
26
29
|
|
|
27
30
|
```js
|
|
28
31
|
app.get('/file', (req, res) => http_stream_range(req, res, '/data/movie.mp4'));
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
const Promise = require('bluebird');
|
|
2
|
+
const assert_positive_integer = require('./assert_positive_integer');
|
|
2
3
|
const stream = require('stream');
|
|
3
4
|
const wait_while = require('./wait_while');
|
|
4
5
|
|
|
@@ -7,6 +8,7 @@ const wait_while = require('./wait_while');
|
|
|
7
8
|
*/
|
|
8
9
|
function mongo_stream_upsert({collection, concurrency = 1})
|
|
9
10
|
{
|
|
11
|
+
assert_positive_integer(concurrency, 'concurrency');
|
|
10
12
|
const errors = [];
|
|
11
13
|
return new stream.Writable({
|
|
12
14
|
objectMode: true,
|
|
@@ -5,6 +5,7 @@ a `replaceOne` upsert keyed by its `_id`, and the batch goes to
|
|
|
5
5
|
|
|
6
6
|
- Up to `concurrency` (default `1`) `bulkWrite` calls run in flight; further
|
|
7
7
|
writes wait until a slot frees up.
|
|
8
|
+
- `concurrency` must be a positive integer.
|
|
8
9
|
- A `bulkWrite` error is reported on the next write or when the stream
|
|
9
10
|
finishes. `final` and `destroy` wait for all in-flight batches first, so an
|
|
10
11
|
error from the last batch is never silently dropped.
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
const Promise = require('bluebird');
|
|
2
|
+
const assert_positive_integer = require('./assert_positive_integer');
|
|
2
3
|
const stream = require('stream');
|
|
3
4
|
const wait_while = require('./wait_while');
|
|
4
5
|
|
|
@@ -7,6 +8,7 @@ const wait_while = require('./wait_while');
|
|
|
7
8
|
*/
|
|
8
9
|
function mongo_stream_write({collection, concurrency = 1})
|
|
9
10
|
{
|
|
11
|
+
assert_positive_integer(concurrency, 'concurrency');
|
|
10
12
|
const errors = [];
|
|
11
13
|
return new stream.Writable({
|
|
12
14
|
objectMode: true,
|
|
@@ -4,6 +4,7 @@ passed to `collection.bulkWrite(operations)` as is.
|
|
|
4
4
|
|
|
5
5
|
- Up to `concurrency` (default `1`) `bulkWrite` calls run in flight; further
|
|
6
6
|
writes wait until a slot frees up.
|
|
7
|
+
- `concurrency` must be a positive integer.
|
|
7
8
|
- A `bulkWrite` error is reported on the next write or when the stream
|
|
8
9
|
finishes. `final` and `destroy` wait for all in-flight batches first, so an
|
|
9
10
|
error from the last batch is never silently dropped.
|
package/src/parallel.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
const NotImplemented = require('./errors/NotImplemented');
|
|
2
2
|
const Promise = require('bluebird');
|
|
3
|
+
const assert_positive_integer = require('./assert_positive_integer');
|
|
3
4
|
const is_fn_async = require('@vbarbarosh/type-helpers/src/is_fn_async');
|
|
4
5
|
const is_fn_gen_async = require('@vbarbarosh/type-helpers/src/is_fn_gen_async');
|
|
5
6
|
|
|
@@ -12,6 +13,7 @@ const is_fn_gen_async = require('@vbarbarosh/type-helpers/src/is_fn_gen_async');
|
|
|
12
13
|
*/
|
|
13
14
|
async function parallel({concurrency, spawn, progress})
|
|
14
15
|
{
|
|
16
|
+
assert_positive_integer(concurrency, 'concurrency');
|
|
15
17
|
if (is_fn_async(spawn) || is_fn_gen_async(spawn)) {
|
|
16
18
|
throw new Error('[spawn] should not be async function. Instead, it should be a simple function returning either [null] or a [promise].');
|
|
17
19
|
}
|
package/src/parallel.md
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
- Run until `spawn` return `null`.
|
|
2
2
|
- Keep no more than `concurrency` number of workers at a time.
|
|
3
|
+
- `concurrency` must be a positive integer.
|
|
3
4
|
|
|
4
5
|
⚠️ Warning: `spawn` should not be async function (async functions are always return `promise`).
|
|
5
6
|
Instead, it should be a simple function returning either `null` or a `promise`.
|
package/src/pending.js
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
const Promise = require('bluebird');
|
|
2
|
+
|
|
3
|
+
function pending(fn)
|
|
4
|
+
{
|
|
5
|
+
let tmp_resolve, tmp_reject;
|
|
6
|
+
const promise = new Promise(function (resolve, reject) {
|
|
7
|
+
tmp_resolve = resolve;
|
|
8
|
+
tmp_reject = reject;
|
|
9
|
+
});
|
|
10
|
+
// noinspection JSUnusedAssignment
|
|
11
|
+
promise.resolve = tmp_resolve;
|
|
12
|
+
// noinspection JSUnusedAssignment
|
|
13
|
+
promise.reject = tmp_reject;
|
|
14
|
+
promise.callback = function (error, data) {
|
|
15
|
+
error ? promise.reject(error) : promise.resolve(data);
|
|
16
|
+
};
|
|
17
|
+
// noinspection EqualityComparisonWithCoercionJS
|
|
18
|
+
if (typeof fn == 'function') {
|
|
19
|
+
fn(promise.callback);
|
|
20
|
+
}
|
|
21
|
+
return promise;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
module.exports = pending;
|
package/src/pending.md
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
Creates a deferred: a bluebird promise with its own `resolve`, `reject`, and
|
|
2
|
+
node-style `callback(error, data)` attached, so it can be settled from outside
|
|
3
|
+
the executor. The optional `fn` receives `callback` immediately — handy for
|
|
4
|
+
wrapping callback-style APIs that take the callback as an argument.
|
|
5
|
+
|
|
6
|
+
## Signature
|
|
7
|
+
|
|
8
|
+
```
|
|
9
|
+
pending(fn = null) → Promise & {resolve, reject, callback}
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
## Examples
|
|
13
|
+
|
|
14
|
+
```
|
|
15
|
+
const promise = pending();
|
|
16
|
+
setTimeout(() => promise.resolve('done'), 100);
|
|
17
|
+
await promise;
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
```
|
|
21
|
+
await pending(callback => legacy_api(arg1, arg2, callback));
|
|
22
|
+
```
|
package/src/redis_poll.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
/* eslint-disable no-unused-vars -- destructured option lists document the full options contract */
|
|
2
2
|
const Promise = require('bluebird');
|
|
3
3
|
const random_int = require('./random_int');
|
|
4
|
+
const redis_rpush = require('./redis_rpush');
|
|
4
5
|
const redis_zshift = require('./redis_zshift');
|
|
5
6
|
|
|
6
7
|
async function redis_poll(options)
|
|
@@ -100,7 +101,7 @@ async function worker(log, message, options)
|
|
|
100
101
|
|
|
101
102
|
async function user_friendly_status(value) {
|
|
102
103
|
log(`[${log_worker_user_friendly_status}] ${value}`);
|
|
103
|
-
await redis
|
|
104
|
+
await redis_rpush(redis, redis_output_queue, JSON.stringify({uid, version, type: 'user_friendly_status', value}));
|
|
104
105
|
}
|
|
105
106
|
}
|
|
106
107
|
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
/* eslint-disable no-unused-vars -- destructured option lists document the full options contract */
|
|
2
2
|
const Promise = require('bluebird');
|
|
3
3
|
const random_int = require('./random_int');
|
|
4
|
+
const redis_rpush = require('./redis_rpush');
|
|
4
5
|
const redis_zshift = require('./redis_zshift');
|
|
5
6
|
|
|
6
7
|
/**
|
|
@@ -82,15 +83,15 @@ async function redis_poll_zshift_callback_rpush(options)
|
|
|
82
83
|
}
|
|
83
84
|
|
|
84
85
|
const value = await worker(log.spawn(), message, options);
|
|
85
|
-
const response = JSON.stringify({uid: message.uid, version, type: 'resolve', value});
|
|
86
|
-
await redis
|
|
86
|
+
const response = JSON.stringify({uid: message.uid, version, type: 'resolve', time: new Date().toJSON(), value});
|
|
87
|
+
await redis_rpush(redis, redis_output_queue, response);
|
|
87
88
|
|
|
88
89
|
log(`[${log_waiter_rpush}]`);
|
|
89
90
|
}
|
|
90
91
|
catch (error) {
|
|
91
|
-
const response = JSON.stringify({uid: message.uid, version, type: 'reject', value: `${(error && (error.stack || error.message)) || 'Error N/A'}`});
|
|
92
|
+
const response = JSON.stringify({uid: message.uid, version, type: 'reject', time: new Date().toJSON(), value: `${(error && (error.stack || error.message)) || 'Error N/A'}`});
|
|
92
93
|
log(`[${log_waiter_error}] ${response}`);
|
|
93
|
-
await redis
|
|
94
|
+
await redis_rpush(redis, redis_output_queue, response);
|
|
94
95
|
}
|
|
95
96
|
}
|
|
96
97
|
}
|
|
@@ -133,7 +134,7 @@ async function worker(log, message, options)
|
|
|
133
134
|
|
|
134
135
|
async function user_friendly_status(value) {
|
|
135
136
|
log(`[${log_worker_user_friendly_status}] ${value}`);
|
|
136
|
-
await redis
|
|
137
|
+
await redis_rpush(redis, redis_output_queue, JSON.stringify({uid, version, type: 'user_friendly_status', time: new Date().toJSON(), value}));
|
|
137
138
|
}
|
|
138
139
|
}
|
|
139
140
|
|
|
@@ -13,5 +13,6 @@ sleeps a random 500–1500ms; the loop runs at most 86400 iterations.
|
|
|
13
13
|
`'Started...'` status is always pushed first so the consumer starts
|
|
14
14
|
refreshing.
|
|
15
15
|
- `options.log` must provide `spawn()`; the `log_waiter_*`/`log_worker_*`
|
|
16
|
-
options are the tag names used in log lines.
|
|
17
|
-
`
|
|
16
|
+
options are the tag names used in log lines. Queue access goes through
|
|
17
|
+
`redis_zshift`/`redis_rpush`, so any redis client from redis@1 to redis@6
|
|
18
|
+
works.
|
|
@@ -4,6 +4,7 @@ const fs_path_resolve = require('./fs_path_resolve');
|
|
|
4
4
|
const fs_tempdir = require('./fs_tempdir');
|
|
5
5
|
const fs_write_json = require('./fs_write_json');
|
|
6
6
|
const random_int = require('./random_int');
|
|
7
|
+
const redis_rpush = require('./redis_rpush');
|
|
7
8
|
const redis_zshift = require('./redis_zshift');
|
|
8
9
|
const stream_data_ln = require('./stream_data_ln');
|
|
9
10
|
|
|
@@ -92,14 +93,14 @@ async function redis_poll_zshift_spawn_rpush(options)
|
|
|
92
93
|
|
|
93
94
|
await worker(log.spawn(), message, options);
|
|
94
95
|
const response = JSON.stringify({uid: message.uid, version, type: 'resolve', value: null});
|
|
95
|
-
await redis
|
|
96
|
+
await redis_rpush(redis, redis_output_queue, response);
|
|
96
97
|
|
|
97
98
|
log(`[${log_waiter_rpush}]`);
|
|
98
99
|
}
|
|
99
100
|
catch (error) {
|
|
100
101
|
const response = JSON.stringify({uid: message.uid, version, type: 'error', value: `${(error && (error.stack || error.message)) || 'Error N/A'}`});
|
|
101
102
|
log(`[${log_waiter_error}] ${response}`);
|
|
102
|
-
await redis
|
|
103
|
+
await redis_rpush(redis, redis_output_queue, response);
|
|
103
104
|
}
|
|
104
105
|
}
|
|
105
106
|
}
|
|
@@ -128,7 +129,7 @@ async function worker(log, request, options)
|
|
|
128
129
|
// Promise won't update its status until at least one request would
|
|
129
130
|
// be taken from the output queue. Pushing generic "Started..." request
|
|
130
131
|
// will tell the promise to refresh its status.
|
|
131
|
-
await redis
|
|
132
|
+
await redis_rpush(redis, redis_output_queue, JSON.stringify({uid, version, type: 'user_friendly_status', value: 'Started...'}));
|
|
132
133
|
await fs_tempdir(async function (d) {
|
|
133
134
|
await fs_write_json(fs_path_resolve(d, 'request.json'), request);
|
|
134
135
|
const proc = child_process.spawn(spawn_command, [], {cwd: d, stdio: ['pipe', 'pipe', 'pipe', 'pipe']});
|
|
@@ -144,7 +145,7 @@ async function worker(log, request, options)
|
|
|
144
145
|
end_stderr = stream_data_ln(proc.stderr, line => log(`[${log_worker_stderr}] ${line}`));
|
|
145
146
|
end_user_friendly_status = stream_data_ln(proc.stdio[3], function (line) {
|
|
146
147
|
log(`[${log_worker_user_friendly_status}] ${line}`);
|
|
147
|
-
redis
|
|
148
|
+
redis_rpush(redis, redis_output_queue, JSON.stringify({uid, version, type: 'user_friendly_status', value: line}));
|
|
148
149
|
});
|
|
149
150
|
});
|
|
150
151
|
}
|
|
@@ -15,6 +15,7 @@ iterations.
|
|
|
15
15
|
- Unparseable messages and messages without `uid` are skipped; a missing or
|
|
16
16
|
past `expires_at` fails the message (payloads carry signed urls with
|
|
17
17
|
limited lifetime).
|
|
18
|
-
- `options.log` must provide `spawn()`;
|
|
19
|
-
`
|
|
18
|
+
- `options.log` must provide `spawn()`; queue access goes through
|
|
19
|
+
`redis_zshift`/`redis_rpush`, so any redis client from redis@1 to redis@6
|
|
20
|
+
works. See `redis_poll_zshift_callback_rpush` for the in-process
|
|
20
21
|
callback variant (which reports failures as `type: 'reject'`).
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
async function redis_rpush(redis, queue, value)
|
|
2
|
+
{
|
|
3
|
+
if (redis.rpush) {
|
|
4
|
+
return new Promise(function (resolve, reject) {
|
|
5
|
+
redis.rpush(queue, value, function (error, out) {
|
|
6
|
+
error ? reject(error) : resolve(out);
|
|
7
|
+
});
|
|
8
|
+
});
|
|
9
|
+
}
|
|
10
|
+
// redis@4
|
|
11
|
+
return redis.rPush(queue, value);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
module.exports = redis_rpush;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
Appends `value` to the tail of a redis list (`RPUSH`). Returns the new list
|
|
2
|
+
length.
|
|
3
|
+
|
|
4
|
+
Works with both legacy callback clients (redis@1–3, detected by the presence
|
|
5
|
+
of a lowercase `rpush` method) and promise clients (redis@4–6); the tests run
|
|
6
|
+
against all six major versions.
|
|
7
|
+
|
|
8
|
+
## Signature
|
|
9
|
+
|
|
10
|
+
```
|
|
11
|
+
redis_rpush(redis, queue, value) → Promise<number>
|
|
12
|
+
```
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
const Promise = require('bluebird');
|
|
2
|
+
const assert_positive_integer = require('./assert_positive_integer');
|
|
2
3
|
const stream = require('stream');
|
|
3
4
|
|
|
4
5
|
/**
|
|
@@ -10,6 +11,7 @@ const stream = require('stream');
|
|
|
10
11
|
*/
|
|
11
12
|
function stream_map_parallel({handler, concurrency})
|
|
12
13
|
{
|
|
14
|
+
assert_positive_integer(concurrency, 'concurrency');
|
|
13
15
|
let running = 0;
|
|
14
16
|
let callback_next = null;
|
|
15
17
|
let callback_flush = null;
|
package/src/stream_multiplex.js
CHANGED
|
@@ -25,12 +25,14 @@ function stream_multiplex(...streams)
|
|
|
25
25
|
streams.forEach(s => s.once('error', e => this.destroy(e)));
|
|
26
26
|
callback();
|
|
27
27
|
},
|
|
28
|
-
destroy:
|
|
28
|
+
destroy: function (error, callback) {
|
|
29
29
|
let done = 0;
|
|
30
|
+
let final_error = error;
|
|
30
31
|
streams.forEach(function (stream) {
|
|
31
|
-
stream.destroy(error, function () {
|
|
32
|
+
stream.destroy(error, function (error2) {
|
|
33
|
+
final_error = final_error || error2;
|
|
32
34
|
if (++done === streams.length) {
|
|
33
|
-
callback();
|
|
35
|
+
callback(final_error);
|
|
34
36
|
}
|
|
35
37
|
});
|
|
36
38
|
});
|
package/src/stream_multiplex.md
CHANGED
|
@@ -7,6 +7,8 @@ completes only after every target accepted the chunk.
|
|
|
7
7
|
- Ending the multiplex ends all targets; destroying it destroys all targets.
|
|
8
8
|
- An error in any target destroys the multiplex (and, through it, the other
|
|
9
9
|
targets) with that error — the first error wins.
|
|
10
|
+
- Destroying the multiplex with an error preserves that error after all targets
|
|
11
|
+
finish cleanup.
|
|
10
12
|
|
|
11
13
|
```js
|
|
12
14
|
await stream.promises.pipeline(
|
package/src/stream_progress.js
CHANGED
|
@@ -16,15 +16,22 @@ function stream_progress({objectMode = false, interval = 1000, total, user_frien
|
|
|
16
16
|
{
|
|
17
17
|
let done = 0;
|
|
18
18
|
const timer = setInterval(tick, interval);
|
|
19
|
+
const timeout = setTimeout(tick, 0);
|
|
19
20
|
const progress = make_progress(total);
|
|
20
21
|
const format_progress = objectMode ? format_progress_kilo : format_progress_bytes;
|
|
21
|
-
setTimeout(tick, 0);
|
|
22
22
|
return new stream.Transform({
|
|
23
23
|
objectMode,
|
|
24
24
|
destroy: function (error, callback) {
|
|
25
|
-
tick();
|
|
26
25
|
clearInterval(timer);
|
|
27
|
-
|
|
26
|
+
clearTimeout(timeout);
|
|
27
|
+
try {
|
|
28
|
+
tick();
|
|
29
|
+
}
|
|
30
|
+
catch (error2) {
|
|
31
|
+
callback(error || error2);
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
callback(error);
|
|
28
35
|
},
|
|
29
36
|
transform: function (buffer, encoding, callback) {
|
|
30
37
|
if (objectMode) {
|