tsdav
Version:
WebDAV, CALDAV, and CARDDAV client for Nodejs and the Browser
2 lines (1 loc) • 35.4 kB
JavaScript
import{fetch as e}from"cross-fetch";import t from"debug";import r from"xml-js";import{encode as a}from"base-64";var s;!function(e){e.CALENDAR_SERVER="http://calendarserver.org/ns/",e.CALDAV_APPLE="http://apple.com/ns/ical/",e.CALDAV="urn:ietf:params:xml:ns:caldav",e.CARDDAV="urn:ietf:params:xml:ns:carddav",e.DAV="DAV:"}(s||(s={}));const o={[s.CALDAV]:"xmlns:c",[s.CARDDAV]:"xmlns:card",[s.CALENDAR_SERVER]:"xmlns:cs",[s.CALDAV_APPLE]:"xmlns:ca",[s.DAV]:"xmlns:d"};var n,c;!function(e){e.CALDAV="c",e.CARDDAV="card",e.CALENDAR_SERVER="cs",e.CALDAV_APPLE="ca",e.DAV="d"}(n||(n={})),function(e){e.VEVENT="VEVENT",e.VTODO="VTODO",e.VJOURNAL="VJOURNAL",e.VFREEBUSY="VFREEBUSY",e.VTIMEZONE="VTIMEZONE",e.VALARM="VALARM"}(c||(c={}));const d=e=>{const t=Number(e);if(!Number.isNaN(t))return t;const r=e.toLowerCase();return"true"===r||"false"!==r&&e},i=(e,t)=>{if(!e&&!t)return!0;if(!e||!t)return!1;const r=e.trim(),a=t.trim();if(Math.abs(r.length-a.length)>1)return!1;const s="/"===r.slice(-1)?r.slice(0,-1):r,o="/"===a.slice(-1)?a.slice(0,-1):a;return e.includes(o)||t.includes(s)},l=(e,t)=>{if(!e&&!t)return!0;if(!e||!t)return!1;const r=e.trim(),a=t.trim(),s="/"===r.slice(-1)?r.slice(0,-1):r,o="/"===a.slice(-1)?a.slice(0,-1):a;return e.includes(o)||t.includes(s)},u=e=>e.reduce(((e,t)=>({...e,[o[t]]:t})),{}),h=e=>Object.entries(e).reduce(((e,[t,r])=>r?{...e,[t]:r}:e),{}),p=(e,t)=>t?{[e]:t}:{},f=(e,t)=>e?t&&0!==t.length?Object.fromEntries(Object.entries(e).filter((([e])=>!t.includes(e)))):e:{};var v=Object.freeze({__proto__:null,cleanupFalsy:h,conditionalParam:p,excludeHeaders:f,getDAVAttribute:u,urlContains:l,urlEquals:i});const y=t("tsdav:request"),O=async t=>{var a;const{url:s,init:o,convertIncoming:n=!0,parseOutgoing:c=!0,fetchOptions:i={}}=t,{headers:l={},body:u,namespace:p,method:f,attributes:v}=o,O=n?r.js2xml({_declaration:{_attributes:{version:"1.0",encoding:"utf-8"}},...u,_attributes:v},{compact:!0,spaces:2,elementNameFn:e=>p&&!/^.+:.+/.test(e)?`${p}:${e}`:e}):u,m={...i};delete m.headers;const A=await e(s,{headers:{"Content-Type":"text/xml;charset=UTF-8",...h(l),...i.headers||{}},body:O,method:f,...m}),g=await A.text();if(!A.ok||!(null===(a=A.headers.get("content-type"))||void 0===a?void 0:a.includes("xml"))||!c)return[{href:A.url,ok:A.ok,status:A.status,statusText:A.statusText,raw:g}];const w=r.xml2js(g,{compact:!0,trim:!0,textFn:(e,t)=>{try{const r=t._parent,a=Object.keys(r),s=a[a.length-1],o=r[s];if(o.length>0){o[o.length-1]=d(e)}else r[s]=d(e)}catch(e){y(e.stack)}},elementNameFn:e=>e.replace(/^.+:/,"").replace(/([-_]\w)/g,(e=>e[1].toUpperCase())),attributesFn:e=>{const t={...e};return delete t.xmlns,t},ignoreDeclaration:!0});return(Array.isArray(w.multistatus.response)?w.multistatus.response:[w.multistatus.response]).map((e=>{var t,r;if(!e)return{status:A.status,statusText:A.statusText,ok:A.ok};const a=/^\S+\s(?<status>\d+)\s(?<statusText>.+)$/.exec(e.status);return{raw:w,href:e.href,status:(null==a?void 0:a.groups)?Number.parseInt(null==a?void 0:a.groups.status,10):A.status,statusText:null!==(r=null===(t=null==a?void 0:a.groups)||void 0===t?void 0:t.statusText)&&void 0!==r?r:A.statusText,ok:!e.error,error:e.error,responsedescription:e.responsedescription,props:(Array.isArray(e.propstat)?e.propstat:[e.propstat]).reduce(((e,t)=>({...e,...null==t?void 0:t.prop})),{})}}))},m=async e=>{const{url:t,props:r,depth:a,headers:o,headersToExclude:c,fetchOptions:d={}}=e;return O({url:t,init:{method:"PROPFIND",headers:f(h({depth:a,...o}),c),namespace:n.DAV,body:{propfind:{_attributes:u([s.CALDAV,s.CALDAV_APPLE,s.CALENDAR_SERVER,s.CARDDAV,s.DAV]),prop:r}}},fetchOptions:d})},A=async t=>{const{url:r,data:a,headers:s,headersToExclude:o,fetchOptions:n={}}=t;return e(r,{method:"PUT",body:a,headers:f(s,o),...n})},g=async t=>{const{url:r,data:a,etag:s,headers:o,headersToExclude:n,fetchOptions:c={}}=t;return e(r,{method:"PUT",body:a,headers:f(h({"If-Match":s,...o}),n),...c})},w=async t=>{const{url:r,headers:a,etag:s,headersToExclude:o,fetchOptions:n={}}=t;return e(r,{method:"DELETE",headers:f(h({"If-Match":s,...a}),o),...n})};var C=Object.freeze({__proto__:null,createObject:A,davRequest:O,deleteObject:w,propfind:m,updateObject:g});function D(e,t){const r=e=>t.every((t=>e[t]));return Array.isArray(e)?e.every((e=>r(e))):r(e)}const b=(e,t)=>t.reduce(((t,r)=>e[r]?t:`${t.length?`${t},`:""}${r.toString()}`),""),V=t("tsdav:collection"),$=async e=>{const{url:t,body:r,depth:a,defaultNamespace:s=n.DAV,headers:o,headersToExclude:c,fetchOptions:d={}}=e,i=await O({url:t,init:{method:"REPORT",headers:f(h({depth:a,...o}),c),namespace:s,body:r},fetchOptions:d});return 1!==i.length||i[0].raw?i:[]},E=async e=>{const{url:t,props:r,depth:a,headers:s,headersToExclude:o,fetchOptions:c={}}=e;return O({url:t,init:{method:"MKCOL",headers:f(h({depth:a,...s}),o),namespace:n.DAV,body:r?{mkcol:{set:{prop:r}}}:void 0},fetchOptions:c})},T=async e=>{var t,r,a,s,o;const{collection:c,headers:d,headersToExclude:i,fetchOptions:l={}}=e;return null!==(o=null===(s=null===(a=null===(r=null===(t=(await m({url:c.url,props:{[`${n.DAV}:supported-report-set`]:{}},depth:"0",headers:f(d,i),fetchOptions:l}))[0])||void 0===t?void 0:t.props)||void 0===r?void 0:r.supportedReportSet)||void 0===a?void 0:a.supportedReport)||void 0===s?void 0:s.map((e=>Object.keys(e.report)[0])))&&void 0!==o?o:[]},k=async e=>{var t,r,a;const{collection:s,headers:o,headersToExclude:c,fetchOptions:d={}}=e,i=(await m({url:s.url,props:{[`${n.CALENDAR_SERVER}:getctag`]:{}},depth:"0",headers:f(o,c),fetchOptions:d})).filter((e=>l(s.url,e.href)))[0];if(!i)throw new Error("Collection does not exist on server");return{isDirty:`${s.ctag}`!=`${null===(t=i.props)||void 0===t?void 0:t.getctag}`,newCtag:null===(a=null===(r=i.props)||void 0===r?void 0:r.getctag)||void 0===a?void 0:a.toString()}},U=e=>{const{url:t,props:r,headers:a,syncLevel:o,syncToken:c,headersToExclude:d,fetchOptions:i}=e;return O({url:t,init:{method:"REPORT",namespace:n.DAV,headers:f({...a},d),body:{"sync-collection":{_attributes:u([s.CALDAV,s.CARDDAV,s.DAV]),"sync-level":o,"sync-token":c,[`${n.DAV}:prop`]:r}}},fetchOptions:i})},_=async e=>{var t,r,a,s,o,c,d,i,u,h,p;const{collection:v,method:y,headers:O,headersToExclude:m,account:A,detailedResult:g,fetchOptions:w={}}=e,C=["accountType","homeUrl"];if(!A||!D(A,C)){if(!A)throw new Error("no account for smartCollectionSync");throw new Error(`account must have ${b(A,C)} before smartCollectionSync`)}const $=null!=y?y:(null===(t=v.reports)||void 0===t?void 0:t.includes("syncCollection"))?"webdav":"basic";if(V(`smart collection sync with type ${A.accountType} and method ${$}`),"webdav"===$){const e=await U({url:v.url,props:{[`${n.DAV}:getetag`]:{},[`${"caldav"===A.accountType?n.CALDAV:n.CARDDAV}:${"caldav"===A.accountType?"calendar-data":"address-data"}`]:{},[`${n.DAV}:displayname`]:{}},syncLevel:1,syncToken:v.syncToken,headers:f(O,m),fetchOptions:w}),t=e.filter((e=>{var t;const r="caldav"===A.accountType?".ics":".vcf";return(null===(t=e.href)||void 0===t?void 0:t.slice(-4))===r})),u=t.filter((e=>404!==e.status)).map((e=>e.href)),h=t.filter((e=>404===e.status)).map((e=>e.href)),p=(u.length&&null!==(a=await(null===(r=null==v?void 0:v.objectMultiGet)||void 0===r?void 0:r.call(v,{url:v.url,props:{[`${n.DAV}:getetag`]:{},[`${"caldav"===A.accountType?n.CALDAV:n.CARDDAV}:${"caldav"===A.accountType?"calendar-data":"address-data"}`]:{}},objectUrls:u,depth:"1",headers:f(O,m),fetchOptions:w})))&&void 0!==a?a:[]).map((e=>{var t,r,a,s,o,n,c,d,i,l;return{url:null!==(t=e.href)&&void 0!==t?t:"",etag:null===(r=e.props)||void 0===r?void 0:r.getetag,data:"caldav"===(null==A?void 0:A.accountType)?null!==(o=null===(s=null===(a=e.props)||void 0===a?void 0:a.calendarData)||void 0===s?void 0:s._cdata)&&void 0!==o?o:null===(n=e.props)||void 0===n?void 0:n.calendarData:null!==(i=null===(d=null===(c=e.props)||void 0===c?void 0:c.addressData)||void 0===d?void 0:d._cdata)&&void 0!==i?i:null===(l=e.props)||void 0===l?void 0:l.addressData}})),y=null!==(s=v.objects)&&void 0!==s?s:[],C=p.filter((e=>y.every((t=>!l(t.url,e.url))))),D=y.reduce(((e,t)=>{const r=p.find((e=>l(e.url,t.url)));return r&&r.etag&&r.etag!==t.etag?[...e,r]:e}),[]),b=h.map((e=>({url:e,etag:""}))),V=y.filter((e=>p.some((t=>l(e.url,t.url)&&t.etag===e.etag))));return{...v,objects:g?{created:C,updated:D,deleted:b}:[...V,...C,...D],syncToken:null!==(i=null===(d=null===(c=null===(o=e[0])||void 0===o?void 0:o.raw)||void 0===c?void 0:c.multistatus)||void 0===d?void 0:d.syncToken)&&void 0!==i?i:v.syncToken}}if("basic"===$){const{isDirty:e,newCtag:t}=await k({collection:v,headers:f(O,m),fetchOptions:w}),r=null!==(u=v.objects)&&void 0!==u?u:[],a=null!==(p=await(null===(h=v.fetchObjects)||void 0===h?void 0:h.call(v,{collection:v,headers:f(O,m),fetchOptions:w})))&&void 0!==p?p:[],s=a.filter((e=>r.every((t=>!l(t.url,e.url))))),o=r.reduce(((e,t)=>{const r=a.find((e=>l(e.url,t.url)));return r&&r.etag&&r.etag!==t.etag?[...e,r]:e}),[]),n=r.filter((e=>a.every((t=>!l(t.url,e.url))))),c=r.filter((e=>a.some((t=>l(e.url,t.url)&&t.etag===e.etag))));if(e)return{...v,objects:g?{created:s,updated:o,deleted:n}:[...c,...s,...o],ctag:t}}return g?{...v,objects:{created:[],updated:[],deleted:[]}}:v};var R=Object.freeze({__proto__:null,collectionQuery:$,isCollectionDirty:k,makeCollection:E,smartCollectionSync:_,supportedReportSet:T,syncCollection:U});const L=t("tsdav:addressBook"),j=async e=>{const{url:t,props:r,filters:a,depth:o,headers:c,headersToExclude:d,fetchOptions:i={}}=e;return $({url:t,body:{"addressbook-query":h({_attributes:u([s.CARDDAV,s.DAV]),[`${n.DAV}:prop`]:r,filter:null!=a?a:{"prop-filter":{_attributes:{name:"FN"}}}})},defaultNamespace:n.CARDDAV,depth:o,headers:f(c,d),fetchOptions:i})},x=async e=>{const{url:t,props:r,objectUrls:a,depth:o,headers:c,headersToExclude:d,fetchOptions:i={}}=e;return $({url:t,body:{"addressbook-multiget":h({_attributes:u([s.DAV,s.CARDDAV]),[`${n.DAV}:prop`]:r,[`${n.DAV}:href`]:a})},defaultNamespace:n.CARDDAV,depth:o,headers:f(c,d),fetchOptions:i})},S=async e=>{const{account:t,headers:r,props:a,headersToExclude:s,fetchOptions:o={}}=null!=e?e:{},c=["homeUrl","rootUrl"];if(!t||!D(t,c)){if(!t)throw new Error("no account for fetchAddressBooks");throw new Error(`account must have ${b(t,c)} before fetchAddressBooks`)}const d=await m({url:t.homeUrl,props:null!=a?a:{[`${n.DAV}:displayname`]:{},[`${n.CALENDAR_SERVER}:getctag`]:{},[`${n.DAV}:resourcetype`]:{},[`${n.DAV}:sync-token`]:{}},depth:"1",headers:f(r,s),fetchOptions:o});return Promise.all(d.filter((e=>{var t,r;return Object.keys(null!==(r=null===(t=e.props)||void 0===t?void 0:t.resourcetype)&&void 0!==r?r:{}).includes("addressbook")})).map((e=>{var r,a,s,o,n,c,d,i,l;const u=null!==(s=null===(a=null===(r=e.props)||void 0===r?void 0:r.displayname)||void 0===a?void 0:a._cdata)&&void 0!==s?s:null===(o=e.props)||void 0===o?void 0:o.displayname;return L(`Found address book named ${"string"==typeof u?u:""},\n props: ${JSON.stringify(e.props)}`),{url:new URL(null!==(n=e.href)&&void 0!==n?n:"",null!==(c=t.rootUrl)&&void 0!==c?c:"").href,ctag:null===(d=e.props)||void 0===d?void 0:d.getctag,displayName:"string"==typeof u?u:"",resourcetype:Object.keys(null===(i=e.props)||void 0===i?void 0:i.resourcetype),syncToken:null===(l=e.props)||void 0===l?void 0:l.syncToken}})).map((async e=>({...e,reports:await T({collection:e,headers:f(r,s),fetchOptions:o})}))))},N=async e=>{const{addressBook:t,headers:r,objectUrls:a,headersToExclude:s,urlFilter:o=e=>e,useMultiGet:c=!0,fetchOptions:d={}}=e;L(`Fetching vcards from ${null==t?void 0:t.url}`);const i=["url"];if(!t||!D(t,i)){if(!t)throw new Error("cannot fetchVCards for undefined addressBook");throw new Error(`addressBook must have ${b(t,i)} before fetchVCards`)}const l=(null!=a?a:(await j({url:t.url,props:{[`${n.DAV}:getetag`]:{}},depth:"1",headers:f(r,s),fetchOptions:d})).map((e=>{var t;return e.ok&&null!==(t=e.href)&&void 0!==t?t:""}))).map((e=>e.startsWith("http")||!e?e:new URL(e,t.url).href)).filter(o).map((e=>new URL(e).pathname));let u=[];return l.length>0&&(u=c?await x({url:t.url,props:{[`${n.DAV}:getetag`]:{},[`${n.CARDDAV}:address-data`]:{}},objectUrls:l,depth:"1",headers:f(r,s),fetchOptions:d}):await j({url:t.url,props:{[`${n.DAV}:getetag`]:{},[`${n.CARDDAV}:address-data`]:{}},depth:"1",headers:f(r,s),fetchOptions:d})),u.map((e=>{var r,a,s,o,n,c;return{url:new URL(null!==(r=e.href)&&void 0!==r?r:"",t.url).href,etag:null===(a=e.props)||void 0===a?void 0:a.getetag,data:null!==(n=null===(o=null===(s=e.props)||void 0===s?void 0:s.addressData)||void 0===o?void 0:o._cdata)&&void 0!==n?n:null===(c=e.props)||void 0===c?void 0:c.addressData}}))},H=async e=>{const{addressBook:t,vCardString:r,filename:a,headers:s,headersToExclude:o,fetchOptions:n={}}=e;return A({url:new URL(a,t.url).href,data:r,headers:f({"content-type":"text/vcard; charset=utf-8","If-None-Match":"*",...s},o),fetchOptions:n})},P=async e=>{const{vCard:t,headers:r,headersToExclude:a,fetchOptions:s={}}=e;return g({url:t.url,data:t.data,etag:t.etag,headers:f({"content-type":"text/vcard; charset=utf-8",...r},a),fetchOptions:s})},B=async e=>{const{vCard:t,headers:r,headersToExclude:a,fetchOptions:s={}}=e;return w({url:t.url,etag:t.etag,headers:f(r,a),fetchOptions:s})};var F=Object.freeze({__proto__:null,addressBookMultiGet:x,addressBookQuery:j,createVCard:H,deleteVCard:B,fetchAddressBooks:S,fetchVCards:N,updateVCard:P});const I=t("tsdav:calendar"),M=async e=>{var t,r,a;const{account:s,headers:o,headersToExclude:c,fetchOptions:d={}}=e,i=["principalUrl","rootUrl"];if(!D(s,i))throw new Error(`account must have ${b(s,i)} before fetchUserAddresses`);I(`Fetch user addresses from ${s.principalUrl}`);const u=(await m({url:s.principalUrl,props:{[`${n.CALDAV}:calendar-user-address-set`]:{}},depth:"0",headers:f(o,c),fetchOptions:d})).find((e=>l(s.principalUrl,e.href)));if(!u||!u.ok)throw new Error("cannot find calendarUserAddresses");const h=(null===(a=null===(r=null===(t=null==u?void 0:u.props)||void 0===t?void 0:t.calendarUserAddressSet)||void 0===r?void 0:r.href)||void 0===a?void 0:a.filter(Boolean))||[];return I(`Fetched calendar user addresses ${h}`),h},z=async e=>{const{url:t,props:r,filters:a,timezone:o,depth:c,headers:d,headersToExclude:i,fetchOptions:l={}}=e;return $({url:t,body:{"calendar-query":h({_attributes:u([s.CALDAV,s.CALENDAR_SERVER,s.CALDAV_APPLE,s.DAV]),[`${n.DAV}:prop`]:r,filter:a,timezone:o})},defaultNamespace:n.CALDAV,depth:c,headers:f(d,i),fetchOptions:l})},Z=async e=>{const{url:t,props:r,objectUrls:a,filters:o,timezone:c,depth:d,headers:i,headersToExclude:l,fetchOptions:p={}}=e;return $({url:t,body:{"calendar-multiget":h({_attributes:u([s.DAV,s.CALDAV]),[`${n.DAV}:prop`]:r,[`${n.DAV}:href`]:a,filter:o,timezone:c})},defaultNamespace:n.CALDAV,depth:d,headers:f(i,l),fetchOptions:p})},G=async e=>{const{url:t,props:r,depth:a,headers:o,headersToExclude:c,fetchOptions:d={}}=e;return O({url:t,init:{method:"MKCALENDAR",headers:f(h({depth:a,...o}),c),namespace:n.DAV,body:{[`${n.CALDAV}:mkcalendar`]:{_attributes:u([s.DAV,s.CALDAV,s.CALDAV_APPLE]),set:{prop:r}}}},fetchOptions:d})},Q=async e=>{const{headers:t,account:r,props:a,projectedProps:s,headersToExclude:o,fetchOptions:d={}}=null!=e?e:{},i=["homeUrl","rootUrl"];if(!r||!D(r,i)){if(!r)throw new Error("no account for fetchCalendars");throw new Error(`account must have ${b(r,i)} before fetchCalendars`)}const l=await m({url:r.homeUrl,props:null!=a?a:{[`${n.CALDAV}:calendar-description`]:{},[`${n.CALDAV}:calendar-timezone`]:{},[`${n.DAV}:displayname`]:{},[`${n.CALDAV_APPLE}:calendar-color`]:{},[`${n.CALENDAR_SERVER}:getctag`]:{},[`${n.DAV}:resourcetype`]:{},[`${n.CALDAV}:supported-calendar-component-set`]:{},[`${n.DAV}:sync-token`]:{}},depth:"1",headers:f(t,o),fetchOptions:d});return Promise.all(l.filter((e=>{var t,r;return Object.keys(null!==(r=null===(t=e.props)||void 0===t?void 0:t.resourcetype)&&void 0!==r?r:{}).includes("calendar")})).filter((e=>{var t,r,a,s,o,n;return(Array.isArray(null===(r=null===(t=e.props)||void 0===t?void 0:t.supportedCalendarComponentSet)||void 0===r?void 0:r.comp)?null===(a=e.props)||void 0===a?void 0:a.supportedCalendarComponentSet.comp.map((e=>e._attributes.name)):[null===(n=null===(o=null===(s=e.props)||void 0===s?void 0:s.supportedCalendarComponentSet)||void 0===o?void 0:o.comp)||void 0===n?void 0:n._attributes.name]).some((e=>Object.values(c).includes(e)))})).map((e=>{var t,a,o,n,c,d,i,l,u,h,f,v,y,O,m,A;const g=null===(t=e.props)||void 0===t?void 0:t.calendarDescription,w=null===(a=e.props)||void 0===a?void 0:a.calendarTimezone;return{description:"string"==typeof g?g:"",timezone:"string"==typeof w?w:"",url:new URL(null!==(o=e.href)&&void 0!==o?o:"",null!==(n=r.rootUrl)&&void 0!==n?n:"").href,ctag:null===(c=e.props)||void 0===c?void 0:c.getctag,calendarColor:null===(d=e.props)||void 0===d?void 0:d.calendarColor,displayName:null!==(l=null===(i=e.props)||void 0===i?void 0:i.displayname._cdata)&&void 0!==l?l:null===(u=e.props)||void 0===u?void 0:u.displayname,components:Array.isArray(null===(h=e.props)||void 0===h?void 0:h.supportedCalendarComponentSet.comp)?null===(f=e.props)||void 0===f?void 0:f.supportedCalendarComponentSet.comp.map((e=>e._attributes.name)):[null===(y=null===(v=e.props)||void 0===v?void 0:v.supportedCalendarComponentSet.comp)||void 0===y?void 0:y._attributes.name],resourcetype:Object.keys(null===(O=e.props)||void 0===O?void 0:O.resourcetype),syncToken:null===(m=e.props)||void 0===m?void 0:m.syncToken,...p("projectedProps",Object.fromEntries(Object.entries(null!==(A=e.props)&&void 0!==A?A:{}).filter((([e])=>null==s?void 0:s[e]))))}})).map((async e=>({...e,reports:await T({collection:e,headers:f(t,o),fetchOptions:d})}))))},q=async e=>{const{calendar:t,objectUrls:r,filters:a,timeRange:s,headers:o,expand:c,urlFilter:d=e=>Boolean(null==e?void 0:e.includes(".ics")),useMultiGet:i=!0,headersToExclude:l,fetchOptions:u={}}=e;if(s){const e=/^\d{4}(-\d\d(-\d\d(T\d\d:\d\d(:\d\d)?(\.\d+)?(([+-]\d\d:\d\d)|Z)?)?)?)?$/i,t=/^\d{4}-\d\d-\d\dT\d\d:\d\d:\d\d(\.\d+)?(([+-]\d\d:\d\d)|Z)?$/i;if(!(e.test(s.start)&&e.test(s.end)||t.test(s.start)&&t.test(s.end)))throw new Error("invalid timeRange format, not in ISO8601")}I(`Fetching calendar objects from ${null==t?void 0:t.url}`);const h=["url"];if(!t||!D(t,h)){if(!t)throw new Error("cannot fetchCalendarObjects for undefined calendar");throw new Error(`calendar must have ${b(t,h)} before fetchCalendarObjects`)}const p=null!=a?a:[{"comp-filter":{_attributes:{name:"VCALENDAR"},"comp-filter":{_attributes:{name:"VEVENT"},...s?{"time-range":{_attributes:{start:`${new Date(s.start).toISOString().slice(0,19).replace(/[-:.]/g,"")}Z`,end:`${new Date(s.end).toISOString().slice(0,19).replace(/[-:.]/g,"")}Z`}}}:{}}}}],v=(null!=r?r:(await z({url:t.url,props:{[`${n.DAV}:getetag`]:{...c&&s?{[`${n.CALDAV}:expand`]:{_attributes:{start:`${new Date(s.start).toISOString().slice(0,19).replace(/[-:.]/g,"")}Z`,end:`${new Date(s.end).toISOString().slice(0,19).replace(/[-:.]/g,"")}Z`}}}:{}}},filters:p,depth:"1",headers:f(o,l),fetchOptions:u})).map((e=>{var t;return null!==(t=e.href)&&void 0!==t?t:""}))).map((e=>e.startsWith("http")||!e?e:new URL(e,t.url).href)).filter(d).map((e=>new URL(e).pathname));let y=[];return v.length>0&&(y=!i||c?await z({url:t.url,props:{[`${n.DAV}:getetag`]:{},[`${n.CALDAV}:calendar-data`]:{...c&&s?{[`${n.CALDAV}:expand`]:{_attributes:{start:`${new Date(s.start).toISOString().slice(0,19).replace(/[-:.]/g,"")}Z`,end:`${new Date(s.end).toISOString().slice(0,19).replace(/[-:.]/g,"")}Z`}}}:{}}},filters:p,depth:"1",headers:f(o,l),fetchOptions:u}):await Z({url:t.url,props:{[`${n.DAV}:getetag`]:{},[`${n.CALDAV}:calendar-data`]:{...c&&s?{[`${n.CALDAV}:expand`]:{_attributes:{start:`${new Date(s.start).toISOString().slice(0,19).replace(/[-:.]/g,"")}Z`,end:`${new Date(s.end).toISOString().slice(0,19).replace(/[-:.]/g,"")}Z`}}}:{}}},objectUrls:v,depth:"1",headers:f(o,l),fetchOptions:u})),y.map((e=>{var r,a,s,o,n,c;return{url:new URL(null!==(r=e.href)&&void 0!==r?r:"",t.url).href,etag:`${null===(a=e.props)||void 0===a?void 0:a.getetag}`,data:null!==(n=null===(o=null===(s=e.props)||void 0===s?void 0:s.calendarData)||void 0===o?void 0:o._cdata)&&void 0!==n?n:null===(c=e.props)||void 0===c?void 0:c.calendarData}}))},J=async e=>{const{calendar:t,iCalString:r,filename:a,headers:s,headersToExclude:o,fetchOptions:n={}}=e;return A({url:new URL(a,t.url).href,data:r,headers:f({"content-type":"text/calendar; charset=utf-8","If-None-Match":"*",...s},o),fetchOptions:n})},K=async e=>{const{calendarObject:t,headers:r,headersToExclude:a,fetchOptions:s={}}=e;return g({url:t.url,data:t.data,etag:t.etag,headers:f({"content-type":"text/calendar; charset=utf-8",...r},a),fetchOptions:s})},W=async e=>{const{calendarObject:t,headers:r,headersToExclude:a,fetchOptions:s={}}=e;return w({url:t.url,etag:t.etag,headers:f(r,a),fetchOptions:s})},Y=async e=>{var t;const{oldCalendars:r,account:a,detailedResult:s,headers:o,headersToExclude:n,fetchOptions:c={}}=e;if(!a)throw new Error("Must have account before syncCalendars");const d=null!==(t=null!=r?r:a.calendars)&&void 0!==t?t:[],i=await Q({account:a,headers:f(o,n),fetchOptions:c}),u=i.filter((e=>d.every((t=>!l(t.url,e.url)))));I(`new calendars: ${u.map((e=>e.displayName))}`);const h=d.reduce(((e,t)=>{const r=i.find((e=>l(e.url,t.url)));return r&&(r.syncToken&&`${r.syncToken}`!=`${t.syncToken}`||r.ctag&&`${r.ctag}`!=`${t.ctag}`)?[...e,r]:e}),[]);I(`updated calendars: ${h.map((e=>e.displayName))}`);const p=await Promise.all(h.map((async e=>await _({collection:{...e,objectMultiGet:Z},method:"webdav",headers:f(o,n),account:a,fetchOptions:c})))),v=d.filter((e=>i.every((t=>!l(t.url,e.url)))));I(`deleted calendars: ${v.map((e=>e.displayName))}`);const y=d.filter((e=>i.some((t=>l(t.url,e.url)&&(t.syncToken&&`${t.syncToken}`!=`${e.syncToken}`||t.ctag&&`${t.ctag}`!=`${e.ctag}`)))));return s?{created:u,updated:h,deleted:v}:[...y,...u,...p]},X=async e=>{const{url:t,timeRange:r,depth:a,headers:o,headersToExclude:c,fetchOptions:d={}}=e;if(!r)throw new Error("timeRange is required");{const e=/^\d{4}(-\d\d(-\d\d(T\d\d:\d\d(:\d\d)?(\.\d+)?(([+-]\d\d:\d\d)|Z)?)?)?)?$/i,t=/^\d{4}-\d\d-\d\dT\d\d:\d\d:\d\d(\.\d+)?(([+-]\d\d:\d\d)|Z)?$/i;if(!(e.test(r.start)&&e.test(r.end)||t.test(r.start)&&t.test(r.end)))throw new Error("invalid timeRange format, not in ISO8601")}return(await $({url:t,body:{"free-busy-query":h({_attributes:u([s.CALDAV]),[`${n.CALDAV}:time-range`]:{_attributes:{start:`${new Date(r.start).toISOString().slice(0,19).replace(/[-:.]/g,"")}Z`,end:`${new Date(r.end).toISOString().slice(0,19).replace(/[-:.]/g,"")}Z`}}})},defaultNamespace:n.CALDAV,depth:a,headers:f(o,c),fetchOptions:d}))[0]};var ee=Object.freeze({__proto__:null,calendarMultiGet:Z,calendarQuery:z,createCalendarObject:J,deleteCalendarObject:W,fetchCalendarObjects:q,fetchCalendarUserAddresses:M,fetchCalendars:Q,freeBusyQuery:X,makeCalendar:G,syncCalendars:Y,updateCalendarObject:K});const te=t("tsdav:account"),re=async t=>{var r,a;te("Service discovery...");const{account:s,headers:o,headersToExclude:n,fetchOptions:c={}}=t,d=new URL(s.serverUrl),i=new URL(`/.well-known/${s.accountType}`,d);i.protocol=null!==(r=d.protocol)&&void 0!==r?r:"http";try{const t=await e(i.href,{headers:f(o,n),method:"PROPFIND",redirect:"manual",...c});if(t.status>=300&&t.status<400){const e=t.headers.get("Location");if("string"==typeof e&&e.length){te(`Service discovery redirected to ${e}`);const t=new URL(e,d);return t.hostname===i.hostname&&i.port&&!t.port&&(t.port=i.port),t.protocol=null!==(a=d.protocol)&&void 0!==a?a:"http",t.href}}}catch(e){te(`Service discovery failed: ${e.stack}`)}return d.href},ae=async e=>{var t,r,a,s,o;const{account:c,headers:d,headersToExclude:i,fetchOptions:l={}}=e,u=["rootUrl"];if(!D(c,u))throw new Error(`account must have ${b(c,u)} before fetchPrincipalUrl`);te(`Fetching principal url from path ${c.rootUrl}`);const[h]=await m({url:c.rootUrl,props:{[`${n.DAV}:current-user-principal`]:{}},depth:"0",headers:f(d,i),fetchOptions:l});if(!h.ok&&(te(`Fetch principal url failed: ${h.statusText}`),401===h.status))throw new Error("Invalid credentials");return te(`Fetched principal url ${null===(r=null===(t=h.props)||void 0===t?void 0:t.currentUserPrincipal)||void 0===r?void 0:r.href}`),new URL(null!==(o=null===(s=null===(a=h.props)||void 0===a?void 0:a.currentUserPrincipal)||void 0===s?void 0:s.href)&&void 0!==o?o:"",c.rootUrl).href},se=async e=>{var t,r;const{account:a,headers:s,headersToExclude:o,fetchOptions:c={}}=e,d=["principalUrl","rootUrl"];if(!D(a,d))throw new Error(`account must have ${b(a,d)} before fetchHomeUrl`);te(`Fetch home url from ${a.principalUrl}`);const i=await m({url:a.principalUrl,props:"caldav"===a.accountType?{[`${n.CALDAV}:calendar-home-set`]:{}}:{[`${n.CARDDAV}:addressbook-home-set`]:{}},depth:"0",headers:f(s,o),fetchOptions:c}),u=i.find((e=>l(a.principalUrl,e.href)));if(!u||!u.ok)throw te(`Fetch home url failed with status ${null==u?void 0:u.statusText} and error ${JSON.stringify(i.map((e=>e.error)))}`),new Error("cannot find homeUrl");const h=new URL("caldav"===a.accountType?null===(t=null==u?void 0:u.props)||void 0===t?void 0:t.calendarHomeSet.href:null===(r=null==u?void 0:u.props)||void 0===r?void 0:r.addressbookHomeSet.href,a.rootUrl).href;return te(`Fetched home url ${h}`),h},oe=async e=>{const{account:t,headers:r,loadCollections:a=!1,loadObjects:s=!1,headersToExclude:o,fetchOptions:n={}}=e,c={...t};return c.rootUrl=await re({account:t,headers:f(r,o),fetchOptions:n}),c.principalUrl=await ae({account:c,headers:f(r,o),fetchOptions:n}),c.homeUrl=await se({account:c,headers:f(r,o),fetchOptions:n}),(a||s)&&("caldav"===t.accountType?c.calendars=await Q({headers:f(r,o),account:c,fetchOptions:n}):"carddav"===t.accountType&&(c.addressBooks=await S({headers:f(r,o),account:c,fetchOptions:n}))),s&&("caldav"===t.accountType&&c.calendars?c.calendars=await Promise.all(c.calendars.map((async e=>({...e,objects:await q({calendar:e,headers:f(r,o),fetchOptions:n})})))):"carddav"===t.accountType&&c.addressBooks&&(c.addressBooks=await Promise.all(c.addressBooks.map((async e=>({...e,objects:await N({addressBook:e,headers:f(r,o),fetchOptions:n})})))))),c};var ne=Object.freeze({__proto__:null,createAccount:oe,fetchHomeUrl:se,fetchPrincipalUrl:ae,serviceDiscovery:re});const ce=t("tsdav:authHelper"),de=(e,t)=>(...r)=>e({...t,...r[0]}),ie=e=>(ce(`Basic auth token generated: ${a(`${e.username}:${e.password}`)}`),{authorization:`Basic ${a(`${e.username}:${e.password}`)}`}),le=async(t,r)=>{const a=["authorizationCode","redirectUrl","clientId","clientSecret","tokenUrl"];if(!D(t,a))throw new Error(`Oauth credentials missing: ${b(t,a)}`);const s=new URLSearchParams({grant_type:"authorization_code",code:t.authorizationCode,redirect_uri:t.redirectUrl,client_id:t.clientId,client_secret:t.clientSecret});ce(t.tokenUrl),ce(s.toString());const o=await e(t.tokenUrl,{method:"POST",body:s.toString(),headers:{"content-length":`${s.toString().length}`,"content-type":"application/x-www-form-urlencoded"},...null!=r?r:{}});if(o.ok){return await o.json()}return ce(`Fetch Oauth tokens failed: ${await o.text()}`),{}},ue=async(t,r)=>{const a=["refreshToken","clientId","clientSecret","tokenUrl"];if(!D(t,a))throw new Error(`Oauth credentials missing: ${b(t,a)}`);const s=new URLSearchParams({client_id:t.clientId,client_secret:t.clientSecret,refresh_token:t.refreshToken,grant_type:"refresh_token"}),o=await e(t.tokenUrl,{method:"POST",body:s.toString(),headers:{"Content-Type":"application/x-www-form-urlencoded"},...null!=r?r:{}});if(o.ok){return await o.json()}return ce(`Refresh access token failed: ${await o.text()}`),{}},he=async(e,t)=>{var r;ce("Fetching oauth headers");let a={};return e.refreshToken?(e.refreshToken&&!e.accessToken||Date.now()>(null!==(r=e.expiration)&&void 0!==r?r:0))&&(a=await ue(e,t)):a=await le(e,t),ce(`Oauth tokens fetched: ${a.access_token}`),{tokens:a,headers:{authorization:`Bearer ${a.access_token}`}}};var pe=Object.freeze({__proto__:null,defaultParam:de,fetchOauthTokens:le,getBasicAuthHeaders:ie,getOauthHeaders:he,refreshAccessToken:ue});const fe=async e=>{var t;const{serverUrl:r,credentials:a,authMethod:s,defaultAccountType:o,authFunction:n}=e;let c={};switch(s){case"Basic":c=ie(a);break;case"Oauth":c=(await he(a)).headers;break;case"Digest":c={Authorization:`Digest ${a.digestString}`};break;case"Custom":c=null!==(t=await(null==n?void 0:n(a)))&&void 0!==t?t:{};break;default:throw new Error("Invalid auth method")}const d=o?await oe({account:{serverUrl:r,credentials:a,accountType:o},headers:c}):void 0,i=de(A,{url:r,headers:c}),l=de(g,{headers:c,url:r}),u=de(w,{headers:c,url:r}),h=de(m,{headers:c}),p=de($,{headers:c}),f=de(E,{headers:c}),v=de(U,{headers:c}),y=de(T,{headers:c}),C=de(k,{headers:c}),D=de(_,{headers:c,account:d}),b=de(z,{headers:c}),V=de(Z,{headers:c}),R=de(G,{headers:c}),L=de(Q,{headers:c,account:d}),F=de(M,{headers:c,account:d}),I=de(q,{headers:c}),X=de(J,{headers:c}),ee=de(K,{headers:c}),te=de(W,{headers:c}),re=de(Y,{account:d,headers:c}),ae=de(j,{headers:c}),se=de(x,{headers:c});return{davRequest:async e=>{const{init:t,...r}=e,{headers:a,...s}=t;return O({...r,init:{...s,headers:{...c,...a}}})},propfind:h,createAccount:async e=>{const{account:t,headers:s,loadCollections:o,loadObjects:n}=e;return oe({account:{serverUrl:r,credentials:a,...t},headers:{...c,...s},loadCollections:o,loadObjects:n})},createObject:i,updateObject:l,deleteObject:u,calendarQuery:b,addressBookQuery:ae,collectionQuery:p,makeCollection:f,calendarMultiGet:V,makeCalendar:R,syncCollection:v,supportedReportSet:y,isCollectionDirty:C,smartCollectionSync:D,fetchCalendars:L,fetchCalendarUserAddresses:F,fetchCalendarObjects:I,createCalendarObject:X,updateCalendarObject:ee,deleteCalendarObject:te,syncCalendars:re,fetchAddressBooks:de(S,{account:d,headers:c}),addressBookMultiGet:se,fetchVCards:de(N,{headers:c}),createVCard:de(H,{headers:c}),updateVCard:de(P,{headers:c}),deleteVCard:de(B,{headers:c})}};class ve{constructor(e){var t,r,a;this.serverUrl=e.serverUrl,this.credentials=e.credentials,this.authMethod=null!==(t=e.authMethod)&&void 0!==t?t:"Basic",this.accountType=null!==(r=e.defaultAccountType)&&void 0!==r?r:"caldav",this.authFunction=e.authFunction,this.fetchOptions=null!==(a=e.fetchOptions)&&void 0!==a?a:{}}async login(){var e;switch(this.authMethod){case"Basic":this.authHeaders=ie(this.credentials);break;case"Oauth":this.authHeaders=(await he(this.credentials,this.fetchOptions)).headers;break;case"Digest":this.authHeaders={Authorization:`Digest ${this.credentials.digestString}`};break;case"Custom":this.authHeaders=await(null===(e=this.authFunction)||void 0===e?void 0:e.call(this,this.credentials));break;default:throw new Error("Invalid auth method")}this.account=this.accountType?await oe({account:{serverUrl:this.serverUrl,credentials:this.credentials,accountType:this.accountType},headers:this.authHeaders,fetchOptions:this.fetchOptions}):void 0}async davRequest(e){const{init:t,...r}=e,{headers:a,...s}=t;return O({...r,init:{...s,headers:{...this.authHeaders,...a}},fetchOptions:this.fetchOptions})}async createObject(...e){return de(A,{url:this.serverUrl,headers:this.authHeaders,fetchOptions:this.fetchOptions})(e[0])}async updateObject(...e){return de(g,{url:this.serverUrl,headers:this.authHeaders,fetchOptions:this.fetchOptions})(e[0])}async deleteObject(...e){return de(w,{url:this.serverUrl,headers:this.authHeaders,fetchOptions:this.fetchOptions})(e[0])}async propfind(...e){return de(m,{headers:this.authHeaders,fetchOptions:this.fetchOptions})(e[0])}async createAccount(e){const{account:t,headers:r,loadCollections:a,loadObjects:s,fetchOptions:o}=e;return oe({account:{serverUrl:this.serverUrl,credentials:this.credentials,...t},headers:{...this.authHeaders,...r},loadCollections:a,loadObjects:s,fetchOptions:null!=o?o:this.fetchOptions})}async collectionQuery(...e){return de($,{headers:this.authHeaders,fetchOptions:this.fetchOptions})(e[0])}async makeCollection(...e){return de(E,{headers:this.authHeaders,fetchOptions:this.fetchOptions})(e[0])}async syncCollection(...e){return de(U,{headers:this.authHeaders,fetchOptions:this.fetchOptions})(e[0])}async supportedReportSet(...e){return de(T,{headers:this.authHeaders,fetchOptions:this.fetchOptions})(e[0])}async isCollectionDirty(...e){return de(k,{headers:this.authHeaders,fetchOptions:this.fetchOptions})(e[0])}async smartCollectionSync(...e){return de(_,{headers:this.authHeaders,fetchOptions:this.fetchOptions,account:this.account})(e[0])}async calendarQuery(...e){return de(z,{headers:this.authHeaders,fetchOptions:this.fetchOptions})(e[0])}async makeCalendar(...e){return de(G,{headers:this.authHeaders,fetchOptions:this.fetchOptions})(e[0])}async calendarMultiGet(...e){return de(Z,{headers:this.authHeaders,fetchOptions:this.fetchOptions})(e[0])}async fetchCalendars(...e){return de(Q,{headers:this.authHeaders,account:this.account,fetchOptions:this.fetchOptions})(null==e?void 0:e[0])}async fetchCalendarUserAddresses(...e){return de(M,{headers:this.authHeaders,account:this.account,fetchOptions:this.fetchOptions})(null==e?void 0:e[0])}async fetchCalendarObjects(...e){return de(q,{headers:this.authHeaders,fetchOptions:this.fetchOptions})(e[0])}async createCalendarObject(...e){return de(J,{headers:this.authHeaders,fetchOptions:this.fetchOptions})(e[0])}async updateCalendarObject(...e){return de(K,{headers:this.authHeaders,fetchOptions:this.fetchOptions})(e[0])}async deleteCalendarObject(...e){return de(W,{headers:this.authHeaders,fetchOptions:this.fetchOptions})(e[0])}async syncCalendars(...e){return de(Y,{headers:this.authHeaders,account:this.account,fetchOptions:this.fetchOptions})(e[0])}async addressBookQuery(...e){return de(j,{headers:this.authHeaders,fetchOptions:this.fetchOptions})(e[0])}async addressBookMultiGet(...e){return de(x,{headers:this.authHeaders,fetchOptions:this.fetchOptions})(e[0])}async fetchAddressBooks(...e){return de(S,{headers:this.authHeaders,account:this.account,fetchOptions:this.fetchOptions})(null==e?void 0:e[0])}async fetchVCards(...e){return de(N,{headers:this.authHeaders,fetchOptions:this.fetchOptions})(e[0])}async createVCard(...e){return de(H,{headers:this.authHeaders,fetchOptions:this.fetchOptions})(e[0])}async updateVCard(...e){return de(P,{headers:this.authHeaders,fetchOptions:this.fetchOptions})(e[0])}async deleteVCard(...e){return de(B,{headers:this.authHeaders,fetchOptions:this.fetchOptions})(e[0])}}var ye={DAVNamespace:s,DAVNamespaceShort:n,DAVAttributeMap:o,...Object.freeze({__proto__:null,DAVClient:ve,createDAVClient:fe}),...C,...R,...ne,...F,...ee,...pe,...v};export{o as DAVAttributeMap,ve as DAVClient,s as DAVNamespace,n as DAVNamespaceShort,x as addressBookMultiGet,j as addressBookQuery,Z as calendarMultiGet,z as calendarQuery,h as cleanupFalsy,$ as collectionQuery,oe as createAccount,J as createCalendarObject,fe as createDAVClient,A as createObject,H as createVCard,O as davRequest,ye as default,W as deleteCalendarObject,w as deleteObject,B as deleteVCard,S as fetchAddressBooks,q as fetchCalendarObjects,M as fetchCalendarUserAddresses,Q as fetchCalendars,le as fetchOauthTokens,N as fetchVCards,X as freeBusyQuery,ie as getBasicAuthHeaders,u as getDAVAttribute,he as getOauthHeaders,k as isCollectionDirty,G as makeCalendar,m as propfind,ue as refreshAccessToken,_ as smartCollectionSync,T as supportedReportSet,Y as syncCalendars,U as syncCollection,K as updateCalendarObject,g as updateObject,P as updateVCard,l as urlContains,i as urlEquals};