buckyos 0.7.153 → 0.7.154
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/cli/dist/cli.mjs +1 -1
- package/cli/dist/cli.mjs.map +1 -1
- package/cli/version.ts +1 -1
- package/dist/nfsp.cjs +1 -1
- package/dist/nfsp.cjs.map +1 -1
- package/dist/nfsp.d.ts +105 -0
- package/dist/nfsp.d.ts.map +1 -1
- package/dist/nfsp.mjs +14 -0
- package/dist/nfsp.mjs.map +1 -1
- package/package.json +1 -1
package/cli/version.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// Generated by scripts/generate-cli-version.mjs. Do not edit.
|
|
2
|
-
export const PACKAGE_VERSION = '0.7.
|
|
2
|
+
export const PACKAGE_VERSION = '0.7.154'
|
|
3
3
|
export const TOOL_VERSION = PACKAGE_VERSION
|
|
4
4
|
export const SDK_VERSION = PACKAGE_VERSION
|
|
5
5
|
export const PROTOCOL_VERSION = '1'
|
package/dist/nfsp.cjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e="nfsp/0",t=e=>"string"==typeof e?e.includes("://")?{uri:e}:{realm:"dfs",path:e}:"type"in e?{ref:e}:e,s=()=>"undefined"!=typeof crypto&&"randomUUID"in crypto?crypto.randomUUID():`${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}`;class a extends Error{constructor(e,t){super(`${e.code}: ${e.message}`),this.name="NfspError",this.code=e.code,this.httpStatus=t,this.details=Object.fromEntries(Object.entries(e).filter((([e])=>"code"!==e&&"message"!==e)))}}const r=e=>{const t={};for(const[s,a]of Object.entries(e))void 0!==a&&(t[s]=a);return t};exports.NFSP_VERSION=e,exports.NfspClient=class{constructor(e){this.session=null,this.seq=0,this.helloResult=null,this.sessionToken=e.sessionToken,this.baseUrl=e.baseUrl.replace(/\/+$/,""),this.fetchFn=e.fetch??((e,t)=>globalThis.fetch(e,t)),this.chunkSize=e.uploadChunkSize??8388608}get sessionId(){return this.session}get features(){var e;return(null==(e=this.helloResult)?void 0:e.features)??[]}get limits(){var e;return(null==(e=this.helloResult)?void 0:e.limits)??null}async hello(t){const s={versions:[e]};t&&(s.features=t);const a=await this.post("hello",{args:s});return this.session=a.session,this.seq=0,this.helloResult=a,a}async bye(){await this.call("bye",{}),this.session=null,this.helloResult=null}async resolve(e,s){return await this.call("resolve",{at:t(e),want:s})}async stat(e,s){return await this.call("stat",{at:t(e),want:null==s?void 0:s.want,args:(null==s?void 0:s.name)?{name:s.name}:{}})}async list(e,s,a){return await this.call("list",{at:t(e),want:a,args:s??{}})}async batch(e,s,a="abort"){return await this.call("batch",{args:{start:t(e),ops:s,on_error:a}})}async mkdir(e,s,a){const r={};return void 0!==s&&(r.name=s),(null==a?void 0:a.expectedRevision)&&(r.expected_revision=a.expectedRevision),await this.write("mkdir",{at:t(e),args:r})}async move(e,t,s){return await this.write("move",{args:{from:{parent_ref:e.parentRef,name:e.name},to:{parent_ref:t.parentRef,name:t.name},expected_from_revision:null==s?void 0:s.expectedFromRevision,expected_to_revision:null==s?void 0:s.expectedToRevision}})}async delete(e,s,a){return await this.write("delete",{at:t(e),args:{name:s,recursive:null==a?void 0:a.recursive,expected_revision:null==a?void 0:a.expectedRevision}})}async bindRef(e,t,s,a){return await this.write("bind_ref",{args:{parent_ref:e,name:t,target_ref:s,expected_revision:null==a?void 0:a.expectedRevision}})}async unlink(e,t){return await this.write("unlink",{args:{entry_ref:e,expected_revision:null==t?void 0:t.expectedRevision}})}async openWrite(e){const t="ref"in e?{ref:e.ref}:{parent_ref:e.parentRef,name:e.name,size:e.size};return await this.write("open_write",{args:t})}async uploadOffset(e){const t=await this.fetchFn(`${this.baseUrl}/nfs/v1/uploads/${e}`,{method:"HEAD",headers:await this.authHeaders()});if(!t.ok)throw await this.httpError(t);return Number(t.headers.get("Upload-Offset")??"0")}async uploadChunk(e,t,s){const a=await this.fetchFn(`${this.baseUrl}/nfs/v1/uploads/${e}`,{method:"PATCH",headers:{...await this.authHeaders(),"Upload-Offset":String(t),"Content-Type":"application/offset+octet-stream"},body:s});if(204!==a.status)throw await this.httpError(a);return Number(a.headers.get("Upload-Offset")??String(t+s.byteLength))}async uploadContent(e,t,s){let a=await this.uploadOffset(e);for(;a<t.byteLength;){const r=t.subarray(a,Math.min(a+this.chunkSize,t.byteLength));a=await this.uploadChunk(e,a,r),null==s||s(a,t.byteLength)}}async abortWrite(e){await this.write("abort_write",{args:{lease_id:e}})}async authHeaders(){var e;const t=await(null==(e=this.sessionToken)?void 0:e.call(this));return t?{Authorization:`Bearer ${t}`}:{}}async commitFile(e,s,a,r){const i={name:s,overwrite:null==r?void 0:r.overwrite,expected_revision:null==r?void 0:r.expectedRevision};return"fbHandle"in a?(i.fb_handle=a.fbHandle,a.leaseId&&(i.lease_id=a.leaseId)):i.hash=a.hash,await this.write("commit_file",{at:t(e),args:i})}async commitObject(e,s,a,r){return await this.write("commit_object",{at:t(e),args:{name:s,obj_id:a,overwrite:null==r?void 0:r.overwrite,expected_revision:null==r?void 0:r.expectedRevision,lease_id:null==r?void 0:r.leaseId}})}async probe(e){return await this.call("probe",{args:{digests:e}})}async uploadFile(e,t,s,a){const r=await this.openWrite({parentRef:e,name:t,size:s.byteLength});return await this.uploadContent(r.fb_handle,s,null==a?void 0:a.onProgress),this.commitFile({ref:e},t,{fbHandle:r.fb_handle,leaseId:r.lease.lease_id},{overwrite:null==a?void 0:a.overwrite})}readUrl(e,t){const s=new URLSearchParams;(null==t?void 0:t.download)&&s.set("download","1"),(null==t?void 0:t.name)&&s.set("name",t.name);const a=s.size>0?`?${s.toString()}`:"";return`${this.baseUrl}/nfs/v1/read/${encodeURIComponent(e)}${a}`}async readFile(e,t){const s=await this.authHeaders();(null==t?void 0:t.range)&&(s.Range=`bytes=${t.range.start}-${t.range.end??""}`),(null==t?void 0:t.ifNoneMatch)&&(s["If-None-Match"]=t.ifNoneMatch);const a=await this.fetchFn(this.readUrl(e),{headers:s,cache:"no-store"});if(!a.ok&&304!==a.status)throw await this.httpError(a);return a}async getMeta(e,s){const a=t(e),r={ns:s};return a.ref&&(r.ref=a.ref),await this.call("get_meta",{at:a,args:r})}async setMeta(e,s){const a=t(e),r={records:s};return a.ref&&(r.ref=a.ref),await this.write("set_meta",{at:a,args:r})}async search(e,s,a){return await this.call("search",{want:a,args:{q:e,limit:null==s?void 0:s.limit,cursor:null==s?void 0:s.cursor,scope:void 0!==(null==s?void 0:s.scope)?t(s.scope):void 0,modes:null==s?void 0:s.modes}})}async openView(e,t){return await this.call("open_view",{want:t,args:{view_id:e}})}async createCollection(e,t,s){return await this.write("create_collection",{want:s,args:{title:e,collection_id:t}})}async openCollection(e,t){return await this.call("open_collection",{want:t,args:{collection_id:e}})}async collectionPatch(e,t,s){return await this.write("collection_patch",{args:{ref:e,ops:t,expected_revision:null==s?void 0:s.expectedRevision}})}async grant(e,s){return await this.write("grant",{args:{subtree:t(e),ops:null==s?void 0:s.ops,ttl:null==s?void 0:s.ttl,audience:null==s?void 0:s.audience,max_uses:null==s?void 0:s.maxUses}})}async revoke(e){return await this.write("revoke",{args:{cap_id:e}})}async getAcl(e){return await this.call("get_acl",{at:t(e)})}async setAcl(e,s,a){return await this.write("set_acl",{at:t(e),args:{inherit:s.inherit,entries:s.entries,expected_revision:null==a?void 0:a.expectedRevision}})}async listAcls(){return await this.call("list_acls",{})}async shareCapabilities(){return await this.call("share.capabilities",{})}async sharePlan(e,s){return await this.call("share.plan",{args:{source:t(e),intent:null==s?void 0:s.intent,target:null==s?void 0:s.target}})}async shareCreate(e,a,r){return await this.write("share.create",{args:{source:t(e),policy:a,title:null==r?void 0:r.title,idempotency_key:(null==r?void 0:r.idempotencyKey)??s(),plan_fingerprint:null==r?void 0:r.planFingerprint,source_hint:null==r?void 0:r.sourceHint}})}async shareOperation(e,t){return await this.call("share.operation",{args:{operation_id:e,cancel:null==t?void 0:t.cancel}})}async waitShareOperation(e,t){var s,a;let r=e;for(;"running"===r.state||"preparing"===r.state;){if(null==(s=null==t?void 0:t.signal)?void 0:s.aborted)throw new DOMException("aborted","AbortError");await new Promise((e=>setTimeout(e,(null==t?void 0:t.intervalMs)??1e3))),r=await this.shareOperation(r.operation_id),null==(a=null==t?void 0:t.onProgress)||a.call(t,r)}return r}async shareGet(e){return await this.call("share.get",{args:{share_id:e}})}async shareList(e){const s=void 0===(null==e?void 0:e.source)||"string"==typeof e.source?null==e?void 0:e.source:t(e.source);return await this.call("share.list",{args:{kind:null==e?void 0:e.kind,status:null==e?void 0:e.status,source:s,obj_id:null==e?void 0:e.objId,q:null==e?void 0:e.q,include_hidden:null==e?void 0:e.includeHidden,limit:null==e?void 0:e.limit,cursor:null==e?void 0:e.cursor}})}async shareUpdate(e,t,s,a){return await this.write("share.update",{args:{share_id:e,revision:t,changes:s,reason:a}})}async shareStop(e,t,s){return await this.write("share.stop",{args:{share_id:e,revision:t,reason:s}})}async shareHide(e,t){return await this.write("share.hide",{args:{share_id:e,hidden:t}})}async shareAppHandoff(e,a,r){return await this.write("share.app.handoff",{args:{source:t(e),target_app:a,title:null==r?void 0:r.title,idempotency_key:(null==r?void 0:r.idempotencyKey)??s()}})}async shareAppReport(e,t,s){return await this.write("share.app.report",{args:{share_id:e,delivery_state:t,business_ref:null==s?void 0:s.businessRef,error:null==s?void 0:s.error,observed_at:(null==s?void 0:s.observedAt)??Date.now()}})}async sharePublicList(e){return await this.call("share.public.list",{args:{refresh:null==e?void 0:e.refresh}})}async shareStats(e){return await this.call("share.stats",{args:{share_id:null==e?void 0:e.shareId,from:null==e?void 0:e.from,to:null==e?void 0:e.to,granularity:null==e?void 0:e.granularity}})}watch(e){var t;if(!this.session)throw new Error("watch requires an active session; call hello() first");const s=new URLSearchParams({session:this.session});(null==(t=null==e?void 0:e.tokens)?void 0:t.length)&&s.set("tokens",e.tokens.join(","));const a=`${this.baseUrl}/nfs/v1/watch?${s.toString()}`,r=new AbortController;(null==e?void 0:e.signal)&&e.signal.addEventListener("abort",(()=>r.abort()),{once:!0});const i=this.fetchFn,n=()=>this.authHeaders();const o=async function*(){const e=await i(a,{headers:{...await n(),Accept:"text/event-stream"},signal:r.signal});if(!e.ok||!e.body)throw new Error(`watch failed: HTTP ${e.status}`);const t=e.body.getReader(),s=new TextDecoder;let o="";try{for(;;){const{done:e,value:a}=await t.read();if(e)return;for(o+=s.decode(a,{stream:!0});;){const e=o.indexOf("\n\n");if(e<0)break;const t=o.slice(0,e);o=o.slice(e+2);let s,a="message";const r=[];for(const n of t.split("\n"))n.startsWith("event:")?a=n.slice(6).trim():n.startsWith("data:")?r.push(n.slice(5).trim()):n.startsWith("id:")&&(s=n.slice(3).trim());if(0===r.length&&"message"===a)continue;let i={};if(r.length>0)try{i=JSON.parse(r.join("\n"))}catch{i={raw:r.join("\n")}}yield{event:a,data:i,id:s}}}}finally{t.cancel().catch((()=>{}))}}();return o.close=()=>r.abort(),o}async call(e,t){return this.post(e,this.envelope(t))}async write(e,t,s=2){const r=++this.seq,i={...this.envelope(t),seq:r};let n;for(let l=0;l<=s;l++)try{return await this.post(e,i)}catch(o){if(o instanceof a)throw o;n=o}throw n}envelope(e){const t={args:r(e.args??{})};return this.session&&(t.session=this.session),e.at&&(t.at=r(e.at)),e.want&&(t.want=e.want),t}async post(e,t){var s;const r=await(null==(s=this.sessionToken)?void 0:s.call(this)),i=await this.fetchFn(`${this.baseUrl}/nfs/v1/${e}`,{method:"POST",headers:{"Content-Type":"application/json",...r?{Authorization:`Bearer ${r}`}:{}},body:JSON.stringify(t)});let n;try{n=await i.json()}catch{throw new a({code:"INTERNAL",message:`non-JSON response (HTTP ${i.status})`},i.status)}if(!0!==n.ok)throw new a(n.error??{code:"INTERNAL",message:"malformed error envelope"},i.status);return n.result}async httpError(e){try{const t=await e.json();if(t.error)return new a(t.error,e.status)}catch{}return new a({code:"INTERNAL",message:`HTTP ${e.status}`},e.status)}},exports.NfspError=a,exports.liveRef=(e,t=0)=>({type:"live",node_id:e,gen:t}),exports.toLocator=t;
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e="nfsp/0",t=e=>"string"==typeof e?e.includes("://")?{uri:e}:{realm:"dfs",path:e}:"type"in e?{ref:e}:e,s=()=>"undefined"!=typeof crypto&&"randomUUID"in crypto?crypto.randomUUID():`${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}`;class a extends Error{constructor(e,t){super(`${e.code}: ${e.message}`),this.name="NfspError",this.code=e.code,this.httpStatus=t,this.details=Object.fromEntries(Object.entries(e).filter((([e])=>"code"!==e&&"message"!==e)))}}const r=e=>{const t={};for(const[s,a]of Object.entries(e))void 0!==a&&(t[s]=a);return t};exports.NFSP_VERSION=e,exports.NfspClient=class{constructor(e){this.session=null,this.seq=0,this.helloResult=null,this.sessionToken=e.sessionToken,this.baseUrl=e.baseUrl.replace(/\/+$/,""),this.fetchFn=e.fetch??((e,t)=>globalThis.fetch(e,t)),this.chunkSize=e.uploadChunkSize??8388608}get sessionId(){return this.session}get reprCapability(){var e;return(null==(e=this.helloResult)?void 0:e.repr)??null}get features(){var e;return(null==(e=this.helloResult)?void 0:e.features)??[]}get limits(){var e;return(null==(e=this.helloResult)?void 0:e.limits)??null}async hello(t){const s={versions:[e]};t&&(s.features=t);const a=await this.post("hello",{args:s});return this.session=a.session,this.seq=0,this.helloResult=a,a}async bye(){await this.call("bye",{}),this.session=null,this.helloResult=null}async resolve(e,s){return await this.call("resolve",{at:t(e),want:s})}async stat(e,s){return await this.call("stat",{at:t(e),want:null==s?void 0:s.want,args:(null==s?void 0:s.name)?{name:s.name}:{}})}async list(e,s,a){return await this.call("list",{at:t(e),want:a,args:s??{}})}async batch(e,s,a="abort"){return await this.call("batch",{args:{start:t(e),ops:s,on_error:a}})}async mkdir(e,s,a){const r={};return void 0!==s&&(r.name=s),(null==a?void 0:a.expectedRevision)&&(r.expected_revision=a.expectedRevision),await this.write("mkdir",{at:t(e),args:r})}async move(e,t,s){return await this.write("move",{args:{from:{parent_ref:e.parentRef,name:e.name},to:{parent_ref:t.parentRef,name:t.name},expected_from_revision:null==s?void 0:s.expectedFromRevision,expected_to_revision:null==s?void 0:s.expectedToRevision}})}async delete(e,s,a){return await this.write("delete",{at:t(e),args:{name:s,recursive:null==a?void 0:a.recursive,expected_revision:null==a?void 0:a.expectedRevision}})}async bindRef(e,t,s,a){return await this.write("bind_ref",{args:{parent_ref:e,name:t,target_ref:s,expected_revision:null==a?void 0:a.expectedRevision}})}async unlink(e,t){return await this.write("unlink",{args:{entry_ref:e,expected_revision:null==t?void 0:t.expectedRevision}})}async openWrite(e){const t="ref"in e?{ref:e.ref}:{parent_ref:e.parentRef,name:e.name,size:e.size};return await this.write("open_write",{args:t})}async uploadOffset(e){const t=await this.fetchFn(`${this.baseUrl}/nfs/v1/uploads/${e}`,{method:"HEAD",headers:await this.authHeaders()});if(!t.ok)throw await this.httpError(t);return Number(t.headers.get("Upload-Offset")??"0")}async uploadChunk(e,t,s){const a=await this.fetchFn(`${this.baseUrl}/nfs/v1/uploads/${e}`,{method:"PATCH",headers:{...await this.authHeaders(),"Upload-Offset":String(t),"Content-Type":"application/offset+octet-stream"},body:s});if(204!==a.status)throw await this.httpError(a);return Number(a.headers.get("Upload-Offset")??String(t+s.byteLength))}async uploadContent(e,t,s){let a=await this.uploadOffset(e);for(;a<t.byteLength;){const r=t.subarray(a,Math.min(a+this.chunkSize,t.byteLength));a=await this.uploadChunk(e,a,r),null==s||s(a,t.byteLength)}}async abortWrite(e){await this.write("abort_write",{args:{lease_id:e}})}async authHeaders(){var e;const t=await(null==(e=this.sessionToken)?void 0:e.call(this));return t?{Authorization:`Bearer ${t}`}:{}}async commitFile(e,s,a,r){const i={name:s,overwrite:null==r?void 0:r.overwrite,expected_revision:null==r?void 0:r.expectedRevision};return"fbHandle"in a?(i.fb_handle=a.fbHandle,a.leaseId&&(i.lease_id=a.leaseId)):i.hash=a.hash,await this.write("commit_file",{at:t(e),args:i})}async commitObject(e,s,a,r){return await this.write("commit_object",{at:t(e),args:{name:s,obj_id:a,overwrite:null==r?void 0:r.overwrite,expected_revision:null==r?void 0:r.expectedRevision,lease_id:null==r?void 0:r.leaseId}})}async probe(e){return await this.call("probe",{args:{digests:e}})}async uploadFile(e,t,s,a){const r=await this.openWrite({parentRef:e,name:t,size:s.byteLength});return await this.uploadContent(r.fb_handle,s,null==a?void 0:a.onProgress),this.commitFile({ref:e},t,{fbHandle:r.fb_handle,leaseId:r.lease.lease_id},{overwrite:null==a?void 0:a.overwrite})}readUrl(e,t){const s=new URLSearchParams;(null==t?void 0:t.download)&&s.set("download","1"),(null==t?void 0:t.name)&&s.set("name",t.name);const a=s.size>0?`?${s.toString()}`:"";return`${this.baseUrl}/nfs/v1/read/${encodeURIComponent(e)}${a}`}async readFile(e,t){const s=await this.authHeaders();(null==t?void 0:t.range)&&(s.Range=`bytes=${t.range.start}-${t.range.end??""}`),(null==t?void 0:t.ifNoneMatch)&&(s["If-None-Match"]=t.ifNoneMatch);const a=await this.fetchFn(this.readUrl(e),{headers:s,cache:"no-store"});if(!a.ok&&304!==a.status)throw await this.httpError(a);return a}async getMeta(e,s){const a=t(e),r={ns:s};return a.ref&&(r.ref=a.ref),await this.call("get_meta",{at:a,args:r})}async setMeta(e,s){const a=t(e),r={records:s};return a.ref&&(r.ref=a.ref),await this.write("set_meta",{at:a,args:r})}async search(e,s,a){return await this.call("search",{want:a,args:{q:e,limit:null==s?void 0:s.limit,cursor:null==s?void 0:s.cursor,scope:void 0!==(null==s?void 0:s.scope)?t(s.scope):void 0,modes:null==s?void 0:s.modes}})}async openView(e,t){return await this.call("open_view",{want:t,args:{view_id:e}})}async createCollection(e,t,s){return await this.write("create_collection",{want:s,args:{title:e,collection_id:t}})}async openCollection(e,t){return await this.call("open_collection",{want:t,args:{collection_id:e}})}async collectionPatch(e,t,s){return await this.write("collection_patch",{args:{ref:e,ops:t,expected_revision:null==s?void 0:s.expectedRevision}})}async grant(e,s){return await this.write("grant",{args:{subtree:t(e),ops:null==s?void 0:s.ops,ttl:null==s?void 0:s.ttl,audience:null==s?void 0:s.audience,max_uses:null==s?void 0:s.maxUses}})}async revoke(e){return await this.write("revoke",{args:{cap_id:e}})}async getAcl(e){return await this.call("get_acl",{at:t(e)})}async setAcl(e,s,a){return await this.write("set_acl",{at:t(e),args:{inherit:s.inherit,entries:s.entries,expected_revision:null==a?void 0:a.expectedRevision}})}async listAcls(){return await this.call("list_acls",{})}async repr(e,s={}){return await this.call("repr",{at:e?t(e):void 0,args:{...s}})}async getRepr(e){return await this.call("get_repr",{args:{work_key:e}})}async shareCapabilities(){return await this.call("share.capabilities",{})}async sharePlan(e,s){return await this.call("share.plan",{args:{source:t(e),intent:null==s?void 0:s.intent,target:null==s?void 0:s.target}})}async shareCreate(e,a,r){return await this.write("share.create",{args:{source:t(e),policy:a,title:null==r?void 0:r.title,idempotency_key:(null==r?void 0:r.idempotencyKey)??s(),plan_fingerprint:null==r?void 0:r.planFingerprint,source_hint:null==r?void 0:r.sourceHint}})}async shareOperation(e,t){return await this.call("share.operation",{args:{operation_id:e,cancel:null==t?void 0:t.cancel}})}async waitShareOperation(e,t){var s,a;let r=e;for(;"running"===r.state||"preparing"===r.state;){if(null==(s=null==t?void 0:t.signal)?void 0:s.aborted)throw new DOMException("aborted","AbortError");await new Promise((e=>setTimeout(e,(null==t?void 0:t.intervalMs)??1e3))),r=await this.shareOperation(r.operation_id),null==(a=null==t?void 0:t.onProgress)||a.call(t,r)}return r}async shareGet(e){return await this.call("share.get",{args:{share_id:e}})}async shareList(e){const s=void 0===(null==e?void 0:e.source)||"string"==typeof e.source?null==e?void 0:e.source:t(e.source);return await this.call("share.list",{args:{kind:null==e?void 0:e.kind,status:null==e?void 0:e.status,source:s,obj_id:null==e?void 0:e.objId,q:null==e?void 0:e.q,include_hidden:null==e?void 0:e.includeHidden,limit:null==e?void 0:e.limit,cursor:null==e?void 0:e.cursor}})}async shareUpdate(e,t,s,a){return await this.write("share.update",{args:{share_id:e,revision:t,changes:s,reason:a}})}async shareStop(e,t,s){return await this.write("share.stop",{args:{share_id:e,revision:t,reason:s}})}async shareHide(e,t){return await this.write("share.hide",{args:{share_id:e,hidden:t}})}async shareAppHandoff(e,a,r){return await this.write("share.app.handoff",{args:{source:t(e),target_app:a,title:null==r?void 0:r.title,idempotency_key:(null==r?void 0:r.idempotencyKey)??s()}})}async shareAppReport(e,t,s){return await this.write("share.app.report",{args:{share_id:e,delivery_state:t,business_ref:null==s?void 0:s.businessRef,error:null==s?void 0:s.error,observed_at:(null==s?void 0:s.observedAt)??Date.now()}})}async sharePublicList(e){return await this.call("share.public.list",{args:{refresh:null==e?void 0:e.refresh}})}async shareStats(e){return await this.call("share.stats",{args:{share_id:null==e?void 0:e.shareId,from:null==e?void 0:e.from,to:null==e?void 0:e.to,granularity:null==e?void 0:e.granularity}})}watch(e){var t;if(!this.session)throw new Error("watch requires an active session; call hello() first");const s=new URLSearchParams({session:this.session});(null==(t=null==e?void 0:e.tokens)?void 0:t.length)&&s.set("tokens",e.tokens.join(","));const a=`${this.baseUrl}/nfs/v1/watch?${s.toString()}`,r=new AbortController;(null==e?void 0:e.signal)&&e.signal.addEventListener("abort",(()=>r.abort()),{once:!0});const i=this.fetchFn,n=()=>this.authHeaders();const o=async function*(){const e=await i(a,{headers:{...await n(),Accept:"text/event-stream"},signal:r.signal});if(!e.ok||!e.body)throw new Error(`watch failed: HTTP ${e.status}`);const t=e.body.getReader(),s=new TextDecoder;let o="";try{for(;;){const{done:e,value:a}=await t.read();if(e)return;for(o+=s.decode(a,{stream:!0});;){const e=o.indexOf("\n\n");if(e<0)break;const t=o.slice(0,e);o=o.slice(e+2);let s,a="message";const r=[];for(const n of t.split("\n"))n.startsWith("event:")?a=n.slice(6).trim():n.startsWith("data:")?r.push(n.slice(5).trim()):n.startsWith("id:")&&(s=n.slice(3).trim());if(0===r.length&&"message"===a)continue;let i={};if(r.length>0)try{i=JSON.parse(r.join("\n"))}catch{i={raw:r.join("\n")}}yield{event:a,data:i,id:s}}}}finally{t.cancel().catch((()=>{}))}}();return o.close=()=>r.abort(),o}async call(e,t){return this.post(e,this.envelope(t))}async write(e,t,s=2){const r=++this.seq,i={...this.envelope(t),seq:r};let n;for(let l=0;l<=s;l++)try{return await this.post(e,i)}catch(o){if(o instanceof a)throw o;n=o}throw n}envelope(e){const t={args:r(e.args??{})};return this.session&&(t.session=this.session),e.at&&(t.at=r(e.at)),e.want&&(t.want=e.want),t}async post(e,t){var s;const r=await(null==(s=this.sessionToken)?void 0:s.call(this)),i=await this.fetchFn(`${this.baseUrl}/nfs/v1/${e}`,{method:"POST",headers:{"Content-Type":"application/json",...r?{Authorization:`Bearer ${r}`}:{}},body:JSON.stringify(t)});let n;try{n=await i.json()}catch{throw new a({code:"INTERNAL",message:`non-JSON response (HTTP ${i.status})`},i.status)}if(!0!==n.ok)throw new a(n.error??{code:"INTERNAL",message:"malformed error envelope"},i.status);return n.result}async httpError(e){try{const t=await e.json();if(t.error)return new a(t.error,e.status)}catch{}return new a({code:"INTERNAL",message:`HTTP ${e.status}`},e.status)}},exports.NfspError=a,exports.liveRef=(e,t=0)=>({type:"live",node_id:e,gen:t}),exports.toLocator=t;
|
|
2
2
|
//# sourceMappingURL=nfsp.cjs.map
|
package/dist/nfsp.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"nfsp.cjs","sources":["../src/nfsp.ts"],"sourcesContent":["/**\n * NFSP v0 client for nfs_server (buckyos/src/frame/nfs_server).\n *\n * Speaks the control plane (`POST /nfs/v1/{method}`), the data plane\n * (`GET /nfs/v1/read/{node_id}`), the minimal tus upload area\n * (`PATCH|HEAD /nfs/v1/uploads/{fb}`) and the watch SSE stream\n * (`GET /nfs/v1/watch`).\n *\n * Protocol references:\n * - cyfs-ndn/doc/NamedFileSystem_Protocol_v0.md (NFSP v0)\n * - buckyos/product/bucky_file/nfs_server.md\n * - buckyos/src/frame/nfs_server/README.md (v1 降级契约)\n *\n * Client contract highlights (nfs_server README §4.2):\n * - `revision` is an opaque equality token: only compare, never order.\n * - Write ops require `seq` (exactly-once); the client auto-assigns one per\n * write and replays with the SAME seq on network retry.\n * - Leases are advisory versus server-local bypass writers: commit may fail\n * with TARGET_MISMATCH{reason:\"bypass_modified\"} — surface, don't retry.\n * - watch is lossy: any `resync` event means \"re-list what you care about\".\n *\n * Uses only fetch/WHATWG streams, so it runs in the browser and in Node ≥ 18.\n */\n\n// ---------------------------------------------------------------------------\n// Wire types\n// ---------------------------------------------------------------------------\n\nexport const NFSP_VERSION = 'nfsp/0'\n\n/** `{\"type\":\"live\",...}` or `{\"type\":\"object\",...}` (NFSP §3.1.2). */\nexport type LiveRef = { type: 'live'; node_id: string; gen?: number }\nexport type ObjectRef = { type: 'object'; obj_id: string; inner_path?: string }\nexport type WireRef = LiveRef | ObjectRef\n\nexport const liveRef = (nodeId: string, gen = 0): LiveRef => ({\n type: 'live',\n node_id: nodeId,\n gen,\n})\n\n/** The `at` locator: ref > uri > path (NFSP §3.4). */\nexport interface Locator {\n realm?: string\n path?: string\n uri?: string\n ref?: WireRef\n}\n\n/** Sugar: accept a dfs path string, a `xxx://` uri, a WireRef or a Locator. */\nexport type LocatorLike = string | WireRef | Locator\n\nexport const toLocator = (at: LocatorLike): Locator => {\n if (typeof at === 'string') {\n if (at.includes('://')) return { uri: at }\n return { realm: 'dfs', path: at }\n }\n if ('type' in at) return { ref: at }\n return at\n}\n\nexport type WantGroup = 'base' | 'ident' | 'access' | 'meta'\n\nexport type NodeKind = 'dir' | 'file' | 'symlink' | 'view' | 'collection' | 'group'\n\n/**\n * The caller's effective permission on a node. `traverse` = only the way to\n * something shared deeper down: listable, but only those children are shown.\n */\nexport type AccessLevel = 'none' | 'traverse' | 'read' | 'write' | 'manage'\n\n/** `user:<user_id>`, `zone_users` (any signed-in user) or `public` (anyone, read only). */\nexport type AclPrincipal = `user:${string}` | 'zone_users' | 'public'\n\nexport interface AclEntry {\n principal: AclPrincipal\n level: Exclude<AccessLevel, 'none' | 'traverse'>\n}\n\n/** `get_acl` result; the entry lists only appear for callers who may manage. */\nexport interface AclInfo {\n path: string\n access_level: AccessLevel\n can_manage: boolean\n revision: string\n inherit?: boolean\n entries?: AclEntry[]\n /** Grants arriving from ancestors, with the directory they come from. */\n inherited?: (AclEntry & { from: string })[]\n /** Built-in rules (zone owner, home owner) that no record can remove. */\n builtin?: (AclEntry & { reason: 'zone_owner' | 'home_owner' })[]\n updated_by?: string\n updated_at?: number\n}\n\nexport interface AclRecordInfo {\n path: string\n inherit: boolean\n entries: AclEntry[]\n home_owner: string | null\n updated_by: string\n updated_at: number\n revision: string\n /** The path no longer exists (removed outside the protocol). */\n missing: boolean\n}\n\nexport interface Capabilities {\n list: boolean\n read: boolean\n accepts_content: boolean\n accepts_references: boolean\n remove_semantics: 'destroy' | 'unlink' | 'none'\n ordered: boolean\n}\n\n/** resolve/stat result (fields beyond `base` appear per the `want` mask). */\nexport interface NodeInfo {\n kind: NodeKind\n state: string\n ref: WireRef\n copy_ref?: WireRef | null\n capabilities: Capabilities\n access_level?: AccessLevel\n revision?: string\n locations?: unknown[]\n // base\n name?: string\n size?: number\n mtime?: number\n ctime?: number\n flags?: string[]\n // ident\n node_id?: string\n gen?: number\n etag?: string\n obj_id?: string\n // access\n access_urls?: { kind: string; url: string }[]\n // meta\n meta_summary?: Record<string, number>\n // view / collection extras\n view_id?: string\n collection_id?: string\n title?: string\n origin?: string\n stale?: boolean\n}\n\nexport type EntryBinding = 'native' | 'reference' | 'member' | 'derived' | 'projection'\n\n/** Compact target of a listing entry (not a full NodeInfo). */\nexport interface EntryTarget {\n ref: WireRef\n copy_ref?: WireRef | null\n kind: NodeKind\n /** Attribute groups per the `want` mask: base → size/mtime/flags, ident → etag/obj_id, access → access_urls. */\n attrs?: {\n size?: number\n mtime?: number\n flags?: string[]\n etag?: string\n obj_id?: string\n access_urls?: { kind: string; url: string }[]\n } & Record<string, unknown>\n /** `stale` when a referenced target no longer resolves, `denied` when the caller may not see it. */\n target_state?: string\n access_level?: AccessLevel\n}\n\nexport interface Entry {\n name: string\n binding: EntryBinding\n entry_ref?: string\n target: EntryTarget\n canonical_path?: string\n context?: { count?: number; provenance?: Record<string, unknown> } & Record<string, unknown>\n}\n\nexport interface Listing {\n container: NodeInfo\n entries: Entry[]\n truncated?: boolean\n next_cursor?: string\n revision_changed?: boolean\n watch_token?: string\n /** Same-name virtual bindings shadowed by native entries (`native_shadow`). */\n conflicts?: { name: string; reason: string; entry_ref?: string; target?: EntryTarget }[]\n}\n\nexport interface ListOptions {\n cursor?: string\n limit?: number\n order?: 'name' | 'mtime' | 'size' | 'manual'\n filter?: { kind?: NodeKind[]; name_glob?: string }\n}\n\nexport interface HelloResult {\n version: string\n session: string\n features: string[]\n limits: { max_batch: number; max_list: number; replay_window: number; attr_ttl_ms: number }\n realms: { id: string; writable: boolean }[]\n /** Who this session acts as (`admin` = the zone owner or a trusted service). */\n identity?: { user_id: string | null; role: 'admin' | 'user' | 'anonymous' }\n}\n\nexport type BatchOp =\n | { m: 'walk'; args: { name?: string; names?: string[]; entry_ref?: string } }\n | { m: 'stat' | 'resolve'; args?: { name?: string }; want?: WantGroup[] }\n | { m: 'list'; args?: ListOptions; want?: WantGroup[] }\n\nexport interface BatchResult {\n completed: number\n results: ({ ok: true; result: unknown } | { ok: false; error: NfspErrorBody })[]\n}\n\nexport interface OpenWriteResult {\n fb_handle: string\n upload_url: string\n lease: { lease_id: string; seq: number; ttl_ms: number }\n target: { path: string; exists: boolean }\n}\n\nexport interface CommitResult {\n ref: WireRef\n entry_ref: string\n revision: string\n obj: { sha256: string; size: number }\n}\n\nexport interface CommitObjectResult {\n ref: WireRef\n entry_ref: string\n revision: string\n obj_id: string\n kind: 'file' | 'dir'\n obj: { size: number; sha256?: string }\n}\n\nexport interface MetaRecord {\n ns: string\n key: string\n value: unknown\n source?: unknown\n confidence?: number\n anchor?: string\n visibility?: string\n}\n\nexport interface SearchHit {\n copy_ref?: WireRef | null\n match_source: string\n canonical_path: string\n explain?: Record<string, unknown>\n [k: string]: unknown\n}\n\nexport interface SearchResult {\n hits: SearchHit[]\n partial: boolean\n sources: { mode: string; state: string; took_ms?: number; reason?: string }[]\n next_cursor?: string\n}\n\nexport interface GrantResult {\n cap_id: string\n token: string\n subtree: string\n ops: string[]\n expires_at?: number\n}\n\n// ---------- shares (`share.*`, nfs-server share module) ----------\n\nexport type ShareAccess = 'holder' | 'password'\nexport type ShareStatus = 'active' | 'stopping' | 'stopped' | 'expired' | 'failed'\nexport type ShareKind = 'link' | 'app_delivery'\nexport type ShareTargetApp = 'messagehub' | 'homestation'\nexport type ShareContentKind = 'image' | 'video' | 'audio' | 'file' | 'folder'\nexport type ShareDeliveryState = 'handed_off' | 'confirmed' | 'canceled' | 'failed' | 'unknown'\nexport type ShareOperationState = 'preparing' | 'running' | 'completed' | 'failed' | 'canceled'\n\nexport interface ShareStatsTotals {\n views: number\n downloads: number\n bytes: number\n visitors: number\n last_access_at?: number | null\n}\n\nexport interface ShareInfo {\n share_id: string\n kind: ShareKind\n title: string\n status: ShareStatus\n status_reason?: string | null\n hidden: boolean\n revision: number\n created_at: number\n updated_at: number\n stopped_at?: number | null\n owner_user_id: string\n created_by_app?: string | null\n related_share_id?: string | null\n obj_id: string\n obj_type?: string\n name?: string\n mime?: string | null\n total_size?: number\n item_count?: number\n content_kind?: ShareContentKind\n excluded?: { path: string; reason: string }[]\n prepared_at?: number\n source_path: string\n retained: boolean\n /** Link shares. `url` is only returned to the owner. */\n access?: ShareAccess\n has_password?: boolean\n allow_download?: boolean\n expires_at?: number | null\n url?: string | null\n /** App deliveries. */\n target_app?: ShareTargetApp\n delivery_state?: ShareDeliveryState\n business_ref?: Record<string, unknown> | null\n handoff_at?: number\n reported_at?: number | null\n delivery_error?: string | null\n stats: ShareStatsTotals\n}\n\nexport interface ShareAuditEntry {\n action: string\n revision_before?: number | null\n revision_after?: number | null\n actor_user_id: string\n actor_app_id?: string | null\n source: string\n reason?: string | null\n outcome: string\n at: number\n}\n\nexport interface ShareDetail extends ShareInfo {\n /** The bucket binding that retains the snapshot (`zone/nfs-server/_/shares`); empty once released. */\n retention: { bucket_id: string; key: string; obj_id: string; version: number; bound_at: number }[]\n audit: ShareAuditEntry[]\n related?: ShareInfo\n}\n\nexport interface ShareCapabilities {\n actions: string[]\n access: ShareAccess[]\n expiry_presets: (number | null)[]\n default_expiry: number\n limits: { sync_threshold: number; max_total_size: number; max_items: number }\n targets: { app: ShareTargetApp; accepts: string | string[]; max_item_size: number; fallback: 'link' }[]\n blocked: { action: string; reason: string }[]\n share_base_url?: string | null\n public: { dir: string; base_url?: string | null }\n}\n\nexport interface ShareTargetFit {\n app: ShareTargetApp\n mode: 'attachment' | 'link'\n reason?: 'folder' | 'not_media' | 'too_large' | null\n kind: ShareContentKind\n}\n\nexport interface SharePlan {\n plan_fingerprint: string\n source: { path: string; name: string; kind: 'file' | 'dir'; mime?: string | null }\n estimate: { total_size: number; item_count: number; excluded: { path: string; reason: string }[] }\n warnings: string[]\n requires_task: boolean\n existing: ShareInfo[]\n source_public: { in_publish_dir: boolean; public_acl: boolean; public_url?: string | null }\n /** Folders with an index.html may be websites (going live is App Service's job). */\n site: { has_index_html: boolean }\n target_fit?: ShareTargetFit\n}\n\nexport interface SharePolicyInput {\n access: ShareAccess\n password?: string\n /** Unix seconds; `null` = does not expire; omitted = seven days. */\n expires_at?: number | null\n allow_download?: boolean\n}\n\nexport interface ShareHandoff {\n share_id: string\n obj_id: string\n name: string\n size: number\n mime?: string | null\n kind: ShareContentKind\n mode: 'attachment' | 'link'\n link_share_id?: string | null\n url?: string | null\n launch: { appId: ShareTargetApp; payload: Record<string, unknown> }\n}\n\nexport interface ShareOperation {\n operation_id: string\n intent: 'create_link' | 'app_handoff'\n state: ShareOperationState\n share_id?: string | null\n task_id?: string | null\n error?: NfspErrorBody | null\n progress: { done_bytes?: number; total_bytes?: number }\n created_at: number\n updated_at: number\n source_changed?: boolean\n obj_id?: string\n url?: string | null\n share?: ShareInfo\n handoff?: ShareHandoff | null\n}\n\nexport interface ShareListFilter {\n kind?: ShareKind\n status?: ShareStatus\n source?: string | Locator\n objId?: string\n q?: string\n includeHidden?: boolean\n limit?: number\n cursor?: string\n}\n\nexport interface ShareStatsPoint {\n t: number\n views: number\n downloads: number\n bytes: number\n visitors: number\n}\n\nexport interface ShareStatsResult {\n granularity: 'hour' | 'day'\n from: number\n to: number\n series: ShareStatsPoint[]\n totals: Omit<ShareStatsTotals, 'last_access_at'>\n /** `expiring_soon`: active links ending within `expiring_within` seconds. */\n summary: { active: number; expiring_soon: number; expiring_within: number }\n unavailable: string[]\n}\n\nexport interface PublicEntry {\n rel_path: string\n entry_kind: 'file' | 'dir' | 'symlink'\n link_target?: string | null\n link_ok?: boolean | null\n size?: number | null\n mtime?: number | null\n first_seen_at: number\n last_seen_at: number\n missing_since?: number | null\n url?: string | null\n}\n\nexport interface PublicListing {\n entries: PublicEntry[]\n last_scan_at: number\n scan_ok: boolean\n dir: string\n base_url?: string | null\n}\n\nconst newIdempotencyKey = (): string =>\n typeof crypto !== 'undefined' && 'randomUUID' in crypto\n ? crypto.randomUUID()\n : `${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}`\n\nexport type CollectionPatchOp =\n | {\n add_ref: {\n target_ref: WireRef\n name?: string\n position?: number\n parent_entry_ref?: string\n }\n }\n | { remove_entry: { entry_ref: string } }\n | { move_entries: { entry_refs: string[]; to_index: number } }\n | { create_group: { name: string; position?: number } }\n | { rename_group: { entry_ref: string; name: string } }\n\nexport interface WatchEvent {\n /** `resync` | `container_changed` | `meta_changed` (extensible). */\n event: string\n /** Parsed JSON payload of the SSE `data:` line. */\n data: Record<string, unknown>\n /** SSE `id:` (the server_rev), when present. */\n id?: string\n}\n\n// ---------------------------------------------------------------------------\n// Errors\n// ---------------------------------------------------------------------------\n\n/** Structured NFSP error body (§8 plus implementation extensions). */\nexport interface NfspErrorBody {\n code: string\n message: string\n [k: string]: unknown\n}\n\nexport class NfspError extends Error {\n readonly code: string\n readonly httpStatus: number\n /** Extra structured fields (reason, holder_session, obj_id, expected, ...). */\n readonly details: Record<string, unknown>\n\n constructor(body: NfspErrorBody, httpStatus: number) {\n super(`${body.code}: ${body.message}`)\n this.name = 'NfspError'\n this.code = body.code\n this.httpStatus = httpStatus\n this.details = Object.fromEntries(Object.entries(body).filter(([key]) => key !== 'code' && key !== 'message'))\n }\n}\n\n// ---------------------------------------------------------------------------\n// Client\n// ---------------------------------------------------------------------------\n\nexport interface NfspClientOptions {\n sessionToken?: () => Promise<string | null>\n /** e.g. `http://127.0.0.1:3260` — no trailing slash needed. */\n baseUrl: string\n /** Override fetch (tests, custom auth wrappers). Defaults to global fetch. */\n fetch?: typeof fetch\n /** tus PATCH chunk size; server guidance is 4–16 MB. Default 8 MB. */\n uploadChunkSize?: number\n}\n\ninterface EnvelopeExtras {\n at?: Locator\n want?: WantGroup[]\n args?: Record<string, unknown>\n}\n\nexport class NfspClient {\n private readonly sessionToken?: () => Promise<string | null>\n readonly baseUrl: string\n private readonly fetchFn: typeof fetch\n private readonly chunkSize: number\n private session: string | null = null\n private seq = 0\n private helloResult: HelloResult | null = null\n\n constructor(opts: NfspClientOptions) {\n this.sessionToken = opts.sessionToken\n this.baseUrl = opts.baseUrl.replace(/\\/+$/, '')\n // Bind to globalThis: an unbound fetch throws \"Illegal invocation\".\n this.fetchFn = opts.fetch ?? ((input, init) => globalThis.fetch(input, init))\n this.chunkSize = opts.uploadChunkSize ?? 8 * 1024 * 1024\n }\n\n get sessionId(): string | null {\n return this.session\n }\n\n /** Features advertised by the server in hello (empty before hello). */\n get features(): string[] {\n return this.helloResult?.features ?? []\n }\n\n get limits(): HelloResult['limits'] | null {\n return this.helloResult?.limits ?? null\n }\n\n // ---------- session ----------\n\n async hello(clientFeatures?: string[]): Promise<HelloResult> {\n const args: Record<string, unknown> = { versions: [NFSP_VERSION] }\n if (clientFeatures) args.features = clientFeatures\n const r = (await this.post('hello', { args })) as HelloResult\n this.session = r.session\n this.seq = 0\n this.helloResult = r\n return r\n }\n\n async bye(): Promise<void> {\n await this.call('bye', {})\n this.session = null\n this.helloResult = null\n }\n\n // ---------- resolve / stat / list / batch ----------\n\n async resolve(at: LocatorLike, want?: WantGroup[]): Promise<NodeInfo> {\n return (await this.call('resolve', { at: toLocator(at), want })) as NodeInfo\n }\n\n /** stat with an optional child `name` step (server-side walk). */\n async stat(at: LocatorLike, opts?: { name?: string; want?: WantGroup[] }): Promise<NodeInfo> {\n return (await this.call('stat', {\n at: toLocator(at),\n want: opts?.want,\n args: opts?.name ? { name: opts.name } : {},\n })) as NodeInfo\n }\n\n async list(at: LocatorLike, opts?: ListOptions, want?: WantGroup[]): Promise<Listing> {\n return (await this.call('list', {\n at: toLocator(at),\n want,\n args: (opts ?? {}) as Record<string, unknown>,\n })) as Listing\n }\n\n async batch(\n start: LocatorLike,\n ops: BatchOp[],\n onError: 'abort' | 'continue' = 'abort',\n ): Promise<BatchResult> {\n return (await this.call('batch', {\n args: { start: toLocator(start), ops, on_error: onError },\n })) as BatchResult\n }\n\n // ---------- structure writes ----------\n\n /**\n * Ref form: create one child under `parent` (optional CAS via\n * `expectedRevision`). Path form: pass a dfs path string and no name —\n * behaves like `mkdir -p` (idempotent, no CAS).\n */\n async mkdir(\n parent: LocatorLike,\n name?: string,\n opts?: { expectedRevision?: string },\n ): Promise<{ ref: WireRef; existed: boolean; revision?: string }> {\n const args: Record<string, unknown> = {}\n if (name !== undefined) args.name = name\n if (opts?.expectedRevision) args.expected_revision = opts.expectedRevision\n return (await this.write('mkdir', { at: toLocator(parent), args })) as {\n ref: WireRef\n existed: boolean\n revision?: string\n }\n }\n\n async move(\n from: { parentRef: WireRef; name: string },\n to: { parentRef: WireRef; name: string },\n opts?: { expectedFromRevision?: string; expectedToRevision?: string },\n ): Promise<{ from_revision: string; to_revision: string }> {\n return (await this.write('move', {\n args: {\n from: { parent_ref: from.parentRef, name: from.name },\n to: { parent_ref: to.parentRef, name: to.name },\n expected_from_revision: opts?.expectedFromRevision,\n expected_to_revision: opts?.expectedToRevision,\n },\n })) as { from_revision: string; to_revision: string }\n }\n\n /** Destroys a native entry. Reference entries must use `unlink` instead. */\n async delete(\n parent: LocatorLike,\n name: string,\n opts?: { recursive?: boolean; expectedRevision?: string },\n ): Promise<{ revision: string }> {\n return (await this.write('delete', {\n at: toLocator(parent),\n args: {\n name,\n recursive: opts?.recursive,\n expected_revision: opts?.expectedRevision,\n },\n })) as { revision: string }\n }\n\n async bindRef(\n parentRef: WireRef,\n name: string,\n targetRef: WireRef,\n opts?: { expectedRevision?: string },\n ): Promise<{ entry_ref: string; revision: string }> {\n return (await this.write('bind_ref', {\n args: {\n parent_ref: parentRef,\n name,\n target_ref: targetRef,\n expected_revision: opts?.expectedRevision,\n },\n })) as { entry_ref: string; revision: string }\n }\n\n /** Removes a reference entry (`be_*`) only; the target is never touched. */\n async unlink(\n entryRef: string,\n opts?: { expectedRevision?: string },\n ): Promise<{ revision: string }> {\n return (await this.write('unlink', {\n args: { entry_ref: entryRef, expected_revision: opts?.expectedRevision },\n })) as { revision: string }\n }\n\n // ---------- content writes (open_write / tus / commit_file / probe) ----------\n\n async openWrite(\n target: { parentRef: WireRef; name: string; size?: number } | { ref: WireRef },\n ): Promise<OpenWriteResult> {\n const args: Record<string, unknown> =\n 'ref' in target\n ? { ref: target.ref }\n : { parent_ref: target.parentRef, name: target.name, size: target.size }\n return (await this.write('open_write', { args })) as OpenWriteResult\n }\n\n /** Current upload offset (tus HEAD) — resume point after interruption. */\n async uploadOffset(fbHandle: string): Promise<number> {\n const resp = await this.fetchFn(`${this.baseUrl}/nfs/v1/uploads/${fbHandle}`, {\n method: 'HEAD',\n headers: await this.authHeaders(),\n })\n if (!resp.ok) throw await this.httpError(resp)\n return Number(resp.headers.get('Upload-Offset') ?? '0')\n }\n\n /** One tus PATCH. Returns the new offset. */\n async uploadChunk(fbHandle: string, offset: number, chunk: Uint8Array): Promise<number> {\n const resp = await this.fetchFn(`${this.baseUrl}/nfs/v1/uploads/${fbHandle}`, {\n method: 'PATCH',\n headers: {\n ...await this.authHeaders(),\n 'Upload-Offset': String(offset),\n 'Content-Type': 'application/offset+octet-stream',\n },\n body: chunk as unknown as BodyInit,\n })\n if (resp.status !== 204) throw await this.httpError(resp)\n return Number(resp.headers.get('Upload-Offset') ?? String(offset + chunk.byteLength))\n }\n\n /** Uploads a whole buffer in chunks, resuming from the server's offset. */\n async uploadContent(\n fbHandle: string,\n content: Uint8Array,\n onProgress?: (sent: number, total: number) => void,\n ): Promise<void> {\n let offset = await this.uploadOffset(fbHandle)\n while (offset < content.byteLength) {\n const chunk = content.subarray(offset, Math.min(offset + this.chunkSize, content.byteLength))\n offset = await this.uploadChunk(fbHandle, offset, chunk)\n onProgress?.(offset, content.byteLength)\n }\n }\n\n async abortWrite(leaseId: string): Promise<void> {\n await this.write('abort_write', { args: { lease_id: leaseId } })\n }\n\n private async authHeaders(): Promise<Record<string, string>> {\n const token = await this.sessionToken?.()\n return token ? { Authorization: `Bearer ${token}` } : {}\n }\n\n async commitFile(\n parent: LocatorLike,\n name: string,\n source: { fbHandle: string; leaseId?: string } | { hash: string },\n opts?: { overwrite?: boolean; expectedRevision?: string },\n ): Promise<CommitResult> {\n const args: Record<string, unknown> = {\n name,\n overwrite: opts?.overwrite,\n expected_revision: opts?.expectedRevision,\n }\n if ('fbHandle' in source) {\n args.fb_handle = source.fbHandle\n if (source.leaseId) args.lease_id = source.leaseId\n } else {\n args.hash = source.hash\n }\n return (await this.write('commit_file', { at: toLocator(parent), args })) as CommitResult\n }\n\n async commitObject(\n parent: LocatorLike,\n name: string,\n objId: string,\n opts?: { overwrite?: boolean; expectedRevision?: string; leaseId?: string },\n ): Promise<CommitObjectResult> {\n return await this.write('commit_object', {\n at: toLocator(parent),\n args: { name, obj_id: objId, overwrite: opts?.overwrite, expected_revision: opts?.expectedRevision, lease_id: opts?.leaseId },\n }) as CommitObjectResult\n }\n\n /** Which of these digests must be uploaded (§ probe / 秒传). */\n async probe(digests: { hash: string; size?: number }[]): Promise<{ missing: { hash: string; size?: number }[] }> {\n return (await this.call('probe', { args: { digests } })) as {\n missing: { hash: string; size?: number }[]\n }\n }\n\n /**\n * Convenience: open_write + chunked tus upload + commit_file.\n * Overwrites an existing file only when `opts.overwrite` is set.\n */\n async uploadFile(\n parentRef: WireRef,\n name: string,\n content: Uint8Array,\n opts?: { overwrite?: boolean; onProgress?: (sent: number, total: number) => void },\n ): Promise<CommitResult> {\n const ow = await this.openWrite({ parentRef, name, size: content.byteLength })\n await this.uploadContent(ow.fb_handle, content, opts?.onProgress)\n return this.commitFile({ ref: parentRef }, name, {\n fbHandle: ow.fb_handle,\n leaseId: ow.lease.lease_id,\n }, { overwrite: opts?.overwrite })\n }\n\n // ---------- data plane read ----------\n\n /**\n * URL for `GET /nfs/v1/read/{node_id}` (usable in <img>, <a download>, …).\n * It carries no token: same-origin requests authenticate with the SSO cookie,\n * anything else only reads public paths.\n */\n readUrl(nodeId: string, opts?: { download?: boolean; name?: string }): string {\n const params = new URLSearchParams()\n if (opts?.download) params.set('download', '1')\n if (opts?.name) params.set('name', opts.name)\n const qs = params.size > 0 ? `?${params.toString()}` : ''\n return `${this.baseUrl}/nfs/v1/read/${encodeURIComponent(nodeId)}${qs}`\n }\n\n /** Reads file content; `range` is inclusive byte positions. */\n async readFile(\n nodeId: string,\n opts?: { range?: { start: number; end?: number }; ifNoneMatch?: string },\n ): Promise<Response> {\n const headers: Record<string, string> = await this.authHeaders()\n if (opts?.range) {\n headers.Range = `bytes=${opts.range.start}-${opts.range.end ?? ''}`\n }\n if (opts?.ifNoneMatch) headers['If-None-Match'] = opts.ifNoneMatch\n const resp = await this.fetchFn(this.readUrl(nodeId), { headers, cache: 'no-store' })\n if (!resp.ok && resp.status !== 304) throw await this.httpError(resp)\n return resp\n }\n\n // ---------- meta ----------\n\n async getMeta(target: LocatorLike, ns?: string[]): Promise<{ records: MetaRecord[] }> {\n const loc = toLocator(target)\n const args: Record<string, unknown> = { ns }\n if (loc.ref) args.ref = loc.ref\n return (await this.call('get_meta', { at: loc, args })) as { records: MetaRecord[] }\n }\n\n /** v1: only `ns: \"user\"` records are writable. */\n async setMeta(\n target: LocatorLike,\n records: { ns: string; key: string; value: unknown; visibility?: string }[],\n ): Promise<{ updated: number }> {\n const loc = toLocator(target)\n const args: Record<string, unknown> = { records }\n if (loc.ref) args.ref = loc.ref\n return (await this.write('set_meta', { at: loc, args })) as { updated: number }\n }\n\n // ---------- search ----------\n\n async search(\n q: string,\n opts?: { limit?: number; cursor?: string; scope?: LocatorLike; modes?: string[] },\n want?: WantGroup[],\n ): Promise<SearchResult> {\n return (await this.call('search', {\n want,\n args: {\n q,\n limit: opts?.limit,\n cursor: opts?.cursor,\n scope: opts?.scope !== undefined ? toLocator(opts.scope) : undefined,\n modes: opts?.modes,\n },\n })) as SearchResult\n }\n\n // ---------- views & collections ----------\n\n async openView(viewId: string, want?: WantGroup[]): Promise<NodeInfo> {\n return (await this.call('open_view', { want, args: { view_id: viewId } })) as NodeInfo\n }\n\n async createCollection(\n title: string,\n collectionId?: string,\n want?: WantGroup[],\n ): Promise<NodeInfo> {\n return (await this.write('create_collection', {\n want,\n args: { title, collection_id: collectionId },\n })) as NodeInfo\n }\n\n async openCollection(collectionId: string, want?: WantGroup[]): Promise<NodeInfo> {\n return (await this.call('open_collection', {\n want,\n args: { collection_id: collectionId },\n })) as NodeInfo\n }\n\n async collectionPatch(\n ref: WireRef,\n ops: CollectionPatchOp[],\n opts?: { expectedRevision?: string },\n ): Promise<{ revision: string }> {\n return (await this.write('collection_patch', {\n args: { ref, ops, expected_revision: opts?.expectedRevision },\n })) as { revision: string }\n }\n\n // ---------- grants ----------\n\n async grant(\n subtree: LocatorLike,\n opts?: { ops?: string[]; ttl?: number; audience?: string; maxUses?: number },\n ): Promise<GrantResult> {\n return (await this.write('grant', {\n args: {\n subtree: toLocator(subtree),\n ops: opts?.ops,\n ttl: opts?.ttl,\n audience: opts?.audience,\n max_uses: opts?.maxUses,\n },\n })) as GrantResult\n }\n\n async revoke(capId: string): Promise<{ revoked: string }> {\n return (await this.write('revoke', { args: { cap_id: capId } })) as { revoked: string }\n }\n\n // ---------- acl ----------\n\n async getAcl(at: LocatorLike): Promise<AclInfo> {\n return (await this.call('get_acl', { at: toLocator(at) })) as AclInfo\n }\n\n /** Replaces the node's own record; `inherit: true` with no entries removes it. */\n async setAcl(\n at: LocatorLike,\n acl: { inherit: boolean; entries: AclEntry[] },\n opts?: { expectedRevision?: string },\n ): Promise<{ path: string; revision: string }> {\n return (await this.write('set_acl', {\n at: toLocator(at),\n args: { inherit: acl.inherit, entries: acl.entries, expected_revision: opts?.expectedRevision },\n })) as { path: string; revision: string }\n }\n\n /** Every ACL record the caller may manage (all of them for the zone owner). */\n async listAcls(): Promise<{ records: AclRecordInfo[]; zone_owner: string | null; is_admin: boolean }> {\n return (await this.call('list_acls', {})) as { records: AclRecordInfo[]; zone_owner: string | null; is_admin: boolean }\n }\n\n // ---------- shares (`share.*`) ----------\n\n async shareCapabilities(): Promise<ShareCapabilities> {\n return (await this.call('share.capabilities', {})) as ShareCapabilities\n }\n\n /** Side-effect free: size, exclusions, existing links, Public state, target fit. */\n async sharePlan(\n source: LocatorLike,\n opts?: { intent?: 'create_link' | 'app_handoff'; target?: ShareTargetApp },\n ): Promise<SharePlan> {\n return (await this.call('share.plan', {\n args: { source: toLocator(source), intent: opts?.intent, target: opts?.target },\n })) as SharePlan\n }\n\n /** Snapshots the source and creates a link. Large sources return `state: 'running'`. */\n async shareCreate(\n source: LocatorLike,\n policy: SharePolicyInput,\n opts?: { title?: string; idempotencyKey?: string; planFingerprint?: string; sourceHint?: 'gui' | 'cli' | 'agent' },\n ): Promise<ShareOperation> {\n return (await this.write('share.create', {\n args: {\n source: toLocator(source),\n policy,\n title: opts?.title,\n idempotency_key: opts?.idempotencyKey ?? newIdempotencyKey(),\n plan_fingerprint: opts?.planFingerprint,\n source_hint: opts?.sourceHint,\n },\n })) as ShareOperation\n }\n\n async shareOperation(operationId: string, opts?: { cancel?: boolean }): Promise<ShareOperation> {\n return (await this.call('share.operation', {\n args: { operation_id: operationId, cancel: opts?.cancel },\n })) as ShareOperation\n }\n\n /** Polls a running operation until it settles. */\n async waitShareOperation(\n op: ShareOperation,\n opts?: { intervalMs?: number; signal?: AbortSignal; onProgress?: (op: ShareOperation) => void },\n ): Promise<ShareOperation> {\n let cur = op\n while (cur.state === 'running' || cur.state === 'preparing') {\n if (opts?.signal?.aborted) throw new DOMException('aborted', 'AbortError')\n await new Promise((r) => setTimeout(r, opts?.intervalMs ?? 1000))\n cur = await this.shareOperation(cur.operation_id)\n opts?.onProgress?.(cur)\n }\n return cur\n }\n\n async shareGet(shareId: string): Promise<ShareDetail> {\n return (await this.call('share.get', { args: { share_id: shareId } })) as ShareDetail\n }\n\n async shareList(filter?: ShareListFilter): Promise<{ items: ShareInfo[]; next_cursor?: string | null }> {\n const source = filter?.source === undefined || typeof filter.source === 'string' ? filter?.source : toLocator(filter.source)\n return (await this.call('share.list', {\n args: {\n kind: filter?.kind,\n status: filter?.status,\n source,\n obj_id: filter?.objId,\n q: filter?.q,\n include_hidden: filter?.includeHidden,\n limit: filter?.limit,\n cursor: filter?.cursor,\n },\n })) as { items: ShareInfo[]; next_cursor?: string | null }\n }\n\n /** `password: null` removes it, `expires_at: null` = no expiry. REVISION_CONFLICT carries `current`. */\n async shareUpdate(\n shareId: string,\n revision: number,\n changes: { title?: string; expires_at?: number | null; password?: string | null; allow_download?: boolean; access?: ShareAccess },\n reason?: string,\n ): Promise<{ revision: number; share: ShareInfo }> {\n return (await this.write('share.update', {\n args: { share_id: shareId, revision, changes, reason },\n })) as { revision: number; share: ShareInfo }\n }\n\n async shareStop(shareId: string, revision: number, reason?: string): Promise<{ status: ShareStatus; revision: number }> {\n return (await this.write('share.stop', {\n args: { share_id: shareId, revision, reason },\n })) as { status: ShareStatus; revision: number }\n }\n\n async shareHide(shareId: string, hidden: boolean): Promise<{ hidden: boolean; revision: number }> {\n return (await this.write('share.hide', { args: { share_id: shareId, hidden } })) as { hidden: boolean; revision: number }\n }\n\n /** Snapshot for an app target; the result's `handoff.launch` opens the app. */\n async shareAppHandoff(\n source: LocatorLike,\n targetApp: ShareTargetApp,\n opts?: { title?: string; idempotencyKey?: string },\n ): Promise<ShareOperation> {\n return (await this.write('share.app.handoff', {\n args: {\n source: toLocator(source),\n target_app: targetApp,\n title: opts?.title,\n idempotency_key: opts?.idempotencyKey ?? newIdempotencyKey(),\n },\n })) as ShareOperation\n }\n\n /** What the target app did; older facts (by `observedAt`, ms) are refused. */\n async shareAppReport(\n shareId: string,\n deliveryState: Exclude<ShareDeliveryState, 'handed_off'>,\n opts?: { businessRef?: Record<string, unknown>; error?: string; observedAt?: number },\n ): Promise<{ accepted: boolean; delivery_state: string }> {\n return (await this.write('share.app.report', {\n args: {\n share_id: shareId,\n delivery_state: deliveryState,\n business_ref: opts?.businessRef,\n error: opts?.error,\n observed_at: opts?.observedAt ?? Date.now(),\n },\n })) as { accepted: boolean; delivery_state: string }\n }\n\n async sharePublicList(opts?: { refresh?: boolean }): Promise<PublicListing> {\n return (await this.call('share.public.list', { args: { refresh: opts?.refresh } })) as PublicListing\n }\n\n async shareStats(opts?: { shareId?: string; from?: number; to?: number; granularity?: 'hour' | 'day' }): Promise<ShareStatsResult> {\n return (await this.call('share.stats', {\n args: { share_id: opts?.shareId, from: opts?.from, to: opts?.to, granularity: opts?.granularity },\n })) as ShareStatsResult\n }\n\n // ---------- watch (SSE) ----------\n\n /**\n * Opens the watch stream. `tokens` filters to specific containers using the\n * `watch_token` returned by list. The stream is lossy by contract: on any\n * `resync` event, re-list watched containers.\n */\n watch(opts?: { tokens?: string[]; signal?: AbortSignal }): AsyncIterableIterator<WatchEvent> & {\n close: () => void\n } {\n if (!this.session) throw new Error('watch requires an active session; call hello() first')\n const params = new URLSearchParams({ session: this.session })\n if (opts?.tokens?.length) params.set('tokens', opts.tokens.join(','))\n const url = `${this.baseUrl}/nfs/v1/watch?${params.toString()}`\n const controller = new AbortController()\n if (opts?.signal) {\n opts.signal.addEventListener('abort', () => controller.abort(), { once: true })\n }\n const fetchFn = this.fetchFn\n const authHeaders = () => this.authHeaders()\n\n async function* events(): AsyncIterableIterator<WatchEvent> {\n const resp = await fetchFn(url, {\n headers: { ...await authHeaders(), Accept: 'text/event-stream' },\n signal: controller.signal,\n })\n if (!resp.ok || !resp.body) {\n throw new Error(`watch failed: HTTP ${resp.status}`)\n }\n const reader = resp.body.getReader()\n const decoder = new TextDecoder()\n let buf = ''\n try {\n for (;;) {\n const { done, value } = await reader.read()\n if (done) return\n buf += decoder.decode(value, { stream: true })\n // SSE frames are separated by a blank line.\n for (;;) {\n const sep = buf.indexOf('\\n\\n')\n if (sep < 0) break\n const frame = buf.slice(0, sep)\n buf = buf.slice(sep + 2)\n let event = 'message'\n let id: string | undefined\n const dataLines: string[] = []\n for (const line of frame.split('\\n')) {\n if (line.startsWith('event:')) event = line.slice(6).trim()\n else if (line.startsWith('data:')) dataLines.push(line.slice(5).trim())\n else if (line.startsWith('id:')) id = line.slice(3).trim()\n // comment lines (`:keep-alive`) are ignored\n }\n if (dataLines.length === 0 && event === 'message') continue\n let data: Record<string, unknown> = {}\n if (dataLines.length > 0) {\n try {\n data = JSON.parse(dataLines.join('\\n')) as Record<string, unknown>\n } catch {\n data = { raw: dataLines.join('\\n') }\n }\n }\n yield { event, data, id }\n }\n }\n } finally {\n reader.cancel().catch(() => {})\n }\n }\n\n const it = events() as AsyncIterableIterator<WatchEvent> & { close: () => void }\n it.close = () => controller.abort()\n return it\n }\n\n // ---------- envelope plumbing ----------\n\n /** Read-path call: no seq. Throws NfspError on `ok:false`. */\n async call(method: string, extras: EnvelopeExtras): Promise<unknown> {\n return this.post(method, this.envelope(extras))\n }\n\n /**\n * Write-path call: assigns the next seq once and reuses it across network\n * retries so the server's replay window guarantees exactly-once.\n */\n async write(method: string, extras: EnvelopeExtras, retries = 2): Promise<unknown> {\n const seq = ++this.seq\n const body = { ...this.envelope(extras), seq }\n let lastErr: unknown\n for (let attempt = 0; attempt <= retries; attempt++) {\n try {\n return await this.post(method, body)\n } catch (e) {\n // Only network-level failures are retried (same seq → replay-safe).\n // NfspError means the server answered: propagate immediately.\n if (e instanceof NfspError) throw e\n lastErr = e\n }\n }\n throw lastErr\n }\n\n private envelope(extras: EnvelopeExtras): Record<string, unknown> {\n const body: Record<string, unknown> = { args: pruneUndefined(extras.args ?? {}) }\n if (this.session) body.session = this.session\n if (extras.at) body.at = pruneUndefined(extras.at as unknown as Record<string, unknown>)\n if (extras.want) body.want = extras.want\n return body\n }\n\n private async post(method: string, body: Record<string, unknown>): Promise<unknown> {\n const token = await this.sessionToken?.()\n const resp = await this.fetchFn(`${this.baseUrl}/nfs/v1/${method}`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json', ...(token ? { Authorization: `Bearer ${token}` } : {}) },\n body: JSON.stringify(body),\n })\n let parsed: { ok?: boolean; result?: unknown; error?: NfspErrorBody }\n try {\n parsed = (await resp.json()) as typeof parsed\n } catch {\n throw new NfspError(\n { code: 'INTERNAL', message: `non-JSON response (HTTP ${resp.status})` },\n resp.status,\n )\n }\n if (parsed.ok !== true) {\n throw new NfspError(\n parsed.error ?? { code: 'INTERNAL', message: 'malformed error envelope' },\n resp.status,\n )\n }\n return parsed.result\n }\n\n private async httpError(resp: Response): Promise<NfspError> {\n try {\n const parsed = (await resp.json()) as { error?: NfspErrorBody }\n if (parsed.error) return new NfspError(parsed.error, resp.status)\n } catch {\n // fall through\n }\n return new NfspError({ code: 'INTERNAL', message: `HTTP ${resp.status}` }, resp.status)\n }\n}\n\n/** Drops undefined values so they don't serialize as JSON nulls. */\nconst pruneUndefined = (obj: Record<string, unknown>): Record<string, unknown> => {\n const out: Record<string, unknown> = {}\n for (const [k, v] of Object.entries(obj)) {\n if (v !== undefined) out[k] = v\n }\n return out\n}\n"],"names":["NFSP_VERSION","toLocator","at","includes","uri","realm","path","ref","newIdempotencyKey","crypto","randomUUID","Date","now","toString","Math","random","slice","NfspError","Error","constructor","body","httpStatus","super","code","message","this","name","details","Object","fromEntries","entries","filter","key","pruneUndefined","obj","out","k","v","opts","session","seq","helloResult","sessionToken","baseUrl","replace","fetchFn","fetch","input","init","globalThis","chunkSize","uploadChunkSize","sessionId","features","_a","limits","hello","clientFeatures","args","versions","r","post","bye","call","resolve","want","stat","list","batch","start","ops","onError","on_error","mkdir","parent","expectedRevision","expected_revision","write","move","from","to","parent_ref","parentRef","expected_from_revision","expectedFromRevision","expected_to_revision","expectedToRevision","recursive","bindRef","targetRef","target_ref","unlink","entryRef","entry_ref","openWrite","target","size","uploadOffset","fbHandle","resp","method","headers","authHeaders","ok","httpError","Number","get","uploadChunk","offset","chunk","String","status","byteLength","uploadContent","content","onProgress","subarray","min","abortWrite","leaseId","lease_id","token","Authorization","commitFile","source","overwrite","fb_handle","hash","commitObject","objId","obj_id","probe","digests","uploadFile","ow","lease","readUrl","nodeId","params","URLSearchParams","download","set","qs","encodeURIComponent","readFile","range","Range","end","ifNoneMatch","cache","getMeta","ns","loc","setMeta","records","search","q","limit","cursor","scope","modes","openView","viewId","view_id","createCollection","title","collectionId","collection_id","openCollection","collectionPatch","grant","subtree","ttl","audience","max_uses","maxUses","revoke","capId","cap_id","getAcl","setAcl","acl","inherit","listAcls","shareCapabilities","sharePlan","intent","shareCreate","policy","idempotency_key","idempotencyKey","plan_fingerprint","planFingerprint","source_hint","sourceHint","shareOperation","operationId","operation_id","cancel","waitShareOperation","op","cur","state","signal","aborted","DOMException","Promise","setTimeout","intervalMs","_b","shareGet","shareId","share_id","shareList","kind","include_hidden","includeHidden","shareUpdate","revision","changes","reason","shareStop","shareHide","hidden","shareAppHandoff","targetApp","target_app","shareAppReport","deliveryState","delivery_state","business_ref","businessRef","error","observed_at","observedAt","sharePublicList","refresh","shareStats","granularity","watch","tokens","length","join","url","controller","AbortController","addEventListener","abort","once","it","async","Accept","reader","getReader","decoder","TextDecoder","buf","done","value","read","decode","stream","sep","indexOf","frame","id","event","dataLines","line","split","startsWith","trim","push","data","JSON","parse","raw","catch","events","close","extras","envelope","retries","lastErr","attempt","e","stringify","parsed","json","result","gen","type","node_id"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"nfsp.cjs","sources":["../src/nfsp.ts"],"sourcesContent":["/**\n * NFSP v0 client for nfs_server (buckyos/src/frame/nfs_server).\n *\n * Speaks the control plane (`POST /nfs/v1/{method}`), the data plane\n * (`GET /nfs/v1/read/{node_id}`), the minimal tus upload area\n * (`PATCH|HEAD /nfs/v1/uploads/{fb}`) and the watch SSE stream\n * (`GET /nfs/v1/watch`).\n *\n * Protocol references:\n * - cyfs-ndn/doc/NamedFileSystem_Protocol_v0.md (NFSP v0)\n * - buckyos/product/bucky_file/nfs_server.md\n * - buckyos/src/frame/nfs_server/README.md (v1 降级契约)\n *\n * Client contract highlights (nfs_server README §4.2):\n * - `revision` is an opaque equality token: only compare, never order.\n * - Write ops require `seq` (exactly-once); the client auto-assigns one per\n * write and replays with the SAME seq on network retry.\n * - Leases are advisory versus server-local bypass writers: commit may fail\n * with TARGET_MISMATCH{reason:\"bypass_modified\"} — surface, don't retry.\n * - watch is lossy: any `resync` event means \"re-list what you care about\".\n *\n * Uses only fetch/WHATWG streams, so it runs in the browser and in Node ≥ 18.\n */\n\n// ---------------------------------------------------------------------------\n// Wire types\n// ---------------------------------------------------------------------------\n\nexport const NFSP_VERSION = 'nfsp/0'\n\n/** `{\"type\":\"live\",...}` or `{\"type\":\"object\",...}` (NFSP §3.1.2). */\nexport type LiveRef = { type: 'live'; node_id: string; gen?: number }\nexport type ObjectRef = { type: 'object'; obj_id: string; inner_path?: string }\nexport type WireRef = LiveRef | ObjectRef\n\nexport const liveRef = (nodeId: string, gen = 0): LiveRef => ({\n type: 'live',\n node_id: nodeId,\n gen,\n})\n\n/** The `at` locator: ref > uri > path (NFSP §3.4). */\nexport interface Locator {\n realm?: string\n path?: string\n uri?: string\n ref?: WireRef\n}\n\n/** Sugar: accept a dfs path string, a `xxx://` uri, a WireRef or a Locator. */\nexport type LocatorLike = string | WireRef | Locator\n\nexport const toLocator = (at: LocatorLike): Locator => {\n if (typeof at === 'string') {\n if (at.includes('://')) return { uri: at }\n return { realm: 'dfs', path: at }\n }\n if ('type' in at) return { ref: at }\n return at\n}\n\nexport type WantGroup = 'base' | 'ident' | 'access' | 'meta'\n\nexport type NodeKind = 'dir' | 'file' | 'symlink' | 'view' | 'collection' | 'group'\n\n/**\n * The caller's effective permission on a node. `traverse` = only the way to\n * something shared deeper down: listable, but only those children are shown.\n */\nexport type AccessLevel = 'none' | 'traverse' | 'read' | 'write' | 'manage'\n\n/** `user:<user_id>`, `zone_users` (any signed-in user) or `public` (anyone, read only). */\nexport type AclPrincipal = `user:${string}` | 'zone_users' | 'public'\n\nexport interface AclEntry {\n principal: AclPrincipal\n level: Exclude<AccessLevel, 'none' | 'traverse'>\n}\n\n/** `get_acl` result; the entry lists only appear for callers who may manage. */\nexport interface AclInfo {\n path: string\n access_level: AccessLevel\n can_manage: boolean\n revision: string\n inherit?: boolean\n entries?: AclEntry[]\n /** Grants arriving from ancestors, with the directory they come from. */\n inherited?: (AclEntry & { from: string })[]\n /** Built-in rules (zone owner, home owner) that no record can remove. */\n builtin?: (AclEntry & { reason: 'zone_owner' | 'home_owner' })[]\n updated_by?: string\n updated_at?: number\n}\n\nexport interface AclRecordInfo {\n path: string\n inherit: boolean\n entries: AclEntry[]\n home_owner: string | null\n updated_by: string\n updated_at: number\n revision: string\n /** The path no longer exists (removed outside the protocol). */\n missing: boolean\n}\n\nexport interface Capabilities {\n list: boolean\n read: boolean\n accepts_content: boolean\n accepts_references: boolean\n remove_semantics: 'destroy' | 'unlink' | 'none'\n ordered: boolean\n}\n\n/** resolve/stat result (fields beyond `base` appear per the `want` mask). */\nexport interface NodeInfo {\n kind: NodeKind\n state: string\n ref: WireRef\n copy_ref?: WireRef | null\n capabilities: Capabilities\n access_level?: AccessLevel\n revision?: string\n locations?: unknown[]\n // base\n name?: string\n size?: number\n mtime?: number\n ctime?: number\n flags?: string[]\n // ident\n node_id?: string\n gen?: number\n etag?: string\n obj_id?: string\n // access\n access_urls?: { kind: string; url: string }[]\n // meta\n meta_summary?: Record<string, number>\n // view / collection extras\n view_id?: string\n collection_id?: string\n title?: string\n origin?: string\n stale?: boolean\n}\n\nexport type EntryBinding = 'native' | 'reference' | 'member' | 'derived' | 'projection'\n\n/** Compact target of a listing entry (not a full NodeInfo). */\nexport interface EntryTarget {\n ref: WireRef\n copy_ref?: WireRef | null\n kind: NodeKind\n /** Attribute groups per the `want` mask: base → size/mtime/flags, ident → etag/obj_id, access → access_urls. */\n attrs?: {\n size?: number\n mtime?: number\n flags?: string[]\n etag?: string\n obj_id?: string\n access_urls?: { kind: string; url: string }[]\n } & Record<string, unknown>\n /** `stale` when a referenced target no longer resolves, `denied` when the caller may not see it. */\n target_state?: string\n access_level?: AccessLevel\n}\n\nexport interface Entry {\n name: string\n binding: EntryBinding\n entry_ref?: string\n target: EntryTarget\n canonical_path?: string\n context?: { count?: number; provenance?: Record<string, unknown> } & Record<string, unknown>\n}\n\nexport interface Listing {\n container: NodeInfo\n entries: Entry[]\n truncated?: boolean\n next_cursor?: string\n revision_changed?: boolean\n watch_token?: string\n /** Same-name virtual bindings shadowed by native entries (`native_shadow`). */\n conflicts?: { name: string; reason: string; entry_ref?: string; target?: EntryTarget }[]\n}\n\nexport interface ListOptions {\n cursor?: string\n limit?: number\n order?: 'name' | 'mtime' | 'size' | 'manual'\n filter?: { kind?: NodeKind[]; name_glob?: string }\n}\n\nexport interface HelloResult {\n version: string\n session: string\n features: string[]\n limits: { max_batch: number; max_list: number; replay_window: number; attr_ttl_ms: number }\n realms: { id: string; writable: boolean }[]\n /** Who this session acts as (`admin` = the zone owner or a trusted service). */\n identity?: { user_id: string | null; role: 'admin' | 'user' | 'anonymous' }\n /** The Preview Pipeline's converter, also when `repr` is not advertised. */\n repr?: ReprCapability\n}\n\n// ---------- Preview Pipeline (`repr` / `get_repr`) ----------\n\n/** What the node converts with: ffmpeg / ffprobe found on it, or why not. */\nexport type ReprCapability =\n | {\n available: true\n ffmpeg: { path: string; version: string }\n ffprobe: { path: string; version: string }\n tonemap: boolean\n h264_encoder: boolean\n heif: boolean\n profiles: string[]\n }\n | { available: false; missing?: string[]; detail?: string }\n\n/** Content that is not an NFSP path / ref (those go in `at`). */\nexport type ReprSource =\n | { bucket: { bucket_id: string; key: string; version?: number; access_token?: string } }\n | { obj_id: string }\n\n/** Runtime capability hints; `video_codecs.hevc` lets the node remux instead of transcoding. */\nexport interface ReprRuntime {\n accept?: string[]\n image?: string[]\n video?: string[]\n audio?: string[]\n video_codecs?: { h264: boolean; hevc: boolean }\n heic?: boolean\n pdf_inline?: boolean\n}\n\nexport interface ReprArgs {\n purpose?: 'preview' | 'thumbnail'\n source?: ReprSource\n runtime?: ReprRuntime\n /** Explicit Retry: a new attempt only if `expected_attempt_id` is still the current one. */\n retry?: boolean\n expected_attempt_id?: string\n}\n\nexport interface ReprResult {\n media_type: string\n result_type: 'image' | 'video' | 'audio'\n /** Bucket data-plane URL with a short-lived read token (Range supported). */\n read_url: string\n result_obj_id: string\n source_version: string\n width?: number\n height?: number\n duration?: number\n fidelity?: string\n size: number\n plan: string\n}\n\n/** `unsupported` is a planning result (`reason` + `detail`), `failed` an execution failure. */\nexport type ReprRecord =\n | { state: 'unsupported'; reason: 'no-pipeline' | 'no-renderer' | 'not-content'; detail?: string }\n | {\n work_key: string\n state: 'processing'\n attempt_id: string\n retry_after_ms?: number\n progress?: { completed: number; total?: number; message?: string }\n }\n | { work_key: string; state: 'completed'; attempt_id: string; result: ReprResult }\n | {\n work_key: string\n state: 'failed'\n attempt_id: string\n error: { code: string; message: string; retryable: boolean; retry_after?: number }\n }\n\nexport type BatchOp =\n | { m: 'walk'; args: { name?: string; names?: string[]; entry_ref?: string } }\n | { m: 'stat' | 'resolve'; args?: { name?: string }; want?: WantGroup[] }\n | { m: 'list'; args?: ListOptions; want?: WantGroup[] }\n\nexport interface BatchResult {\n completed: number\n results: ({ ok: true; result: unknown } | { ok: false; error: NfspErrorBody })[]\n}\n\nexport interface OpenWriteResult {\n fb_handle: string\n upload_url: string\n lease: { lease_id: string; seq: number; ttl_ms: number }\n target: { path: string; exists: boolean }\n}\n\nexport interface CommitResult {\n ref: WireRef\n entry_ref: string\n revision: string\n obj: { sha256: string; size: number }\n}\n\nexport interface CommitObjectResult {\n ref: WireRef\n entry_ref: string\n revision: string\n obj_id: string\n kind: 'file' | 'dir'\n obj: { size: number; sha256?: string }\n}\n\nexport interface MetaRecord {\n ns: string\n key: string\n value: unknown\n source?: unknown\n confidence?: number\n anchor?: string\n visibility?: string\n}\n\nexport interface SearchHit {\n copy_ref?: WireRef | null\n match_source: string\n canonical_path: string\n explain?: Record<string, unknown>\n [k: string]: unknown\n}\n\nexport interface SearchResult {\n hits: SearchHit[]\n partial: boolean\n sources: { mode: string; state: string; took_ms?: number; reason?: string }[]\n next_cursor?: string\n}\n\nexport interface GrantResult {\n cap_id: string\n token: string\n subtree: string\n ops: string[]\n expires_at?: number\n}\n\n// ---------- shares (`share.*`, nfs-server share module) ----------\n\nexport type ShareAccess = 'holder' | 'password'\nexport type ShareStatus = 'active' | 'stopping' | 'stopped' | 'expired' | 'failed'\nexport type ShareKind = 'link' | 'app_delivery'\nexport type ShareTargetApp = 'messagehub' | 'homestation'\nexport type ShareContentKind = 'image' | 'video' | 'audio' | 'file' | 'folder'\nexport type ShareDeliveryState = 'handed_off' | 'confirmed' | 'canceled' | 'failed' | 'unknown'\nexport type ShareOperationState = 'preparing' | 'running' | 'completed' | 'failed' | 'canceled'\n\nexport interface ShareStatsTotals {\n views: number\n downloads: number\n bytes: number\n visitors: number\n last_access_at?: number | null\n}\n\nexport interface ShareInfo {\n share_id: string\n kind: ShareKind\n title: string\n status: ShareStatus\n status_reason?: string | null\n hidden: boolean\n revision: number\n created_at: number\n updated_at: number\n stopped_at?: number | null\n owner_user_id: string\n created_by_app?: string | null\n related_share_id?: string | null\n obj_id: string\n obj_type?: string\n name?: string\n mime?: string | null\n total_size?: number\n item_count?: number\n content_kind?: ShareContentKind\n excluded?: { path: string; reason: string }[]\n prepared_at?: number\n source_path: string\n retained: boolean\n /** Link shares. `url` is only returned to the owner. */\n access?: ShareAccess\n has_password?: boolean\n allow_download?: boolean\n expires_at?: number | null\n url?: string | null\n /** App deliveries. */\n target_app?: ShareTargetApp\n delivery_state?: ShareDeliveryState\n business_ref?: Record<string, unknown> | null\n handoff_at?: number\n reported_at?: number | null\n delivery_error?: string | null\n stats: ShareStatsTotals\n}\n\nexport interface ShareAuditEntry {\n action: string\n revision_before?: number | null\n revision_after?: number | null\n actor_user_id: string\n actor_app_id?: string | null\n source: string\n reason?: string | null\n outcome: string\n at: number\n}\n\nexport interface ShareDetail extends ShareInfo {\n /** The bucket binding that retains the snapshot (`zone/nfs-server/_/shares`); empty once released. */\n retention: { bucket_id: string; key: string; obj_id: string; version: number; bound_at: number }[]\n audit: ShareAuditEntry[]\n related?: ShareInfo\n}\n\nexport interface ShareCapabilities {\n actions: string[]\n access: ShareAccess[]\n expiry_presets: (number | null)[]\n default_expiry: number\n limits: { sync_threshold: number; max_total_size: number; max_items: number }\n targets: { app: ShareTargetApp; accepts: string | string[]; max_item_size: number; fallback: 'link' }[]\n blocked: { action: string; reason: string }[]\n share_base_url?: string | null\n public: { dir: string; base_url?: string | null }\n}\n\nexport interface ShareTargetFit {\n app: ShareTargetApp\n mode: 'attachment' | 'link'\n reason?: 'folder' | 'not_media' | 'too_large' | null\n kind: ShareContentKind\n}\n\nexport interface SharePlan {\n plan_fingerprint: string\n source: { path: string; name: string; kind: 'file' | 'dir'; mime?: string | null }\n estimate: { total_size: number; item_count: number; excluded: { path: string; reason: string }[] }\n warnings: string[]\n requires_task: boolean\n existing: ShareInfo[]\n source_public: { in_publish_dir: boolean; public_acl: boolean; public_url?: string | null }\n /** Folders with an index.html may be websites (going live is App Service's job). */\n site: { has_index_html: boolean }\n target_fit?: ShareTargetFit\n}\n\nexport interface SharePolicyInput {\n access: ShareAccess\n password?: string\n /** Unix seconds; `null` = does not expire; omitted = seven days. */\n expires_at?: number | null\n allow_download?: boolean\n}\n\nexport interface ShareHandoff {\n share_id: string\n obj_id: string\n name: string\n size: number\n mime?: string | null\n kind: ShareContentKind\n mode: 'attachment' | 'link'\n link_share_id?: string | null\n url?: string | null\n launch: { appId: ShareTargetApp; payload: Record<string, unknown> }\n}\n\nexport interface ShareOperation {\n operation_id: string\n intent: 'create_link' | 'app_handoff'\n state: ShareOperationState\n share_id?: string | null\n task_id?: string | null\n error?: NfspErrorBody | null\n progress: { done_bytes?: number; total_bytes?: number }\n created_at: number\n updated_at: number\n source_changed?: boolean\n obj_id?: string\n url?: string | null\n share?: ShareInfo\n handoff?: ShareHandoff | null\n}\n\nexport interface ShareListFilter {\n kind?: ShareKind\n status?: ShareStatus\n source?: string | Locator\n objId?: string\n q?: string\n includeHidden?: boolean\n limit?: number\n cursor?: string\n}\n\nexport interface ShareStatsPoint {\n t: number\n views: number\n downloads: number\n bytes: number\n visitors: number\n}\n\nexport interface ShareStatsResult {\n granularity: 'hour' | 'day'\n from: number\n to: number\n series: ShareStatsPoint[]\n totals: Omit<ShareStatsTotals, 'last_access_at'>\n /** `expiring_soon`: active links ending within `expiring_within` seconds. */\n summary: { active: number; expiring_soon: number; expiring_within: number }\n unavailable: string[]\n}\n\nexport interface PublicEntry {\n rel_path: string\n entry_kind: 'file' | 'dir' | 'symlink'\n link_target?: string | null\n link_ok?: boolean | null\n size?: number | null\n mtime?: number | null\n first_seen_at: number\n last_seen_at: number\n missing_since?: number | null\n url?: string | null\n}\n\nexport interface PublicListing {\n entries: PublicEntry[]\n last_scan_at: number\n scan_ok: boolean\n dir: string\n base_url?: string | null\n}\n\nconst newIdempotencyKey = (): string =>\n typeof crypto !== 'undefined' && 'randomUUID' in crypto\n ? crypto.randomUUID()\n : `${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}`\n\nexport type CollectionPatchOp =\n | {\n add_ref: {\n target_ref: WireRef\n name?: string\n position?: number\n parent_entry_ref?: string\n }\n }\n | { remove_entry: { entry_ref: string } }\n | { move_entries: { entry_refs: string[]; to_index: number } }\n | { create_group: { name: string; position?: number } }\n | { rename_group: { entry_ref: string; name: string } }\n\nexport interface WatchEvent {\n /** `resync` | `container_changed` | `meta_changed` (extensible). */\n event: string\n /** Parsed JSON payload of the SSE `data:` line. */\n data: Record<string, unknown>\n /** SSE `id:` (the server_rev), when present. */\n id?: string\n}\n\n// ---------------------------------------------------------------------------\n// Errors\n// ---------------------------------------------------------------------------\n\n/** Structured NFSP error body (§8 plus implementation extensions). */\nexport interface NfspErrorBody {\n code: string\n message: string\n [k: string]: unknown\n}\n\nexport class NfspError extends Error {\n readonly code: string\n readonly httpStatus: number\n /** Extra structured fields (reason, holder_session, obj_id, expected, ...). */\n readonly details: Record<string, unknown>\n\n constructor(body: NfspErrorBody, httpStatus: number) {\n super(`${body.code}: ${body.message}`)\n this.name = 'NfspError'\n this.code = body.code\n this.httpStatus = httpStatus\n this.details = Object.fromEntries(Object.entries(body).filter(([key]) => key !== 'code' && key !== 'message'))\n }\n}\n\n// ---------------------------------------------------------------------------\n// Client\n// ---------------------------------------------------------------------------\n\nexport interface NfspClientOptions {\n sessionToken?: () => Promise<string | null>\n /** e.g. `http://127.0.0.1:3260` — no trailing slash needed. */\n baseUrl: string\n /** Override fetch (tests, custom auth wrappers). Defaults to global fetch. */\n fetch?: typeof fetch\n /** tus PATCH chunk size; server guidance is 4–16 MB. Default 8 MB. */\n uploadChunkSize?: number\n}\n\ninterface EnvelopeExtras {\n at?: Locator\n want?: WantGroup[]\n args?: Record<string, unknown>\n}\n\nexport class NfspClient {\n private readonly sessionToken?: () => Promise<string | null>\n readonly baseUrl: string\n private readonly fetchFn: typeof fetch\n private readonly chunkSize: number\n private session: string | null = null\n private seq = 0\n private helloResult: HelloResult | null = null\n\n constructor(opts: NfspClientOptions) {\n this.sessionToken = opts.sessionToken\n this.baseUrl = opts.baseUrl.replace(/\\/+$/, '')\n // Bind to globalThis: an unbound fetch throws \"Illegal invocation\".\n this.fetchFn = opts.fetch ?? ((input, init) => globalThis.fetch(input, init))\n this.chunkSize = opts.uploadChunkSize ?? 8 * 1024 * 1024\n }\n\n get sessionId(): string | null {\n return this.session\n }\n\n /** The Preview Pipeline converter reported by hello (null before hello). */\n get reprCapability(): ReprCapability | null {\n return this.helloResult?.repr ?? null\n }\n\n /** Features advertised by the server in hello (empty before hello). */\n get features(): string[] {\n return this.helloResult?.features ?? []\n }\n\n get limits(): HelloResult['limits'] | null {\n return this.helloResult?.limits ?? null\n }\n\n // ---------- session ----------\n\n async hello(clientFeatures?: string[]): Promise<HelloResult> {\n const args: Record<string, unknown> = { versions: [NFSP_VERSION] }\n if (clientFeatures) args.features = clientFeatures\n const r = (await this.post('hello', { args })) as HelloResult\n this.session = r.session\n this.seq = 0\n this.helloResult = r\n return r\n }\n\n async bye(): Promise<void> {\n await this.call('bye', {})\n this.session = null\n this.helloResult = null\n }\n\n // ---------- resolve / stat / list / batch ----------\n\n async resolve(at: LocatorLike, want?: WantGroup[]): Promise<NodeInfo> {\n return (await this.call('resolve', { at: toLocator(at), want })) as NodeInfo\n }\n\n /** stat with an optional child `name` step (server-side walk). */\n async stat(at: LocatorLike, opts?: { name?: string; want?: WantGroup[] }): Promise<NodeInfo> {\n return (await this.call('stat', {\n at: toLocator(at),\n want: opts?.want,\n args: opts?.name ? { name: opts.name } : {},\n })) as NodeInfo\n }\n\n async list(at: LocatorLike, opts?: ListOptions, want?: WantGroup[]): Promise<Listing> {\n return (await this.call('list', {\n at: toLocator(at),\n want,\n args: (opts ?? {}) as Record<string, unknown>,\n })) as Listing\n }\n\n async batch(\n start: LocatorLike,\n ops: BatchOp[],\n onError: 'abort' | 'continue' = 'abort',\n ): Promise<BatchResult> {\n return (await this.call('batch', {\n args: { start: toLocator(start), ops, on_error: onError },\n })) as BatchResult\n }\n\n // ---------- structure writes ----------\n\n /**\n * Ref form: create one child under `parent` (optional CAS via\n * `expectedRevision`). Path form: pass a dfs path string and no name —\n * behaves like `mkdir -p` (idempotent, no CAS).\n */\n async mkdir(\n parent: LocatorLike,\n name?: string,\n opts?: { expectedRevision?: string },\n ): Promise<{ ref: WireRef; existed: boolean; revision?: string }> {\n const args: Record<string, unknown> = {}\n if (name !== undefined) args.name = name\n if (opts?.expectedRevision) args.expected_revision = opts.expectedRevision\n return (await this.write('mkdir', { at: toLocator(parent), args })) as {\n ref: WireRef\n existed: boolean\n revision?: string\n }\n }\n\n async move(\n from: { parentRef: WireRef; name: string },\n to: { parentRef: WireRef; name: string },\n opts?: { expectedFromRevision?: string; expectedToRevision?: string },\n ): Promise<{ from_revision: string; to_revision: string }> {\n return (await this.write('move', {\n args: {\n from: { parent_ref: from.parentRef, name: from.name },\n to: { parent_ref: to.parentRef, name: to.name },\n expected_from_revision: opts?.expectedFromRevision,\n expected_to_revision: opts?.expectedToRevision,\n },\n })) as { from_revision: string; to_revision: string }\n }\n\n /** Destroys a native entry. Reference entries must use `unlink` instead. */\n async delete(\n parent: LocatorLike,\n name: string,\n opts?: { recursive?: boolean; expectedRevision?: string },\n ): Promise<{ revision: string }> {\n return (await this.write('delete', {\n at: toLocator(parent),\n args: {\n name,\n recursive: opts?.recursive,\n expected_revision: opts?.expectedRevision,\n },\n })) as { revision: string }\n }\n\n async bindRef(\n parentRef: WireRef,\n name: string,\n targetRef: WireRef,\n opts?: { expectedRevision?: string },\n ): Promise<{ entry_ref: string; revision: string }> {\n return (await this.write('bind_ref', {\n args: {\n parent_ref: parentRef,\n name,\n target_ref: targetRef,\n expected_revision: opts?.expectedRevision,\n },\n })) as { entry_ref: string; revision: string }\n }\n\n /** Removes a reference entry (`be_*`) only; the target is never touched. */\n async unlink(\n entryRef: string,\n opts?: { expectedRevision?: string },\n ): Promise<{ revision: string }> {\n return (await this.write('unlink', {\n args: { entry_ref: entryRef, expected_revision: opts?.expectedRevision },\n })) as { revision: string }\n }\n\n // ---------- content writes (open_write / tus / commit_file / probe) ----------\n\n async openWrite(\n target: { parentRef: WireRef; name: string; size?: number } | { ref: WireRef },\n ): Promise<OpenWriteResult> {\n const args: Record<string, unknown> =\n 'ref' in target\n ? { ref: target.ref }\n : { parent_ref: target.parentRef, name: target.name, size: target.size }\n return (await this.write('open_write', { args })) as OpenWriteResult\n }\n\n /** Current upload offset (tus HEAD) — resume point after interruption. */\n async uploadOffset(fbHandle: string): Promise<number> {\n const resp = await this.fetchFn(`${this.baseUrl}/nfs/v1/uploads/${fbHandle}`, {\n method: 'HEAD',\n headers: await this.authHeaders(),\n })\n if (!resp.ok) throw await this.httpError(resp)\n return Number(resp.headers.get('Upload-Offset') ?? '0')\n }\n\n /** One tus PATCH. Returns the new offset. */\n async uploadChunk(fbHandle: string, offset: number, chunk: Uint8Array): Promise<number> {\n const resp = await this.fetchFn(`${this.baseUrl}/nfs/v1/uploads/${fbHandle}`, {\n method: 'PATCH',\n headers: {\n ...await this.authHeaders(),\n 'Upload-Offset': String(offset),\n 'Content-Type': 'application/offset+octet-stream',\n },\n body: chunk as unknown as BodyInit,\n })\n if (resp.status !== 204) throw await this.httpError(resp)\n return Number(resp.headers.get('Upload-Offset') ?? String(offset + chunk.byteLength))\n }\n\n /** Uploads a whole buffer in chunks, resuming from the server's offset. */\n async uploadContent(\n fbHandle: string,\n content: Uint8Array,\n onProgress?: (sent: number, total: number) => void,\n ): Promise<void> {\n let offset = await this.uploadOffset(fbHandle)\n while (offset < content.byteLength) {\n const chunk = content.subarray(offset, Math.min(offset + this.chunkSize, content.byteLength))\n offset = await this.uploadChunk(fbHandle, offset, chunk)\n onProgress?.(offset, content.byteLength)\n }\n }\n\n async abortWrite(leaseId: string): Promise<void> {\n await this.write('abort_write', { args: { lease_id: leaseId } })\n }\n\n private async authHeaders(): Promise<Record<string, string>> {\n const token = await this.sessionToken?.()\n return token ? { Authorization: `Bearer ${token}` } : {}\n }\n\n async commitFile(\n parent: LocatorLike,\n name: string,\n source: { fbHandle: string; leaseId?: string } | { hash: string },\n opts?: { overwrite?: boolean; expectedRevision?: string },\n ): Promise<CommitResult> {\n const args: Record<string, unknown> = {\n name,\n overwrite: opts?.overwrite,\n expected_revision: opts?.expectedRevision,\n }\n if ('fbHandle' in source) {\n args.fb_handle = source.fbHandle\n if (source.leaseId) args.lease_id = source.leaseId\n } else {\n args.hash = source.hash\n }\n return (await this.write('commit_file', { at: toLocator(parent), args })) as CommitResult\n }\n\n async commitObject(\n parent: LocatorLike,\n name: string,\n objId: string,\n opts?: { overwrite?: boolean; expectedRevision?: string; leaseId?: string },\n ): Promise<CommitObjectResult> {\n return await this.write('commit_object', {\n at: toLocator(parent),\n args: { name, obj_id: objId, overwrite: opts?.overwrite, expected_revision: opts?.expectedRevision, lease_id: opts?.leaseId },\n }) as CommitObjectResult\n }\n\n /** Which of these digests must be uploaded (§ probe / 秒传). */\n async probe(digests: { hash: string; size?: number }[]): Promise<{ missing: { hash: string; size?: number }[] }> {\n return (await this.call('probe', { args: { digests } })) as {\n missing: { hash: string; size?: number }[]\n }\n }\n\n /**\n * Convenience: open_write + chunked tus upload + commit_file.\n * Overwrites an existing file only when `opts.overwrite` is set.\n */\n async uploadFile(\n parentRef: WireRef,\n name: string,\n content: Uint8Array,\n opts?: { overwrite?: boolean; onProgress?: (sent: number, total: number) => void },\n ): Promise<CommitResult> {\n const ow = await this.openWrite({ parentRef, name, size: content.byteLength })\n await this.uploadContent(ow.fb_handle, content, opts?.onProgress)\n return this.commitFile({ ref: parentRef }, name, {\n fbHandle: ow.fb_handle,\n leaseId: ow.lease.lease_id,\n }, { overwrite: opts?.overwrite })\n }\n\n // ---------- data plane read ----------\n\n /**\n * URL for `GET /nfs/v1/read/{node_id}` (usable in <img>, <a download>, …).\n * It carries no token: same-origin requests authenticate with the SSO cookie,\n * anything else only reads public paths.\n */\n readUrl(nodeId: string, opts?: { download?: boolean; name?: string }): string {\n const params = new URLSearchParams()\n if (opts?.download) params.set('download', '1')\n if (opts?.name) params.set('name', opts.name)\n const qs = params.size > 0 ? `?${params.toString()}` : ''\n return `${this.baseUrl}/nfs/v1/read/${encodeURIComponent(nodeId)}${qs}`\n }\n\n /** Reads file content; `range` is inclusive byte positions. */\n async readFile(\n nodeId: string,\n opts?: { range?: { start: number; end?: number }; ifNoneMatch?: string },\n ): Promise<Response> {\n const headers: Record<string, string> = await this.authHeaders()\n if (opts?.range) {\n headers.Range = `bytes=${opts.range.start}-${opts.range.end ?? ''}`\n }\n if (opts?.ifNoneMatch) headers['If-None-Match'] = opts.ifNoneMatch\n const resp = await this.fetchFn(this.readUrl(nodeId), { headers, cache: 'no-store' })\n if (!resp.ok && resp.status !== 304) throw await this.httpError(resp)\n return resp\n }\n\n // ---------- meta ----------\n\n async getMeta(target: LocatorLike, ns?: string[]): Promise<{ records: MetaRecord[] }> {\n const loc = toLocator(target)\n const args: Record<string, unknown> = { ns }\n if (loc.ref) args.ref = loc.ref\n return (await this.call('get_meta', { at: loc, args })) as { records: MetaRecord[] }\n }\n\n /** v1: only `ns: \"user\"` records are writable. */\n async setMeta(\n target: LocatorLike,\n records: { ns: string; key: string; value: unknown; visibility?: string }[],\n ): Promise<{ updated: number }> {\n const loc = toLocator(target)\n const args: Record<string, unknown> = { records }\n if (loc.ref) args.ref = loc.ref\n return (await this.write('set_meta', { at: loc, args })) as { updated: number }\n }\n\n // ---------- search ----------\n\n async search(\n q: string,\n opts?: { limit?: number; cursor?: string; scope?: LocatorLike; modes?: string[] },\n want?: WantGroup[],\n ): Promise<SearchResult> {\n return (await this.call('search', {\n want,\n args: {\n q,\n limit: opts?.limit,\n cursor: opts?.cursor,\n scope: opts?.scope !== undefined ? toLocator(opts.scope) : undefined,\n modes: opts?.modes,\n },\n })) as SearchResult\n }\n\n // ---------- views & collections ----------\n\n async openView(viewId: string, want?: WantGroup[]): Promise<NodeInfo> {\n return (await this.call('open_view', { want, args: { view_id: viewId } })) as NodeInfo\n }\n\n async createCollection(\n title: string,\n collectionId?: string,\n want?: WantGroup[],\n ): Promise<NodeInfo> {\n return (await this.write('create_collection', {\n want,\n args: { title, collection_id: collectionId },\n })) as NodeInfo\n }\n\n async openCollection(collectionId: string, want?: WantGroup[]): Promise<NodeInfo> {\n return (await this.call('open_collection', {\n want,\n args: { collection_id: collectionId },\n })) as NodeInfo\n }\n\n async collectionPatch(\n ref: WireRef,\n ops: CollectionPatchOp[],\n opts?: { expectedRevision?: string },\n ): Promise<{ revision: string }> {\n return (await this.write('collection_patch', {\n args: { ref, ops, expected_revision: opts?.expectedRevision },\n })) as { revision: string }\n }\n\n // ---------- grants ----------\n\n async grant(\n subtree: LocatorLike,\n opts?: { ops?: string[]; ttl?: number; audience?: string; maxUses?: number },\n ): Promise<GrantResult> {\n return (await this.write('grant', {\n args: {\n subtree: toLocator(subtree),\n ops: opts?.ops,\n ttl: opts?.ttl,\n audience: opts?.audience,\n max_uses: opts?.maxUses,\n },\n })) as GrantResult\n }\n\n async revoke(capId: string): Promise<{ revoked: string }> {\n return (await this.write('revoke', { args: { cap_id: capId } })) as { revoked: string }\n }\n\n // ---------- acl ----------\n\n async getAcl(at: LocatorLike): Promise<AclInfo> {\n return (await this.call('get_acl', { at: toLocator(at) })) as AclInfo\n }\n\n /** Replaces the node's own record; `inherit: true` with no entries removes it. */\n async setAcl(\n at: LocatorLike,\n acl: { inherit: boolean; entries: AclEntry[] },\n opts?: { expectedRevision?: string },\n ): Promise<{ path: string; revision: string }> {\n return (await this.write('set_acl', {\n at: toLocator(at),\n args: { inherit: acl.inherit, entries: acl.entries, expected_revision: opts?.expectedRevision },\n })) as { path: string; revision: string }\n }\n\n /** Every ACL record the caller may manage (all of them for the zone owner). */\n async listAcls(): Promise<{ records: AclRecordInfo[]; zone_owner: string | null; is_admin: boolean }> {\n return (await this.call('list_acls', {})) as { records: AclRecordInfo[]; zone_owner: string | null; is_admin: boolean }\n }\n\n // ---------- Preview Pipeline ----------\n\n /** Ensures a preview of `at` (or `args.source`); idempotent per work key. */\n async repr(at: LocatorLike | null, args: ReprArgs = {}): Promise<ReprRecord> {\n return (await this.call('repr', { at: at ? toLocator(at) : undefined, args: { ...args } })) as ReprRecord\n }\n\n /** Queries a work this principal ensured; never starts an attempt. */\n async getRepr(workKey: string): Promise<ReprRecord> {\n return (await this.call('get_repr', { args: { work_key: workKey } })) as ReprRecord\n }\n\n // ---------- shares (`share.*`) ----------\n\n async shareCapabilities(): Promise<ShareCapabilities> {\n return (await this.call('share.capabilities', {})) as ShareCapabilities\n }\n\n /** Side-effect free: size, exclusions, existing links, Public state, target fit. */\n async sharePlan(\n source: LocatorLike,\n opts?: { intent?: 'create_link' | 'app_handoff'; target?: ShareTargetApp },\n ): Promise<SharePlan> {\n return (await this.call('share.plan', {\n args: { source: toLocator(source), intent: opts?.intent, target: opts?.target },\n })) as SharePlan\n }\n\n /** Snapshots the source and creates a link. Large sources return `state: 'running'`. */\n async shareCreate(\n source: LocatorLike,\n policy: SharePolicyInput,\n opts?: { title?: string; idempotencyKey?: string; planFingerprint?: string; sourceHint?: 'gui' | 'cli' | 'agent' },\n ): Promise<ShareOperation> {\n return (await this.write('share.create', {\n args: {\n source: toLocator(source),\n policy,\n title: opts?.title,\n idempotency_key: opts?.idempotencyKey ?? newIdempotencyKey(),\n plan_fingerprint: opts?.planFingerprint,\n source_hint: opts?.sourceHint,\n },\n })) as ShareOperation\n }\n\n async shareOperation(operationId: string, opts?: { cancel?: boolean }): Promise<ShareOperation> {\n return (await this.call('share.operation', {\n args: { operation_id: operationId, cancel: opts?.cancel },\n })) as ShareOperation\n }\n\n /** Polls a running operation until it settles. */\n async waitShareOperation(\n op: ShareOperation,\n opts?: { intervalMs?: number; signal?: AbortSignal; onProgress?: (op: ShareOperation) => void },\n ): Promise<ShareOperation> {\n let cur = op\n while (cur.state === 'running' || cur.state === 'preparing') {\n if (opts?.signal?.aborted) throw new DOMException('aborted', 'AbortError')\n await new Promise((r) => setTimeout(r, opts?.intervalMs ?? 1000))\n cur = await this.shareOperation(cur.operation_id)\n opts?.onProgress?.(cur)\n }\n return cur\n }\n\n async shareGet(shareId: string): Promise<ShareDetail> {\n return (await this.call('share.get', { args: { share_id: shareId } })) as ShareDetail\n }\n\n async shareList(filter?: ShareListFilter): Promise<{ items: ShareInfo[]; next_cursor?: string | null }> {\n const source = filter?.source === undefined || typeof filter.source === 'string' ? filter?.source : toLocator(filter.source)\n return (await this.call('share.list', {\n args: {\n kind: filter?.kind,\n status: filter?.status,\n source,\n obj_id: filter?.objId,\n q: filter?.q,\n include_hidden: filter?.includeHidden,\n limit: filter?.limit,\n cursor: filter?.cursor,\n },\n })) as { items: ShareInfo[]; next_cursor?: string | null }\n }\n\n /** `password: null` removes it, `expires_at: null` = no expiry. REVISION_CONFLICT carries `current`. */\n async shareUpdate(\n shareId: string,\n revision: number,\n changes: { title?: string; expires_at?: number | null; password?: string | null; allow_download?: boolean; access?: ShareAccess },\n reason?: string,\n ): Promise<{ revision: number; share: ShareInfo }> {\n return (await this.write('share.update', {\n args: { share_id: shareId, revision, changes, reason },\n })) as { revision: number; share: ShareInfo }\n }\n\n async shareStop(shareId: string, revision: number, reason?: string): Promise<{ status: ShareStatus; revision: number }> {\n return (await this.write('share.stop', {\n args: { share_id: shareId, revision, reason },\n })) as { status: ShareStatus; revision: number }\n }\n\n async shareHide(shareId: string, hidden: boolean): Promise<{ hidden: boolean; revision: number }> {\n return (await this.write('share.hide', { args: { share_id: shareId, hidden } })) as { hidden: boolean; revision: number }\n }\n\n /** Snapshot for an app target; the result's `handoff.launch` opens the app. */\n async shareAppHandoff(\n source: LocatorLike,\n targetApp: ShareTargetApp,\n opts?: { title?: string; idempotencyKey?: string },\n ): Promise<ShareOperation> {\n return (await this.write('share.app.handoff', {\n args: {\n source: toLocator(source),\n target_app: targetApp,\n title: opts?.title,\n idempotency_key: opts?.idempotencyKey ?? newIdempotencyKey(),\n },\n })) as ShareOperation\n }\n\n /** What the target app did; older facts (by `observedAt`, ms) are refused. */\n async shareAppReport(\n shareId: string,\n deliveryState: Exclude<ShareDeliveryState, 'handed_off'>,\n opts?: { businessRef?: Record<string, unknown>; error?: string; observedAt?: number },\n ): Promise<{ accepted: boolean; delivery_state: string }> {\n return (await this.write('share.app.report', {\n args: {\n share_id: shareId,\n delivery_state: deliveryState,\n business_ref: opts?.businessRef,\n error: opts?.error,\n observed_at: opts?.observedAt ?? Date.now(),\n },\n })) as { accepted: boolean; delivery_state: string }\n }\n\n async sharePublicList(opts?: { refresh?: boolean }): Promise<PublicListing> {\n return (await this.call('share.public.list', { args: { refresh: opts?.refresh } })) as PublicListing\n }\n\n async shareStats(opts?: { shareId?: string; from?: number; to?: number; granularity?: 'hour' | 'day' }): Promise<ShareStatsResult> {\n return (await this.call('share.stats', {\n args: { share_id: opts?.shareId, from: opts?.from, to: opts?.to, granularity: opts?.granularity },\n })) as ShareStatsResult\n }\n\n // ---------- watch (SSE) ----------\n\n /**\n * Opens the watch stream. `tokens` filters to specific containers using the\n * `watch_token` returned by list. The stream is lossy by contract: on any\n * `resync` event, re-list watched containers.\n */\n watch(opts?: { tokens?: string[]; signal?: AbortSignal }): AsyncIterableIterator<WatchEvent> & {\n close: () => void\n } {\n if (!this.session) throw new Error('watch requires an active session; call hello() first')\n const params = new URLSearchParams({ session: this.session })\n if (opts?.tokens?.length) params.set('tokens', opts.tokens.join(','))\n const url = `${this.baseUrl}/nfs/v1/watch?${params.toString()}`\n const controller = new AbortController()\n if (opts?.signal) {\n opts.signal.addEventListener('abort', () => controller.abort(), { once: true })\n }\n const fetchFn = this.fetchFn\n const authHeaders = () => this.authHeaders()\n\n async function* events(): AsyncIterableIterator<WatchEvent> {\n const resp = await fetchFn(url, {\n headers: { ...await authHeaders(), Accept: 'text/event-stream' },\n signal: controller.signal,\n })\n if (!resp.ok || !resp.body) {\n throw new Error(`watch failed: HTTP ${resp.status}`)\n }\n const reader = resp.body.getReader()\n const decoder = new TextDecoder()\n let buf = ''\n try {\n for (;;) {\n const { done, value } = await reader.read()\n if (done) return\n buf += decoder.decode(value, { stream: true })\n // SSE frames are separated by a blank line.\n for (;;) {\n const sep = buf.indexOf('\\n\\n')\n if (sep < 0) break\n const frame = buf.slice(0, sep)\n buf = buf.slice(sep + 2)\n let event = 'message'\n let id: string | undefined\n const dataLines: string[] = []\n for (const line of frame.split('\\n')) {\n if (line.startsWith('event:')) event = line.slice(6).trim()\n else if (line.startsWith('data:')) dataLines.push(line.slice(5).trim())\n else if (line.startsWith('id:')) id = line.slice(3).trim()\n // comment lines (`:keep-alive`) are ignored\n }\n if (dataLines.length === 0 && event === 'message') continue\n let data: Record<string, unknown> = {}\n if (dataLines.length > 0) {\n try {\n data = JSON.parse(dataLines.join('\\n')) as Record<string, unknown>\n } catch {\n data = { raw: dataLines.join('\\n') }\n }\n }\n yield { event, data, id }\n }\n }\n } finally {\n reader.cancel().catch(() => {})\n }\n }\n\n const it = events() as AsyncIterableIterator<WatchEvent> & { close: () => void }\n it.close = () => controller.abort()\n return it\n }\n\n // ---------- envelope plumbing ----------\n\n /** Read-path call: no seq. Throws NfspError on `ok:false`. */\n async call(method: string, extras: EnvelopeExtras): Promise<unknown> {\n return this.post(method, this.envelope(extras))\n }\n\n /**\n * Write-path call: assigns the next seq once and reuses it across network\n * retries so the server's replay window guarantees exactly-once.\n */\n async write(method: string, extras: EnvelopeExtras, retries = 2): Promise<unknown> {\n const seq = ++this.seq\n const body = { ...this.envelope(extras), seq }\n let lastErr: unknown\n for (let attempt = 0; attempt <= retries; attempt++) {\n try {\n return await this.post(method, body)\n } catch (e) {\n // Only network-level failures are retried (same seq → replay-safe).\n // NfspError means the server answered: propagate immediately.\n if (e instanceof NfspError) throw e\n lastErr = e\n }\n }\n throw lastErr\n }\n\n private envelope(extras: EnvelopeExtras): Record<string, unknown> {\n const body: Record<string, unknown> = { args: pruneUndefined(extras.args ?? {}) }\n if (this.session) body.session = this.session\n if (extras.at) body.at = pruneUndefined(extras.at as unknown as Record<string, unknown>)\n if (extras.want) body.want = extras.want\n return body\n }\n\n private async post(method: string, body: Record<string, unknown>): Promise<unknown> {\n const token = await this.sessionToken?.()\n const resp = await this.fetchFn(`${this.baseUrl}/nfs/v1/${method}`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json', ...(token ? { Authorization: `Bearer ${token}` } : {}) },\n body: JSON.stringify(body),\n })\n let parsed: { ok?: boolean; result?: unknown; error?: NfspErrorBody }\n try {\n parsed = (await resp.json()) as typeof parsed\n } catch {\n throw new NfspError(\n { code: 'INTERNAL', message: `non-JSON response (HTTP ${resp.status})` },\n resp.status,\n )\n }\n if (parsed.ok !== true) {\n throw new NfspError(\n parsed.error ?? { code: 'INTERNAL', message: 'malformed error envelope' },\n resp.status,\n )\n }\n return parsed.result\n }\n\n private async httpError(resp: Response): Promise<NfspError> {\n try {\n const parsed = (await resp.json()) as { error?: NfspErrorBody }\n if (parsed.error) return new NfspError(parsed.error, resp.status)\n } catch {\n // fall through\n }\n return new NfspError({ code: 'INTERNAL', message: `HTTP ${resp.status}` }, resp.status)\n }\n}\n\n/** Drops undefined values so they don't serialize as JSON nulls. */\nconst pruneUndefined = (obj: Record<string, unknown>): Record<string, unknown> => {\n const out: Record<string, unknown> = {}\n for (const [k, v] of Object.entries(obj)) {\n if (v !== undefined) out[k] = v\n }\n return out\n}\n"],"names":["NFSP_VERSION","toLocator","at","includes","uri","realm","path","ref","newIdempotencyKey","crypto","randomUUID","Date","now","toString","Math","random","slice","NfspError","Error","constructor","body","httpStatus","super","code","message","this","name","details","Object","fromEntries","entries","filter","key","pruneUndefined","obj","out","k","v","opts","session","seq","helloResult","sessionToken","baseUrl","replace","fetchFn","fetch","input","init","globalThis","chunkSize","uploadChunkSize","sessionId","reprCapability","_a","repr","features","limits","hello","clientFeatures","args","versions","r","post","bye","call","resolve","want","stat","list","batch","start","ops","onError","on_error","mkdir","parent","expectedRevision","expected_revision","write","move","from","to","parent_ref","parentRef","expected_from_revision","expectedFromRevision","expected_to_revision","expectedToRevision","recursive","bindRef","targetRef","target_ref","unlink","entryRef","entry_ref","openWrite","target","size","uploadOffset","fbHandle","resp","method","headers","authHeaders","ok","httpError","Number","get","uploadChunk","offset","chunk","String","status","byteLength","uploadContent","content","onProgress","subarray","min","abortWrite","leaseId","lease_id","token","Authorization","commitFile","source","overwrite","fb_handle","hash","commitObject","objId","obj_id","probe","digests","uploadFile","ow","lease","readUrl","nodeId","params","URLSearchParams","download","set","qs","encodeURIComponent","readFile","range","Range","end","ifNoneMatch","cache","getMeta","ns","loc","setMeta","records","search","q","limit","cursor","scope","modes","openView","viewId","view_id","createCollection","title","collectionId","collection_id","openCollection","collectionPatch","grant","subtree","ttl","audience","max_uses","maxUses","revoke","capId","cap_id","getAcl","setAcl","acl","inherit","listAcls","getRepr","workKey","work_key","shareCapabilities","sharePlan","intent","shareCreate","policy","idempotency_key","idempotencyKey","plan_fingerprint","planFingerprint","source_hint","sourceHint","shareOperation","operationId","operation_id","cancel","waitShareOperation","op","cur","state","signal","aborted","DOMException","Promise","setTimeout","intervalMs","_b","shareGet","shareId","share_id","shareList","kind","include_hidden","includeHidden","shareUpdate","revision","changes","reason","shareStop","shareHide","hidden","shareAppHandoff","targetApp","target_app","shareAppReport","deliveryState","delivery_state","business_ref","businessRef","error","observed_at","observedAt","sharePublicList","refresh","shareStats","granularity","watch","tokens","length","join","url","controller","AbortController","addEventListener","abort","once","it","async","Accept","reader","getReader","decoder","TextDecoder","buf","done","value","read","decode","stream","sep","indexOf","frame","id","event","dataLines","line","split","startsWith","trim","push","data","JSON","parse","raw","catch","events","close","extras","envelope","retries","lastErr","attempt","e","stringify","parsed","json","result","gen","type","node_id"],"mappings":"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"}
|
package/dist/nfsp.d.ts
CHANGED
|
@@ -202,7 +202,106 @@ export interface HelloResult {
|
|
|
202
202
|
user_id: string | null;
|
|
203
203
|
role: 'admin' | 'user' | 'anonymous';
|
|
204
204
|
};
|
|
205
|
+
/** The Preview Pipeline's converter, also when `repr` is not advertised. */
|
|
206
|
+
repr?: ReprCapability;
|
|
205
207
|
}
|
|
208
|
+
/** What the node converts with: ffmpeg / ffprobe found on it, or why not. */
|
|
209
|
+
export type ReprCapability = {
|
|
210
|
+
available: true;
|
|
211
|
+
ffmpeg: {
|
|
212
|
+
path: string;
|
|
213
|
+
version: string;
|
|
214
|
+
};
|
|
215
|
+
ffprobe: {
|
|
216
|
+
path: string;
|
|
217
|
+
version: string;
|
|
218
|
+
};
|
|
219
|
+
tonemap: boolean;
|
|
220
|
+
h264_encoder: boolean;
|
|
221
|
+
heif: boolean;
|
|
222
|
+
profiles: string[];
|
|
223
|
+
} | {
|
|
224
|
+
available: false;
|
|
225
|
+
missing?: string[];
|
|
226
|
+
detail?: string;
|
|
227
|
+
};
|
|
228
|
+
/** Content that is not an NFSP path / ref (those go in `at`). */
|
|
229
|
+
export type ReprSource = {
|
|
230
|
+
bucket: {
|
|
231
|
+
bucket_id: string;
|
|
232
|
+
key: string;
|
|
233
|
+
version?: number;
|
|
234
|
+
access_token?: string;
|
|
235
|
+
};
|
|
236
|
+
} | {
|
|
237
|
+
obj_id: string;
|
|
238
|
+
};
|
|
239
|
+
/** Runtime capability hints; `video_codecs.hevc` lets the node remux instead of transcoding. */
|
|
240
|
+
export interface ReprRuntime {
|
|
241
|
+
accept?: string[];
|
|
242
|
+
image?: string[];
|
|
243
|
+
video?: string[];
|
|
244
|
+
audio?: string[];
|
|
245
|
+
video_codecs?: {
|
|
246
|
+
h264: boolean;
|
|
247
|
+
hevc: boolean;
|
|
248
|
+
};
|
|
249
|
+
heic?: boolean;
|
|
250
|
+
pdf_inline?: boolean;
|
|
251
|
+
}
|
|
252
|
+
export interface ReprArgs {
|
|
253
|
+
purpose?: 'preview' | 'thumbnail';
|
|
254
|
+
source?: ReprSource;
|
|
255
|
+
runtime?: ReprRuntime;
|
|
256
|
+
/** Explicit Retry: a new attempt only if `expected_attempt_id` is still the current one. */
|
|
257
|
+
retry?: boolean;
|
|
258
|
+
expected_attempt_id?: string;
|
|
259
|
+
}
|
|
260
|
+
export interface ReprResult {
|
|
261
|
+
media_type: string;
|
|
262
|
+
result_type: 'image' | 'video' | 'audio';
|
|
263
|
+
/** Bucket data-plane URL with a short-lived read token (Range supported). */
|
|
264
|
+
read_url: string;
|
|
265
|
+
result_obj_id: string;
|
|
266
|
+
source_version: string;
|
|
267
|
+
width?: number;
|
|
268
|
+
height?: number;
|
|
269
|
+
duration?: number;
|
|
270
|
+
fidelity?: string;
|
|
271
|
+
size: number;
|
|
272
|
+
plan: string;
|
|
273
|
+
}
|
|
274
|
+
/** `unsupported` is a planning result (`reason` + `detail`), `failed` an execution failure. */
|
|
275
|
+
export type ReprRecord = {
|
|
276
|
+
state: 'unsupported';
|
|
277
|
+
reason: 'no-pipeline' | 'no-renderer' | 'not-content';
|
|
278
|
+
detail?: string;
|
|
279
|
+
} | {
|
|
280
|
+
work_key: string;
|
|
281
|
+
state: 'processing';
|
|
282
|
+
attempt_id: string;
|
|
283
|
+
retry_after_ms?: number;
|
|
284
|
+
progress?: {
|
|
285
|
+
completed: number;
|
|
286
|
+
total?: number;
|
|
287
|
+
message?: string;
|
|
288
|
+
};
|
|
289
|
+
} | {
|
|
290
|
+
work_key: string;
|
|
291
|
+
state: 'completed';
|
|
292
|
+
attempt_id: string;
|
|
293
|
+
result: ReprResult;
|
|
294
|
+
} | {
|
|
295
|
+
work_key: string;
|
|
296
|
+
state: 'failed';
|
|
297
|
+
attempt_id: string;
|
|
298
|
+
error: {
|
|
299
|
+
code: string;
|
|
300
|
+
message: string;
|
|
301
|
+
retryable: boolean;
|
|
302
|
+
retry_after?: number;
|
|
303
|
+
};
|
|
304
|
+
};
|
|
206
305
|
export type BatchOp = {
|
|
207
306
|
m: 'walk';
|
|
208
307
|
args: {
|
|
@@ -603,6 +702,8 @@ export declare class NfspClient {
|
|
|
603
702
|
private helloResult;
|
|
604
703
|
constructor(opts: NfspClientOptions);
|
|
605
704
|
get sessionId(): string | null;
|
|
705
|
+
/** The Preview Pipeline converter reported by hello (null before hello). */
|
|
706
|
+
get reprCapability(): ReprCapability | null;
|
|
606
707
|
/** Features advertised by the server in hello (empty before hello). */
|
|
607
708
|
get features(): string[];
|
|
608
709
|
get limits(): HelloResult['limits'] | null;
|
|
@@ -776,6 +877,10 @@ export declare class NfspClient {
|
|
|
776
877
|
zone_owner: string | null;
|
|
777
878
|
is_admin: boolean;
|
|
778
879
|
}>;
|
|
880
|
+
/** Ensures a preview of `at` (or `args.source`); idempotent per work key. */
|
|
881
|
+
repr(at: LocatorLike | null, args?: ReprArgs): Promise<ReprRecord>;
|
|
882
|
+
/** Queries a work this principal ensured; never starts an attempt. */
|
|
883
|
+
getRepr(workKey: string): Promise<ReprRecord>;
|
|
779
884
|
shareCapabilities(): Promise<ShareCapabilities>;
|
|
780
885
|
/** Side-effect free: size, exclusions, existing links, Public state, target fit. */
|
|
781
886
|
sharePlan(source: LocatorLike, opts?: {
|