nemar-cli 0.10.4-PR1405.ba5371f → 0.10.4-PR1405.e3fdbed
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/dist/index.js +2 -2
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -99,7 +99,7 @@ ${t}`,dSe,fSe,pSe=(e,t,r)=>{let n=r===""?"":`with ${r.trim()}() `,o=uSe.bind(nul
|
|
|
99
99
|
`)}var cE=!1;var{spawn:W7e}=globalThis.Bun;async function C(e,t={}){let r={...process.env,GIT_TERMINAL_PROMPT:"0",...t.env};for(let u of t.unsetEnv??[])delete r[u];let n=W7e({cmd:e,cwd:t.cwd,...t.stdin===void 0?{}:{stdin:new TextEncoder().encode(t.stdin)},stdout:"pipe",stderr:"pipe",env:r}),o=!1,i;if(t.timeout)i=setTimeout(()=>{o=!0,n.kill()},t.timeout);if(lE()){let u=t.cwd?` (cwd=${t.cwd})`:"";Tf(l.dim(`$ ${e.join(" ")}${u}`))}let s=await new Response(n.stdout).text(),a=await new Response(n.stderr).text(),c=await n.exited;if(i)clearTimeout(i);if(lE()){if(s.trim())Tf(l.dim(s.trimEnd()));if(a.trim())Tf(l.yellow(a.trimEnd()));Tf(l.dim(`(exit ${c})`))}if(o)return{stdout:s,stderr:a||`Command timed out after ${Math.round(t.timeout/1000)}s`,exitCode:c??1,timedOut:!0};return{stdout:s,stderr:a,exitCode:c,timedOut:!1}}var vt=O(()=>{Xe()});function Y7e(){if(process.platform==="darwin")return"macos";if(process.platform==="win32")return"windows";return"linux"}function YK(e,t=Y7e()){return e.installInstructions[t]}function J7e(e){let t=e.match(/(\d+\.\d+(?:\.\d+)?)/);return t?t[1]:void 0}function Z7e(){let e=Number(process.env.TEST_PROBE_TIMEOUT_MS);return Number.isFinite(e)&&e>0?e:X7e}async function JK(e){try{let{exitCode:t,stdout:r,timedOut:n}=await C(e.cmd,{timeout:Z7e()});if(n)return{available:!1,timedOut:!0};if(t!==0)return{available:!1};return{available:!0,version:J7e(r)}}catch(t){let r=t instanceof Error?t.message:String(t);if(!r.includes("ENOENT")&&!r.includes("not found"))console.error(` Warning: ${e.name} check failed unexpectedly: ${r}`);return{available:!1}}}async function Nf(){let e=Object.entries(KK);return Promise.all(e.map(async([t,r])=>{let{available:n,version:o,timedOut:i}=await JK(r);return{key:t,name:r.name,purpose:r.purpose,required:r.required,available:n,version:o,timedOut:i,installInstruction:YK(r)}}))}async function XK(){let t=(await Nf()).filter((r)=>r.required&&!r.available);if(t.length===0)return[];console.warn(`
|
|
100
100
|
Heads up: some tools NEMAR needs for uploading/validating aren't installed yet:`);for(let r of t)console.warn(` - ${r.name} (${r.purpose})`),console.warn(` Install: ${r.installInstruction}`);return console.warn("Run `nemar doctor` anytime to re-check. You can finish signup without them.\n"),t}async function Ra(e){let r=K7e[e].map((s)=>KK[s]).filter(Boolean),n=await Promise.all(r.map(async(s)=>{let a=await JK(s);return{check:s,available:a.available,timedOut:a.timedOut}}));for(let s of n)if(s.timedOut&&s.check.required)console.warn(`Warning: ${s.check.name} did not respond to a version check in time; continuing anyway.`);let o=n.filter((s)=>!s.available&&!s.timedOut&&s.check.required).map((s)=>({tool:s.check.name,installInstruction:YK(s.check)}));if(o.length===0)return;let i=[`
|
|
101
101
|
Missing required tools:`];for(let s of o)i.push(` ${s.tool} not installed`),i.push(` Install: ${s.installInstruction}`);throw Error(i.join(`
|
|
102
|
-
`))}var KK,K7e,X7e=4000;var jf=O(()=>{vt();KK={git:{name:"git",purpose:"version control for dataset metadata",cmd:["git","--version"],required:!0,installInstructions:{macos:"brew install git (or install Xcode Command Line Tools)",linux:"sudo apt-get install git OR sudo dnf install git",windows:"winget install Git.Git (or https://git-scm.com/download/win)"}},"git-annex":{name:"git-annex",purpose:"large-file data transfer (upload/download)",cmd:["git-annex","version"],required:!0,installInstructions:{macos:"brew install git-annex",linux:"sudo apt-get install git-annex OR sudo dnf install git-annex",windows:"Download the installer from https://git-annex.branchable.com/install/Windows/"}},gh:{name:"GitHub CLI (gh)",purpose:"GitHub authentication + repository operations",cmd:["gh","--version"],required:!0,installInstructions:{macos:"brew install gh",linux:"See https://cli.github.com/manual/installation",windows:"winget install GitHub.cli (or: scoop install gh)"}},aws:{name:"AWS CLI",purpose:"S3 data upload/download",cmd:["aws","--version"],required:!0,installInstructions:{macos:"brew install awscli",linux:"pip install awscli OR sudo snap install aws-cli --classic",windows:"winget install Amazon.AWSCLI (or the MSI from https://aws.amazon.com/cli/)"}},deno:{name:"Deno",purpose:"BIDS validation",cmd:["deno","--version"],required:!0,installInstructions:{macos:"brew install deno (or: curl -fsSL https://deno.land/install.sh | sh)",linux:"curl -fsSL https://deno.land/install.sh | sh",windows:"winget install DenoLand.Deno (or: irm https://deno.land/install.ps1 | iex)"}}},K7e={upload:["git-annex","gh","aws","deno"],download:["gh"],clone:["git","gh"],push:["git-annex","gh"],publish:["gh","aws"],update:["git","gh"],release:["git","gh"]}});var QK;var ZK=O(()=>{QK={name:"nemar-cli",version:"0.10.4-PR1405.
|
|
102
|
+
`))}var KK,K7e,X7e=4000;var jf=O(()=>{vt();KK={git:{name:"git",purpose:"version control for dataset metadata",cmd:["git","--version"],required:!0,installInstructions:{macos:"brew install git (or install Xcode Command Line Tools)",linux:"sudo apt-get install git OR sudo dnf install git",windows:"winget install Git.Git (or https://git-scm.com/download/win)"}},"git-annex":{name:"git-annex",purpose:"large-file data transfer (upload/download)",cmd:["git-annex","version"],required:!0,installInstructions:{macos:"brew install git-annex",linux:"sudo apt-get install git-annex OR sudo dnf install git-annex",windows:"Download the installer from https://git-annex.branchable.com/install/Windows/"}},gh:{name:"GitHub CLI (gh)",purpose:"GitHub authentication + repository operations",cmd:["gh","--version"],required:!0,installInstructions:{macos:"brew install gh",linux:"See https://cli.github.com/manual/installation",windows:"winget install GitHub.cli (or: scoop install gh)"}},aws:{name:"AWS CLI",purpose:"S3 data upload/download",cmd:["aws","--version"],required:!0,installInstructions:{macos:"brew install awscli",linux:"pip install awscli OR sudo snap install aws-cli --classic",windows:"winget install Amazon.AWSCLI (or the MSI from https://aws.amazon.com/cli/)"}},deno:{name:"Deno",purpose:"BIDS validation",cmd:["deno","--version"],required:!0,installInstructions:{macos:"brew install deno (or: curl -fsSL https://deno.land/install.sh | sh)",linux:"curl -fsSL https://deno.land/install.sh | sh",windows:"winget install DenoLand.Deno (or: irm https://deno.land/install.ps1 | iex)"}}},K7e={upload:["git-annex","gh","aws","deno"],download:["gh"],clone:["git","gh"],push:["git-annex","gh"],publish:["gh","aws"],update:["git","gh"],release:["git","gh"]}});var QK;var ZK=O(()=>{QK={name:"nemar-cli",version:"0.10.4-PR1405.e3fdbed",description:"CLI for NEMAR (Neuroelectromagnetic Data Archive and Tools Resource) dataset management",type:"module",main:"dist/index.js",bin:{nemar:"dist/index.js"},scripts:{dev:"bun run src/index.ts",build:"bun build src/index.ts --outdir dist --target bun --minify && sed '1s|#!/usr/bin/env node|#!/usr/bin/env bun|' dist/index.js > dist/index.js.tmp && mv dist/index.js.tmp dist/index.js",test:"bun test",lint:"biome check src/","migrations:d1-check":"bun run scripts/d1-migration-check.ts","zarr:geometry-check":"bun run backend/scripts/zarr-geometry-conformance.ts","lint:fix":"biome check --fix src/",format:"biome format --write src/",typecheck:"tsc --noEmit && tsc --noEmit -p backend","generate-openapi":"bun run scripts/generate-openapi.ts",prepublishOnly:"bun run build",prepare:"husky",postinstall:"bun scripts/postinstall-check.mjs",deploy:"wrangler deploy",preview:"wrangler dev"},keywords:["nemar","bids","neuroimaging","eeg","emg","datalad","cli"],author:"NEMAR Team",license:"CC-BY-NC-ND-4.0",repository:{type:"git",url:"git+https://github.com/nemarOrg/nemar-cli.git"},bugs:{url:"https://github.com/nemarOrg/nemar-cli/issues"},homepage:"https://docs.nemar.org",engines:{bun:">=1.0.0"},files:["dist","scripts/postinstall-check.mjs","scripts/recover-datasets.json","scripts/withdrawn-datasets.json","README.md","LICENSE"],dependencies:{chalk:"^5.3.0",commander:"^12.1.0",conf:"^13.0.1",inquirer:"^9.2.15",ora:"^8.0.1",semver:"^7.8.5",zod:"^3.23.8"},"lint-staged":{"src/**/*.{ts,tsx}":["biome check --fix"],"backend/src/**/*.{ts,tsx}":["biome check --fix"]},devDependencies:{"@asteasolutions/zod-to-openapi":"^7.3.4","@biomejs/biome":"1.9.4","@types/bun":"latest","@types/inquirer":"^9.0.7","@types/semver":"^7.8.0",ajv:"^8.20.0","ajv-formats":"^3.0.1",bcryptjs:"^3.0.3",husky:"^9.1.7","lint-staged":"^16.3.2",typescript:"^5.5.4",wrangler:"^4.70.0",yaml:"^2.8.4"}}});var wi;var qf=O(()=>{ZK();wi=QK.version});import{mkdirSync as eLe,readdirSync as tLe,unlinkSync as rLe,writeFileSync as nLe}from"fs";import{join as uE}from"path";function iY(){Al=!0}function Aa(){return Al}function sY(e,t=process.env){return e.includes("--debug")||t.NEMAR_DEBUG==="1"}function Lf(e){oY=e,$r(`Step: ${e}`)}function Bf(){rY=!0}function aY(){return rY}function fE(){nY=!0}function cY(){return nY}function $r(e){if(Al)process.stderr.write(`[debug] ${e}
|
|
103
103
|
`)}function aLe(e){let t={};for(let[r,n]of Object.entries(e))t[r]=sLe.has(r.toLowerCase())?"[REDACTED]":n;return t}function uY(e){let t=e.indexOf("@");if(t<=0)return"***";return`${e[0]}***${e.slice(t)}`}function dE(e,t,r=0){if(r>lLe)return"[REDACTED: depth]";if(Array.isArray(t))return t.map((n)=>dE(e,n,r+1));if(t&&typeof t==="object"){let n={};for(let[o,i]of Object.entries(t))n[o]=dE(o,i,r+1);return n}if(typeof t==="string"){if(cLe.test(e))return"[REDACTED]";return t.replace(lY,uY)}return t}function pE(e){return e.replace(uLe,"Bearer [REDACTED]").replace(dLe,"[REDACTED_AWS_KEY]").replace(fLe,"$1[REDACTED]").replace(pLe,"$1$2=[REDACTED]").replace(lY,uY)}function mLe(e){return pE(e)}function eY(e,t=iLe){if(e===void 0)return;let r=e;try{let n=JSON.parse(e);r=JSON.stringify(dE("",n))}catch{}if(r=pE(r),Buffer.byteLength(r,"utf8")>t)r=`${Buffer.from(r,"utf8").subarray(0,t).toString("utf8")}... [truncated]`;return r}function A0(e){if(!Al)return;let t=mLe(e.url);try{let r={...e,url:t,requestHeaders:e.requestHeaders?aLe(e.requestHeaders):void 0,requestBody:eY(e.requestBody),responseBody:eY(e.responseBody)};R0.push(r),$r(`${e.method} ${t} -> ${e.status??"ERROR"} (${e.durationMs}ms)`)}catch(r){let n=T(r);R0.push({method:e.method,url:t,status:e.status,durationMs:e.durationMs,note:`redaction failed: ${n}`}),$r(`redaction failed for ${e.method} ${t}: ${n}`)}}async function hLe(){let e=[];try{let t=process.versions.bun?`Bun ${process.versions.bun}`:`Node ${process.version}`;e.push(`CLI version: ${wi}`),e.push(`OS/Arch: ${process.platform}/${process.arch}`),e.push(`Runtime: ${t}`)}catch(t){e.push(`(could not read CLI/OS/runtime info: ${T(t)})`)}e.push(""),e.push("Active account:");try{let t=ot();if(t.apiKey){if(t.username)e.push(` Username: ${t.username}`);if(e.push(` API URL: ${t.apiUrl}`),t.role)e.push(` Role: ${t.role}`);e.push(` Sandbox completed: ${!!t.sandboxCompleted}`)}else e.push(" (not authenticated)")}catch(t){e.push(` (could not read account config: ${T(t)})`)}e.push(""),e.push("External tools:");try{let t=await Nf();for(let r of t){let n=r.available?r.version??"installed":r.timedOut?"(timed out)":"not installed";e.push(` ${r.name}: ${n}`)}}catch(t){e.push(` (could not probe external tools: ${T(t)})`)}return e}async function mE(){return(await hLe()).join(`
|
|
104
104
|
`)}async function dY(){if(!Al||k0!==void 0)return;try{k0=await mE()}catch(e){let t=T(e);k0=`(could not build environment report: ${t})`,$r(`environment snapshot failed: ${t}`)}}function fY(e){if(tY.has(e))return{flag:e};for(let t of tY){if(!e.startsWith(t)||e.length<=t.length)continue;if(t.length===2)return{flag:t,kind:"short-attached"};if(e[t.length]==="=")return{flag:t,kind:"long-eq"}}return null}function gLe(e){let t=[];for(let r=0;r<e.length;r++){let n=e[r],o=fY(n);if(!o){t.push(n);continue}if(o.kind==="long-eq")t.push(`${o.flag}=[REDACTED]`);else if(o.kind==="short-attached")t.push(`${o.flag}[REDACTED]`);else if(t.push(n),r+1<e.length)t.push("[REDACTED]"),r++}return t}function yLe(e){let t=[];for(let r=0;r<e.length;r++){let n=e[r],o=fY(n);if(!o){t.push(n);continue}if(!o.kind&&r+1<e.length)r++}return t}function bLe(e){let t=[];for(let n of yLe(e)){if(n.startsWith("-"))continue;if(t.push(n),t.length===2)break}return(t.length>0?t.join("-"):"nemar").replace(/[^a-zA-Z0-9_-]/g,"_")}function xLe(e,t){let r=[];if(r.push("NEMAR CLI Debug Log"),r.push(`Generated: ${new Date().toISOString()}`),r.push(`Command: nemar ${pE(gLe(e).join(" "))}`),r.push(""),r.push(k0??"(environment snapshot unavailable)"),r.push(""),r.push("HTTP requests:"),R0.length===0)r.push(" (none)");else R0.forEach((n,o)=>{if(r.push(` [${o+1}] ${n.method} ${n.url} -> ${n.status??"ERROR"} (${n.durationMs}ms)`),n.error)r.push(` Error: ${n.error}`);if(n.note)r.push(` Note: ${n.note}`);if(n.requestHeaders)r.push(` Request headers: ${JSON.stringify(n.requestHeaders)}`);if(n.requestBody)r.push(` Request body: ${n.requestBody}`);if(n.responseBody)r.push(` Response body: ${n.responseBody}`)});return r.push(""),r.push(`Failing step: ${oY??"(none recorded)"}`),r.push(`Exit code: ${t}`),`${r.join(`
|
|
105
105
|
`)}
|
|
@@ -193,7 +193,7 @@ Exemplar clone + publish complete: ${i} -> ${o}`)),console.log(l.dim(` GitHub:
|
|
|
193
193
|
`).filter(Boolean))].sort()}async function NHe(e,t=mp){let{stdout:r,exitCode:n}=await C(["git","show","git-annex:remote.log"],{cwd:e});if(n!==0)return null;for(let o of r.split(`
|
|
194
194
|
`)){let i=o.trim().split(/\s+/);if(!i.some((a)=>a===`name=${t}`))continue;let s=i[0];if(s)return s}return null}async function jHe(e,t,r,n=mp){let o=await NHe(t,n),i=await THe(t);if(!o)return{datasetId:e,remoteUuid:null,annexed:i,registered:[],inBucket:[],toRegister:[],missingContent:[],falselyClaimed:[]};let s=await Jee(t,o),a=await r(e),c=new Set(s),u=i.filter((d)=>nn(d,a));return{datasetId:e,remoteUuid:o,annexed:i,registered:s,inBucket:u,toRegister:u.filter((d)=>!c.has(d)),missingContent:i.filter((d)=>!nn(d,a)),falselyClaimed:i.filter((d)=>c.has(d)&&!nn(d,a))}}async function qHe(e,t,r){let n=r.remoteName??mp;if(!PHe.test(e))return{datasetId:e,action:"failed",pushed:!1,notes:[],error:`"${e}" is not a dataset id, and it would become a directory this deletes`};let o=FHe(r.workRoot,e),i=[];q2(o,{recursive:!0,force:!0});let s=r.originUrl??`https://github.com/nemarDatasets/${e}.git`,a=await M2(s,o);if(a)return q2(o,{recursive:!0,force:!0}),{datasetId:e,action:"failed",pushed:!1,notes:i,error:a};try{let c=await jHe(e,o,t,n);if(!c.remoteUuid)return{datasetId:e,action:"skipped-no-remote",state:c,pushed:!1,notes:[`no ${n} remote in the git-annex branch; nothing to register against`]};if(r.retractFalseClaims&&c.falselyClaimed.length>0){if(!r.apply)return{datasetId:e,action:"would-repair",state:c,pushed:!1,notes:[`${c.falselyClaimed.length} key(s) are advertised at ${n} and not in the bucket; would withdraw`]};let p=await BQ(o,c.falselyClaimed,c.remoteUuid);if(p.failed>0)return{datasetId:e,action:"failed",state:c,pushed:!1,notes:i,error:`${p.failed} claim(s) still stand after setpresentkey 0: ${p.missing.join(", ")}`};i.push(`withdrew ${p.success} claim(s) the bucket cannot back`);let h=Yee(await Tt(o,"origin"));if(h)return{datasetId:e,action:"failed",state:c,pushed:!1,notes:i,error:`the retraction did not reach GitHub: ${h}. The claims are still advertised; re-run to redo it.`};return{datasetId:e,action:"repaired",state:c,pushed:!0,notes:i}}if(c.missingContent.length>0&&!r.includeIncomplete)return{datasetId:e,action:"skipped-missing-content",state:c,pushed:!1,notes:[`${c.missingContent.length} of ${c.annexed.length} annexed key(s) have no object in the bucket${c.falselyClaimed.length>0?`, ${c.falselyClaimed.length} of them advertised at ${n} anyway (rerun with retractFalseClaims to withdraw)`:""}, so this is missing content (#1396) rather than a lost registration; first: ${c.missingContent[0]}`]};if(c.toRegister.length===0){if(c.missingContent.length>0)return{datasetId:e,action:"skipped-missing-content",state:c,pushed:!1,notes:[`nothing to register: the bucket holds none of the ${c.missingContent.length} key(s) still outstanding (#1396)`]};return{datasetId:e,action:"compliant",state:c,pushed:!1,notes:i}}if(!r.apply)return{datasetId:e,action:"would-repair",state:c,pushed:!1,notes:[`${c.toRegister.length} key(s) are in the bucket and not in the log`]};let u=await Ms(o,c.toRegister,c.remoteUuid),d=new Set(await Jee(o,c.remoteUuid)),f=c.toRegister.filter((p)=>!d.has(p));if(f.length>0)return{datasetId:e,action:"failed",state:c,pushed:!1,notes:i,error:`registered ${u.success} of ${c.toRegister.length}, and the location log still does not record ${f.length} of them (first: ${f[0]}). Nothing pushed.`};if(i.push(`registered ${c.toRegister.length} key(s), all confirmed in the location log`),r.push===!1)return{datasetId:e,action:"repaired",state:c,pushed:!1,notes:i};let m=Yee(await Tt(o,"origin"));if(m)return{datasetId:e,action:"failed",state:c,pushed:!1,notes:i,error:`the git-annex branch did not push: ${m}. The registration is local only; re-run to redo it.`};return{datasetId:e,action:"repaired",state:c,pushed:!0,notes:i}}finally{q2(o,{recursive:!0,force:!0})}}async function hp(e,t,r){let n=Array(e.length),o=0,i=!1,s=Array.from({length:Math.max(1,Math.min(t,e.length))},async()=>{while(!i){let u=o++;if(u>=e.length)return;try{n[u]=await r(e[u],u)}catch(d){throw i=!0,d}}}),c=(await Promise.allSettled(s)).find((u)=>u.status==="rejected");if(c?.status==="rejected")throw c.reason;return n}async function Xee(e,t,r){let n=[...new Set(e)],o=0,i=await hp(n,r.concurrency??4,async(c)=>{let u;try{u=await qHe(c,t,r)}catch(d){u={datasetId:c,action:"failed",pushed:!1,notes:[],error:d instanceof Error?d.message:String(d)}}return r.onDataset?.(u,++o,n.length),u}),s={compliant:0,repaired:0,"would-repair":0,"skipped-missing-content":0,"skipped-no-remote":0,failed:0},a=0;for(let c of i)if(s[c.action]++,c.action==="repaired")a+=c.state?.toRegister.length??0;return{outcomes:i,tally:s,keysRegistered:a}}var mp="nemar-s3",PHe;var gp=O(()=>{Si();Ul();Bo();Mo();vt();kn();Oi();Oi();PHe=/^[a-z]{2}[0-9]{6}$/});function ete(e){let t=Ia(e),r=/^([A-Z0-9]+)-s\d+(?:-[SC]\d+)*--(.+)$/.exec(e);if(t===null||!r)return null;let[,n,o]=r,i=VHe[n],s=i&&o.length>=i?o.slice(0,i).toLowerCase():null;return{backend:n,size:t,hashHex:s&&/^[0-9a-f]+$/.test(s)?s:null}}function U2(e){let t=new Map;for(let r of e.split(`
|
|
195
195
|
`)){let n=r.trim().split(/\s+/),o=n[0];if(!o||n.length<2)continue;let i=(a)=>n.find((c)=>c.startsWith(`${a}=`))?.slice(a.length+1),s=i("name");if(!s)continue;t.set(o,{uuid:o,name:s,bucket:i("bucket"),fileprefix:i("fileprefix")})}return t}function GHe(e){if(!e.startsWith("!"))return e;let t=e.slice(1),r=Buffer.from(t,"base64");if(r.toString("base64").replace(/=+$/,"")!==t.replace(/=+$/,""))return e;return r.toString("utf8")}function tte(e,t){let r=[];for(let o of e.split(`
|
|
196
|
-
`)){let i=/^(\S+?)s?\s+([0-9a-f-]{36}):V\s+([+-])(\S+)$/.exec(o.trim());if(!i)continue;let s=t.get(i[2]);if(!s?.bucket)continue;let a=GHe(i[4]),c=a.indexOf("#");if(c<=0)continue;let u=Number.parseFloat(i[1])||0;r.push({stamp:u,retracted:i[3]==="-",value:a,pin:{bucket:s.bucket,object:a.slice(c+1),version:a.slice(0,c),remoteName:s.name}})}r.sort((o,i)=>o.stamp-i.stamp);let n=new Map;for(let o of r)if(o.retracted)n.delete(o.value);else n.set(o.value,o.pin);return[...n.values()]}async function rte(e){let t=["aws","s3api","list-object-versions","--bucket",e.bucket,"--prefix",e.prefix,"--output","json","--query","Versions[].[Key,VersionId,Size,ETag]","--page-size","1000"];if(!e.signed)t.push("--no-sign-request");let{stdout:r,stderr:n,exitCode:o,timedOut:i}=await C(t,{unsetEnv:B2,timeout:L2});if(o!==0||i)throw Error(`listing s3://${e.bucket}/${e.prefix} failed: ${i?"timed out":n.trim()||`exit ${o}`}`);return HHe(r)}function HHe(e){let t=new Map,r=e.trim()?JSON.parse(e):[];for(let[n,o,i,s]of r??[]){let a=t.get(n)??[];a.push({object:n,version:o,size:i,etag:(s??"").replace(/"/g,"")}),t.set(n,a)}return t}function nte(e){let t=ete(e.key);if(!t)return{key:e.key,size:0,reason:"not a parseable annex key"};let r={key:e.key,size:t.size},n=e.pins[e.pins.length-1],o=e.upstream?WHe(t.size,e):null;if(n){let i=o&&o.version!==n.version?[o]:void 0;return{...r,source:{...n,origin:"pinned",size:t.size},alternatives:i}}if(!e.upstream)return{...r,reason:"no upstream remote to recover from"};if(o)return{...r,source:o};return{...r,reason:KHe(t.size,e)}}function WHe(e,t){let r=t.upstream;if(!r)return null;let n=t.paths.flatMap((s)=>r.index.get(`${r.prefix}${s}`)?.filter((a)=>a.size===e)??[]),o=new Map(n.map((s)=>[s.etag,s]));if(o.size!==1)return null;let[i]=o.values();return{bucket:r.bucket,object:i.object,version:i.version,etag:i.etag,origin:"version-match",size:e}}function KHe(e,t){let r=t.upstream;if(!r)return"no upstream remote to recover from";let n=t.paths.flatMap((i)=>r.index.get(`${r.prefix}${i}`)?.filter((s)=>s.size===e)??[]),o=new Set(n.map((i)=>i.etag));return o.size>1?`${o.size} distinct upstream objects carry this key's size; refusing to guess`:"no upstream object of this key's size at any of its paths"}function ote(e){return e==="pinned"}function YHe(e){let t=ete(e.key);if(!t)return{ok:!1,method:"unparseable-key",detail:"unparseable key"};if(e.checksumSha256&&t.backend.startsWith("SHA256")&&t.hashHex){let n=Buffer.from(t.hashHex,"hex").toString("base64");return e.checksumSha256===n?{ok:!0,method:"checksum"}:{ok:!1,method:"checksum",detail:`S3 hashed the object to ${e.checksumSha256}, the key says ${n}`}}let r=e.etag?.replace(/"/g,"");if(r&&!r.includes("-")&&t.backend.startsWith("MD5")&&t.hashHex)return r===t.hashHex?{ok:!0,method:"etag"}:{ok:!1,method:"etag",detail:`the object's MD5 is ${r}, the key says ${t.hashHex}`};if(e.size==null)return{ok:!1,method:"unmeasured",detail:"the bucket did not answer for the copy, so nothing about it was checked"};if(e.size!==t.size)return{ok:!1,method:"size",detail:`the object is ${e.size} bytes, the key says ${t.size}`};if(!ote(e.origin))return{ok:!1,method:"size-and-pin",detail:"only the size could be checked, and nothing pins this source to this key"};if(e.sourceCrc64&&e.crc64)return e.sourceCrc64===e.crc64?{ok:!0,method:"crc64-of-source"}:{ok:!1,method:"crc64-of-source",detail:`the copy's CRC64 is ${e.crc64}, the source reads ${e.sourceCrc64}`};return{ok:!0,method:"size-and-pin"}}function ite(e){let t=`${e.bucket}/${e.object}`;return e.version?`${t}?versionId=${e.version}`:t}function XHe(e){return JHe.test(e)}async function Ii(e,t){let r=await C(["aws",...e],{env:t,unsetEnv:B2,timeout:L2});for(let n=1;n<=ZHe;n++){if(r.exitCode===0||!XHe(r.stderr))return r;let o=QHe*2**(n-1)*(1+Math.random());await new Promise((i)=>setTimeout(i,o)),r=await C(["aws",...e],{env:t,unsetEnv:B2,timeout:L2})}return r}async function eWe(e){if(e.source.size>Qee)return{...await rWe(e),multipart:!0};let{stdout:t,stderr:r,exitCode:n,timedOut:o}=await Ii(["s3api","copy-object","--bucket",e.destBucket,"--key",e.destKey,"--copy-source",ite(e.source),"--tagging-directive","REPLACE","--tagging","","--checksum-algorithm","SHA256","--output","json"],e.env);if(n!==0)throw Error(`copy-object failed: ${o?"timed out":r.trim()||`exit ${n}`}`);let i=JSON.parse(t||"{}");return{checksumSha256:i.CopyObjectResult?.ChecksumSHA256??null,etag:i.CopyObjectResult?.ETag?.replace(/"/g,"")??null,multipart:!1}}function tWe(e,t){let r=[];for(let n=0,o=1;n<e;n+=t,o++)r.push({part:o,offset:n,end:Math.min(n+t,e)-1});return r}async function rWe(e){let t=await Ii(["s3api","create-multipart-upload","--bucket",e.destBucket,"--key",e.destKey,"--checksum-algorithm","CRC64NVME","--checksum-type","FULL_OBJECT","--output","json"],e.env);if(t.exitCode!==0)throw Error(`create-multipart-upload failed: ${t.stderr.trim()||`exit ${t.exitCode}`}`);let r=JSON.parse(t.stdout||"{}").UploadId;if(!r)throw Error("create-multipart-upload returned no UploadId");let n=tWe(e.source.size,UHe);try{let o=await hp(n,zHe,async(a)=>{let c=await Ii(["s3api","upload-part-copy","--bucket",e.destBucket,"--key",e.destKey,"--upload-id",r,"--part-number",String(a.part),"--copy-source",ite(e.source),"--copy-source-range",`bytes=${a.offset}-${a.end}`,"--output","json"],e.env);if(c.exitCode!==0)throw Error(`upload-part-copy ${a.part} failed: ${c.stderr.trim()||`exit ${c.exitCode}`}`);let u=JSON.parse(c.stdout||"{}").CopyPartResult?.ETag;if(!u)throw Error(`upload-part-copy ${a.part} returned no ETag`);return{ETag:u,PartNumber:a.part}}),i=await Ii(["s3api","complete-multipart-upload","--bucket",e.destBucket,"--key",e.destKey,"--upload-id",r,"--multipart-upload",JSON.stringify({Parts:o}),"--output","json"],e.env);if(i.exitCode!==0)throw Error(`complete-multipart-upload failed: ${i.stderr.trim()||`exit ${i.exitCode}`}`);return{checksumSha256:null,etag:JSON.parse(i.stdout||"{}").ETag??null}}catch(o){let i=await Ii(["s3api","abort-multipart-upload","--bucket",e.destBucket,"--key",e.destKey,"--upload-id",r],e.env).catch(()=>({exitCode:1,stderr:"abort-multipart-upload could not be invoked"}));if(i.exitCode!==0)console.warn([`[content-recovery] FAILED to abort multipart upload ${r}`,`for ${e.destBucket}/${e.destKey}: ${i.stderr.trim().slice(0,300)}.`,"It is billable storage invisible to every object listing; clear it with",`aws s3api abort-multipart-upload --bucket ${e.destBucket}`,`--key ${e.destKey} --upload-id ${r}`].join(" "));throw o}}async function nWe(e){let{stdout:t,stderr:r,exitCode:n,timedOut:o}=await Ii(["s3api","head-object","--bucket",e.bucket,"--key",e.key,"--checksum-mode","ENABLED","--output","json"],e.env);if(n!==0){let s=o?"timed out":r.trim()||`exit ${n}`;return LHe.test(r)?{object:null,failed:null}:{object:null,failed:s}}let i=JSON.parse(t||"{}");return{object:{size:i.ContentLength??0,etag:i.ETag?.replace(/"/g,"")??null,checksumSha256:i.ChecksumSHA256??null,crc64:i.ChecksumType==="FULL_OBJECT"?i.ChecksumCRC64NVME??null:null},failed:null}}async function Zee(e,t){let r=["s3api","head-object","--no-sign-request","--bucket",e.bucket,"--key",e.object];if(e.version)r.push("--version-id",e.version);let{stderr:n,exitCode:o,timedOut:i}=await Ii(r,t);if(o===0)return{readable:!0,refusedByUpstream:!1,detail:null};let s=i?"timed out":n.trim()||`exit ${o}`;return{readable:!1,refusedByUpstream:BHe.test(n),detail:s}}async function oWe(e,t){let r=["s3api","head-object","--no-sign-request","--checksum-mode","ENABLED","--bucket",e.bucket,"--key",e.object,"--output","json"];if(e.version)r.push("--version-id",e.version);let{stdout:n,stderr:o,exitCode:i,timedOut:s}=await Ii(r,t);if(i!==0)return{crc64:null,failed:s?"timed out":o.trim()||`exit ${i}`};let a=JSON.parse(n||"{}");return{crc64:a.ChecksumType==="FULL_OBJECT"?a.ChecksumCRC64NVME??null:null,failed:null}}async function iWe(e){let{stderr:t,exitCode:r,timedOut:n}=await Ii(["s3api","delete-object","--bucket",e.bucket,"--key",e.key],e.env);if(r===0)return{deleted:!0,detail:null};return{deleted:!1,detail:n?"timed out":t.trim()||`exit ${r}`}}async function ste(e){let{entry:t}=e;if(!t.source)return{key:t.key,size:t.size,action:"unrecoverable",detail:t.reason};let r=t.source.origin,n=(u)=>t.size>Qee&&!ote(u.origin),o="above CopyObject's 5 GB limit; a multipart copy cannot carry the key's SHA-256, and matching the source's CRC64 would only prove we faithfully copied a guess";if(n(t.source)&&(t.alternatives??[]).every(n))return{key:t.key,size:t.size,action:"unrecoverable",origin:r,detail:o};if(!e.apply){for(let u of[t.source,...t.alternatives??[]]){if(n(u))continue;if((await Zee(u,e.env)).readable)return{key:t.key,size:t.size,action:"would-recover",origin:u.origin}}return{key:t.key,size:t.size,action:"unrecoverable",origin:r,detail:"every recorded source for this key is unreadable"}}let i=[t.source,...t.alternatives??[]].filter((u)=>!n(u)),s=[];for(let u of i){let d;try{d=await eWe({source:u,destBucket:e.destBucket,destKey:e.destKey,env:e.env})}catch(b){let x=b instanceof Error?b.message:String(b);if(s.push(x),MHe.test(x))continue;return{key:t.key,size:t.size,action:"failed",origin:u.origin,detail:x}}let f=await nWe({bucket:e.destBucket,key:e.destKey,env:e.env}),m=d.checksumSha256??f.object?.checksumSha256??null,p=!m&&f.object?.crc64?await oWe(u,e.env):null;if(p?.failed)s.push(`could not read the source's CRC64: ${p.failed}`);let h=YHe({key:t.key,origin:u.origin,checksumSha256:m,etag:d.etag??f.object?.etag??null,size:f.object?.size??null,crc64:f.object?.crc64??null,sourceCrc64:p?.crc64??null});if(h.ok)return{key:t.key,size:t.size,action:"recovered",origin:u.origin,verification:h.method};let y=await iWe({bucket:e.destBucket,key:e.destKey,env:e.env});return{key:t.key,size:t.size,action:"failed",detail:[`refused by ${h.method}: ${h.detail}`,y.deleted?"the object was deleted":`the object was LEFT IN THE BUCKET (delete failed: ${y.detail})`].join("; "),origin:u.origin,leftInBucket:!y.deleted}}let a=await Zee(t.source,e.env),c=s[s.length-1]??"no candidate source could be copied";if(a.refusedByUpstream)return{key:t.key,size:t.size,action:"unrecoverable",origin:t.source.origin,detail:`upstream will not serve any recorded source for this key (${a.detail}): ${c.slice(0,160)}`};return{key:t.key,size:t.size,action:"failed",origin:t.source.origin,detail:a.readable?c:`the source could not be probed (${a.detail}), so whether upstream serves it is unknown: ${c.slice(0,160)}`}}var MHe,LHe,BHe,Qee=5368709120,UHe=1073741824,zHe=8,L2=1800000,B2,VHe,JHe,ZHe=4,QHe=750;var ate=O(()=>{gp();vt();Oi();MHe=/\((?:AccessDenied|NoSuchVersion|NoSuchKey|NotFound|Forbidden|InvalidArgument|403|404)\)/i,LHe=/\((?:404|NoSuchKey|NotFound)\)/i,BHe=/\((?:403|404|AccessDenied|Forbidden|NoSuchKey|NotFound|NoSuchVersion|InvalidArgument)\)/i,B2=["AWS_ENDPOINT_URL","AWS_ENDPOINT_URL_S3"],VHe={SHA256:64,SHA256E:64,MD5:32,MD5E:32};JHe=/\((?:429|503|SlowDown|Throttling\w*|ThrottledException|RequestTimeout|RequestTimeoutException|InternalError|ServiceUnavailable)\)|Rate exceeded/i});import{rmSync as z2}from"fs";import{join as sWe}from"path";async function cWe(e){let t=await Yl(e),r=new Map;for(let[n,o]of t){let i=r.get(o)??[];i.push(n),r.set(o,i)}return r}function lte(e){return/does not exist in/.test(e)}async function lWe(e,t,r){let n=new Map;if(r.length===0)return n;let o=Bun.spawn({cmd:["git","cat-file","--batch"],cwd:e,stdin:new TextEncoder().encode(r.map((u)=>`${t}:${u}
|
|
196
|
+
`)){let i=/^(\S+?)s?\s+([0-9a-f-]{36}):V\s+([+-])(\S+)$/.exec(o.trim());if(!i)continue;let s=t.get(i[2]);if(!s?.bucket)continue;let a=GHe(i[4]),c=a.indexOf("#");if(c<=0)continue;let u=Number.parseFloat(i[1])||0;r.push({stamp:u,retracted:i[3]==="-",value:a,pin:{bucket:s.bucket,object:a.slice(c+1),version:a.slice(0,c),remoteName:s.name}})}r.sort((o,i)=>o.stamp-i.stamp);let n=new Map;for(let o of r)if(o.retracted)n.delete(o.value);else n.set(o.value,o.pin);return[...n.values()]}async function rte(e){let t=["aws","s3api","list-object-versions","--bucket",e.bucket,"--prefix",e.prefix,"--output","json","--query","Versions[].[Key,VersionId,Size,ETag]","--page-size","1000"];if(!e.signed)t.push("--no-sign-request");let{stdout:r,stderr:n,exitCode:o,timedOut:i}=await C(t,{unsetEnv:B2,timeout:L2});if(o!==0||i)throw Error(`listing s3://${e.bucket}/${e.prefix} failed: ${i?"timed out":n.trim()||`exit ${o}`}`);return HHe(r)}function HHe(e){let t=new Map,r=e.trim()?JSON.parse(e):[];for(let[n,o,i,s]of r??[]){let a=t.get(n)??[];a.push({object:n,version:o,size:i,etag:(s??"").replace(/"/g,"")}),t.set(n,a)}return t}function nte(e){let t=ete(e.key);if(!t)return{key:e.key,size:0,reason:"not a parseable annex key"};let r={key:e.key,size:t.size},n=e.pins[e.pins.length-1],o=e.upstream?WHe(t.size,e):null;if(n){let i=o&&o.version!==n.version?[o]:void 0;return{...r,source:{...n,origin:"pinned",size:t.size},alternatives:i}}if(!e.upstream)return{...r,reason:"no upstream remote to recover from"};if(o)return{...r,source:o};return{...r,reason:KHe(t.size,e)}}function WHe(e,t){let r=t.upstream;if(!r)return null;let n=t.paths.flatMap((s)=>r.index.get(`${r.prefix}${s}`)?.filter((a)=>a.size===e)??[]),o=new Map(n.map((s)=>[s.etag,s]));if(o.size!==1)return null;let[i]=o.values();return{bucket:r.bucket,object:i.object,version:i.version,remoteName:"upstream",origin:"version-match",size:e}}function KHe(e,t){let r=t.upstream;if(!r)return"no upstream remote to recover from";let n=t.paths.flatMap((i)=>r.index.get(`${r.prefix}${i}`)?.filter((s)=>s.size===e)??[]),o=new Set(n.map((i)=>i.etag));return o.size>1?`${o.size} distinct upstream objects carry this key's size; refusing to guess`:"no upstream object of this key's size at any of its paths"}function ote(e){return e==="pinned"}function YHe(e){let t=ete(e.key);if(!t)return{ok:!1,method:"unparseable-key",detail:"unparseable key"};if(e.checksumSha256&&t.backend.startsWith("SHA256")&&t.hashHex){let n=Buffer.from(t.hashHex,"hex").toString("base64");return e.checksumSha256===n?{ok:!0,method:"checksum"}:{ok:!1,method:"checksum",detail:`S3 hashed the object to ${e.checksumSha256}, the key says ${n}`}}let r=e.etag?.replace(/"/g,"");if(r&&!r.includes("-")&&t.backend.startsWith("MD5")&&t.hashHex)return r===t.hashHex?{ok:!0,method:"etag"}:{ok:!1,method:"etag",detail:`the object's MD5 is ${r}, the key says ${t.hashHex}`};if(e.size==null)return{ok:!1,method:"unmeasured",detail:"the bucket did not answer for the copy, so nothing about it was checked"};if(e.size!==t.size)return{ok:!1,method:"size",detail:`the object is ${e.size} bytes, the key says ${t.size}`};if(!ote(e.origin))return{ok:!1,method:"size-and-pin",detail:"only the size could be checked, and nothing pins this source to this key"};if(e.sourceCrc64&&e.crc64)return e.sourceCrc64===e.crc64?{ok:!0,method:"crc64-of-source"}:{ok:!1,method:"crc64-of-source",detail:`the copy's CRC64 is ${e.crc64}, the source reads ${e.sourceCrc64}`};return{ok:!0,method:"size-and-pin"}}function ite(e){let t=`${e.bucket}/${e.object}`;return e.version?`${t}?versionId=${e.version}`:t}function XHe(e){return JHe.test(e)}async function Ii(e,t){let r=await C(["aws",...e],{env:t,unsetEnv:B2,timeout:L2});for(let n=1;n<=ZHe;n++){if(r.exitCode===0||!XHe(r.stderr))return r;let o=QHe*2**(n-1)*(1+Math.random());await new Promise((i)=>setTimeout(i,o)),r=await C(["aws",...e],{env:t,unsetEnv:B2,timeout:L2})}return r}async function eWe(e){if(e.source.size>Qee)return{...await rWe(e),multipart:!0};let{stdout:t,stderr:r,exitCode:n,timedOut:o}=await Ii(["s3api","copy-object","--bucket",e.destBucket,"--key",e.destKey,"--copy-source",ite(e.source),"--tagging-directive","REPLACE","--tagging","","--checksum-algorithm","SHA256","--output","json"],e.env);if(n!==0)throw Error(`copy-object failed: ${o?"timed out":r.trim()||`exit ${n}`}`);let i=JSON.parse(t||"{}");return{checksumSha256:i.CopyObjectResult?.ChecksumSHA256??null,etag:i.CopyObjectResult?.ETag?.replace(/"/g,"")??null,multipart:!1}}function tWe(e,t){let r=[];for(let n=0,o=1;n<e;n+=t,o++)r.push({part:o,offset:n,end:Math.min(n+t,e)-1});return r}async function rWe(e){let t=await Ii(["s3api","create-multipart-upload","--bucket",e.destBucket,"--key",e.destKey,"--checksum-algorithm","CRC64NVME","--checksum-type","FULL_OBJECT","--output","json"],e.env);if(t.exitCode!==0)throw Error(`create-multipart-upload failed: ${t.stderr.trim()||`exit ${t.exitCode}`}`);let r=JSON.parse(t.stdout||"{}").UploadId;if(!r)throw Error("create-multipart-upload returned no UploadId");let n=tWe(e.source.size,UHe);try{let o=await hp(n,zHe,async(a)=>{let c=await Ii(["s3api","upload-part-copy","--bucket",e.destBucket,"--key",e.destKey,"--upload-id",r,"--part-number",String(a.part),"--copy-source",ite(e.source),"--copy-source-range",`bytes=${a.offset}-${a.end}`,"--output","json"],e.env);if(c.exitCode!==0)throw Error(`upload-part-copy ${a.part} failed: ${c.stderr.trim()||`exit ${c.exitCode}`}`);let u=JSON.parse(c.stdout||"{}").CopyPartResult?.ETag;if(!u)throw Error(`upload-part-copy ${a.part} returned no ETag`);return{ETag:u,PartNumber:a.part}}),i=await Ii(["s3api","complete-multipart-upload","--bucket",e.destBucket,"--key",e.destKey,"--upload-id",r,"--multipart-upload",JSON.stringify({Parts:o}),"--output","json"],e.env);if(i.exitCode!==0)throw Error(`complete-multipart-upload failed: ${i.stderr.trim()||`exit ${i.exitCode}`}`);return{checksumSha256:null,etag:JSON.parse(i.stdout||"{}").ETag??null}}catch(o){let i=await Ii(["s3api","abort-multipart-upload","--bucket",e.destBucket,"--key",e.destKey,"--upload-id",r],e.env).catch(()=>({exitCode:1,stderr:"abort-multipart-upload could not be invoked"}));if(i.exitCode!==0)console.warn([`[content-recovery] FAILED to abort multipart upload ${r}`,`for ${e.destBucket}/${e.destKey}: ${i.stderr.trim().slice(0,300)}.`,"It is billable storage invisible to every object listing; clear it with",`aws s3api abort-multipart-upload --bucket ${e.destBucket}`,`--key ${e.destKey} --upload-id ${r}`].join(" "));throw o}}async function nWe(e){let{stdout:t,stderr:r,exitCode:n,timedOut:o}=await Ii(["s3api","head-object","--bucket",e.bucket,"--key",e.key,"--checksum-mode","ENABLED","--output","json"],e.env);if(n!==0){let s=o?"timed out":r.trim()||`exit ${n}`;return LHe.test(r)?{object:null,failed:null}:{object:null,failed:s}}let i=JSON.parse(t||"{}");return{object:{size:i.ContentLength??0,etag:i.ETag?.replace(/"/g,"")??null,checksumSha256:i.ChecksumSHA256??null,crc64:i.ChecksumType==="FULL_OBJECT"?i.ChecksumCRC64NVME??null:null},failed:null}}async function Zee(e,t){let r=["s3api","head-object","--no-sign-request","--bucket",e.bucket,"--key",e.object];if(e.version)r.push("--version-id",e.version);let{stderr:n,exitCode:o,timedOut:i}=await Ii(r,t);if(o===0)return{readable:!0,refusedByUpstream:!1,detail:null};let s=i?"timed out":n.trim()||`exit ${o}`;return{readable:!1,refusedByUpstream:BHe.test(n),detail:s}}async function oWe(e,t){let r=["s3api","head-object","--no-sign-request","--checksum-mode","ENABLED","--bucket",e.bucket,"--key",e.object,"--output","json"];if(e.version)r.push("--version-id",e.version);let{stdout:n,stderr:o,exitCode:i,timedOut:s}=await Ii(r,t);if(i!==0)return{crc64:null,failed:s?"timed out":o.trim()||`exit ${i}`};let a=JSON.parse(n||"{}");return{crc64:a.ChecksumType==="FULL_OBJECT"?a.ChecksumCRC64NVME??null:null,failed:null}}async function iWe(e){let{stderr:t,exitCode:r,timedOut:n}=await Ii(["s3api","delete-object","--bucket",e.bucket,"--key",e.key],e.env);if(r===0)return{deleted:!0,detail:null};return{deleted:!1,detail:n?"timed out":t.trim()||`exit ${r}`}}async function ste(e){let{entry:t}=e;if(!t.source)return{key:t.key,size:t.size,action:"unrecoverable",detail:t.reason};let r=t.source.origin,n=(u)=>t.size>Qee&&!ote(u.origin),o="above CopyObject's 5 GB limit; a multipart copy cannot carry the key's SHA-256, and matching the source's CRC64 would only prove we faithfully copied a guess";if(n(t.source)&&(t.alternatives??[]).every(n))return{key:t.key,size:t.size,action:"unrecoverable",origin:r,detail:o};if(!e.apply){for(let u of[t.source,...t.alternatives??[]]){if(n(u))continue;if((await Zee(u,e.env)).readable)return{key:t.key,size:t.size,action:"would-recover",origin:u.origin}}return{key:t.key,size:t.size,action:"unrecoverable",origin:r,detail:"every recorded source for this key is unreadable"}}let i=[t.source,...t.alternatives??[]].filter((u)=>!n(u)),s=[];for(let u of i){let d;try{d=await eWe({source:u,destBucket:e.destBucket,destKey:e.destKey,env:e.env})}catch(b){let x=b instanceof Error?b.message:String(b);if(s.push(x),MHe.test(x))continue;return{key:t.key,size:t.size,action:"failed",origin:u.origin,detail:x}}let f=await nWe({bucket:e.destBucket,key:e.destKey,env:e.env}),m=d.checksumSha256??f.object?.checksumSha256??null,p=!m&&f.object?.crc64?await oWe(u,e.env):null;if(p?.failed)s.push(`could not read the source's CRC64: ${p.failed}`);let h=YHe({key:t.key,origin:u.origin,checksumSha256:m,etag:d.etag??f.object?.etag??null,size:f.object?.size??null,crc64:f.object?.crc64??null,sourceCrc64:p?.crc64??null});if(h.ok)return{key:t.key,size:t.size,action:"recovered",origin:u.origin,verification:h.method};let y=await iWe({bucket:e.destBucket,key:e.destKey,env:e.env});return{key:t.key,size:t.size,action:"failed",detail:[`refused by ${h.method}: ${h.detail}`,y.deleted?"the object was deleted":`the object was LEFT IN THE BUCKET (delete failed: ${y.detail})`].join("; "),origin:u.origin,leftInBucket:!y.deleted}}let a=await Zee(t.source,e.env),c=s[s.length-1]??"no candidate source could be copied";if(a.refusedByUpstream)return{key:t.key,size:t.size,action:"unrecoverable",origin:t.source.origin,detail:`upstream will not serve any recorded source for this key (${a.detail}): ${c.slice(0,160)}`};return{key:t.key,size:t.size,action:"failed",origin:t.source.origin,detail:a.readable?c:`the source could not be probed (${a.detail}), so whether upstream serves it is unknown: ${c.slice(0,160)}`}}var MHe,LHe,BHe,Qee=5368709120,UHe=1073741824,zHe=8,L2=1800000,B2,VHe,JHe,ZHe=4,QHe=750;var ate=O(()=>{gp();vt();Oi();MHe=/\((?:AccessDenied|NoSuchVersion|NoSuchKey|NotFound|Forbidden|InvalidArgument|403|404)\)/i,LHe=/\((?:404|NoSuchKey|NotFound)\)/i,BHe=/\((?:403|404|AccessDenied|Forbidden|NoSuchKey|NotFound|NoSuchVersion|InvalidArgument)\)/i,B2=["AWS_ENDPOINT_URL","AWS_ENDPOINT_URL_S3"],VHe={SHA256:64,SHA256E:64,MD5:32,MD5E:32};JHe=/\((?:429|503|SlowDown|Throttling\w*|ThrottledException|RequestTimeout|RequestTimeoutException|InternalError|ServiceUnavailable)\)|Rate exceeded/i});import{rmSync as z2}from"fs";import{join as sWe}from"path";async function cWe(e){let t=await Yl(e),r=new Map;for(let[n,o]of t){let i=r.get(o)??[];i.push(n),r.set(o,i)}return r}function lte(e){return/does not exist in/.test(e)}async function lWe(e,t,r){let n=new Map;if(r.length===0)return n;let o=Bun.spawn({cmd:["git","cat-file","--batch"],cwd:e,stdin:new TextEncoder().encode(r.map((u)=>`${t}:${u}
|
|
197
197
|
`).join("")),stdout:"pipe",stderr:"pipe"}),i=Buffer.from(await new Response(o.stdout).arrayBuffer()),s=await new Response(o.stderr).text(),a=await o.exited;if(a!==0)throw Error(`git cat-file --batch failed over ${r.length} record(s): ${s.trim()||`exit ${a}`}`);let c=0;for(let u of r){let d=i.indexOf(10,c);if(d<0)throw Error(`git cat-file --batch returned ${n.size} of ${r.length} record(s); the stream ended early`);let f=i.subarray(c,d).toString("utf8").split(" ");if(f[1]==="missing"){c=d+1;continue}let m=Number(f[2]);if(!Number.isFinite(m)||m<0)throw Error(`git cat-file --batch returned an unparseable header for ${u}`);let p=d+1;n.set(u,i.subarray(p,p+m).toString("utf8")),c=p+m+1}return n}async function uWe(e,t,r="git-annex"){let n=await C(["git","show",`${r}:remote.log`],{cwd:e});if(n.exitCode!==0&&!lte(n.stderr))throw Error(`could not read ${r}:remote.log: ${n.stderr.trim()||`exit ${n.exitCode}`}`);let o=U2(n.stdout),i=await C(["git","ls-tree","-r","--name-only",r],{cwd:e});if(i.exitCode!==0)throw Error(`could not list ${r}: ${i.stderr.trim()||`exit ${i.exitCode}`}`);let s=new Set(t),a=[];for(let d of i.stdout.split(`
|
|
198
198
|
`)){if(!d.endsWith(".log.rmet"))continue;let f=d.slice(d.lastIndexOf("/")+1,-9);if(s.has(f))a.push([f,d])}let c=await lWe(e,r,a.map(([,d])=>d)),u=new Map;for(let[d,f]of a){let m=c.get(f);if(!m)continue;let p=tte(m,o);if(p.length>0)u.set(d,p)}return u}async function dWe(e,t,r=mp,n="git-annex"){let{stdout:o,stderr:i,exitCode:s}=await C(["git","show",`${n}:remote.log`],{cwd:e});if(s!==0&&!lte(i))throw Error(`could not read ${n}:remote.log to find ${r}'s object prefix: ${i.trim()||`exit ${s}`}`);for(let a of U2(o).values())if(a.name===r&&a.fileprefix)return a.fileprefix;return`${t}/objects/`}function Py(e,t,r){let n=(d)=>r.filter(d).reduce((f,m)=>f+m.size,0),o=r.filter((d)=>d.action==="recovered").length,i=r.filter((d)=>d.action==="unrecoverable").length,s=r.filter((d)=>d.action==="failed").length,a=r.filter((d)=>d.action==="would-recover").length,c=t.length-r.length,u;if(t.length===0)u="nothing-missing";else if(s>0)u="failed";else if(a>0)u="would-recover";else if(o>0)u=i>0||c>0?"partial":"recovered";else u="unrecoverable";return{datasetId:e,action:u,measured:!0,missing:t.length,missingBytes:t.reduce((d,f)=>d+f.size,0),recovered:o,recoveredBytes:n((d)=>d.action==="recovered"),unrecoverable:i,unrecoverableBytes:n((d)=>d.action==="unrecoverable"),failed:s,keys:r}}async function fWe(e,t,r){let n={...Py(e,[],[]),measured:!1,action:"failed"};if(!aWe.test(e))return{...n,error:`"${e}" is not a dataset id, and it would become a directory this deletes`};let o=sWe(r.workRoot,e);z2(o,{recursive:!0,force:!0});let i=r.originUrl??`https://github.com/nemarDatasets/${e}.git`,s=await M2(i,o,{partial:!1,description:"fleet-content-recovery"});if(s)return z2(o,{recursive:!0,force:!0}),{...n,error:s};try{let a=await cWe(o),c=await t(e),u=[...a.keys()].filter((x)=>!nn(x,c));if(u.length===0)return Py(e,[],[]);let d=await uWe(o,u),f;if(e.startsWith("on")){let x=`ds${e.slice(2)}/`;f={bucket:cte,prefix:x,index:await rte({bucket:cte,prefix:x})}}let m=u.map((x)=>nte({key:x,paths:a.get(x)??[],pins:d.get(x)??[],upstream:f})).sort((x,w)=>x.size-w.size),p=r.limit?m.slice(0,r.limit):m,h=await dWe(o,e,r.remoteName),y=0,b=await hp(p,r.concurrency??8,async(x)=>{let w=await ste({entry:x,destBucket:"nemar",destKey:`${h}${x.key}`,apply:r.apply===!0,env:r.env});return r.onKey?.(w,++y,p.length),w});return Py(e,m,b)}catch(a){return{...n,error:a instanceof Error?a.message:String(a)}}finally{z2(o,{recursive:!0,force:!0})}}async function ute(e,t,r){let n=[...new Set(e)],o=[],i=0;for(let u of n){let d;try{d=await fWe(u,t,r)}catch(f){d={...Py(u,[],[]),measured:!1,action:"failed",error:f instanceof Error?f.message:String(f)}}o.push(d),r.onDataset?.(d,++i,n.length)}let s={"nothing-missing":0,recovered:0,"would-recover":0,partial:0,unrecoverable:0,failed:0},a=0,c=0;for(let u of o)s[u.action]++,a+=u.recovered,c+=u.recoveredBytes;return{outcomes:o,tally:s,recoveredKeys:a,recoveredBytes:c}}var aWe,cte="openneuro.org";var dte=O(()=>{ate();gp();vt();kn();Oi();aWe=/^[a-z]{2}[0-9]{6}$/});var mne,M_t;var hne=O(()=>{mne=["IsCitedBy","Cites","IsSupplementTo","IsSupplementedBy","IsContinuedBy","Continues","IsDescribedBy","Describes","HasMetadata","IsMetadataFor","HasVersion","IsVersionOf","IsNewVersionOf","IsPreviousVersionOf","IsPartOf","HasPart","IsReferencedBy","References","IsDocumentedBy","Documents","IsCompiledBy","Compiles","IsVariantFormOf","IsOriginalFormOf","IsIdenticalTo","IsCollectedBy","Collects","IsRequiredBy","Requires","IsObsoletedBy","Obsoletes","IsDerivedFrom","IsSourceOf","IsReviewedBy","Reviews","IsPublishedIn","HasTranslation","IsTranslationOf"],M_t=new Set(mne)});var gne=()=>{};function yne(e){return e.replace(/^(doi:|https?:\/\/(dx\.)?doi\.org\/)/i,"").trim()}function bne(e){let t=e.split(",").map((r)=>r.trim());if(t.length>=2)return{name:e,familyName:t[0],givenName:t.slice(1).join(", ")};return{name:e}}var xne=O(()=>{hne();gne()});function TYe(e){let t=[],r=new Set,n=(o,i)=>{let s=yne(o).trim();if(PYe.test(s)&&!r.has(s))r.add(s),t.push({doi:s,source:i})};if(Array.isArray(e.SourceDatasets))for(let o of e.SourceDatasets){if(!o||typeof o!=="object")continue;let i=o;if(typeof i.DOI==="string")n(i.DOI,"SourceDatasets");else if(typeof i.URL==="string"){let s=i.URL.match(/(?:doi\.org\/|doi:)(10\.\d{4,}\/.+)/);if(s)n(s[1],"SourceDatasets")}}if(Array.isArray(e.ReferencesAndLinks))for(let o of e.ReferencesAndLinks){if(typeof o!=="string"||!o)continue;let i=o.match(/(?:doi\.org\/|^)(10\.\d{4,}\/[^\s]+)/);if(i)n(i[1],"ReferencesAndLinks")}if(typeof e.HowToAcknowledge==="string"){let i=e.HowToAcknowledge.matchAll(/(?:doi\.org\/|(?<=\s|^))(10\.\d{4,}\/[^\s,)]+)/g);for(let s of i)n(s[1].replace(/[.;:]+$/,""),"HowToAcknowledge")}return t}function wne(e,t,r){let n=r instanceof Error?r.message:String(r);if(n.includes("AbortError")||n.includes("timeout")||n.includes("fetch"))console.warn(`[orcid-discovery] ${e} query failed for ${t}: ${n}`);else console.error(`[orcid-discovery] Unexpected error querying ${e} for ${t}:`,r)}async function jYe(e){try{let t=await fetch(`${NYe}/${encodeURIComponent(e)}`,{headers:{Accept:"application/vnd.datacite.datacite+json"},signal:AbortSignal.timeout(1e4)});if(!t.ok){if(t.status!==404)console.warn(`[orcid-discovery] DataCite returned HTTP ${t.status} for ${e}`);return null}let r=await t.json();return{doi:e,creators:Array.isArray(r.creators)?r.creators:[]}}catch(t){return wne("DataCite",e,t),null}}async function qYe(e){try{let t=await fetch(`https://api.crossref.org/works/${encodeURIComponent(e)}`,{headers:{Accept:"application/json","User-Agent":"NEMAR/1.0 (https://nemar.org; mailto:nemar@ucsd.edu)"},signal:AbortSignal.timeout(1e4)});if(!t.ok){if(t.status!==404)console.warn(`[orcid-discovery] Crossref returned HTTP ${t.status} for ${e}`);return null}let n=(await t.json()).message?.author;if(!Array.isArray(n)||n.length===0)return null;let o=n.map((i)=>{let s=[];if(i.ORCID)s.push({nameIdentifier:i.ORCID,nameIdentifierScheme:"ORCID"});return{name:i.family&&i.given?`${i.family}, ${i.given}`:i.name||i.family||"",givenName:i.given,familyName:i.family,nameIdentifiers:s,affiliation:(i.affiliation||[]).filter((a)=>a.name)}}).filter((i)=>i.name.trim()!=="");return{doi:e,creators:o}}catch(t){return wne("Crossref",e,t),null}}async function MYe(e){let t=await jYe(e),r=await qYe(e);if(!t)return r;if(!r)return t;for(let n of t.creators){if(n.nameIdentifiers?.some((a)=>a.nameIdentifierScheme==="ORCID")||!n.familyName)continue;let s=r.creators.find((a)=>a.familyName&&An(a.familyName)===An(n.familyName))?.nameIdentifiers?.find((a)=>a.nameIdentifierScheme==="ORCID");if(s)n.nameIdentifiers=[...n.nameIdentifiers??[],s]}return t}function An(e){return e.normalize("NFD").replace(/\p{Diacritic}/gu,"").replace(/\./g,"").toLowerCase().trim()}function _ne(e){if(!e)return"";return An(e).charAt(0)}function LYe(e,t){let r=[],n=new Set,o=new Set,i=t.map((s)=>({original:s,parsed:bne(s)}));for(let s=0;s<e.length;s++){if(o.has(s))continue;let a=e[s],c=An(a.name);for(let u of i){if(n.has(u.original))continue;if(An(u.original)===c){r.push({bidsAuthor:u.original,matchedCreator:a,confidence:"exact"}),n.add(u.original),o.add(s);break}if(u.parsed.familyName&&u.parsed.givenName){if(An(`${u.parsed.givenName} ${u.parsed.familyName}`)===c){r.push({bidsAuthor:u.original,matchedCreator:a,confidence:"exact"}),n.add(u.original),o.add(s);break}}if(a.givenName&&a.familyName){let d=An(`${a.givenName} ${a.familyName}`);if(An(u.original)===d){r.push({bidsAuthor:u.original,matchedCreator:a,confidence:"exact"}),n.add(u.original),o.add(s);break}}}}for(let s=0;s<e.length;s++){if(o.has(s))continue;let a=e[s];if(!a.familyName)continue;let c=An(a.familyName),u=_ne(a.givenName);for(let d of i){if(n.has(d.original))continue;if(!d.parsed.familyName)continue;if(An(d.parsed.familyName)!==c)continue;let m=_ne(d.parsed.givenName);if(m&&u&&m===u){r.push({bidsAuthor:d.original,matchedCreator:a,confidence:"high"}),n.add(d.original),o.add(s);break}}}for(let s=0;s<e.length;s++){if(o.has(s))continue;let a=e[s];if(!a.familyName)continue;let c=An(a.familyName);for(let u of i){if(n.has(u.original))continue;if(!u.parsed.familyName)continue;if(An(u.parsed.familyName)===c){r.push({bidsAuthor:u.original,matchedCreator:a,confidence:"medium"}),n.add(u.original),o.add(s);break}}}return r}async function Dne(e,t,r){let n=TYe(e);if(r?.length)n.push(...r);if(n.length===0)return{discoveries:{},unresolvedDois:[],totalDoisQueried:0};let o=Array.isArray(e.Authors)?e.Authors.filter((d)=>typeof d==="string"):[];if(o.length===0)return{discoveries:{},unresolvedDois:[],totalDoisQueried:n.length};let i=new Set;if(t){for(let[d,f]of Object.entries(t))if(f.orcid)i.add(d)}let s=o.filter((d)=>!i.has(d));if(s.length===0)return{discoveries:{},unresolvedDois:[],totalDoisQueried:n.length};let a=[],c=new Map;for(let d=0;d<n.length;d+=vne){let f=n.slice(d,d+vne),m=await Promise.all(f.map((p)=>MYe(p.doi)));for(let p=0;p<f.length;p++)if(m[p])c.set(f[p].doi,m[p]?.creators??[]);else a.push(f[p].doi)}let u={};for(let[d,f]of c){let m=f.filter((h)=>h.nameIdentifiers?.some((y)=>y.nameIdentifierScheme==="ORCID"));if(m.length===0)continue;let p=LYe(m,s);for(let h of p){if(u[h.bidsAuthor])continue;let y=h.matchedCreator.nameIdentifiers.find((w)=>w.nameIdentifierScheme==="ORCID");if(!y)continue;let b=y.nameIdentifier.replace(/^https?:\/\/orcid\.org\//i,"").trim();if(!IYe.test(b))continue;let x=h.matchedCreator.affiliation?.filter((w)=>w.name).map((w)=>({name:w.name,...w.affiliationIdentifier&&{identifier:w.affiliationIdentifier},...w.affiliationIdentifierScheme&&{scheme:w.affiliationIdentifierScheme}}));u[h.bidsAuthor]={orcid:b,affiliations:x?.length?x:void 0,sourceDoi:d,confidence:h.confidence}}}return{discoveries:u,unresolvedDois:a,totalDoisQueried:n.length}}var PYe,IYe,NYe="https://api.datacite.org/application/vnd.datacite.datacite+json",vne=5;var Ene=O(()=>{xne();PYe=/^10\.\d{4,}\/[^\s]+$/,IYe=/^\d{4}-\d{4}-\d{4}-[\dX]{4}$/});Xe();var $b={};IS($b,{program:()=>a$,createCommand:()=>c$,createOption:()=>l$,createArgument:()=>u$,Command:()=>d$,Option:()=>f$,Argument:()=>p$,Help:()=>m$,CommanderError:()=>h$,InvalidArgumentError:()=>g$,InvalidOptionArgumentError:()=>y$},{program:(iXe)=>a$=iXe,createCommand:(iXe)=>c$=iXe,createOption:(iXe)=>l$=iXe,createArgument:(iXe)=>u$=iXe,Command:(iXe)=>d$=iXe,Option:(iXe)=>f$=iXe,Argument:(iXe)=>p$=iXe,Help:(iXe)=>m$=iXe,CommanderError:(iXe)=>h$=iXe,InvalidArgumentError:(iXe)=>g$=iXe,InvalidOptionArgumentError:(iXe)=>y$=iXe});var{Argument:o$}=Pp(),{Command:Sb}=n$(),{CommanderError:wie,InvalidArgumentError:i$}=au(),{Help:Die}=xb(),{Option:s$}=_b();var a$=new Sb,c$=(e)=>new Sb(e),l$=(e,t)=>new s$(e,t),u$=(e,t)=>new o$(e,t),d$=Sb,f$=s$,p$=o$,m$=Die,h$=wie,g$=i$,y$=i$;var{program:aXe,createCommand:cXe,createArgument:lXe,createOption:uXe,CommanderError:dXe,InvalidArgumentError:Cb,InvalidOptionArgumentError:fXe,Command:ae,Argument:pXe,Option:cu,Help:mXe}=$b;var kb={dataset:["search","download","upload","validate","status","list"],admin:["users","approve","revoke","publish","doi","make-public","delete-dataset","notify","doctor"]};var Rb=process.argv.includes("--help-all");if(process.argv.includes("--no-color"))l.level=0;var b$=process.argv.indexOf("--help-all");if(b$!==-1)process.argv[b$]="--help";var lu=ae.prototype.addHelpText,x$=`
|
|
199
199
|
Run with --help-all for examples and detailed descriptions.
|
package/package.json
CHANGED