Comparing version 2.2.0 to 2.3.0
@@ -1,5 +0,6 @@ | ||
var Ot=Object.create;var rt=Object.defineProperty;var vt=Object.getOwnPropertyDescriptor;var Ft=Object.getOwnPropertyNames;var It=Object.getPrototypeOf,Nt=Object.prototype.hasOwnProperty;var Ve=(t=>typeof require<"u"?require:typeof Proxy<"u"?new Proxy(t,{get:(e,r)=>(typeof require<"u"?require:e)[r]}):t)(function(t){if(typeof require<"u")return require.apply(this,arguments);throw new Error('Dynamic require of "'+t+'" is not supported')});var Ht=(t,e)=>()=>(e||t((e={exports:{}}).exports,e),e.exports);var Dt=(t,e,r,o)=>{if(e&&typeof e=="object"||typeof e=="function")for(let n of Ft(e))!Nt.call(t,n)&&n!==r&&rt(t,n,{get:()=>e[n],enumerable:!(o=vt(e,n))||o.enumerable});return t};var qt=(t,e,r)=>(r=t!=null?Ot(It(t)):{},Dt(e||!t||!t.__esModule?rt(r,"default",{value:t,enumerable:!0}):r,t));var je=(t,e,r)=>{if(!e.has(t))throw TypeError("Cannot "+r)};var i=(t,e,r)=>(je(t,e,"read from private field"),r?r.call(t):e.get(t)),d=(t,e,r)=>{if(e.has(t))throw TypeError("Cannot add the same private member more than once");e instanceof WeakSet?e.add(t):e.set(t,r)},b=(t,e,r,o)=>(je(t,e,"write to private field"),o?o.call(t,r):e.set(t,r),r),Me=(t,e,r,o)=>({set _(n){b(t,e,n,r)},get _(){return i(t,e,o)}}),p=(t,e,r)=>(je(t,e,"access private method"),r);var ct=Ht(Qe=>{"use strict";Qe.byteLength=Lt;Qe.toByteArray=Bt;Qe.fromByteArray=zt;var k=[],E=[],Wt=typeof Uint8Array<"u"?Uint8Array:Array,Ge="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";for(K=0,at=Ge.length;K<at;++K)k[K]=Ge[K],E[Ge.charCodeAt(K)]=K;var K,at;E["-".charCodeAt(0)]=62;E["_".charCodeAt(0)]=63;function it(t){var e=t.length;if(e%4>0)throw new Error("Invalid string. Length must be a multiple of 4");var r=t.indexOf("=");r===-1&&(r=e);var o=r===e?0:4-r%4;return[r,o]}function Lt(t){var e=it(t),r=e[0],o=e[1];return(r+o)*3/4-o}function Ut(t,e,r){return(e+r)*3/4-r}function Bt(t){var e,r=it(t),o=r[0],n=r[1],s=new Wt(Ut(t,o,n)),a=0,u=n>0?o-4:o,c;for(c=0;c<u;c+=4)e=E[t.charCodeAt(c)]<<18|E[t.charCodeAt(c+1)]<<12|E[t.charCodeAt(c+2)]<<6|E[t.charCodeAt(c+3)],s[a++]=e>>16&255,s[a++]=e>>8&255,s[a++]=e&255;return n===2&&(e=E[t.charCodeAt(c)]<<2|E[t.charCodeAt(c+1)]>>4,s[a++]=e&255),n===1&&(e=E[t.charCodeAt(c)]<<10|E[t.charCodeAt(c+1)]<<4|E[t.charCodeAt(c+2)]>>2,s[a++]=e>>8&255,s[a++]=e&255),s}function $t(t){return k[t>>18&63]+k[t>>12&63]+k[t>>6&63]+k[t&63]}function Gt(t,e,r){for(var o,n=[],s=e;s<r;s+=3)o=(t[s]<<16&16711680)+(t[s+1]<<8&65280)+(t[s+2]&255),n.push($t(o));return n.join("")}function zt(t){for(var e,r=t.length,o=r%3,n=[],s=16383,a=0,u=r-o;a<u;a+=s)n.push(Gt(t,a,a+s>u?u:a+s));return o===1?(e=t[r-1],n.push(k[e>>2]+k[e<<4&63]+"==")):o===2&&(e=(t[r-2]<<8)+t[r-1],n.push(k[e>>10]+k[e>>4&63]+k[e<<2&63]+"=")),n.join("")}});var We={default:new URL("https://db.fauna.com"),local:new URL("http://localhost:8443"),localhost:new URL("http://localhost:8443")};var C=class extends Error{constructor(...e){super(...e)}},y=class extends C{httpStatus;code;queryInfo;constraint_failures;constructor(e,r){super(e.error.message),Error.captureStackTrace&&Error.captureStackTrace(this,y),this.name="ServiceError",this.code=e.error.code,this.httpStatus=r;let o={txn_ts:e.txn_ts,summary:e.summary,query_tags:e.query_tags,stats:e.stats};this.queryInfo=o,this.constraint_failures=e.error.constraint_failures}},re=class extends y{constructor(e,r){super(e,r),Error.captureStackTrace&&Error.captureStackTrace(this,re),this.name="QueryRuntimeError"}},L=class extends y{constructor(e,r){super(e,r),Error.captureStackTrace&&Error.captureStackTrace(this,L),this.name="QueryCheckError"}},X=class extends y{constructor(e,r){super(e,r),Error.captureStackTrace&&Error.captureStackTrace(this,X),this.name="InvalidRequestError"}},Se=class extends y{constraint_failures;constructor(e,r){super(e,r),Error.captureStackTrace&&Error.captureStackTrace(this,L),this.name="ConstraintFailureError",this.constraint_failures=e.error.constraint_failures}},xe=class extends y{abort;constructor(e,r){super(e,r),Error.captureStackTrace&&Error.captureStackTrace(this,L),this.name="AbortError",this.abort=e.error.abort}},ne=class extends y{constructor(e,r){super(e,r),Error.captureStackTrace&&Error.captureStackTrace(this,ne),this.name="AuthenticationError"}},oe=class extends y{constructor(e,r){super(e,r),Error.captureStackTrace&&Error.captureStackTrace(this,oe),this.name="AuthorizationError"}},we=class extends y{constructor(e,r){super(e,r),Error.captureStackTrace&&Error.captureStackTrace(this,X),this.name="ContendedTransactionError"}},U=class extends y{constructor(e,r){super(e,r),Error.captureStackTrace&&Error.captureStackTrace(this,U),this.name="ThrottlingError"}},se=class extends y{stats;constructor(e,r){super(e,r),Error.captureStackTrace&&Error.captureStackTrace(this,se),this.name="QueryTimeoutError",this.stats=e.stats}},ae=class extends y{constructor(e,r){super(e,r),Error.captureStackTrace&&Error.captureStackTrace(this,ae),this.name="ServiceInternalError"}},T=class extends C{constructor(e,r){super(e,r),Error.captureStackTrace&&Error.captureStackTrace(this,T),this.name="ClientError"}},F=class extends C{constructor(e,r){super(e,r),Error.captureStackTrace&&Error.captureStackTrace(this,F),this.name="ClientClosedError"}},S=class extends C{constructor(e,r){super(e,r),Error.captureStackTrace&&Error.captureStackTrace(this,S),this.name="NetworkError"}},I=class extends C{httpStatus;constructor(e){super(e.message),Error.captureStackTrace&&Error.captureStackTrace(this,I),this.name="ProtocolError",this.httpStatus=e.httpStatus}},Y=(t,e)=>{switch(t.error.code){case"invalid_query":return new L(t,e);case"invalid_request":return new X(t,e);case"abort":if(t.error.abort!==void 0)return new xe(t,e);break;case"constraint_failure":if(t.error.constraint_failures!==void 0)return new Se(t,e);break;case"unauthorized":return new ne(t,e);case"forbidden":return new oe(t,e);case"contended_transaction":return new we(t,e);case"limit_exceeded":return new U(t,e);case"time_out":return new se(t,e);case"internal_error":return new ae(t,e)}return new re(t,e)};var le=class{#e;#t;#r;constructor({url:e,fetch_keepalive:r}){this.#e=new URL("/query/1",e).toString(),this.#t=new URL("/stream/1",e).toString(),this.#r=r}async request({data:e,headers:r,method:o,client_timeout_ms:n}){let s=AbortSignal.timeout===void 0?(()=>{let l=new AbortController,h=l.signal;return setTimeout(()=>l.abort(),n),h})():AbortSignal.timeout(n),a=await fetch(this.#e,{method:o,headers:{...r,"Content-Type":"application/json"},body:JSON.stringify(e),signal:s,keepalive:this.#r}).catch(l=>{throw new S("The network connection encountered a problem.",{cause:l})}),u=a.status,c={};a.headers.forEach((l,h)=>c[h]=l);let m=await a.text();return{status:u,body:m,headers:c}}stream({data:e,headers:r,method:o}){let n=new Request(this.#t,{method:o,headers:{...r,"Content-Type":"application/json"},body:JSON.stringify(e),keepalive:this.#r}),s=new AbortController,a={signal:s.signal};async function*u(){let c=await fetch(n,a).catch(f=>{throw new S("The network connection encountered a problem.",{cause:f})}),m=c.status;if(!(m>=200&&m<400)){let f=await c.json();throw Y(f,m)}let l=c.body;if(!l)throw new Error("Response body is undefined.");let h=l.getReader();try{for await(let f of Vt(h))yield f}catch(f){throw new S("The network connection encountered a problem while streaming events.",{cause:f})}}return{read:u(),close:()=>{s.abort("Stream closed by the client.")}}}close(){}};async function*Vt(t){let e=new TextDecoder,r="";for await(let o of jt(t)){let n=e.decode(o),s=(r+n).split(` | ||
`);for(let a=0;a<s.length-1;a++)yield s[a].trim();r=s[s.length-1]}r.trim()!==""&&(yield r)}async function*jt(t){let e=!1;do{let r=await t.read();r.value!==void 0&&(yield r.value),e=r.done}while(!e)}var Q;try{Q=Ve("node:http2")}catch{Q=void 0}var ie,fe,pe,ye,B,x,_e,nt,ce,Ee,ge,Le,Ae,ot,Ce,st,J=class{constructor({http2_session_idle_ms:e,url:r,http2_max_streams:o}){d(this,ce);d(this,ge);d(this,Ae);d(this,Ce);d(this,fe,void 0);d(this,pe,void 0);d(this,ye,void 0);d(this,B,0);d(this,x,void 0);if(Q===void 0)throw new Error("Your platform does not support Node's http2 library");b(this,fe,e),b(this,pe,o),b(this,ye,r),b(this,x,null)}static getClient(e){var n;let r=p(n=J,_e,nt).call(n,e);i(J,ie).has(r)||i(J,ie).set(r,new J(e));let o=i(J,ie).get(r);return Me(o,B)._++,o}async request(e){let r=0,o;do try{return await p(this,Ae,ot).call(this,e)}catch(n){if(n?.code!=="ERR_HTTP2_GOAWAY_SESSION")throw new S("The network connection encountered a problem.",{cause:n});o=n,r++}while(r<3);throw new S("The network connection encountered a problem.",{cause:o})}stream(e){return p(this,Ce,st).call(this,e)}close(){this.isClosed()||(Me(this,B)._--,i(this,B)===0&&i(this,x)&&!i(this,x).closed&&i(this,x).close())}isClosed(){return i(this,B)===0}},Z=J;ie=new WeakMap,fe=new WeakMap,pe=new WeakMap,ye=new WeakMap,B=new WeakMap,x=new WeakMap,_e=new WeakSet,nt=function({http2_session_idle_ms:e,url:r}){return`${r}|${e}`},ce=new WeakSet,Ee=function(){b(this,B,0),i(this,x)&&!i(this,x).closed&&i(this,x).close()},ge=new WeakSet,Le=function(){if(!i(this,x)||i(this,x).closed||i(this,x).destroyed){let e=Q.connect(i(this,ye),{peerMaxConcurrentStreams:i(this,pe)}).once("error",()=>p(this,ce,Ee).call(this)).once("goaway",()=>p(this,ce,Ee).call(this));e.setTimeout(i(this,fe),()=>{p(this,ce,Ee).call(this)}),b(this,x,e)}return i(this,x)},Ae=new WeakSet,ot=function({client_timeout_ms:e,data:r,headers:o,method:n}){return new Promise((s,a)=>{let u,c=m=>{let l=Number(m[Q.constants.HTTP2_HEADER_STATUS]),h="";u.on("data",f=>{h+=f}),u.on("end",()=>{s({status:l,body:h,headers:m})})};try{let m={...o,[Q.constants.HTTP2_HEADER_PATH]:"/query/1",[Q.constants.HTTP2_HEADER_METHOD]:n};u=p(this,ge,Le).call(this).request(m).setEncoding("utf8").on("error",h=>{a(h)}).on("response",c),u.write(JSON.stringify(r),"utf8"),u.setTimeout(e,()=>{u.destroy(new Error("Client timeout"))}),u.end()}catch(m){a(m)}})},Ce=new WeakSet,st=function({data:e,headers:r,method:o}){let n,s,a=()=>new Promise((f,M)=>{n=f,s=M}),u=a(),c,m=f=>{let M=Number(f[Q.constants.HTTP2_HEADER_STATUS]);if(M>=200&&M<400){let W="";c.on("data",A=>{let z=(W+A).split(` | ||
`);n(z.map(qe=>qe.trim()).slice(0,-1)),u=a(),W=z[z.length-1]}),c.on("end",()=>{n([W])})}else{let W="";c.on("data",A=>{W+=A}),c.on("end",()=>{try{let A=JSON.parse(W);s(Y(A,M))}catch(A){s(new S("Could not process query failure.",{cause:A}))}})}},l=this;async function*h(){var A;let f={...r,[Q.constants.HTTP2_HEADER_PATH]:"/stream/1",[Q.constants.HTTP2_HEADER_METHOD]:o};c=p(A=l,ge,Le).call(A).request(f).setEncoding("utf8").on("error",z=>{s(z)}).on("response",m);let W=JSON.stringify(e);for(c.write(W,"utf8"),c.end();;){let z=await u;for(let qe of z)yield qe}}return{read:h(),close:()=>{c&&c.close()}}},d(Z,_e),d(Z,ie,new Map);var Ue=t=>Mt()?Z.getClient(t):new le(t),Be=t=>t instanceof Object&&"body"in t&&"headers"in t&&"status"in t,$e=t=>"stream"in t&&typeof t.stream=="function",Mt=()=>{if(typeof process<"u"&&process&&process.release?.name==="node")try{return Ve("node:http2"),!0}catch{return!1}return!1};var Je=qt(ct());var Xt=/(?:\d{4}|[\u2212-]\d{4,}|\+\d{5,})/,Yt=/(?:0[1-9]|1[0-2])/,Jt=/(?:0[1-9]|[12]\d|3[01])/,ut=/(?:[01][0-9]|2[0-3])/,he=/(?:[0-5][0-9])/,Zt=/(?:\.\d+)/,ze=new RegExp(`(${Xt.source}-(${Yt.source})-(${Jt.source}))`),Kt=new RegExp(`(${ut.source}:${he.source}:${he.source}${Zt.source}?)`),er=new RegExp(`([zZ]|[+\u2212-]${ut.source}(?::?${he.source}|:${he.source}:${he.source}))`),dt=new RegExp(`^${ze.source}$`),mt=new RegExp(`^${ze.source}`),lt=new RegExp(`^${ze.source}T${Kt.source}${er.source}$`);var R=class{isoString;constructor(e){this.isoString=e}static from(e){if(typeof e!="string")throw new TypeError(`Expected string but received ${typeof e}: ${e}`);if(lt.exec(e)===null)throw new RangeError(`(regex) Expected an ISO date string but received '${e}'`);return new R(e)}static fromDate(e){return new R(e.toISOString())}toDate(){let e=new Date(this.isoString);if(e.toString()==="Invalid Date")throw new RangeError("Fauna Date could not be converted to Javascript Date");return e}toString(){return`TimeStub("${this.isoString}")`}},P=class{dateString;constructor(e){this.dateString=e}static from(e){if(typeof e!="string")throw new TypeError(`Expected string but received ${typeof e}: ${e}`);let r=dt.exec(e);if(r===null)throw new RangeError(`Expected a plain date string but received '${e}'`);return new P(r[0])}static fromDate(e){let r=e.toISOString(),o=mt.exec(r);if(o===null)throw new T(`Failed to parse date '${e}'`);return new P(o[0])}toDate(){let e=new Date(this.dateString+"T00:00:00Z");if(e.toString()==="Invalid Date")throw new RangeError("Fauna Date could not be converted to Javascript Date");return e}toString(){return`DateStub("${this.dateString}")`}};var N=class{coll;id;constructor({coll:e,id:r}){this.id=r,typeof e=="string"?this.coll=new H(e):this.coll=e}},ue=class extends N{ts;ttl;constructor(e){let{coll:r,id:o,ts:n,...s}=e;super({coll:r,id:o}),this.ts=n,Object.assign(this,s)}toObject(){return{...this}}},$=class{coll;name;constructor({coll:e,name:r}){this.name=r,typeof e=="string"?this.coll=new H(e):this.coll=e}},de=class extends ${ts;data;constructor(e){let{coll:r,name:o,ts:n,data:s,...a}=e;super({coll:r,name:o}),this.ts=n,this.data=s||{},Object.assign(this,a)}toObject(){return{...this}}},H=class{name;constructor(e){this.name=e}},ee=class{ref;cause;constructor(e,r){this.ref=e,this.cause=r}};var O=class{data;after;constructor({data:e,after:r}){this.data=e,this.after=r}},D=class{after;constructor(e){this.after=e}},q=class{#e;constructor(e,r,o){if(o=o??{},r instanceof Function)this.#e=rr(e,r,o);else if(r instanceof O||r instanceof D)this.#e=ft(e,r,o);else throw new TypeError(`Expected 'Page<T> | EmbeddedSet | (() => Promise<T | Page<T> | EmbeddedSet>)', but received ${JSON.stringify(r)}`)}static fromQuery(e,r,o){return new q(e,async()=>(await e.query(r,o)).data,o)}static fromPageable(e,r,o){return new q(e,r,o)}flatten(){return new Xe(this)}async next(){return this.#e.next()}async return(){return this.#e.return()}async throw(e){return this.#e.throw(e)}[Symbol.asyncIterator](){return this}},Xe=class{#e;constructor(e){this.#e=nr(e)}async next(){return this.#e.next()}async return(){return this.#e.return()}async throw(e){return this.#e.throw(e)}[Symbol.asyncIterator](){return this}};async function*ft(t,e,r){let o=e;for(o instanceof O&&(yield o.data);o.after;){let n=Ye`Set.paginate(${o.after})`;o=(await t.query(n,r)).data,yield o.data}}async function*rr(t,e,r){let o=await e();if(o instanceof O||o instanceof D){for await(let n of ft(t,o,r))yield n;return}yield[o]}async function*nr(t){for await(let e of t)for(let r of e)yield r}var v=class{token;constructor(e){this.token=e}};var V=class{static encode(e){return me(e)}static encodeInterpolation(e){return ke(e)}static decode(e,r){return JSON.parse(e,(o,n)=>{if(n==null)return null;if(n["@mod"])return new H(n["@mod"]);if(n["@doc"]){if(typeof n["@doc"]=="string"){let[a,u]=n["@doc"].split(":");return new N({coll:a,id:u})}let s=n["@doc"];return s.id?new ue(s):new de(s)}else if(n["@ref"]){let s=n["@ref"],a;return s.id?a=new N(s):a=new $(s),"exists"in s&&s.exists===!1?new ee(a,s.cause):a}else{if(n["@set"])return typeof n["@set"]=="string"?new D(n["@set"]):new O(n["@set"]);if(n["@int"])return Number(n["@int"]);if(n["@long"]){let s=BigInt(n["@long"]);return r.long_type==="number"?((s>Number.MAX_SAFE_INTEGER||s<Number.MIN_SAFE_INTEGER)&&console.warn("Value is too large to be represented as a number. Returning as Number with loss of precision. Use long_type 'bigint' instead."),Number(s)):s}else{if(n["@double"])return Number(n["@double"]);if(n["@date"])return P.from(n["@date"]);if(n["@time"])return R.from(n["@time"]);if(n["@object"])return n["@object"];if(n["@stream"])return new v(n["@stream"]);if(n["@bytes"])return ir(n["@bytes"])}}return n})}},ht=BigInt("-9223372036854775808"),Tt=BigInt("9223372036854775807"),pt=-(2**31),yt=2**31-1,g={bigint:t=>{if(t<ht||t>Tt)throw new RangeError("BigInt value exceeds max magnitude for a 64-bit Fauna long. Use a 'number' to represent doubles beyond that limit.");return t>=pt&&t<=yt?{"@int":t.toString()}:{"@long":t.toString()}},number:t=>{if(t===Number.POSITIVE_INFINITY||t===Number.NEGATIVE_INFINITY)throw new RangeError(`Cannot convert ${t} to a Fauna type.`);return Number.isInteger(t)?t>=pt&&t<=yt?{"@int":t.toString()}:Number.isSafeInteger(t)?{"@long":t.toString()}:{"@double":t.toString()}:{"@double":t.toString()}},string:t=>t,object:t=>{let e=!1,r={};for(let o in t)o.startsWith("@")&&(e=!0),t[o]!==void 0&&(r[o]=me(t[o]));return e?{"@object":r}:r},array:t=>t.map(me),date:t=>({"@time":t.toISOString()}),faunadate:t=>({"@date":t.dateString}),faunatime:t=>({"@time":t.isoString}),module:t=>({"@mod":t.name}),documentReference:t=>({"@ref":{id:t.id,coll:{"@mod":t.coll.name}}}),document:t=>({"@ref":{id:t.id,coll:{"@mod":t.coll.name}}}),namedDocumentReference:t=>({"@ref":{name:t.name,coll:{"@mod":t.coll.name}}}),namedDocument:t=>({"@ref":{name:t.name,coll:{"@mod":t.coll.name}}}),set:t=>{throw new T("Page could not be encoded. Fauna does not accept encoded Set values, yet. Use Page.data and Page.after as arguments, instead.")},streamToken:t=>t.token,bytes:t=>({"@bytes":cr(t)})},me=t=>{switch(typeof t){case"bigint":return g.bigint(t);case"string":return g.string(t);case"number":return g.number(t);case"boolean":return t;case"object":if(t==null)return null;if(Array.isArray(t))return g.array(t);if(t instanceof Date)return g.date(t);if(t instanceof P)return g.faunadate(t);if(t instanceof R)return g.faunatime(t);if(t instanceof H)return g.module(t);if(t instanceof ue)return g.document(t);if(t instanceof N)return g.documentReference(t);if(t instanceof de)return g.namedDocument(t);if(t instanceof $)return g.namedDocumentReference(t);if(t instanceof ee)return me(t.ref);if(t instanceof O)return g.set(t);if(t instanceof D)return g.set(t);if(t instanceof v)return g.streamToken(t);if(t instanceof Uint8Array||t instanceof ArrayBuffer)return g.bytes(t);if(ArrayBuffer.isView(t))throw new T("Error encoding TypedArray to Fauna Bytes. Convert your TypedArray to Uint8Array or ArrayBuffer before passing it to Fauna. See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray");if(t instanceof j)throw new TypeError("Cannot encode instance of type 'Query'. Try using TaggedTypeFormat.encodeInterpolation instead.");return g.object(t);default:throw new TypeError(`Passing ${typeof t} as a QueryArgument is not supported`)}},ke=t=>{switch(typeof t){case"bigint":case"string":case"number":case"boolean":return gt(me(t));case"object":return t==null||t instanceof Date||t instanceof P||t instanceof R||t instanceof H||t instanceof N||t instanceof $||t instanceof O||t instanceof D||t instanceof v||t instanceof Uint8Array||t instanceof ArrayBuffer||ArrayBuffer.isView(t)?gt(me(t)):t instanceof ee?ke(t.ref):t instanceof j?ar(t):Array.isArray(t)?sr(t):or(t);default:throw new TypeError(`Passing ${typeof t} as a QueryArgument is not supported`)}},or=t=>{let e={};for(let r in t)t[r]!==void 0&&(e[r]=ke(t[r]));return{object:e}},sr=t=>({array:t.map(ke)}),ar=t=>t.encode(),gt=t=>({value:t});function ir(t){return Je.default.toByteArray(t)}function cr(t){let e=t instanceof Uint8Array?t:new Uint8Array(t);return Je.default.fromByteArray(e)}function Ye(t,...e){return new j(t,...e)}var j=class{#e;#t;#r;constructor(e,...r){if(e.length===0||e.length!==r.length+1)throw new Error("invalid query constructed");this.#e=e,this.#t=r,this.#r=void 0}encode(){if(this.#e.length===1)return{fql:[this.#e[0]]};let e=this.#e.flatMap((r,o)=>{if(o===this.#e.length-1)return r===""?[]:[r];let n=this.#t[o],s=V.encodeInterpolation(n);return[r,s]});return e=e.filter(r=>r!==""),{fql:e}}};var bt="2.2.0";var Re;try{Re=Ve("node:os")}catch{Re=void 0}var wt=()=>{let t={driver:["javascript",bt].join("-"),env:"unknown",os:"unknown",runtime:"unknown"};try{let e=typeof window>"u"&&typeof process<"u"&&process.versions!=null&&process.versions.node!=null,r=typeof window<"u"&&typeof window.document<"u",o=typeof self=="object"&&self.constructor&&self.constructor.name==="DedicatedWorkerGlobalScope";e?(t.runtime=["nodejs",process.version].join("-"),t.env=dr(),t.os=[Re.platform(),Re.release()].join("-")):o?(t.runtime=St(navigator),t.env="Service Worker",t.os=xt(navigator)):r?(t.runtime=St(navigator),t.env="browser",t.os=xt(navigator)):typeof EdgeRuntime!="string"&&(t.runtime="Vercel Edge Runtime",t.env="edge")}catch{}return Object.entries(t).filter(([e,r])=>r!=="unknown").map(e=>e.join("=")).join("; ")},St=t=>{let e=t.appName,r=""+parseFloat(t.appVersion),o,n,s;return(n=t.userAgent.indexOf("Opera"))!=-1?(e="Opera",r=t.userAgent.substring(n+6),(n=t.userAgent.indexOf("Version"))!=-1&&(r=t.userAgent.substring(n+8))):(n=t.userAgent.indexOf("MSIE"))!=-1?(e="Microsoft Internet Explorer",r=t.userAgent.substring(n+5)):e=="Netscape"&&t.userAgent.indexOf("Trident/")!=-1?(e="Microsoft Internet Explorer",r=t.userAgent.substring(n+5),(n=t.userAgent.indexOf("rv:"))!=-1&&(r=t.userAgent.substring(n+3))):(n=t.userAgent.indexOf("Chrome"))!=-1?(e="Chrome",r=t.userAgent.substring(n+7)):(n=t.userAgent.indexOf("Safari"))!=-1?(e="Safari",r=t.userAgent.substring(n+7),(n=t.userAgent.indexOf("Version"))!=-1&&(r=t.userAgent.substring(n+8)),t.userAgent.indexOf("CriOS")!=-1&&(e="Chrome")):(n=t.userAgent.indexOf("Firefox"))!=-1?(e="Firefox",r=t.userAgent.substring(n+8)):(o=t.userAgent.lastIndexOf(" ")+1)<(n=t.userAgent.lastIndexOf("/"))&&(e=t.userAgent.substring(o,n),r=t.userAgent.substring(n+1),e.toLowerCase()==e.toUpperCase()&&(e=t.appName)),(s=r.indexOf(";"))!=-1&&(r=r.substring(0,s)),(s=r.indexOf(" "))!=-1&&(r=r.substring(0,s)),(s=r.indexOf(")"))!=-1&&(r=r.substring(0,s)),[e,r].join("-")},xt=t=>{let e="unknown",r=[{s:"Windows 10",r:/(Windows 10.0|Windows NT 10.0)/},{s:"Windows 8.1",r:/(Windows 8.1|Windows NT 6.3)/},{s:"Windows 8",r:/(Windows 8|Windows NT 6.2)/},{s:"Windows 7",r:/(Windows 7|Windows NT 6.1)/},{s:"Windows Vista",r:/Windows NT 6.0/},{s:"Windows Server 2003",r:/Windows NT 5.2/},{s:"Windows XP",r:/(Windows NT 5.1|Windows XP)/},{s:"Windows 2000",r:/(Windows NT 5.0|Windows 2000)/},{s:"Windows ME",r:/(Win 9x 4.90|Windows ME)/},{s:"Windows 98",r:/(Windows 98|Win98)/},{s:"Windows 95",r:/(Windows 95|Win95|Windows_95)/},{s:"Windows NT 4.0",r:/(Windows NT 4.0|WinNT4.0|WinNT|Windows NT)/},{s:"Windows CE",r:/Windows CE/},{s:"Windows 3.11",r:/Win16/},{s:"Android",r:/Android/},{s:"Open BSD",r:/OpenBSD/},{s:"Sun OS",r:/SunOS/},{s:"Chrome OS",r:/CrOS/},{s:"Linux",r:/(Linux|X11(?!.*CrOS))/},{s:"iOS",r:/(iPhone|iPad|iPod)/},{s:"Mac OS X",r:/Mac OS X/},{s:"Mac OS",r:/(Mac OS|MacPPC|MacIntel|Mac_PowerPC|Macintosh)/},{s:"QNX",r:/QNX/},{s:"UNIX",r:/UNIX/},{s:"BeOS",r:/BeOS/},{s:"OS/2",r:/OS\/2/},{s:"Search Bot",r:/(nuhk|Googlebot|Yammybot|Openbot|Slurp|MSNBot|Ask Jeeves\/Teoma|ia_archiver)/}];for(let n in r){let s=r[n];if(s.r.test(t.userAgent)){e=s.s;break}}let o="unknown";if(/Windows/.test(e)){let n=/Windows (.*)/.exec(e);n&&(o=n[1]),e="Windows"}switch(e){case"Mac OS":case"Mac OS X":case"Android":{let n=/(?:Android|Mac OS|Mac OS X|MacPPC|MacIntel|Mac_PowerPC|Macintosh) ([._\d]+)/.exec(t.userAgent);n&&(o=n[1]);break}case"iOS":{let n=/OS (\d+)_(\d+)_?(\d+)?/.exec(t.appVersion);n&&(o=n[1]+"."+n[2]+"."+(n[3]??0));break}}return[e,o].join("-")},ur=typeof window<"u"?window:typeof globalThis<"u"?globalThis:typeof global<"u"?global:self,dr=()=>{if(!(typeof process<"u"&&process&&process.env&&typeof process.env=="object"))return"unknown";let e=[{name:"Netlify",check:function(){return!!process.env.NETLIFY_IMAGES_CDN_DOMAIN}},{name:"Vercel",check:function(){return!!process.env.VERCEL}},{name:"Heroku",check:function(){return!!process.env.PATH&&process.env.PATH.indexOf(".heroku")!==-1}},{name:"AWS Lambda",check:function(){return!!process.env.AWS_LAMBDA_FUNCTION_VERSION}},{name:"GCP Cloud Functions",check:function(){return!!process.env._&&process.env._.indexOf("google")!==-1}},{name:"GCP Compute Instances",check:function(){return!!process.env.GOOGLE_CLOUD_PROJECT}},{name:"Azure Cloud Functions",check:function(){return!!process.env.WEBSITE_FUNCTIONS_AZUREMONITOR_CATEGORIES}},{name:"Azure Compute",check:function(){return!!process.env.ORYX_ENV_TYPE&&!!process.env.WEBSITE_INSTANCE_ID&&process.env.ORYX_ENV_TYPE==="AppService"}},{name:"Mongo Stitch",check:function(){return typeof ur?.StitchError=="function"}},{name:"Render",check:function(){return!!process.env.RENDER_SERVICE_ID}},{name:"Begin",check:function(){return!!process.env.BEGIN_DATA_SCOPE_ID}}].find(r=>r.check());return e?e.name:"unknown"};var Et=t=>t instanceof Object&&"data"in t,_t=t=>t instanceof Object&&"error"in t&&t.error instanceof Object&&"code"in t.error&&"message"in t.error;var Ze={client_timeout_buffer_ms:5e3,format:"tagged",http2_session_idle_ms:5e3,http2_max_streams:100,long_type:"number",fetch_keepalive:!1,query_timeout_ms:5e3,max_attempts:3,max_backoff:20},ve,w,G,_,te,Te,Ke,be,et,Fe,At,Ie,Ct,Ne,Qt,He,kt,De,Rt,tt=class{constructor(e,r){d(this,Te);d(this,be);d(this,Fe);d(this,Ie);d(this,Ne);d(this,He);d(this,De);d(this,w,void 0);d(this,G,void 0);d(this,_,void 0);d(this,te,!1);b(this,w,{...Ze,...e,secret:p(this,Fe,At).call(this,e),endpoint:p(this,Ie,Ct).call(this,e)}),p(this,De,Rt).call(this),r?b(this,G,r):b(this,G,Ue({url:i(this,w).endpoint.toString(),http2_session_idle_ms:i(this,w).http2_session_idle_ms,http2_max_streams:i(this,w).http2_max_streams,fetch_keepalive:i(this,w).fetch_keepalive}))}get lastTxnTs(){return i(this,_)}set lastTxnTs(e){e!==void 0&&b(this,_,i(this,_)?Math.max(e,i(this,_)):e)}get clientConfiguration(){let{...e}=i(this,w);return e}close(){if(i(this,te))throw new F("Your client is closed. You cannot close it again.");i(this,G).close(),b(this,te,!0)}paginate(e,r){return e instanceof j?q.fromQuery(this,e,r):q.fromPageable(this,e,r)}async query(e,r){if(i(this,te))throw new F("Your client is closed. No further requests can be issued.");let o={query:e.encode()};return r?.arguments&&(o.arguments=V.encode(r.arguments)),p(this,Te,Ke).call(this,o,r)}stream(e,r){if(i(this,te))throw new F("Your client is closed. No further requests can be issued.");let o=i(this,G);if($e(o)){let n={...i(this,w),httpStreamClient:o,...r},s=e instanceof j?()=>this.query(e).then(a=>a.data):e;return new Oe(s,n)}else throw new T("Streaming is not supported by this client.")}},Pe=tt;ve=new WeakMap,w=new WeakMap,G=new WeakMap,_=new WeakMap,te=new WeakMap,Te=new WeakSet,Ke=async function(e,r,o=0){let n=this.clientConfiguration.max_backoff??Ze.max_backoff,s=this.clientConfiguration.max_attempts??Ze.max_attempts,a=Math.min(Math.random()*2**o,n)*1e3;o+=1;try{return await p(this,Ne,Qt).call(this,e,r,o)}catch(u){if(u instanceof U&&o<s)return await Pt(a),p(this,Te,Ke).call(this,e,r,o);throw u}},be=new WeakSet,et=function(e){if(e instanceof T||e instanceof S||e instanceof I||e instanceof y)return e;if(Be(e)){if(_t(e.body)){let r=e.body,o=e.status;return Y(r,o)}return new I({message:`Response is in an unkown format: ${e.body}`,httpStatus:e.status})}return new T("A client level error occurred. Fauna was not called.",{cause:e})},Fe=new WeakSet,At=function(e){let r;typeof process<"u"&&process&&typeof process=="object"&&process.env&&typeof process.env=="object"&&(r=process.env.FAUNA_SECRET);let o=e?.secret??r;if(o===void 0)throw new TypeError("You must provide a secret to the driver. Set it in an environmental variable named FAUNA_SECRET or pass it to the Client constructor.");return o},Ie=new WeakSet,Ct=function(e){if(e&&"endpoint"in e&&e.endpoint===void 0)throw new TypeError("ClientConfiguration option endpoint must be defined.");let r;return typeof process<"u"&&process&&typeof process=="object"&&process.env&&typeof process.env=="object"&&(r=process.env.FAUNA_ENDPOINT?new URL(process.env.FAUNA_ENDPOINT):void 0),e?.endpoint??r??We.default},Ne=new WeakSet,Qt=async function(e,r,o=0){try{let n={...i(this,w),...r},s={Authorization:`Bearer ${n.secret}`};p(this,He,kt).call(this,n,s);let a=n.format==="tagged",u=n.query_timeout_ms+i(this,w).client_timeout_buffer_ms,c=await i(this,G).request({client_timeout_ms:u,data:e,headers:s,method:"POST"}),m;try{if(m={...c,body:a?V.decode(c.body,{long_type:n.long_type}):JSON.parse(c.body)},m.body.query_tags){let f=m.body.query_tags.split(",").map(M=>M.split("="));m.body.query_tags=Object.fromEntries(f)}}catch(f){throw new I({message:`Error parsing response as JSON: ${f}`,httpStatus:c.status})}if(!Et(m.body))throw p(this,be,et).call(this,m);let l=m.body.txn_ts;(i(this,_)===void 0&&l!==void 0||l!==void 0&&i(this,_)!==void 0&&i(this,_)<l)&&b(this,_,l);let h=m.body;return h.stats&&(h.stats.attempts=o),h}catch(n){throw p(this,be,et).call(this,n)}},He=new WeakSet,kt=function(e,r){let o=(n,s,a=u=>String(u))=>{s!==void 0&&(r[n]=a(s))};o("x-format",e.format),o("x-typecheck",e.typecheck),o("x-query-timeout-ms",e.query_timeout_ms),o("x-linearized",e.linearized),o("x-max-contention-retries",e.max_contention_retries),o("traceparent",e.traceparent),o("x-query-tags",e.query_tags,n=>Object.entries(n).map(s=>s.join("=")).join(",")),o("x-last-txn-ts",i(this,_),n=>n),o("x-driver-env",i(tt,ve))},De=new WeakSet,Rt=function(){let e=i(this,w);if(["client_timeout_buffer_ms","endpoint","format","http2_session_idle_ms","long_type","query_timeout_ms","fetch_keepalive","http2_max_streams","max_backoff","max_attempts"].forEach(o=>{if(e[o]===void 0)throw new TypeError(`ClientConfiguration option '${o}' must be defined.`)}),e.http2_max_streams<=0)throw new RangeError("'http2_max_streams' must be greater than zero.");if(e.client_timeout_buffer_ms<=0)throw new RangeError("'client_timeout_buffer_ms' must be greater than zero.");if(e.query_timeout_ms<=0)throw new RangeError("'query_timeout_ms' must be greater than zero.");if(e.max_backoff<=0)throw new RangeError("'max_backoff' must be greater than zero.");if(e.max_attempts<=0)throw new RangeError("'max_attempts' must be greater than zero.")},d(Pe,ve,wt());var Oe=class{closed=!1;#e;#t=0;#r;#o;#n;#s;constructor(e,r){e instanceof v?this.#r=()=>Promise.resolve(e):this.#r=e,this.#e=r,this.#i()}start(e,r){if(typeof e!="function")throw new TypeError(`Expected a function as the 'onEvent' argument, but received ${typeof e}. Please provide a valid function.`);if(r&&typeof r!="function")throw new TypeError(`Expected a function as the 'onError' argument, but received ${typeof r}. Please provide a valid function.`);(async()=>{try{for await(let n of this)e(n)}catch(n){r&&r(n)}})()}async*[Symbol.asyncIterator](){if(this.closed)throw new T("The stream has been closed and cannot be reused.");for(this.#s||(this.#s=await this.#r().then(e=>{if(!(e instanceof v))throw new T(`Error requesting a stream token. Expected a StreamToken as the query result, but received ${typeof e}. Your query must return the result of '<Set>.toStream' or '<Set>.changesOn') | ||
Query result: ${JSON.stringify(e,null)}`);return e})),this.#t=1;!this.closed;){let e=Math.min(Math.random()*2**this.#t,this.#e.max_backoff)*1e3;try{for await(let r of this.#a(this.#o))yield r}catch(r){if(r instanceof C||this.#t>=this.#e.max_attempts)throw this.close(),r;this.#t+=1,await Pt(e)}}}close(){this.#n&&(this.#n.close(),this.#n=void 0),this.closed=!0}get last_ts(){return this.#o}async*#a(e){let r=this.#s,o={Authorization:`Bearer ${this.#e.secret}`},n=this.#e.httpStreamClient.stream({data:{token:r.token,start_ts:e},headers:o,method:"POST"});this.#n=n;for await(let s of n.read){let a=V.decode(s,{long_type:this.#e.long_type});if(a.type==="error")throw this.close(),Y(a);this.#o=a.txn_ts,a.type==="start"&&(a.type="status"),!(!this.#e.status_events&&a.type==="status")&&(yield a)}}#i(){let e=this.#e;if(["long_type","httpStreamClient","max_backoff","max_attempts","secret"].forEach(o=>{if(e[o]===void 0)throw new TypeError(`ClientConfiguration option '${o}' must be defined.`)}),e.max_backoff<=0)throw new RangeError("'max_backoff' must be greater than zero.");if(e.max_attempts<=0)throw new RangeError("'max_attempts' must be greater than zero.")}};function Pt(t){return new Promise(e=>setTimeout(e,t))}export{xe as AbortError,ne as AuthenticationError,oe as AuthorizationError,Pe as Client,F as ClientClosedError,T as ClientError,Se as ConstraintFailureError,we as ContendedTransactionError,P as DateStub,ue as Document,N as DocumentReference,D as EmbeddedSet,C as FaunaError,le as FetchClient,X as InvalidRequestError,Tt as LONG_MAX,ht as LONG_MIN,H as Module,de as NamedDocument,$ as NamedDocumentReference,S as NetworkError,Z as NodeHTTP2Client,ee as NullDocument,O as Page,I as ProtocolError,L as QueryCheckError,re as QueryRuntimeError,se as QueryTimeoutError,y as ServiceError,ae as ServiceInternalError,q as SetIterator,Oe as StreamClient,v as StreamToken,V as TaggedTypeFormat,U as ThrottlingError,R as TimeStub,We as endpoints,Ye as fql,Ue as getDefaultHTTPClient,Be as isHTTPResponse,$e as isStreamClient}; | ||
var er=Object.create;var Et=Object.defineProperty;var tr=Object.getOwnPropertyDescriptor;var rr=Object.getOwnPropertyNames;var nr=Object.getPrototypeOf,sr=Object.prototype.hasOwnProperty;var nt=(t=>typeof require<"u"?require:typeof Proxy<"u"?new Proxy(t,{get:(e,r)=>(typeof require<"u"?require:e)[r]}):t)(function(t){if(typeof require<"u")return require.apply(this,arguments);throw new Error('Dynamic require of "'+t+'" is not supported')});var or=(t,e)=>()=>(e||t((e={exports:{}}).exports,e),e.exports);var ar=(t,e,r,s)=>{if(e&&typeof e=="object"||typeof e=="function")for(let n of rr(e))!sr.call(t,n)&&n!==r&&Et(t,n,{get:()=>e[n],enumerable:!(s=tr(e,n))||s.enumerable});return t};var ir=(t,e,r)=>(r=t!=null?er(nr(t)):{},ar(e||!t||!t.__esModule?Et(r,"default",{value:t,enumerable:!0}):r,t));var st=(t,e,r)=>{if(!e.has(t))throw TypeError("Cannot "+r)};var a=(t,e,r)=>(st(t,e,"read from private field"),r?r.call(t):e.get(t)),u=(t,e,r)=>{if(e.has(t))throw TypeError("Cannot add the same private member more than once");e instanceof WeakSet?e.add(t):e.set(t,r)},f=(t,e,r,s)=>(st(t,e,"write to private field"),s?s.call(t,r):e.set(t,r),r),ot=(t,e,r,s)=>({set _(n){f(t,e,n,r)},get _(){return a(t,e,s)}}),l=(t,e,r)=>(st(t,e,"access private method"),r);var Qt=or(Ve=>{"use strict";Ve.byteLength=lr;Ve.toByteArray=pr;Ve.fromByteArray=hr;var I=[],C=[],mr=typeof Uint8Array<"u"?Uint8Array:Array,mt="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";for(te=0,Pt=mt.length;te<Pt;++te)I[te]=mt[te],C[mt.charCodeAt(te)]=te;var te,Pt;C["-".charCodeAt(0)]=62;C["_".charCodeAt(0)]=63;function Rt(t){var e=t.length;if(e%4>0)throw new Error("Invalid string. Length must be a multiple of 4");var r=t.indexOf("=");r===-1&&(r=e);var s=r===e?0:4-r%4;return[r,s]}function lr(t){var e=Rt(t),r=e[0],s=e[1];return(r+s)*3/4-s}function fr(t,e,r){return(e+r)*3/4-r}function pr(t){var e,r=Rt(t),s=r[0],n=r[1],o=new mr(fr(t,s,n)),i=0,d=n>0?s-4:s,c;for(c=0;c<d;c+=4)e=C[t.charCodeAt(c)]<<18|C[t.charCodeAt(c+1)]<<12|C[t.charCodeAt(c+2)]<<6|C[t.charCodeAt(c+3)],o[i++]=e>>16&255,o[i++]=e>>8&255,o[i++]=e&255;return n===2&&(e=C[t.charCodeAt(c)]<<2|C[t.charCodeAt(c+1)]>>4,o[i++]=e&255),n===1&&(e=C[t.charCodeAt(c)]<<10|C[t.charCodeAt(c+1)]<<4|C[t.charCodeAt(c+2)]>>2,o[i++]=e>>8&255,o[i++]=e&255),o}function yr(t){return I[t>>18&63]+I[t>>12&63]+I[t>>6&63]+I[t&63]}function gr(t,e,r){for(var s,n=[],o=e;o<r;o+=3)s=(t[o]<<16&16711680)+(t[o+1]<<8&65280)+(t[o+2]&255),n.push(yr(s));return n.join("")}function hr(t){for(var e,r=t.length,s=r%3,n=[],o=16383,i=0,d=r-s;i<d;i+=o)n.push(gr(t,i,i+o>d?d:i+o));return s===1?(e=t[r-1],n.push(I[e>>2]+I[e<<4&63]+"==")):s===2&&(e=(t[r-2]<<8)+t[r-1],n.push(I[e>>10]+I[e>>4&63]+I[e<<2&63]+"=")),n.join("")}});var at={default:new URL("https://db.fauna.com"),local:new URL("http://localhost:8443"),localhost:new URL("http://localhost:8443")};var Q=class extends Error{constructor(...e){super(...e)}},h=class extends Q{httpStatus;code;queryInfo;constraint_failures;constructor(e,r){super(e.error.message),Error.captureStackTrace&&Error.captureStackTrace(this,h),this.name="ServiceError",this.code=e.error.code,this.httpStatus=r;let s={txn_ts:e.txn_ts,summary:e.summary,query_tags:e.query_tags,stats:e.stats};this.queryInfo=s,this.constraint_failures=e.error.constraint_failures}},ae=class extends h{constructor(e,r){super(e,r),Error.captureStackTrace&&Error.captureStackTrace(this,ae),this.name="QueryRuntimeError"}},G=class extends h{constructor(e,r){super(e,r),Error.captureStackTrace&&Error.captureStackTrace(this,G),this.name="QueryCheckError"}},Z=class extends h{constructor(e,r){super(e,r),Error.captureStackTrace&&Error.captureStackTrace(this,Z),this.name="InvalidRequestError"}},ve=class extends h{constraint_failures;constructor(e,r){super(e,r),Error.captureStackTrace&&Error.captureStackTrace(this,G),this.name="ConstraintFailureError",this.constraint_failures=e.error.constraint_failures}},Fe=class extends h{abort;constructor(e,r){super(e,r),Error.captureStackTrace&&Error.captureStackTrace(this,G),this.name="AbortError",this.abort=e.error.abort}},ie=class extends h{constructor(e,r){super(e,r),Error.captureStackTrace&&Error.captureStackTrace(this,ie),this.name="AuthenticationError"}},ue=class extends h{constructor(e,r){super(e,r),Error.captureStackTrace&&Error.captureStackTrace(this,ue),this.name="AuthorizationError"}},Oe=class extends h{constructor(e,r){super(e,r),Error.captureStackTrace&&Error.captureStackTrace(this,Z),this.name="ContendedTransactionError"}},V=class extends h{constructor(e,r){super(e,r),Error.captureStackTrace&&Error.captureStackTrace(this,V),this.name="ThrottlingError"}},ce=class extends h{stats;constructor(e,r){super(e,r),Error.captureStackTrace&&Error.captureStackTrace(this,ce),this.name="QueryTimeoutError",this.stats=e.stats}},de=class extends h{constructor(e,r){super(e,r),Error.captureStackTrace&&Error.captureStackTrace(this,de),this.name="ServiceInternalError"}},y=class extends Q{constructor(e,r){super(e,r),Error.captureStackTrace&&Error.captureStackTrace(this,y),this.name="ClientError"}},v=class extends Q{constructor(e,r){super(e,r),Error.captureStackTrace&&Error.captureStackTrace(this,v),this.name="ClientClosedError"}},w=class extends Q{constructor(e,r){super(e,r),Error.captureStackTrace&&Error.captureStackTrace(this,w),this.name="NetworkError"}},F=class extends Q{httpStatus;constructor(e){super(e.message),Error.captureStackTrace&&Error.captureStackTrace(this,F),this.name="ProtocolError",this.httpStatus=e.httpStatus}},O=(t,e)=>{switch(t.error.code){case"invalid_query":return new G(t,e);case"invalid_request":return new Z(t,e);case"abort":if(t.error.abort!==void 0)return new Fe(t,e);break;case"constraint_failure":if(t.error.constraint_failures!==void 0)return new ve(t,e);break;case"unauthorized":return new ie(t,e);case"forbidden":return new ue(t,e);case"contended_transaction":return new Oe(t,e);case"limit_exceeded":return new V(t,e);case"time_out":return new ce(t,e);case"internal_error":return new de(t,e)}return new ae(t,e)};var j={QUERY:"/query/1",STREAM:"/stream/1",EVENT_FEED:"/feed/1"};var be=class{#e;#t=j.QUERY;#r=j.STREAM;#n;constructor({url:e,fetch_keepalive:r}){this.#e=e,this.#n=r}#s(e){return new URL(e,this.#e).toString()}async request({data:e,headers:r,method:s,client_timeout_ms:n,path:o=this.#t}){let i=AbortSignal.timeout===void 0?(()=>{let g=new AbortController,x=g.signal;return setTimeout(()=>g.abort(),n),x})():AbortSignal.timeout(n),d=await fetch(this.#s(o),{method:s,headers:{...r,"Content-Type":"application/json"},body:JSON.stringify(e),signal:i,keepalive:this.#n}).catch(g=>{throw new w("The network connection encountered a problem.",{cause:g})}),c=d.status,m={};d.headers.forEach((g,x)=>m[x]=g);let p=await d.text();return{status:c,body:p,headers:m}}stream({data:e,headers:r,method:s,path:n=this.#r}){let o=new Request(this.#s(n),{method:s,headers:{...r,"Content-Type":"application/json"},body:JSON.stringify(e),keepalive:this.#n}),i=new AbortController,d={signal:i.signal};async function*c(){let m=await fetch(o,d).catch(T=>{throw new w("The network connection encountered a problem.",{cause:T})}),p=m.status;if(!(p>=200&&p<400)){let T=await m.json();throw O(T,p)}let g=m.body;if(!g)throw new Error("Response body is undefined.");let x=g.getReader();try{for await(let T of ur(x))yield T}catch(T){throw new w("The network connection encountered a problem while streaming events.",{cause:T})}}return{read:c(),close:()=>{i.abort("Stream closed by the client.")}}}close(){}};async function*ur(t){let e=new TextDecoder,r="";for await(let s of cr(t)){let n=e.decode(s),o=(r+n).split(` | ||
`);for(let i=0;i<o.length-1;i++)yield o[i].trim();r=o[o.length-1]}r.trim()!==""&&(yield r)}async function*cr(t){let e=!1;do{let r=await t.read();r.value!==void 0&&(yield r.value),e=r.done}while(!e)}var k;try{k=nt("node:http2")}catch{k=void 0}var me,Se,xe,we,z,E,Ie,qe,Ne,_t,le,ke,Ee,it,De,Ct,He,At,K=class{constructor({http2_session_idle_ms:e,url:r,http2_max_streams:s}){u(this,le);u(this,Ee);u(this,De);u(this,He);u(this,Se,void 0);u(this,xe,void 0);u(this,we,void 0);u(this,z,0);u(this,E,void 0);u(this,Ie,j.QUERY);u(this,qe,j.STREAM);if(k===void 0)throw new Error("Your platform does not support Node's http2 library");f(this,Se,e),f(this,xe,s),f(this,we,r),f(this,E,null)}static getClient(e){var n;let r=l(n=K,Ne,_t).call(n,e);a(K,me).has(r)||a(K,me).set(r,new K(e));let s=a(K,me).get(r);return ot(s,z)._++,s}async request(e){let r=0,s;do try{return await l(this,De,Ct).call(this,e)}catch(n){if(n?.code!=="ERR_HTTP2_GOAWAY_SESSION")throw new w("The network connection encountered a problem.",{cause:n});s=n,r++}while(r<3);throw new w("The network connection encountered a problem.",{cause:s})}stream(e){return l(this,He,At).call(this,e)}close(){this.isClosed()||(ot(this,z)._--,a(this,z)===0&&a(this,E)&&!a(this,E).closed&&a(this,E).close())}isClosed(){return a(this,z)===0}},ee=K;me=new WeakMap,Se=new WeakMap,xe=new WeakMap,we=new WeakMap,z=new WeakMap,E=new WeakMap,Ie=new WeakMap,qe=new WeakMap,Ne=new WeakSet,_t=function({http2_session_idle_ms:e,url:r}){return`${r}|${e}`},le=new WeakSet,ke=function(){f(this,z,0),a(this,E)&&!a(this,E).closed&&a(this,E).close()},Ee=new WeakSet,it=function(){if(!a(this,E)||a(this,E).closed||a(this,E).destroyed){let e=k.connect(a(this,we),{peerMaxConcurrentStreams:a(this,xe)}).once("error",()=>l(this,le,ke).call(this)).once("goaway",()=>l(this,le,ke).call(this));e.setTimeout(a(this,Se),()=>{l(this,le,ke).call(this)}),f(this,E,e)}return a(this,E)},De=new WeakSet,Ct=function({client_timeout_ms:e,data:r,headers:s,method:n,path:o=a(this,Ie)}){return new Promise((i,d)=>{let c,m=p=>{let g=Number(p[k.constants.HTTP2_HEADER_STATUS]),x="";c.on("data",T=>{x+=T}),c.on("end",()=>{i({status:g,body:x,headers:p})})};try{let p={...s,[k.constants.HTTP2_HEADER_PATH]:o,[k.constants.HTTP2_HEADER_METHOD]:n};c=l(this,Ee,it).call(this).request(p).setEncoding("utf8").on("error",x=>{d(x)}).on("response",m),c.write(JSON.stringify(r),"utf8"),c.setTimeout(e,()=>{c.destroy(new Error("Client timeout"))}),c.end()}catch(p){d(p)}})},He=new WeakSet,At=function({data:e,headers:r,method:s,path:n=a(this,qe)}){let o,i,d=()=>new Promise((T,oe)=>{o=T,i=oe}),c=d(),m,p=T=>{let oe=Number(T[k.constants.HTTP2_HEADER_STATUS]);if(oe>=200&&oe<400){let $="";m.on("data",R=>{let X=($+R).split(` | ||
`);o(X.map(rt=>rt.trim()).slice(0,-1)),c=d(),$=X[X.length-1]}),m.on("end",()=>{o([$])})}else{let $="";m.on("data",R=>{$+=R}),m.on("end",()=>{try{let R=JSON.parse($);i(O(R,oe))}catch(R){i(new w("Could not process query failure.",{cause:R}))}})}},g=this;async function*x(){var R;let T={...r,[k.constants.HTTP2_HEADER_PATH]:n,[k.constants.HTTP2_HEADER_METHOD]:s};m=l(R=g,Ee,it).call(R).request(T).setEncoding("utf8").on("error",X=>{i(X)}).on("response",p);let $=JSON.stringify(e);for(m.write($,"utf8"),m.end();;){let X=await c;for(let rt of X)yield rt}}return{read:x(),close:()=>{m&&m.close()}}},u(ee,Ne),u(ee,me,new Map);var ut=t=>dr()?ee.getClient(t):new be(t),ct=t=>t instanceof Object&&"body"in t&&"headers"in t&&"status"in t,dt=t=>"stream"in t&&typeof t.stream=="function",dr=()=>{if(typeof process<"u"&&process&&process.release?.name==="node")try{return nt("node:http2"),!0}catch{return!1}return!1};var pt=ir(Qt());var Tr=/(?:\d{4}|[\u2212-]\d{4,}|\+\d{5,})/,br=/(?:0[1-9]|1[0-2])/,Sr=/(?:0[1-9]|[12]\d|3[01])/,vt=/(?:[01][0-9]|2[0-3])/,_e=/(?:[0-5][0-9])/,xr=/(?:\.\d+)/,lt=new RegExp(`(${Tr.source}-(${br.source})-(${Sr.source}))`),wr=new RegExp(`(${vt.source}:${_e.source}:${_e.source}${xr.source}?)`),Er=new RegExp(`([zZ]|[+\u2212-]${vt.source}(?::?${_e.source}|:${_e.source}:${_e.source}))`),Ft=new RegExp(`^${lt.source}$`),Ot=new RegExp(`^${lt.source}`),kt=new RegExp(`^${lt.source}T${wr.source}${Er.source}$`);var q=class{isoString;constructor(e){this.isoString=e}static from(e){if(typeof e!="string")throw new TypeError(`Expected string but received ${typeof e}: ${e}`);if(kt.exec(e)===null)throw new RangeError(`(regex) Expected an ISO date string but received '${e}'`);return new q(e)}static fromDate(e){return new q(e.toISOString())}toDate(){let e=new Date(this.isoString);if(e.toString()==="Invalid Date")throw new RangeError("Fauna Date could not be converted to Javascript Date");return e}toString(){return`TimeStub("${this.isoString}")`}},N=class{dateString;constructor(e){this.dateString=e}static from(e){if(typeof e!="string")throw new TypeError(`Expected string but received ${typeof e}: ${e}`);let r=Ft.exec(e);if(r===null)throw new RangeError(`Expected a plain date string but received '${e}'`);return new N(r[0])}static fromDate(e){let r=e.toISOString(),s=Ot.exec(r);if(s===null)throw new y(`Failed to parse date '${e}'`);return new N(s[0])}toDate(){let e=new Date(this.dateString+"T00:00:00Z");if(e.toString()==="Invalid Date")throw new RangeError("Fauna Date could not be converted to Javascript Date");return e}toString(){return`DateStub("${this.dateString}")`}};var M=class{coll;id;constructor({coll:e,id:r}){this.id=r,typeof e=="string"?this.coll=new W(e):this.coll=e}},fe=class extends M{ts;ttl;constructor(e){let{coll:r,id:s,ts:n,...o}=e;super({coll:r,id:s}),this.ts=n,Object.assign(this,o)}toObject(){return{...this}}},Y=class{coll;name;constructor({coll:e,name:r}){this.name=r,typeof e=="string"?this.coll=new W(e):this.coll=e}},pe=class extends Y{ts;data;constructor(e){let{coll:r,name:s,ts:n,data:o,...i}=e;super({coll:r,name:s}),this.ts=n,this.data=o||{},Object.assign(this,i)}toObject(){return{...this}}},W=class{name;constructor(e){this.name=e}},re=class{ref;cause;constructor(e,r){this.ref=e,this.cause=r}};var D=class{data;after;constructor({data:e,after:r}){this.data=e,this.after=r}},L=class{after;constructor(e){this.after=e}},U=class{#e;constructor(e,r,s){if(s=s??{},r instanceof Function)this.#e=Cr(e,r,s);else if(r instanceof D||r instanceof L)this.#e=It(e,r,s);else throw new TypeError(`Expected 'Page<T> | EmbeddedSet | (() => Promise<T | Page<T> | EmbeddedSet>)', but received ${JSON.stringify(r)}`)}static fromQuery(e,r,s){return new U(e,async()=>(await e.query(r,s)).data,s)}static fromPageable(e,r,s){return new U(e,r,s)}flatten(){return new je(this)}async next(){return this.#e.next()}async return(){return this.#e.return()}async throw(e){return this.#e.throw(e)}[Symbol.asyncIterator](){return this}},je=class{#e;constructor(e){this.#e=Ar(e)}async next(){return this.#e.next()}async return(){return this.#e.return()}async throw(e){return this.#e.throw(e)}[Symbol.asyncIterator](){return this}};async function*It(t,e,r){let s=e;for(s instanceof D&&(yield s.data);s.after;){let n=ft`Set.paginate(${s.after})`;s=(await t.query(n,r)).data,yield s.data}}async function*Cr(t,e,r){let s=await e();if(s instanceof D||s instanceof L){for await(let n of It(t,s,r))yield n;return}yield[s]}async function*Ar(t){for await(let e of t)for(let r of e)yield r}function Ae(t){return typeof t.token=="string"}var ne=class{token;constructor(e){this.token=e}},Ce=class{events;cursor;hasNext;stats;constructor({events:e,cursor:r,has_next:s,stats:n}){this.events=this.#e(e),this.cursor=r,this.hasNext=s,this.stats=n}*#e(e){for(let r of e){if(r.type==="error")throw O(r);yield r}}};var H=class{static encode(e){return ye(e)}static encodeInterpolation(e){return Me(e)}static decode(e,r){return JSON.parse(e,(s,n)=>{if(n==null)return null;if(n["@mod"])return new W(n["@mod"]);if(n["@doc"]){if(typeof n["@doc"]=="string"){let[i,d]=n["@doc"].split(":");return new M({coll:i,id:d})}let o=n["@doc"];return o.id?new fe(o):new pe(o)}else if(n["@ref"]){let o=n["@ref"],i;return o.id?i=new M(o):i=new Y(o),"exists"in o&&o.exists===!1?new re(i,o.cause):i}else{if(n["@set"])return typeof n["@set"]=="string"?new L(n["@set"]):new D(n["@set"]);if(n["@int"])return Number(n["@int"]);if(n["@long"]){let o=BigInt(n["@long"]);return r.long_type==="number"?((o>Number.MAX_SAFE_INTEGER||o<Number.MIN_SAFE_INTEGER)&&console.warn("Value is too large to be represented as a number. Returning as Number with loss of precision. Use long_type 'bigint' instead."),Number(o)):o}else{if(n["@double"])return Number(n["@double"]);if(n["@date"])return N.from(n["@date"]);if(n["@time"])return q.from(n["@time"]);if(n["@object"])return n["@object"];if(n["@stream"])return new ne(n["@stream"]);if(n["@bytes"])return vr(n["@bytes"])}}return n})}},Ht=BigInt("-9223372036854775808"),Vt=BigInt("9223372036854775807"),qt=-(2**31),Nt=2**31-1,b={bigint:t=>{if(t<Ht||t>Vt)throw new RangeError("BigInt value exceeds max magnitude for a 64-bit Fauna long. Use a 'number' to represent doubles beyond that limit.");return t>=qt&&t<=Nt?{"@int":t.toString()}:{"@long":t.toString()}},number:t=>{if(t===Number.POSITIVE_INFINITY||t===Number.NEGATIVE_INFINITY)throw new RangeError(`Cannot convert ${t} to a Fauna type.`);return Number.isInteger(t)?t>=qt&&t<=Nt?{"@int":t.toString()}:Number.isSafeInteger(t)?{"@long":t.toString()}:{"@double":t.toString()}:{"@double":t.toString()}},string:t=>t,object:t=>{let e=!1,r={};for(let s in t)s.startsWith("@")&&(e=!0),t[s]!==void 0&&(r[s]=ye(t[s]));return e?{"@object":r}:r},array:t=>t.map(ye),date:t=>({"@time":t.toISOString()}),faunadate:t=>({"@date":t.dateString}),faunatime:t=>({"@time":t.isoString}),module:t=>({"@mod":t.name}),documentReference:t=>({"@ref":{id:t.id,coll:{"@mod":t.coll.name}}}),document:t=>({"@ref":{id:t.id,coll:{"@mod":t.coll.name}}}),namedDocumentReference:t=>({"@ref":{name:t.name,coll:{"@mod":t.coll.name}}}),namedDocument:t=>({"@ref":{name:t.name,coll:{"@mod":t.coll.name}}}),set:t=>{throw new y("Page could not be encoded. Fauna does not accept encoded Set values, yet. Use Page.data and Page.after as arguments, instead.")},streamToken:t=>t.token,bytes:t=>({"@bytes":Fr(t)})},ye=t=>{switch(typeof t){case"bigint":return b.bigint(t);case"string":return b.string(t);case"number":return b.number(t);case"boolean":return t;case"object":if(t==null)return null;if(Array.isArray(t))return b.array(t);if(t instanceof Date)return b.date(t);if(t instanceof N)return b.faunadate(t);if(t instanceof q)return b.faunatime(t);if(t instanceof W)return b.module(t);if(t instanceof fe)return b.document(t);if(t instanceof M)return b.documentReference(t);if(t instanceof pe)return b.namedDocument(t);if(t instanceof Y)return b.namedDocumentReference(t);if(t instanceof re)return ye(t.ref);if(t instanceof D)return b.set(t);if(t instanceof L)return b.set(t);if(t instanceof ne)return b.streamToken(t);if(t instanceof Uint8Array||t instanceof ArrayBuffer)return b.bytes(t);if(ArrayBuffer.isView(t))throw new y("Error encoding TypedArray to Fauna Bytes. Convert your TypedArray to Uint8Array or ArrayBuffer before passing it to Fauna. See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray");if(t instanceof P)throw new TypeError("Cannot encode instance of type 'Query'. Try using TaggedTypeFormat.encodeInterpolation instead.");return b.object(t);default:throw new TypeError(`Passing ${typeof t} as a QueryArgument is not supported`)}},Me=t=>{switch(typeof t){case"bigint":case"string":case"number":case"boolean":return Dt(ye(t));case"object":return t==null||t instanceof Date||t instanceof N||t instanceof q||t instanceof W||t instanceof M||t instanceof Y||t instanceof D||t instanceof L||t instanceof ne||t instanceof Uint8Array||t instanceof ArrayBuffer||ArrayBuffer.isView(t)?Dt(ye(t)):t instanceof re?Me(t.ref):t instanceof P?Qr(t):Array.isArray(t)?Rr(t):Pr(t);default:throw new TypeError(`Passing ${typeof t} as a QueryArgument is not supported`)}},Pr=t=>{let e={};for(let r in t)t[r]!==void 0&&(e[r]=Me(t[r]));return{object:e}},Rr=t=>({array:t.map(Me)}),Qr=t=>t.encode(),Dt=t=>({value:t});function vr(t){return pt.default.toByteArray(t)}function Fr(t){let e=t instanceof Uint8Array?t:new Uint8Array(t);return pt.default.fromByteArray(e)}function ft(t,...e){return new P(t,...e)}var P=class{#e;#t;#r;constructor(e,...r){if(e.length===0||e.length!==r.length+1)throw new Error("invalid query constructed");this.#e=e,this.#t=r,this.#r=void 0}encode(){if(this.#e.length===1)return{fql:[this.#e[0]]};let e=this.#e.flatMap((r,s)=>{if(s===this.#e.length-1)return r===""?[]:[r];let n=this.#t[s],o=H.encodeInterpolation(n);return[r,o]});return e=e.filter(r=>r!==""),{fql:e}}};var jt="2.3.0";var We;try{We=nt("node:os")}catch{We=void 0}var yt=()=>{let t={driver:["javascript",jt].join("-"),env:"unknown",os:"unknown",runtime:"unknown"};try{let e=typeof window>"u"&&typeof process<"u"&&process.versions!=null&&process.versions.node!=null,r=typeof window<"u"&&typeof window.document<"u",s=typeof self=="object"&&self.constructor&&self.constructor.name==="DedicatedWorkerGlobalScope";e?(t.runtime=["nodejs",process.version].join("-"),t.env=kr(),t.os=[We.platform(),We.release()].join("-")):s?(t.runtime=Mt(navigator),t.env="Service Worker",t.os=Wt(navigator)):r?(t.runtime=Mt(navigator),t.env="browser",t.os=Wt(navigator)):typeof EdgeRuntime!="string"&&(t.runtime="Vercel Edge Runtime",t.env="edge")}catch{}return Object.entries(t).filter(([e,r])=>r!=="unknown").map(e=>e.join("=")).join("; ")},Mt=t=>{let e=t.appName,r=""+parseFloat(t.appVersion),s,n,o;return(n=t.userAgent.indexOf("Opera"))!=-1?(e="Opera",r=t.userAgent.substring(n+6),(n=t.userAgent.indexOf("Version"))!=-1&&(r=t.userAgent.substring(n+8))):(n=t.userAgent.indexOf("MSIE"))!=-1?(e="Microsoft Internet Explorer",r=t.userAgent.substring(n+5)):e=="Netscape"&&t.userAgent.indexOf("Trident/")!=-1?(e="Microsoft Internet Explorer",r=t.userAgent.substring(n+5),(n=t.userAgent.indexOf("rv:"))!=-1&&(r=t.userAgent.substring(n+3))):(n=t.userAgent.indexOf("Chrome"))!=-1?(e="Chrome",r=t.userAgent.substring(n+7)):(n=t.userAgent.indexOf("Safari"))!=-1?(e="Safari",r=t.userAgent.substring(n+7),(n=t.userAgent.indexOf("Version"))!=-1&&(r=t.userAgent.substring(n+8)),t.userAgent.indexOf("CriOS")!=-1&&(e="Chrome")):(n=t.userAgent.indexOf("Firefox"))!=-1?(e="Firefox",r=t.userAgent.substring(n+8)):(s=t.userAgent.lastIndexOf(" ")+1)<(n=t.userAgent.lastIndexOf("/"))&&(e=t.userAgent.substring(s,n),r=t.userAgent.substring(n+1),e.toLowerCase()==e.toUpperCase()&&(e=t.appName)),(o=r.indexOf(";"))!=-1&&(r=r.substring(0,o)),(o=r.indexOf(" "))!=-1&&(r=r.substring(0,o)),(o=r.indexOf(")"))!=-1&&(r=r.substring(0,o)),[e,r].join("-")},Wt=t=>{let e="unknown",r=[{s:"Windows 10",r:/(Windows 10.0|Windows NT 10.0)/},{s:"Windows 8.1",r:/(Windows 8.1|Windows NT 6.3)/},{s:"Windows 8",r:/(Windows 8|Windows NT 6.2)/},{s:"Windows 7",r:/(Windows 7|Windows NT 6.1)/},{s:"Windows Vista",r:/Windows NT 6.0/},{s:"Windows Server 2003",r:/Windows NT 5.2/},{s:"Windows XP",r:/(Windows NT 5.1|Windows XP)/},{s:"Windows 2000",r:/(Windows NT 5.0|Windows 2000)/},{s:"Windows ME",r:/(Win 9x 4.90|Windows ME)/},{s:"Windows 98",r:/(Windows 98|Win98)/},{s:"Windows 95",r:/(Windows 95|Win95|Windows_95)/},{s:"Windows NT 4.0",r:/(Windows NT 4.0|WinNT4.0|WinNT|Windows NT)/},{s:"Windows CE",r:/Windows CE/},{s:"Windows 3.11",r:/Win16/},{s:"Android",r:/Android/},{s:"Open BSD",r:/OpenBSD/},{s:"Sun OS",r:/SunOS/},{s:"Chrome OS",r:/CrOS/},{s:"Linux",r:/(Linux|X11(?!.*CrOS))/},{s:"iOS",r:/(iPhone|iPad|iPod)/},{s:"Mac OS X",r:/Mac OS X/},{s:"Mac OS",r:/(Mac OS|MacPPC|MacIntel|Mac_PowerPC|Macintosh)/},{s:"QNX",r:/QNX/},{s:"UNIX",r:/UNIX/},{s:"BeOS",r:/BeOS/},{s:"OS/2",r:/OS\/2/},{s:"Search Bot",r:/(nuhk|Googlebot|Yammybot|Openbot|Slurp|MSNBot|Ask Jeeves\/Teoma|ia_archiver)/}];for(let n in r){let o=r[n];if(o.r.test(t.userAgent)){e=o.s;break}}let s="unknown";if(/Windows/.test(e)){let n=/Windows (.*)/.exec(e);n&&(s=n[1]),e="Windows"}switch(e){case"Mac OS":case"Mac OS X":case"Android":{let n=/(?:Android|Mac OS|Mac OS X|MacPPC|MacIntel|Mac_PowerPC|Macintosh) ([._\d]+)/.exec(t.userAgent);n&&(s=n[1]);break}case"iOS":{let n=/OS (\d+)_(\d+)_?(\d+)?/.exec(t.appVersion);n&&(s=n[1]+"."+n[2]+"."+(n[3]??0));break}}return[e,s].join("-")},Or=typeof window<"u"?window:typeof globalThis<"u"?globalThis:typeof global<"u"?global:self,kr=()=>{if(!(typeof process<"u"&&process&&process.env&&typeof process.env=="object"))return"unknown";let e=[{name:"Netlify",check:function(){return!!process.env.NETLIFY_IMAGES_CDN_DOMAIN}},{name:"Vercel",check:function(){return!!process.env.VERCEL}},{name:"Heroku",check:function(){return!!process.env.PATH&&process.env.PATH.indexOf(".heroku")!==-1}},{name:"AWS Lambda",check:function(){return!!process.env.AWS_LAMBDA_FUNCTION_VERSION}},{name:"GCP Cloud Functions",check:function(){return!!process.env._&&process.env._.indexOf("google")!==-1}},{name:"GCP Compute Instances",check:function(){return!!process.env.GOOGLE_CLOUD_PROJECT}},{name:"Azure Cloud Functions",check:function(){return!!process.env.WEBSITE_FUNCTIONS_AZUREMONITOR_CATEGORIES}},{name:"Azure Compute",check:function(){return!!process.env.ORYX_ENV_TYPE&&!!process.env.WEBSITE_INSTANCE_ID&&process.env.ORYX_ENV_TYPE==="AppService"}},{name:"Mongo Stitch",check:function(){return typeof Or?.StitchError=="function"}},{name:"Render",check:function(){return!!process.env.RENDER_SERVICE_ID}},{name:"Begin",check:function(){return!!process.env.BEGIN_DATA_SCOPE_ID}}].find(r=>r.check());return e?e.name:"unknown"};var gt=async(t,{maxAttempts:e,maxBackoff:r,shouldRetry:s=()=>!0,attempt:n=0,sleepFn:o=setTimeout})=>{let i=n>0?Math.min(Math.random()*2**n,r)*1e3:0;n+=1;try{return await t()}catch(d){if(n>=e||s(d)!==!0)throw d;return await new Promise(c=>o(c,i)),gt(t,{maxAttempts:e,maxBackoff:r,shouldRetry:s,attempt:n,sleepFn:o})}};var Lt=t=>t instanceof Object&&"data"in t,ht=t=>t instanceof Object&&"error"in t&&t.error instanceof Object&&"code"in t.error&&"message"in t.error;var Tt={client_timeout_buffer_ms:5e3,format:"tagged",http2_session_idle_ms:5e3,http2_max_streams:100,long_type:"number",fetch_keepalive:!1,query_timeout_ms:5e3,max_attempts:3,max_backoff:20},Be,_,B,A,J,Re,bt,Qe,St,$e,Ut,Ge,Bt,ze,$t,Ye,Gt,Je,zt,xt=class{constructor(e,r){u(this,Re);u(this,Qe);u(this,$e);u(this,Ge);u(this,ze);u(this,Ye);u(this,Je);u(this,_,void 0);u(this,B,void 0);u(this,A,void 0);u(this,J,!1);f(this,_,{...Tt,...e,secret:l(this,$e,Ut).call(this,e),endpoint:l(this,Ge,Bt).call(this,e)}),l(this,Je,zt).call(this),r?f(this,B,r):f(this,B,ut({url:a(this,_).endpoint.toString(),http2_session_idle_ms:a(this,_).http2_session_idle_ms,http2_max_streams:a(this,_).http2_max_streams,fetch_keepalive:a(this,_).fetch_keepalive}))}get lastTxnTs(){return a(this,A)}set lastTxnTs(e){e!==void 0&&f(this,A,a(this,A)?Math.max(e,a(this,A)):e)}get clientConfiguration(){let{...e}=a(this,_);return e}close(){if(a(this,J))throw new v("Your client is closed. You cannot close it again.");a(this,B).close(),f(this,J,!0)}paginate(e,r){return e instanceof P?U.fromQuery(this,e,r):U.fromPageable(this,e,r)}async query(e,r){if(a(this,J))throw new v("Your client is closed. No further requests can be issued.");let s={query:e.encode()};return r?.arguments&&(s.arguments=H.encode(r.arguments)),l(this,Re,bt).call(this,s,r)}stream(e,r){if(a(this,J))throw new v("Your client is closed. No further requests can be issued.");let s=a(this,B);if(dt(s)){let n={...a(this,_),httpStreamClient:s,...r};if(n.cursor!==void 0&&e instanceof P)throw new y("The `cursor` configuration can only be used with a stream token.");let o=e instanceof P?()=>this.query(e).then(i=>i.data):e;return new Ue(o,n)}else throw new y("Streaming is not supported by this client.")}feed(e,r){if(a(this,J))throw new v("Your client is closed. No further requests can be issued.");let s={...a(this,_),httpClient:a(this,B),...r},n=e instanceof P?()=>this.query(e).then(o=>o.data):e;return new Pe(n,s)}},Le=xt;Be=new WeakMap,_=new WeakMap,B=new WeakMap,A=new WeakMap,J=new WeakMap,Re=new WeakSet,bt=async function(e,r,s=0){let n=this.clientConfiguration.max_backoff??Tt.max_backoff,o=this.clientConfiguration.max_attempts??Tt.max_attempts,i=Math.min(Math.random()*2**s,n)*1e3;s+=1;try{return await l(this,ze,$t).call(this,e,r,s)}catch(d){if(d instanceof V&&s<o)return await Kt(i),l(this,Re,bt).call(this,e,r,s);throw d}},Qe=new WeakSet,St=function(e){if(e instanceof y||e instanceof w||e instanceof F||e instanceof h)return e;if(ct(e)){if(ht(e.body)){let r=e.body,s=e.status;return O(r,s)}return new F({message:`Response is in an unkown format: ${e.body}`,httpStatus:e.status})}return new y("A client level error occurred. Fauna was not called.",{cause:e})},$e=new WeakSet,Ut=function(e){let r;typeof process<"u"&&process&&typeof process=="object"&&process.env&&typeof process.env=="object"&&(r=process.env.FAUNA_SECRET);let s=e?.secret??r;if(s===void 0)throw new TypeError("You must provide a secret to the driver. Set it in an environmental variable named FAUNA_SECRET or pass it to the Client constructor.");return s},Ge=new WeakSet,Bt=function(e){if(e&&"endpoint"in e&&e.endpoint===void 0)throw new TypeError("ClientConfiguration option endpoint must be defined.");let r;return typeof process<"u"&&process&&typeof process=="object"&&process.env&&typeof process.env=="object"&&(r=process.env.FAUNA_ENDPOINT?new URL(process.env.FAUNA_ENDPOINT):void 0),e?.endpoint??r??at.default},ze=new WeakSet,$t=async function(e,r,s=0){try{let n={...a(this,_),...r},o={Authorization:`Bearer ${n.secret}`};l(this,Ye,Gt).call(this,n,o);let i=n.format==="tagged",d=n.query_timeout_ms+a(this,_).client_timeout_buffer_ms,c=await a(this,B).request({client_timeout_ms:d,data:e,headers:o,method:"POST"}),m;try{if(m={...c,body:i?H.decode(c.body,{long_type:n.long_type}):JSON.parse(c.body)},m.body.query_tags){let x=m.body.query_tags.split(",").map(T=>T.split("="));m.body.query_tags=Object.fromEntries(x)}}catch(x){throw new F({message:`Error parsing response as JSON: ${x}`,httpStatus:c.status})}if(!Lt(m.body))throw l(this,Qe,St).call(this,m);let p=m.body.txn_ts;(a(this,A)===void 0&&p!==void 0||p!==void 0&&a(this,A)!==void 0&&a(this,A)<p)&&f(this,A,p);let g=m.body;return g.stats&&(g.stats.attempts=s),g}catch(n){throw l(this,Qe,St).call(this,n)}},Ye=new WeakSet,Gt=function(e,r){let s=(n,o,i=d=>String(d))=>{o!==void 0&&(r[n]=i(o))};s("x-format",e.format),s("x-typecheck",e.typecheck),s("x-query-timeout-ms",e.query_timeout_ms),s("x-linearized",e.linearized),s("x-max-contention-retries",e.max_contention_retries),s("traceparent",e.traceparent),s("x-query-tags",e.query_tags,n=>Object.entries(n).map(o=>o.join("=")).join(",")),s("x-last-txn-ts",a(this,A),n=>n),s("x-driver-env",a(xt,Be))},Je=new WeakSet,zt=function(){let e=a(this,_);if(["client_timeout_buffer_ms","endpoint","format","http2_session_idle_ms","long_type","query_timeout_ms","fetch_keepalive","http2_max_streams","max_backoff","max_attempts"].forEach(s=>{if(e[s]===void 0)throw new TypeError(`ClientConfiguration option '${s}' must be defined.`)}),e.http2_max_streams<=0)throw new RangeError("'http2_max_streams' must be greater than zero.");if(e.client_timeout_buffer_ms<=0)throw new RangeError("'client_timeout_buffer_ms' must be greater than zero.");if(e.query_timeout_ms<=0)throw new RangeError("'query_timeout_ms' must be greater than zero.");if(e.max_backoff<=0)throw new RangeError("'max_backoff' must be greater than zero.");if(e.max_attempts<=0)throw new RangeError("'max_attempts' must be greater than zero.")},u(Le,Be,yt());var Ue=class{closed=!1;#e;#t=0;#r;#n;#s;#o;#a;constructor(e,r){Ae(e)?this.#r=()=>Promise.resolve(e):this.#r=e,this.#e=r,this.#u()}start(e,r){if(typeof e!="function")throw new TypeError(`Expected a function as the 'onEvent' argument, but received ${typeof e}. Please provide a valid function.`);if(r&&typeof r!="function")throw new TypeError(`Expected a function as the 'onError' argument, but received ${typeof r}. Please provide a valid function.`);(async()=>{try{for await(let n of this)e(n)}catch(n){r&&r(n)}})()}async*[Symbol.asyncIterator](){if(this.closed)throw new y("The stream has been closed and cannot be reused.");for(this.#a||(this.#a=await this.#r().then(e=>{if(!Ae(e))throw new y(`Error requesting a stream token. Expected a EventSource as the query result, but received ${typeof e}. Your query must return the result of '<Set>.eventSource' or '<Set>.eventsOn') | ||
Query result: ${JSON.stringify(e,null)}`);return e})),this.#t=1;!this.closed;){let e=Math.min(Math.random()*2**this.#t,this.#e.max_backoff)*1e3;try{for await(let r of this.#i())yield r}catch(r){if(r instanceof Q||this.#t>=this.#e.max_attempts)throw this.close(),r;this.#t+=1,await Kt(e)}}}close(){this.#o&&(this.#o.close(),this.#o=void 0),this.closed=!0}get last_ts(){return this.#n}async*#i(){let e=this.#a,r={Authorization:`Bearer ${this.#e.secret}`},s=this.#e.httpStreamClient.stream({data:{token:e.token,cursor:this.#s||this.#e.cursor},headers:r,method:"POST"});this.#o=s;for await(let n of s.read){let o=H.decode(n,{long_type:this.#e.long_type});if(o.type==="error")throw this.close(),O(o);this.#n=o.txn_ts,this.#s=o.cursor,o.type==="start"&&(o.type="status"),!(!this.#e.status_events&&o.type==="status")&&(yield o)}}#u(){let e=this.#e;if(["long_type","httpStreamClient","max_backoff","max_attempts","secret"].forEach(s=>{if(e[s]===void 0)throw new TypeError(`ClientConfiguration option '${s}' must be defined.`)}),e.max_backoff<=0)throw new RangeError("'max_backoff' must be greater than zero.");if(e.max_attempts<=0)throw new RangeError("'max_attempts' must be greater than zero.")}},Xe,ge,S,se,he,Te,Ze,Yt,Ke,Jt,et,Xt,tt,Zt,wt=class{constructor(e,r){u(this,Ze);u(this,Ke);u(this,et);u(this,tt);u(this,ge,void 0);u(this,S,void 0);u(this,se,void 0);u(this,he,void 0);u(this,Te,void 0);Ae(e)?f(this,ge,()=>Promise.resolve(e)):f(this,ge,e),f(this,S,r),f(this,se,r.cursor),l(this,tt,Zt).call(this)}async*[Symbol.asyncIterator](){for(;!a(this,Te);)yield await this.nextPage()}async nextPage(){if(a(this,Te))throw new y("The event feed has no more pages to fetch.");let{httpClient:e}=a(this,S),r=await l(this,Ke,Jt).call(this),s=await gt(()=>e.request(r),{maxAttempts:a(this,S).max_attempts,maxBackoff:a(this,S).max_backoff,shouldRetry:i=>i instanceof V}),n;try{n=H.decode(s.body,{long_type:a(this,S).long_type})}catch(i){throw new F({message:`Error parsing response as JSON: ${i}`,httpStatus:s.status})}if(ht(n))throw O(n,s.status);let o=new Ce(n);return f(this,se,o.cursor),f(this,Te,!o.hasNext),o}async*flatten(){for await(let e of this)for(let r of e.events)yield r}},Pe=wt;Xe=new WeakMap,ge=new WeakMap,S=new WeakMap,se=new WeakMap,he=new WeakMap,Te=new WeakMap,Ze=new WeakSet,Yt=function(){return{Authorization:`Bearer ${a(this,S).secret}`,"x-format":"tagged","x-driver-env":a(wt,Xe),"x-query-timeout-ms":a(this,S).query_timeout_ms.toString()}},Ke=new WeakSet,Jt=async function(){a(this,he)||f(this,he,await l(this,et,Xt).call(this,a(this,ge)));let r={headers:l(this,Ze,Yt).call(this),client_timeout_ms:a(this,S).client_timeout_buffer_ms+a(this,S).query_timeout_ms,data:{token:a(this,he).token},method:"POST",path:j.EVENT_FEED};return a(this,S).page_size&&(r.data.page_size=a(this,S).page_size),a(this,se)?r.data.cursor=a(this,se):a(this,S).start_ts&&(r.data.start_ts=a(this,S).start_ts),r},et=new WeakSet,Xt=async function(e){return await e().then(r=>{if(!Ae(r))throw new y(`Error requesting a stream token. Expected a EventSource as the query result, but received ${typeof r}. Your query must return the result of '<Set>.eventSource' or '<Set>.eventsOn') | ||
Query result: ${JSON.stringify(r,null)}`);return r})},tt=new WeakSet,Zt=function(){let e=a(this,S);if(["long_type","httpClient","max_backoff","max_attempts","client_timeout_buffer_ms","query_timeout_ms","secret"].forEach(s=>{if(e[s]===void 0)throw new TypeError(`ClientConfiguration option '${s}' must be defined.`)}),e.max_backoff<=0)throw new RangeError("'max_backoff' must be greater than zero.");if(e.max_attempts<=0)throw new RangeError("'max_attempts' must be greater than zero.");if(e.query_timeout_ms<=0)throw new RangeError("'query_timeout_ms' must be greater than zero.");if(e.client_timeout_buffer_ms<0)throw new RangeError("'client_timeout_buffer_ms' must be greater than or equal to zero.");if(e.start_ts!==void 0&&e.cursor!==void 0)throw new TypeError("Only one of 'start_ts' or 'cursor' can be defined in the client configuration.");if(e.cursor!==void 0&&typeof e.cursor!="string")throw new TypeError("'cursor' must be a string.")},u(Pe,Xe,yt());function Kt(t){return new Promise(e=>setTimeout(e,t))}export{Fe as AbortError,ie as AuthenticationError,ue as AuthorizationError,Le as Client,v as ClientClosedError,y as ClientError,ve as ConstraintFailureError,Oe as ContendedTransactionError,N as DateStub,fe as Document,M as DocumentReference,L as EmbeddedSet,j as FaunaAPIPaths,Q as FaunaError,Pe as FeedClient,Ce as FeedPage,be as FetchClient,je as FlattenedSetIterator,Z as InvalidRequestError,Vt as LONG_MAX,Ht as LONG_MIN,W as Module,pe as NamedDocument,Y as NamedDocumentReference,w as NetworkError,ee as NodeHTTP2Client,re as NullDocument,D as Page,F as ProtocolError,G as QueryCheckError,ae as QueryRuntimeError,ce as QueryTimeoutError,h as ServiceError,de as ServiceInternalError,U as SetIterator,Ue as StreamClient,ne as StreamToken,H as TaggedTypeFormat,V as ThrottlingError,q as TimeStub,at as endpoints,ft as fql,ut as getDefaultHTTPClient,ct as isHTTPResponse,dt as isStreamClient}; | ||
//# sourceMappingURL=index.js.map |
@@ -1,2 +0,2 @@ | ||
import { HTTPStreamClient } from "./http-client"; | ||
import { HTTPClient, HTTPStreamClient } from "./http-client"; | ||
import type { ValueFormat } from "./wire-protocol"; | ||
@@ -18,3 +18,3 @@ /** | ||
/** | ||
* The {@link URL} of Fauna to call. See {@link endpoints} for some default options. | ||
* The {@link https://developer.mozilla.org/en-US/docs/Web/API/URL|URL} of Fauna to call. See {@link endpoints} for some default options. | ||
*/ | ||
@@ -170,8 +170,35 @@ endpoint?: URL; | ||
* update the client with the latest valid timestamp (in the event of a | ||
* dropped connection) as well as metrics about about the cost of maintaining | ||
* dropped connection) as well as metrics about the cost of maintaining | ||
* the stream other than the cost of the received events. | ||
*/ | ||
status_events?: boolean; | ||
/** | ||
* The last seen event cursor to resume the stream from. When provided, the | ||
* stream will start from the given cursor position (exclusively). | ||
*/ | ||
cursor?: string; | ||
}; | ||
/** | ||
* Configuration for an event feed client. | ||
*/ | ||
export type FeedClientConfiguration = Required<Pick<ClientConfiguration, "long_type" | "max_attempts" | "max_backoff" | "client_timeout_buffer_ms" | "query_timeout_ms" | "secret">> & { | ||
/** | ||
* The underlying {@link HTTPClient} that will execute the actual HTTP calls | ||
*/ | ||
httpClient: HTTPClient; | ||
/** | ||
* The starting timestamp of the event feed, exclusive. If set, Fauna will return events starting after | ||
the timestamp. | ||
*/ | ||
start_ts?: number; | ||
/** | ||
* The starting event cursor, exclusive. If set, Fauna will return events starting after the cursor. | ||
*/ | ||
cursor?: string; | ||
/** | ||
* The desired number of events per page. | ||
*/ | ||
page_size?: number; | ||
}; | ||
/** | ||
* A extensible set of endpoints for calling Fauna. | ||
@@ -178,0 +205,0 @@ * @remarks Most clients will will not need to extend this set. |
@@ -1,5 +0,5 @@ | ||
import { ClientConfiguration, StreamClientConfiguration } from "./client-configuration"; | ||
import { FeedClientConfiguration, ClientConfiguration, StreamClientConfiguration } from "./client-configuration"; | ||
import { type HTTPClient } from "./http-client"; | ||
import { Query } from "./query-builder"; | ||
import { EmbeddedSet, Page, SetIterator, StreamToken } from "./values"; | ||
import { FeedPage, EmbeddedSet, Page, SetIterator, EventSource } from "./values"; | ||
import { QueryOptions, StreamEventData, StreamEventStatus, type QuerySuccess, type QueryValue } from "./wire-protocol"; | ||
@@ -43,3 +43,3 @@ /** | ||
/** | ||
* Closes the underlying HTTP client. Subsquent query or close calls | ||
* Closes the underlying HTTP client. Subsequent query or close calls | ||
* will fail. | ||
@@ -121,3 +121,3 @@ */ | ||
* if the provided query used a type parameter. | ||
* @param query - A string-encoded streaming token, or a {@link Query} | ||
* @param tokenOrQuery - A string-encoded token for an {@link EventSource}, or a {@link Query} | ||
* @returns A {@link StreamClient} that which can be used to listen to a stream | ||
@@ -128,3 +128,3 @@ * of events | ||
* ```javascript | ||
* const stream = client.stream(fql`MyCollection.all().toStream()`) | ||
* const stream = client.stream(fql`MyCollection.all().eventSource()`) | ||
* | ||
@@ -153,3 +153,3 @@ * try { | ||
* ```javascript | ||
* const stream = client.stream(fql`MyCollection.all().toStream()`) | ||
* const stream = client.stream(fql`MyCollection.all().eventSource()`) | ||
* | ||
@@ -177,3 +177,44 @@ * stream.start( | ||
*/ | ||
stream<T extends QueryValue>(tokenOrQuery: StreamToken | Query<StreamToken>, options?: Partial<StreamClientConfiguration>): StreamClient<T>; | ||
stream<T extends QueryValue>(tokenOrQuery: EventSource | Query<EventSource>, options?: Partial<StreamClientConfiguration>): StreamClient<T>; | ||
/** | ||
* Initialize a event feed in Fauna and returns an asynchronous iterator of | ||
* feed events. | ||
* @typeParam T - The expected type of the response from Fauna. T can be inferred | ||
* if the provided query used a type parameter. | ||
* @param tokenOrQuery - A string-encoded token for an {@link EventSource}, or a {@link Query} | ||
* @returns A {@link FeedClient} that which can be used to listen to a feed | ||
* of events | ||
* | ||
* @example | ||
* ```javascript | ||
* const feed = client.feed(fql`MyCollection.all().eventSource()`) | ||
* | ||
* try { | ||
* for await (const page of feed) { | ||
* for (const event of page.events) { | ||
* // ... handle event | ||
* } | ||
* } | ||
* } catch (error) { | ||
* // An error will be handled here if Fauna returns a terminal, "error" event, or | ||
* // if Fauna returns a non-200 response when trying to connect, or | ||
* // if the max number of retries on network errors is reached. | ||
* | ||
* // ... handle fatal error | ||
* }; | ||
* ``` | ||
* @example | ||
* The {@link FeedClient.flatten} method can be used so the iterator yields | ||
* events directly. Each event is fetched asynchronously and hides when | ||
* additional pages are fetched. | ||
* | ||
* ```javascript | ||
* const feed = client.feed(fql`MyCollection.all().eventSource()`) | ||
* | ||
* for await (const user of feed.flatten()) { | ||
* // do something with each event | ||
* } | ||
* ``` | ||
*/ | ||
feed<T extends QueryValue>(tokenOrQuery: EventSource | Query<EventSource>, options?: Partial<FeedClientConfiguration>): FeedClient<T>; | ||
} | ||
@@ -189,12 +230,10 @@ /** | ||
* | ||
* @param query - A lambda that returns a promise for a {@link StreamToken} | ||
* @param token - A lambda that returns a promise for a {@link EventSource} | ||
* @param clientConfiguration - The {@link ClientConfiguration} to apply | ||
* @param httpStreamClient - The underlying {@link HTTPStreamClient} that will | ||
* execute the actual HTTP calls | ||
* @example | ||
* ```typescript | ||
* const streamClient = client.stream(streamToken); | ||
* const streamClient = client.stream(eventSource); | ||
* ``` | ||
*/ | ||
constructor(token: StreamToken | (() => Promise<StreamToken>), clientConfiguration: StreamClientConfiguration); | ||
constructor(token: EventSource | (() => Promise<EventSource>), clientConfiguration: StreamClientConfiguration); | ||
/** | ||
@@ -212,1 +251,37 @@ * A synchronous method to start listening to the stream and handle events | ||
} | ||
/** | ||
* A class to iterate through to a Fauna event feed. | ||
*/ | ||
export declare class FeedClient<T extends QueryValue = any> { | ||
#private; | ||
/** | ||
* | ||
* @param token - A lambda that returns a promise for a {@link EventSource} | ||
* @param clientConfiguration - The {@link FeedClientConfiguration} to apply | ||
* @example | ||
* ```typescript | ||
* const feed = client.feed(eventSource); | ||
* ``` | ||
*/ | ||
constructor(token: EventSource | (() => Promise<EventSource>), clientConfiguration: FeedClientConfiguration); | ||
[Symbol.asyncIterator](): AsyncGenerator<FeedPage<T>>; | ||
/** | ||
* Fetches the next page of the event feed. If there are no more pages to | ||
* fetch, this method will throw a {@link ClientError}. | ||
*/ | ||
nextPage(): Promise<FeedPage<T>>; | ||
/** | ||
* Returns an async generator that yields the events of the event feed | ||
* directly. | ||
* | ||
* @example | ||
* ```javascript | ||
* const feed = client.feed(fql`MyCollection.all().eventSource()`) | ||
* | ||
* for await (const user of feed.flatten()) { | ||
* // do something with each event | ||
* } | ||
* ``` | ||
*/ | ||
flatten(): AsyncGenerator<StreamEventData<T>>; | ||
} |
@@ -1,2 +0,2 @@ | ||
import type { ConstraintFailure, QueryFailure, QueryInfo, QueryValue } from "./wire-protocol"; | ||
import type { ConstraintFailure, QueryFailure, QueryInfo, QueryStats, QueryValue } from "./wire-protocol"; | ||
/** | ||
@@ -128,6 +128,7 @@ * A common error base class for all other errors. | ||
* Statistics regarding the query. | ||
* | ||
* TODO: Deprecate this `stats` field. All `ServiceError`s already provide | ||
* access to stats through `queryInfo.stats` | ||
*/ | ||
readonly stats?: { | ||
[key: string]: number; | ||
}; | ||
readonly stats?: QueryStats; | ||
constructor(failure: QueryFailure, httpStatus?: number); | ||
@@ -134,0 +135,0 @@ } |
/** following reference needed to include types for experimental fetch API in Node */ | ||
/// <reference lib="dom" /> | ||
import { QueryRequest } from "../wire-protocol"; | ||
import { HTTPClient, HTTPClientOptions, HTTPRequest, HTTPResponse, HTTPStreamRequest, HTTPStreamClient, StreamAdapter } from "./http-client"; | ||
@@ -11,7 +12,7 @@ /** | ||
/** {@inheritDoc HTTPClient.request} */ | ||
request({ data, headers: requestHeaders, method, client_timeout_ms, }: HTTPRequest): Promise<HTTPResponse>; | ||
request<T = QueryRequest>({ data, headers: requestHeaders, method, client_timeout_ms, path, }: HTTPRequest<T>): Promise<HTTPResponse>; | ||
/** {@inheritDoc HTTPStreamClient.stream} */ | ||
stream({ data, headers: requestHeaders, method, }: HTTPStreamRequest): StreamAdapter; | ||
stream({ data, headers: requestHeaders, method, path, }: HTTPStreamRequest): StreamAdapter; | ||
/** {@inheritDoc HTTPClient.close} */ | ||
close(): void; | ||
} |
import { QueryRequest, StreamRequest } from "../wire-protocol"; | ||
import { SupportedFaunaAPIPaths } from "./paths"; | ||
/** | ||
@@ -6,3 +7,3 @@ * An object representing an http request. | ||
*/ | ||
export type HTTPRequest = { | ||
export type HTTPRequest<T = QueryRequest> = { | ||
/** | ||
@@ -13,3 +14,3 @@ * The timeout of each http request, in milliseconds. | ||
/** The encoded Fauna query to send */ | ||
data: QueryRequest; | ||
data: T; | ||
/** Headers in object format */ | ||
@@ -19,2 +20,4 @@ headers: Record<string, string | undefined>; | ||
method: "POST"; | ||
/** The path of the endpoint to call if not using the default */ | ||
path?: SupportedFaunaAPIPaths; | ||
}; | ||
@@ -37,3 +40,3 @@ /** | ||
/** | ||
* An interface to provide implementation-specific, asyncronous http calls. | ||
* An interface to provide implementation-specific, asynchronous http calls. | ||
* This driver provides default implementations for common environments. Users | ||
@@ -49,3 +52,3 @@ * can configure the {@link Client} to use custom implementations if desired. | ||
*/ | ||
request(req: HTTPRequest): Promise<HTTPResponse>; | ||
request<T>(req: HTTPRequest<T>): Promise<HTTPResponse>; | ||
/** | ||
@@ -74,2 +77,4 @@ * Flags the calling {@link Client} as no longer | ||
method: "POST"; | ||
/** The path of the endpoint to call if not using the default */ | ||
path?: string; | ||
}; | ||
@@ -84,3 +89,3 @@ /** | ||
/** | ||
* An interface to provide implementation-specific, asyncronous http calls. | ||
* An interface to provide implementation-specific, asynchronous http calls. | ||
* This driver provides default implementations for common environments. Users | ||
@@ -87,0 +92,0 @@ * can configure the {@link Client} to use custom implementations if desired. |
import { HTTPClient, HTTPClientOptions, HTTPResponse, HTTPStreamClient } from "./http-client"; | ||
export * from "./paths"; | ||
export * from "./fetch-client"; | ||
@@ -3,0 +4,0 @@ export * from "./http-client"; |
import { HTTPClient, HTTPClientOptions, HTTPRequest, HTTPResponse, HTTPStreamClient, HTTPStreamRequest, StreamAdapter } from "./http-client"; | ||
import { QueryRequest } from "../wire-protocol"; | ||
/** | ||
@@ -9,9 +10,9 @@ * An implementation for {@link HTTPClient} that uses the node http package | ||
/** | ||
* Gets a {@link NodeHTTP2Client} matching the {@link HTTTPClientOptions} | ||
* @param httpClientOptions - the {@link HTTTPClientOptions} | ||
* @returns a {@link NodeHTTP2Client} matching the {@link HTTTPClientOptions} | ||
* Gets a {@link NodeHTTP2Client} matching the {@link HTTPClientOptions} | ||
* @param httpClientOptions - the {@link HTTPClientOptions} | ||
* @returns a {@link NodeHTTP2Client} matching the {@link HTTPClientOptions} | ||
*/ | ||
static getClient(httpClientOptions: HTTPClientOptions): NodeHTTP2Client; | ||
/** {@inheritDoc HTTPClient.request} */ | ||
request(req: HTTPRequest): Promise<HTTPResponse>; | ||
request<T = QueryRequest>(req: HTTPRequest<T>): Promise<HTTPResponse>; | ||
/** {@inheritDoc HTTPStreamClient.stream} */ | ||
@@ -18,0 +19,0 @@ stream(req: HTTPStreamRequest): StreamAdapter; |
@@ -1,8 +0,8 @@ | ||
export { Client, StreamClient } from "./client"; | ||
export { endpoints, type ClientConfiguration, type Endpoints, type StreamClientConfiguration, } from "./client-configuration"; | ||
export { Client, StreamClient, FeedClient } from "./client"; | ||
export { endpoints, type ClientConfiguration, type Endpoints, type StreamClientConfiguration, type FeedClientConfiguration, } from "./client-configuration"; | ||
export { AbortError, AuthenticationError, AuthorizationError, ClientError, ClientClosedError, ConstraintFailureError, ContendedTransactionError, FaunaError, InvalidRequestError, NetworkError, ProtocolError, QueryCheckError, QueryRuntimeError, QueryTimeoutError, ServiceError, ServiceInternalError, ThrottlingError, } from "./errors"; | ||
export { type Query, type QueryArgument, fql } from "./query-builder"; | ||
export { LONG_MAX, LONG_MIN, TaggedTypeFormat } from "./tagged-type"; | ||
export { type QueryValueObject, type QueryValue, type QueryFailure, type QueryInfo, type QueryInterpolation, type QueryOptions, type QueryRequest, type QueryStats, type QuerySuccess, type Span, type ValueFragment, } from "./wire-protocol"; | ||
export { DateStub, Document, DocumentReference, EmbeddedSet, Module, NamedDocument, NamedDocumentReference, NullDocument, Page, SetIterator, StreamToken, TimeStub, type DocumentT, } from "./values"; | ||
export { FetchClient, getDefaultHTTPClient, isHTTPResponse, isStreamClient, NodeHTTP2Client, type HTTPClient, type HTTPRequest, type HTTPResponse, type HTTPStreamClient, type StreamAdapter, } from "./http-client"; | ||
export { fql, type Query, type QueryArgument, type QueryArgumentObject, } from "./query-builder"; | ||
export { DecodeOptions, LONG_MAX, LONG_MIN, TaggedTypeFormat, } from "./tagged-type"; | ||
export { type ArrayFragment, type ConstraintFailure, type EncodedObject, type FeedError, type FeedRequest, type FeedSuccess, type FQLFragment, type ObjectFragment, type QueryFailure, type QueryInfo, type QueryInterpolation, type QueryOptions, type QueryRequest, type QueryStats, type QuerySuccess, type QueryValue, type QueryValueObject, type Span, type StreamEventData, type StreamEventError, type StreamEventStatus, type StreamRequest, type TaggedBytes, type TaggedDate, type TaggedDouble, type TaggedInt, type TaggedLong, type TaggedMod, type TaggedObject, type TaggedRef, type TaggedTime, type TaggedType, type ValueFormat, type ValueFragment, } from "./wire-protocol"; | ||
export { DateStub, Document, DocumentReference, EmbeddedSet, FlattenedSetIterator, Module, NamedDocument, NamedDocumentReference, NullDocument, Page, SetIterator, StreamToken, TimeStub, FeedPage, type EventSource, type DocumentT, } from "./values"; | ||
export { FaunaAPIPaths, FetchClient, getDefaultHTTPClient, HTTPClientOptions, HTTPStreamRequest, isHTTPResponse, isStreamClient, NodeHTTP2Client, SupportedFaunaAPIPaths, type HTTPClient, type HTTPRequest, type HTTPResponse, type HTTPStreamClient, type StreamAdapter, } from "./http-client"; |
@@ -20,3 +20,3 @@ import type { FQLFragment, QueryValue } from "./wire-protocol"; | ||
* @typeParam T - The expected type of the response from Fauna when evaluated. | ||
* @param queryFragments - a {@link TemplateStringsArray} that constitute | ||
* @param queryFragments - An array that constitutes | ||
* the strings that are the basis of the query. | ||
@@ -23,0 +23,0 @@ * @param queryArgs - an Array\<QueryValue | Query\> that |
/** The current package version. */ | ||
export declare const packageVersion = "2.2.0"; | ||
export declare const packageVersion = "2.3.0"; |
@@ -80,9 +80,17 @@ import { Client } from "../client"; | ||
flatten(): FlattenedSetIterator<T>; | ||
/** Implement {@link AsyncGenerator.next} */ | ||
/** Implement | ||
* {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/AsyncGenerator/next| AsyncGenerator.next} | ||
* */ | ||
next(): Promise<IteratorResult<T[], void>>; | ||
/** Implement {@link AsyncGenerator.return} */ | ||
/** Implement | ||
* {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/AsyncGenerator/return| AsyncGenerator.return} | ||
* */ | ||
return(): Promise<IteratorResult<T[], void>>; | ||
/** Implement {@link AsyncGenerator.throw} */ | ||
/** Implement | ||
* {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/AsyncGenerator/throw| AsyncGenerator.throw} | ||
* */ | ||
throw(e: any): Promise<IteratorResult<T[], void>>; | ||
/** Implement {@link AsyncGenerator} */ | ||
/** Implement | ||
* {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/AsyncGenerator| AsyncGenerator} | ||
* */ | ||
[Symbol.asyncIterator](): this; | ||
@@ -109,10 +117,18 @@ } | ||
constructor(setIterator: SetIterator<T>); | ||
/** Implement {@link AsyncGenerator.next} */ | ||
/** Implement | ||
* {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/AsyncGenerator/next| AsyncGenerator.next} | ||
* */ | ||
next(): Promise<IteratorResult<T, void>>; | ||
/** Implement {@link AsyncGenerator.return} */ | ||
/** Implement | ||
* {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/AsyncGenerator/return| AsyncGenerator.return} | ||
* */ | ||
return(): Promise<IteratorResult<T, void>>; | ||
/** Implement {@link AsyncGenerator.throw} */ | ||
/** Implement | ||
* {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/AsyncGenerator/throw| AsyncGenerator.throw} | ||
* */ | ||
throw(e: any): Promise<IteratorResult<T, void>>; | ||
/** Implement {@link AsyncGenerator} */ | ||
/** Implement | ||
* {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/AsyncGenerator| AsyncGenerator} | ||
* */ | ||
[Symbol.asyncIterator](): this; | ||
} |
@@ -0,5 +1,6 @@ | ||
import { FeedSuccess, QueryValue, StreamEventData, QueryStats } from "../wire-protocol"; | ||
/** | ||
* A token used to initiate a Fauna stream at a particular snapshot in time. | ||
* A token used to initiate a Fauna event source at a particular snapshot in time. | ||
* | ||
* The example below shows how to request a stream token from Fauna and use it | ||
* The example below shows how to request an event token from Fauna and use it | ||
* to establish an event steam. | ||
@@ -12,5 +13,5 @@ * | ||
* `); | ||
* const token = response.data; | ||
* const eventSource = response.data; | ||
* | ||
* const stream = client.stream(token) | ||
* const stream = client.stream(eventSource) | ||
* .on("add", (event) => console.log("New message", event)) | ||
@@ -21,5 +22,20 @@ * | ||
*/ | ||
export declare class StreamToken { | ||
export interface EventSource { | ||
readonly token: string; | ||
} | ||
export declare function isEventSource(value: any): value is EventSource; | ||
export declare class StreamToken implements EventSource { | ||
readonly token: string; | ||
constructor(token: string); | ||
} | ||
/** | ||
* A class to represent a page of events from a Fauna stream. | ||
*/ | ||
export declare class FeedPage<T extends QueryValue> { | ||
#private; | ||
readonly events: IterableIterator<StreamEventData<T>>; | ||
readonly cursor: string; | ||
readonly hasNext: boolean; | ||
readonly stats?: QueryStats; | ||
constructor({ events, cursor, has_next, stats }: FeedSuccess<T>); | ||
} |
@@ -108,2 +108,7 @@ import { QueryArgumentObject } from "./query-builder"; | ||
attempts: number; | ||
/** | ||
* A list of rate limits hit. | ||
* Included with QueryFailure responses when the query is rate limited. | ||
*/ | ||
rate_limits_hit?: ("read" | "write" | "compute")[]; | ||
}; | ||
@@ -314,2 +319,3 @@ export type QueryInfo = { | ||
start_ts?: number; | ||
cursor?: string; | ||
}; | ||
@@ -320,2 +326,3 @@ export type StreamEventType = "status" | "add" | "remove" | "update" | "error"; | ||
txn_ts: number; | ||
cursor: string; | ||
stats: QueryStats; | ||
@@ -326,2 +333,3 @@ }; | ||
txn_ts: number; | ||
cursor: string; | ||
stats: QueryStats; | ||
@@ -334,2 +342,12 @@ data: T; | ||
export type StreamEvent<T extends QueryValue> = StreamEventStatus | StreamEventData<T> | StreamEventError; | ||
export type FeedRequest = StreamRequest & { | ||
page_size?: number; | ||
}; | ||
export type FeedSuccess<T extends QueryValue> = { | ||
events: (StreamEventData<T> | StreamEventError)[]; | ||
cursor: string; | ||
has_next: boolean; | ||
stats?: QueryStats; | ||
}; | ||
export type FeedError = QueryFailure; | ||
export type TaggedBytes = { | ||
@@ -336,0 +354,0 @@ "@bytes": string; |
{ | ||
"name": "fauna", | ||
"version": "2.2.0", | ||
"version": "2.3.0", | ||
"description": "A driver to query Fauna databases in browsers, Node.js, and other Javascript runtimes", | ||
@@ -37,2 +37,3 @@ "homepage": "https://fauna.com", | ||
"ts-node": "^10.9.2", | ||
"typedoc": "^0.26.5", | ||
"typescript": "^5.4.3" | ||
@@ -45,2 +46,3 @@ }, | ||
"build:types": "tsc -emitDeclarationOnly --declaration true", | ||
"doc": "typedoc", | ||
"lint": "eslint -f unix \"src/**/*.{ts,tsx}\"", | ||
@@ -47,0 +49,0 @@ "fauna-local": "docker start faunadb-local || docker run --rm -d --name faunadb-local -p 8443:8443 -p 8084:8084 fauna/faunadb", |
190
README.md
@@ -1,2 +0,2 @@ | ||
# The Official JavaScript Driver for [Fauna](https://fauna.com). | ||
# Official JavaScript Driver for [Fauna v10](https://fauna.com) (current) | ||
@@ -8,3 +8,3 @@ [![npm Version](https://img.shields.io/npm/v/fauna.svg?maxAge=21600)](https://www.npmjs.com/package/fauna) | ||
See the [Fauna Documentation](https://docs.fauna.com/fauna/current/) for additional information how to configure and query your databases. | ||
See the [Fauna Documentation](https://docs.fauna.com/fauna/current/) for additional information on how to configure and query your databases. | ||
@@ -14,4 +14,5 @@ <details> | ||
- [The Official JavaScript Driver for Fauna.](#the-official-javascript-driver-for-fauna) | ||
- [Official JavaScript Driver for Fauna v10 (current)](#official-javascript-driver-for-fauna-v10-current) | ||
- [Supported runtimes](#supported-runtimes) | ||
- [API reference](#api-reference) | ||
- [Install](#install) | ||
@@ -33,2 +34,7 @@ - [Usage](#usage) | ||
- [HTTP/2 session idle timeout](#http2-session-idle-timeout) | ||
- [Event Feeds](#event-feeds) | ||
- [Request an Event Feed](#request-a-event-feed) | ||
- [Iterate on an Event Feed](#iterate-on-a-event-feed) | ||
- [Error handling](#error-handling) | ||
- [Event Feed options](#event-feed-options) | ||
- [Event Streaming](#event-streaming) | ||
@@ -54,4 +60,5 @@ - [Start a stream](#start-a-stream) | ||
- Current - v20 | ||
- LTS - v18 | ||
- Current - v22 | ||
- LTS - v20 | ||
- LTS (Maintenance) - v18 | ||
@@ -74,2 +81,8 @@ **Cloud providers** | ||
## API reference | ||
API reference documentation for the driver is available at | ||
https://fauna.github.io/fauna-js/. The docs are generated using | ||
[TypeDoc](https://typedoc.org/). | ||
## Install | ||
@@ -353,3 +366,3 @@ | ||
The driver's `Client` instance comes with reasonable defaults that should be | ||
used in most cases. Yu can override these defaults if needed. | ||
used in most cases. You can override these defaults if needed. | ||
@@ -466,2 +479,124 @@ In addition to configuring the client, you can also set default [query | ||
## Event Feeds | ||
The driver supports [Event Feeds](https://docs.fauna.com/fauna/current/learn/cdc/#event-feeds). | ||
### Request an Event Feed | ||
An Event Feed asynchronously polls an [event source](https://docs.fauna.com/fauna/current/learn/cdc/#create-an-event-source) for events. | ||
To get an event source, append `eventSource()` or `eventsOn()` to a set from a | ||
[supported Set](https://docs.fauna.com/fauna/current/reference/streaming_reference/#sets). | ||
To get paginated events, pass the event source to `feed()`: | ||
```javascript | ||
const response = await client.query(fql` | ||
let set = Product.all() | ||
{ | ||
initialPage: set.pageSize(10), | ||
eventSource: set.eventSource() | ||
} | ||
`); | ||
const { initialPage, eventSource } = response.data; | ||
const feed = client.feed(eventSource); | ||
``` | ||
You can also pass a query that produces an event source directly to `feed()`: | ||
```javascript | ||
const query = fql`Product.all().eventsOn(.price, .stock)`; | ||
const feed = client.feed(query); | ||
``` | ||
### Iterate on a Event Feed | ||
`feed()` returns a `FeedClient` instance that can act as an `AsyncIterator`. You can use `for await...of` to iterate through all the pages: | ||
```ts | ||
const query = fql`Product.all().eventsOn(.price, .stock)`; | ||
const feed = client.feed(query); | ||
for await (const page of feed) { | ||
console.log("Page stats", page.stats); | ||
for (event in page.events) { | ||
switch (event.type) { | ||
case "update": | ||
case "add": | ||
case "remove": | ||
console.log("Event: ", event); | ||
// ... | ||
break; | ||
} | ||
} | ||
} | ||
``` | ||
Alternatively, use `flatten()` to get paginated results as a single, flat array: | ||
```ts | ||
const query = fql`Product.all().eventsOn(.price, .stock)`; | ||
const feed = client.feed(query); | ||
for await (const event of feed.flatten()) { | ||
console.log("Event: ", event); | ||
} | ||
``` | ||
### Error handling | ||
Exceptions can be raised at two different places: | ||
1. While fetching a page | ||
1. While iterating a page's events | ||
This distinction allows for you to ignore errors originating from event processing. | ||
For example: | ||
```ts | ||
const feed = client.feed(fql` | ||
Product.all().map(.details.toUpperCase()).eventSource() | ||
`); | ||
try { | ||
for await (const page of feed) { | ||
// Pages will stop at the first error encountered. | ||
// Therefore, its safe to handle an event failures | ||
// and then pull more pages. | ||
try { | ||
for (const event of page.events) { | ||
console.log("Event: ", event); | ||
} | ||
} catch (error: unknown) { | ||
console.log("Feed event error: ", error); | ||
} | ||
} | ||
} catch (error: unknown) { | ||
console.log("Non-retryable error: ", error); | ||
} | ||
``` | ||
### Event Feed options | ||
The client configuration sets the default options for `feed()`. You can pass a `FeedClientConfiguration` object to override these defaults: | ||
```ts | ||
const options: FeedClientConfiguration = { | ||
long_type: "number", | ||
max_attempts: 5, | ||
max_backoff: 1000, | ||
query_timeout_ms: 5000, | ||
client_timeout_buffer_ms: 5000, | ||
secret: "FAUNA_SECRET", | ||
cursor: undefined, | ||
start_ts: undefined, | ||
}; | ||
client.feed(fql`Product.all().eventSource()`, options); | ||
``` | ||
## Event Streaming | ||
@@ -473,10 +608,10 @@ | ||
To get a stream token, append | ||
[`toStream()`](https://docs.fauna.com/fauna/current/reference/reference/schema_entities/set/tostream) | ||
To get an event source, append | ||
[`eventSource()`](https://docs.fauna.com/fauna/current/reference/reference/schema_entities/set/eventsource) | ||
or | ||
[`changesOn()`](https://docs.fauna.com/fauna/current/reference/reference/schema_entities/set/changeson) | ||
[`eventsOn()`](https://docs.fauna.com/fauna/current/reference/reference/schema_entities/set/eventson) | ||
to a set from a [supported | ||
source](https://docs.fauna.com/fauna/current/reference/streaming_reference/#supported-sources). | ||
source](https://docs.fauna.com/fauna/current/reference/streaming_reference/#sets). | ||
To start and subscribe to the stream, pass the stream token to `stream()`: | ||
To start and subscribe to the stream, pass the event source to `stream()`: | ||
@@ -489,14 +624,14 @@ ```javascript | ||
initialPage: set.pageSize(10), | ||
streamToken: set.toStream() | ||
eventSource: set.eventSource() | ||
} | ||
`); | ||
const { initialPage, streamToken } = response.data; | ||
const { initialPage, eventSource } = response.data; | ||
client.stream(streamToken); | ||
client.stream(eventSource); | ||
``` | ||
You can also pass a query that produces a stream token directly to `stream()`: | ||
You can also pass a query that produces an event source directly to `stream()`: | ||
```javascript | ||
const query = fql`Product.all().changesOn(.price, .quantity)`; | ||
const query = fql`Product.all().eventsOn(.price, .stock)`; | ||
@@ -517,3 +652,3 @@ client.stream(query); | ||
case "remove": | ||
console.log("Stream event:", event); | ||
console.log("Event: ", event); | ||
// ... | ||
@@ -540,3 +675,3 @@ break; | ||
case "remove": | ||
console.log("Stream event:", event); | ||
console.log("Event: ", event); | ||
// ... | ||
@@ -560,7 +695,7 @@ break; | ||
```javascript | ||
const stream = await client.stream(fql`Product.all().toStream()`); | ||
const stream = await client.stream(fql`Product.all().eventSource()`); | ||
let count = 0; | ||
for await (const event of stream) { | ||
console.log("Stream event:", event); | ||
console.log("Event: ", event); | ||
// ... | ||
@@ -582,6 +717,6 @@ count++; | ||
You can pass an `options` object to override these defaults: | ||
You can pass an `StreamClientConfiguration` object to override these defaults: | ||
```javascript | ||
const options = { | ||
const options: StreamClientConfiguration = { | ||
long_type: "number", | ||
@@ -592,14 +727,15 @@ max_attempts: 5, | ||
status_events: true, | ||
cursor: null, | ||
}; | ||
client.stream(fql`Product.all().toStream()`, options); | ||
client.stream(fql`Product.all().eventSource()`, options); | ||
``` | ||
For supported properties, see [Stream | ||
options](https://docs.fauna.com/fauna/current/drivers/js-client#stream-options) | ||
in the Fauna docs. | ||
For supported properties, see | ||
[StreamClientConfiguration](https://fauna.github.io/fauna-js/latest/types/StreamClientConfiguration.html) | ||
in the API reference. | ||
## Contributing | ||
Any contributions are from the community are greatly appreciated! | ||
Any contributions from the community are greatly appreciated! | ||
@@ -606,0 +742,0 @@ If you have a suggestion that would make this better, please fork the repo and create a pull request. You may also simply open an issue. We provide templates, so please complete those to the best of your ability. |
@@ -1,2 +0,2 @@ | ||
import { HTTPStreamClient } from "./http-client"; | ||
import { HTTPClient, HTTPStreamClient } from "./http-client"; | ||
import type { ValueFormat } from "./wire-protocol"; | ||
@@ -20,3 +20,3 @@ | ||
/** | ||
* The {@link URL} of Fauna to call. See {@link endpoints} for some default options. | ||
* The {@link https://developer.mozilla.org/en-US/docs/Web/API/URL|URL} of Fauna to call. See {@link endpoints} for some default options. | ||
*/ | ||
@@ -196,9 +196,51 @@ endpoint?: URL; | ||
* update the client with the latest valid timestamp (in the event of a | ||
* dropped connection) as well as metrics about about the cost of maintaining | ||
* dropped connection) as well as metrics about the cost of maintaining | ||
* the stream other than the cost of the received events. | ||
*/ | ||
status_events?: boolean; | ||
/** | ||
* The last seen event cursor to resume the stream from. When provided, the | ||
* stream will start from the given cursor position (exclusively). | ||
*/ | ||
cursor?: string; | ||
}; | ||
/** | ||
* Configuration for an event feed client. | ||
*/ | ||
export type FeedClientConfiguration = Required< | ||
Pick< | ||
ClientConfiguration, | ||
| "long_type" | ||
| "max_attempts" | ||
| "max_backoff" | ||
| "client_timeout_buffer_ms" | ||
| "query_timeout_ms" | ||
| "secret" | ||
> | ||
> & { | ||
/** | ||
* The underlying {@link HTTPClient} that will execute the actual HTTP calls | ||
*/ | ||
httpClient: HTTPClient; | ||
/** | ||
* The starting timestamp of the event feed, exclusive. If set, Fauna will return events starting after | ||
the timestamp. | ||
*/ | ||
start_ts?: number; | ||
/** | ||
* The starting event cursor, exclusive. If set, Fauna will return events starting after the cursor. | ||
*/ | ||
cursor?: string; | ||
/** | ||
* The desired number of events per page. | ||
*/ | ||
page_size?: number; | ||
}; | ||
/** | ||
* A extensible set of endpoints for calling Fauna. | ||
@@ -205,0 +247,0 @@ * @remarks Most clients will will not need to extend this set. |
import { | ||
FeedClientConfiguration, | ||
ClientConfiguration, | ||
@@ -23,2 +24,4 @@ StreamClientConfiguration, | ||
type HTTPClient, | ||
HTTPRequest, | ||
FaunaAPIPaths, | ||
} from "./http-client"; | ||
@@ -28,4 +31,14 @@ import { Query } from "./query-builder"; | ||
import { getDriverEnv } from "./util/environment"; | ||
import { EmbeddedSet, Page, SetIterator, StreamToken } from "./values"; | ||
import { withRetries } from "./util/retryable"; | ||
import { | ||
FeedPage, | ||
EmbeddedSet, | ||
Page, | ||
SetIterator, | ||
EventSource, | ||
isEventSource, | ||
} from "./values"; | ||
import { | ||
FeedRequest, | ||
FeedSuccess, | ||
EncodedObject, | ||
@@ -41,2 +54,3 @@ isQueryFailure, | ||
type QueryValue, | ||
FeedError, | ||
} from "./wire-protocol"; | ||
@@ -161,3 +175,3 @@ | ||
/** | ||
* Closes the underlying HTTP client. Subsquent query or close calls | ||
* Closes the underlying HTTP client. Subsequent query or close calls | ||
* will fail. | ||
@@ -279,3 +293,3 @@ */ | ||
* if the provided query used a type parameter. | ||
* @param query - A string-encoded streaming token, or a {@link Query} | ||
* @param tokenOrQuery - A string-encoded token for an {@link EventSource}, or a {@link Query} | ||
* @returns A {@link StreamClient} that which can be used to listen to a stream | ||
@@ -286,3 +300,3 @@ * of events | ||
* ```javascript | ||
* const stream = client.stream(fql`MyCollection.all().toStream()`) | ||
* const stream = client.stream(fql`MyCollection.all().eventSource()`) | ||
* | ||
@@ -311,3 +325,3 @@ * try { | ||
* ```javascript | ||
* const stream = client.stream(fql`MyCollection.all().toStream()`) | ||
* const stream = client.stream(fql`MyCollection.all().eventSource()`) | ||
* | ||
@@ -336,3 +350,3 @@ * stream.start( | ||
stream<T extends QueryValue>( | ||
tokenOrQuery: StreamToken | Query<StreamToken>, | ||
tokenOrQuery: EventSource | Query<EventSource>, | ||
options?: Partial<StreamClientConfiguration>, | ||
@@ -355,5 +369,14 @@ ): StreamClient<T> { | ||
if ( | ||
streamClientConfig.cursor !== undefined && | ||
tokenOrQuery instanceof Query | ||
) { | ||
throw new ClientError( | ||
"The `cursor` configuration can only be used with a stream token.", | ||
); | ||
} | ||
const tokenOrGetToken = | ||
tokenOrQuery instanceof Query | ||
? () => this.query<StreamToken>(tokenOrQuery).then((res) => res.data) | ||
? () => this.query<EventSource>(tokenOrQuery).then((res) => res.data) | ||
: tokenOrQuery; | ||
@@ -367,2 +390,66 @@ | ||
/** | ||
* Initialize a event feed in Fauna and returns an asynchronous iterator of | ||
* feed events. | ||
* @typeParam T - The expected type of the response from Fauna. T can be inferred | ||
* if the provided query used a type parameter. | ||
* @param tokenOrQuery - A string-encoded token for an {@link EventSource}, or a {@link Query} | ||
* @returns A {@link FeedClient} that which can be used to listen to a feed | ||
* of events | ||
* | ||
* @example | ||
* ```javascript | ||
* const feed = client.feed(fql`MyCollection.all().eventSource()`) | ||
* | ||
* try { | ||
* for await (const page of feed) { | ||
* for (const event of page.events) { | ||
* // ... handle event | ||
* } | ||
* } | ||
* } catch (error) { | ||
* // An error will be handled here if Fauna returns a terminal, "error" event, or | ||
* // if Fauna returns a non-200 response when trying to connect, or | ||
* // if the max number of retries on network errors is reached. | ||
* | ||
* // ... handle fatal error | ||
* }; | ||
* ``` | ||
* @example | ||
* The {@link FeedClient.flatten} method can be used so the iterator yields | ||
* events directly. Each event is fetched asynchronously and hides when | ||
* additional pages are fetched. | ||
* | ||
* ```javascript | ||
* const feed = client.feed(fql`MyCollection.all().eventSource()`) | ||
* | ||
* for await (const user of feed.flatten()) { | ||
* // do something with each event | ||
* } | ||
* ``` | ||
*/ | ||
feed<T extends QueryValue>( | ||
tokenOrQuery: EventSource | Query<EventSource>, | ||
options?: Partial<FeedClientConfiguration>, | ||
): FeedClient<T> { | ||
if (this.#isClosed) { | ||
throw new ClientClosedError( | ||
"Your client is closed. No further requests can be issued.", | ||
); | ||
} | ||
const clientConfiguration: FeedClientConfiguration = { | ||
...this.#clientConfiguration, | ||
httpClient: this.#httpClient, | ||
...options, | ||
}; | ||
const tokenOrGetToken = | ||
tokenOrQuery instanceof Query | ||
? () => this.query<EventSource>(tokenOrQuery).then((res) => res.data) | ||
: tokenOrQuery; | ||
return new FeedClient(tokenOrGetToken, clientConfiguration); | ||
} | ||
async #queryWithRetries<T extends QueryValue>( | ||
@@ -645,27 +732,27 @@ queryRequest: QueryRequest, | ||
#connectionAttempts = 0; | ||
/** A lambda that returns a promise for a {@link StreamToken} */ | ||
#query: () => Promise<StreamToken>; | ||
/** A lambda that returns a promise for a {@link EventSource} */ | ||
#query: () => Promise<EventSource>; | ||
/** The last `txn_ts` value received from events */ | ||
#last_ts?: number; | ||
/** The last `cursor` value received from events */ | ||
#last_cursor?: string; | ||
/** A common interface to operate a stream from any HTTPStreamClient */ | ||
#streamAdapter?: StreamAdapter; | ||
/** A saved copy of the StreamToken once received */ | ||
#streamToken?: StreamToken; | ||
/** A saved copy of the EventSource once received */ | ||
#eventSource?: EventSource; | ||
/** | ||
* | ||
* @param query - A lambda that returns a promise for a {@link StreamToken} | ||
* @param token - A lambda that returns a promise for a {@link EventSource} | ||
* @param clientConfiguration - The {@link ClientConfiguration} to apply | ||
* @param httpStreamClient - The underlying {@link HTTPStreamClient} that will | ||
* execute the actual HTTP calls | ||
* @example | ||
* ```typescript | ||
* const streamClient = client.stream(streamToken); | ||
* const streamClient = client.stream(eventSource); | ||
* ``` | ||
*/ | ||
constructor( | ||
token: StreamToken | (() => Promise<StreamToken>), | ||
token: EventSource | (() => Promise<EventSource>), | ||
clientConfiguration: StreamClientConfiguration, | ||
) { | ||
if (token instanceof StreamToken) { | ||
if (isEventSource(token)) { | ||
this.#query = () => Promise.resolve(token); | ||
@@ -723,7 +810,7 @@ } else { | ||
if (!this.#streamToken) { | ||
this.#streamToken = await this.#query().then((maybeStreamToken) => { | ||
if (!(maybeStreamToken instanceof StreamToken)) { | ||
if (!this.#eventSource) { | ||
this.#eventSource = await this.#query().then((maybeStreamToken) => { | ||
if (!isEventSource(maybeStreamToken)) { | ||
throw new ClientError( | ||
`Error requesting a stream token. Expected a StreamToken as the query result, but received ${typeof maybeStreamToken}. Your query must return the result of '<Set>.toStream' or '<Set>.changesOn')\n` + | ||
`Error requesting a stream token. Expected a EventSource as the query result, but received ${typeof maybeStreamToken}. Your query must return the result of '<Set>.eventSource' or '<Set>.eventsOn')\n` + | ||
`Query result: ${JSON.stringify(maybeStreamToken, null)}`, | ||
@@ -745,3 +832,3 @@ ); | ||
try { | ||
for await (const event of this.#startStream(this.#last_ts)) { | ||
for await (const event of this.#startStream()) { | ||
yield event; | ||
@@ -777,7 +864,7 @@ } | ||
async *#startStream( | ||
start_ts?: number, | ||
): AsyncGenerator<StreamEventData<T> | StreamEventStatus> { | ||
async *#startStream(): AsyncGenerator< | ||
StreamEventData<T> | StreamEventStatus | ||
> { | ||
// Safety: This method must only be called after a stream token has been acquired | ||
const streamToken = this.#streamToken as StreamToken; | ||
const eventSource = this.#eventSource as EventSource; | ||
@@ -789,3 +876,6 @@ const headers = { | ||
const streamAdapter = this.#clientConfiguration.httpStreamClient.stream({ | ||
data: { token: streamToken.token, start_ts }, | ||
data: { | ||
token: eventSource.token, | ||
cursor: this.#last_cursor || this.#clientConfiguration.cursor, | ||
}, | ||
headers, | ||
@@ -810,2 +900,3 @@ method: "POST", | ||
this.#last_ts = deserializedEvent.txn_ts; | ||
this.#last_cursor = deserializedEvent.cursor; | ||
@@ -856,2 +947,224 @@ // TODO: remove this once all environments have updated the events to use "status" instead of "start" | ||
/** | ||
* A class to iterate through to a Fauna event feed. | ||
*/ | ||
export class FeedClient<T extends QueryValue = any> { | ||
/** A static copy of the driver env header to send with each request */ | ||
static readonly #driverEnvHeader = getDriverEnv(); | ||
/** A lambda that returns a promise for a {@link EventSource} */ | ||
#query: () => Promise<EventSource>; | ||
/** The event feed's client options */ | ||
#clientConfiguration: FeedClientConfiguration; | ||
/** The last `cursor` value received for the current page */ | ||
#lastCursor?: string; | ||
/** A saved copy of the EventSource once received */ | ||
#eventSource?: EventSource; | ||
/** Whether or not another page can be fetched by the client */ | ||
#isDone?: boolean; | ||
/** | ||
* | ||
* @param token - A lambda that returns a promise for a {@link EventSource} | ||
* @param clientConfiguration - The {@link FeedClientConfiguration} to apply | ||
* @example | ||
* ```typescript | ||
* const feed = client.feed(eventSource); | ||
* ``` | ||
*/ | ||
constructor( | ||
token: EventSource | (() => Promise<EventSource>), | ||
clientConfiguration: FeedClientConfiguration, | ||
) { | ||
if (isEventSource(token)) { | ||
this.#query = () => Promise.resolve(token); | ||
} else { | ||
this.#query = token; | ||
} | ||
this.#clientConfiguration = clientConfiguration; | ||
this.#lastCursor = clientConfiguration.cursor; | ||
this.#validateConfiguration(); | ||
} | ||
#getHeaders(): Record<string, string> { | ||
return { | ||
Authorization: `Bearer ${this.#clientConfiguration.secret}`, | ||
"x-format": "tagged", | ||
"x-driver-env": FeedClient.#driverEnvHeader, | ||
"x-query-timeout-ms": | ||
this.#clientConfiguration.query_timeout_ms.toString(), | ||
}; | ||
} | ||
async #nextPageHttpRequest() { | ||
// If we never resolved the stream token, do it now since we need it here when | ||
// building the payload | ||
if (!this.#eventSource) { | ||
this.#eventSource = await this.#resolveEventSource(this.#query); | ||
} | ||
const headers = this.#getHeaders(); | ||
const req: HTTPRequest<FeedRequest> = { | ||
headers, | ||
client_timeout_ms: | ||
this.#clientConfiguration.client_timeout_buffer_ms + | ||
this.#clientConfiguration.query_timeout_ms, | ||
data: { | ||
token: this.#eventSource.token, | ||
}, | ||
method: "POST", | ||
path: FaunaAPIPaths.EVENT_FEED, | ||
}; | ||
// Set the page size if it is available | ||
if (this.#clientConfiguration.page_size) { | ||
req.data.page_size = this.#clientConfiguration.page_size; | ||
} | ||
// If we have a cursor, use that. Otherwise, use the start_ts if available. | ||
// When the config is validated, if both are set, an error is thrown. | ||
if (this.#lastCursor) { | ||
req.data.cursor = this.#lastCursor; | ||
} else if (this.#clientConfiguration.start_ts) { | ||
req.data.start_ts = this.#clientConfiguration.start_ts; | ||
} | ||
return req; | ||
} | ||
async *[Symbol.asyncIterator](): AsyncGenerator<FeedPage<T>> { | ||
while (!this.#isDone) { | ||
yield await this.nextPage(); | ||
} | ||
} | ||
/** | ||
* Fetches the next page of the event feed. If there are no more pages to | ||
* fetch, this method will throw a {@link ClientError}. | ||
*/ | ||
async nextPage(): Promise<FeedPage<T>> { | ||
if (this.#isDone) { | ||
throw new ClientError("The event feed has no more pages to fetch."); | ||
} | ||
const { httpClient } = this.#clientConfiguration; | ||
const request = await this.#nextPageHttpRequest(); | ||
const response = await withRetries(() => httpClient.request(request), { | ||
maxAttempts: this.#clientConfiguration.max_attempts, | ||
maxBackoff: this.#clientConfiguration.max_backoff, | ||
shouldRetry: (error) => error instanceof ThrottlingError, | ||
}); | ||
let body: FeedSuccess<T> | FeedError; | ||
try { | ||
body = TaggedTypeFormat.decode(response.body, { | ||
long_type: this.#clientConfiguration.long_type, | ||
}); | ||
} catch (error: unknown) { | ||
throw new ProtocolError({ | ||
message: `Error parsing response as JSON: ${error}`, | ||
httpStatus: response.status, | ||
}); | ||
} | ||
if (isQueryFailure(body)) { | ||
throw getServiceError(body, response.status); | ||
} | ||
const page = new FeedPage<T>(body); | ||
this.#lastCursor = page.cursor; | ||
this.#isDone = !page.hasNext; | ||
return page; | ||
} | ||
/** | ||
* Returns an async generator that yields the events of the event feed | ||
* directly. | ||
* | ||
* @example | ||
* ```javascript | ||
* const feed = client.feed(fql`MyCollection.all().eventSource()`) | ||
* | ||
* for await (const user of feed.flatten()) { | ||
* // do something with each event | ||
* } | ||
* ``` | ||
*/ | ||
async *flatten(): AsyncGenerator<StreamEventData<T>> { | ||
for await (const page of this) { | ||
for (const event of page.events) { | ||
yield event; | ||
} | ||
} | ||
} | ||
async #resolveEventSource( | ||
fn: () => Promise<EventSource>, | ||
): Promise<EventSource> { | ||
return await fn().then((maybeEventSource) => { | ||
if (!isEventSource(maybeEventSource)) { | ||
throw new ClientError( | ||
`Error requesting a stream token. Expected a EventSource as the query result, but received ${typeof maybeEventSource}. Your query must return the result of '<Set>.eventSource' or '<Set>.eventsOn')\n` + | ||
`Query result: ${JSON.stringify(maybeEventSource, null)}`, | ||
); | ||
} | ||
return maybeEventSource; | ||
}); | ||
} | ||
#validateConfiguration() { | ||
const config = this.#clientConfiguration; | ||
const required_options: (keyof FeedClientConfiguration)[] = [ | ||
"long_type", | ||
"httpClient", | ||
"max_backoff", | ||
"max_attempts", | ||
"client_timeout_buffer_ms", | ||
"query_timeout_ms", | ||
"secret", | ||
]; | ||
required_options.forEach((option) => { | ||
if (config[option] === undefined) { | ||
throw new TypeError( | ||
`ClientConfiguration option '${option}' must be defined.`, | ||
); | ||
} | ||
}); | ||
if (config.max_backoff <= 0) { | ||
throw new RangeError(`'max_backoff' must be greater than zero.`); | ||
} | ||
if (config.max_attempts <= 0) { | ||
throw new RangeError(`'max_attempts' must be greater than zero.`); | ||
} | ||
if (config.query_timeout_ms <= 0) { | ||
throw new RangeError(`'query_timeout_ms' must be greater than zero.`); | ||
} | ||
if (config.client_timeout_buffer_ms < 0) { | ||
throw new RangeError( | ||
`'client_timeout_buffer_ms' must be greater than or equal to zero.`, | ||
); | ||
} | ||
if (config.start_ts !== undefined && config.cursor !== undefined) { | ||
throw new TypeError( | ||
"Only one of 'start_ts' or 'cursor' can be defined in the client configuration.", | ||
); | ||
} | ||
if (config.cursor !== undefined && typeof config.cursor !== "string") { | ||
throw new TypeError("'cursor' must be a string."); | ||
} | ||
} | ||
} | ||
// Private types and constants for internal logic. | ||
@@ -858,0 +1171,0 @@ |
@@ -5,2 +5,3 @@ import type { | ||
QueryInfo, | ||
QueryStats, | ||
QueryValue, | ||
@@ -230,4 +231,7 @@ } from "./wire-protocol"; | ||
* Statistics regarding the query. | ||
* | ||
* TODO: Deprecate this `stats` field. All `ServiceError`s already provide | ||
* access to stats through `queryInfo.stats` | ||
*/ | ||
readonly stats?: { [key: string]: number }; | ||
readonly stats?: QueryStats; | ||
@@ -234,0 +238,0 @@ constructor(failure: QueryFailure, httpStatus?: number) { |
@@ -5,3 +5,4 @@ /** following reference needed to include types for experimental fetch API in Node */ | ||
import { getServiceError, NetworkError } from "../errors"; | ||
import { QueryFailure } from "../wire-protocol"; | ||
import { QueryFailure, QueryRequest } from "../wire-protocol"; | ||
import { FaunaAPIPaths } from "./paths"; | ||
import { | ||
@@ -21,14 +22,18 @@ HTTPClient, | ||
export class FetchClient implements HTTPClient, HTTPStreamClient { | ||
#queryURL: string; | ||
#streamURL: string; | ||
#baseUrl: string; | ||
#defaultRequestPath = FaunaAPIPaths.QUERY; | ||
#defaultStreamPath = FaunaAPIPaths.STREAM; | ||
#keepalive: boolean; | ||
constructor({ url, fetch_keepalive }: HTTPClientOptions) { | ||
this.#queryURL = new URL("/query/1", url).toString(); | ||
this.#streamURL = new URL("/stream/1", url).toString(); | ||
this.#baseUrl = url; | ||
this.#keepalive = fetch_keepalive; | ||
} | ||
#resolveURL(path: string): string { | ||
return new URL(path, this.#baseUrl).toString(); | ||
} | ||
/** {@inheritDoc HTTPClient.request} */ | ||
async request({ | ||
async request<T = QueryRequest>({ | ||
data, | ||
@@ -38,3 +43,4 @@ headers: requestHeaders, | ||
client_timeout_ms, | ||
}: HTTPRequest): Promise<HTTPResponse> { | ||
path = this.#defaultRequestPath, | ||
}: HTTPRequest<T>): Promise<HTTPResponse> { | ||
const signal = | ||
@@ -50,3 +56,3 @@ AbortSignal.timeout === undefined | ||
const response = await fetch(this.#queryURL, { | ||
const response = await fetch(this.#resolveURL(path), { | ||
method, | ||
@@ -82,4 +88,5 @@ headers: { ...requestHeaders, "Content-Type": "application/json" }, | ||
method, | ||
path = this.#defaultStreamPath, | ||
}: HTTPStreamRequest): StreamAdapter { | ||
const request = new Request(this.#streamURL, { | ||
const request = new Request(this.#resolveURL(path), { | ||
method, | ||
@@ -86,0 +93,0 @@ headers: { ...requestHeaders, "Content-Type": "application/json" }, |
// eslint-disable-next-line @typescript-eslint/no-unused-vars | ||
import type { Client } from "../client"; | ||
import { QueryRequest, StreamRequest } from "../wire-protocol"; | ||
import { SupportedFaunaAPIPaths } from "./paths"; | ||
@@ -9,3 +10,3 @@ /** | ||
*/ | ||
export type HTTPRequest = { | ||
export type HTTPRequest<T = QueryRequest> = { | ||
/** | ||
@@ -17,3 +18,3 @@ * The timeout of each http request, in milliseconds. | ||
/** The encoded Fauna query to send */ | ||
data: QueryRequest; | ||
data: T; | ||
@@ -25,2 +26,5 @@ /** Headers in object format */ | ||
method: "POST"; | ||
/** The path of the endpoint to call if not using the default */ | ||
path?: SupportedFaunaAPIPaths; | ||
}; | ||
@@ -46,3 +50,3 @@ | ||
/** | ||
* An interface to provide implementation-specific, asyncronous http calls. | ||
* An interface to provide implementation-specific, asynchronous http calls. | ||
* This driver provides default implementations for common environments. Users | ||
@@ -58,3 +62,3 @@ * can configure the {@link Client} to use custom implementations if desired. | ||
*/ | ||
request(req: HTTPRequest): Promise<HTTPResponse>; | ||
request<T>(req: HTTPRequest<T>): Promise<HTTPResponse>; | ||
@@ -88,2 +92,5 @@ /** | ||
method: "POST"; | ||
/** The path of the endpoint to call if not using the default */ | ||
path?: string; | ||
}; | ||
@@ -100,3 +107,3 @@ | ||
/** | ||
* An interface to provide implementation-specific, asyncronous http calls. | ||
* An interface to provide implementation-specific, asynchronous http calls. | ||
* This driver provides default implementations for common environments. Users | ||
@@ -103,0 +110,0 @@ * can configure the {@link Client} to use custom implementations if desired. |
@@ -10,2 +10,3 @@ import { FetchClient } from "./fetch-client"; | ||
export * from "./paths"; | ||
export * from "./fetch-client"; | ||
@@ -12,0 +13,0 @@ export * from "./http-client"; |
@@ -17,3 +17,4 @@ let http2: any; | ||
import { NetworkError, getServiceError } from "../errors"; | ||
import { QueryFailure } from "../wire-protocol"; | ||
import { QueryFailure, QueryRequest } from "../wire-protocol"; | ||
import { FaunaAPIPaths } from "./paths"; | ||
@@ -39,2 +40,5 @@ // alias http2 types | ||
#defaultRequestPath = FaunaAPIPaths.QUERY; | ||
#defaultStreamPath = FaunaAPIPaths.STREAM; | ||
private constructor({ | ||
@@ -56,5 +60,5 @@ http2_session_idle_ms, | ||
/** | ||
* Gets a {@link NodeHTTP2Client} matching the {@link HTTTPClientOptions} | ||
* @param httpClientOptions - the {@link HTTTPClientOptions} | ||
* @returns a {@link NodeHTTP2Client} matching the {@link HTTTPClientOptions} | ||
* Gets a {@link NodeHTTP2Client} matching the {@link HTTPClientOptions} | ||
* @param httpClientOptions - the {@link HTTPClientOptions} | ||
* @returns a {@link NodeHTTP2Client} matching the {@link HTTPClientOptions} | ||
*/ | ||
@@ -80,3 +84,3 @@ static getClient(httpClientOptions: HTTPClientOptions): NodeHTTP2Client { | ||
/** {@inheritDoc HTTPClient.request} */ | ||
async request(req: HTTPRequest): Promise<HTTPResponse> { | ||
async request<T = QueryRequest>(req: HTTPRequest<T>): Promise<HTTPResponse> { | ||
let retryCount = 0; | ||
@@ -151,3 +155,3 @@ let memoizedError: any; | ||
if (!this.#session || this.#session.closed || this.#session.destroyed) { | ||
const new_session: ClientHttp2Session = http2 | ||
const newSession: ClientHttp2Session = http2 | ||
.connect(this.#url, { | ||
@@ -159,7 +163,7 @@ peerMaxConcurrentStreams: this.#http2_max_streams, | ||
new_session.setTimeout(this.#http2_session_idle_ms, () => { | ||
newSession.setTimeout(this.#http2_session_idle_ms, () => { | ||
this.#closeForAll(); | ||
}); | ||
this.#session = new_session; | ||
this.#session = newSession; | ||
} | ||
@@ -169,3 +173,3 @@ return this.#session; | ||
#doRequest({ | ||
#doRequest<T = QueryRequest>({ | ||
client_timeout_ms, | ||
@@ -175,3 +179,4 @@ data: requestData, | ||
method, | ||
}: HTTPRequest): Promise<HTTPResponse> { | ||
path = this.#defaultRequestPath, | ||
}: HTTPRequest<T>): Promise<HTTPResponse> { | ||
return new Promise<HTTPResponse>((resolvePromise, rejectPromise) => { | ||
@@ -206,3 +211,3 @@ let req: ClientHttp2Stream; | ||
...requestHeaders, | ||
[http2.constants.HTTP2_HEADER_PATH]: "/query/1", | ||
[http2.constants.HTTP2_HEADER_PATH]: path, | ||
[http2.constants.HTTP2_HEADER_METHOD]: method, | ||
@@ -239,2 +244,3 @@ }; | ||
method, | ||
path = this.#defaultStreamPath, | ||
}: HTTPStreamRequest): StreamAdapter { | ||
@@ -311,3 +317,3 @@ let resolveChunk: (chunk: string[]) => void; | ||
...requestHeaders, | ||
[http2.constants.HTTP2_HEADER_PATH]: "/stream/1", | ||
[http2.constants.HTTP2_HEADER_PATH]: path, | ||
[http2.constants.HTTP2_HEADER_METHOD]: method, | ||
@@ -314,0 +320,0 @@ }; |
@@ -1,2 +0,2 @@ | ||
export { Client, StreamClient } from "./client"; | ||
export { Client, StreamClient, FeedClient } from "./client"; | ||
export { | ||
@@ -7,2 +7,3 @@ endpoints, | ||
type StreamClientConfiguration, | ||
type FeedClientConfiguration, | ||
} from "./client-configuration"; | ||
@@ -28,7 +29,23 @@ export { | ||
} from "./errors"; | ||
export { type Query, type QueryArgument, fql } from "./query-builder"; | ||
export { LONG_MAX, LONG_MIN, TaggedTypeFormat } from "./tagged-type"; | ||
export { | ||
type QueryValueObject, | ||
type QueryValue, | ||
fql, | ||
type Query, | ||
type QueryArgument, | ||
type QueryArgumentObject, | ||
} from "./query-builder"; | ||
export { | ||
DecodeOptions, | ||
LONG_MAX, | ||
LONG_MIN, | ||
TaggedTypeFormat, | ||
} from "./tagged-type"; | ||
export { | ||
type ArrayFragment, | ||
type ConstraintFailure, | ||
type EncodedObject, | ||
type FeedError, | ||
type FeedRequest, | ||
type FeedSuccess, | ||
type FQLFragment, | ||
type ObjectFragment, | ||
type QueryFailure, | ||
@@ -41,3 +58,20 @@ type QueryInfo, | ||
type QuerySuccess, | ||
type QueryValue, | ||
type QueryValueObject, | ||
type Span, | ||
type StreamEventData, | ||
type StreamEventError, | ||
type StreamEventStatus, | ||
type StreamRequest, | ||
type TaggedBytes, | ||
type TaggedDate, | ||
type TaggedDouble, | ||
type TaggedInt, | ||
type TaggedLong, | ||
type TaggedMod, | ||
type TaggedObject, | ||
type TaggedRef, | ||
type TaggedTime, | ||
type TaggedType, | ||
type ValueFormat, | ||
type ValueFragment, | ||
@@ -50,2 +84,3 @@ } from "./wire-protocol"; | ||
EmbeddedSet, | ||
FlattenedSetIterator, | ||
Module, | ||
@@ -59,10 +94,16 @@ NamedDocument, | ||
TimeStub, | ||
FeedPage, | ||
type EventSource, | ||
type DocumentT, | ||
} from "./values"; | ||
export { | ||
FaunaAPIPaths, | ||
FetchClient, | ||
getDefaultHTTPClient, | ||
HTTPClientOptions, | ||
HTTPStreamRequest, | ||
isHTTPResponse, | ||
isStreamClient, | ||
NodeHTTP2Client, | ||
SupportedFaunaAPIPaths, | ||
type HTTPClient, | ||
@@ -69,0 +110,0 @@ type HTTPRequest, |
@@ -35,3 +35,3 @@ import { TaggedTypeFormat } from "./tagged-type"; | ||
* @typeParam T - The expected type of the response from Fauna when evaluated. | ||
* @param queryFragments - a {@link TemplateStringsArray} that constitute | ||
* @param queryFragments - An array that constitutes | ||
* the strings that are the basis of the query. | ||
@@ -38,0 +38,0 @@ * @param queryArgs - an Array\<QueryValue | Query\> that |
//THIS FILE IS AUTOGENERATED. DO NOT EDIT. SEE .husky/pre-commit | ||
/** The current package version. */ | ||
export const packageVersion = "2.2.0"; | ||
export const packageVersion = "2.3.0"; |
@@ -71,3 +71,3 @@ import { Client } from "../client"; | ||
initial: Page<T> | EmbeddedSet | (() => Promise<T | Page<T> | EmbeddedSet>), | ||
options?: QueryOptions | ||
options?: QueryOptions, | ||
) { | ||
@@ -82,4 +82,4 @@ options = options ?? {}; | ||
`Expected 'Page<T> | EmbeddedSet | (() => Promise<T | Page<T> | EmbeddedSet>)', but received ${JSON.stringify( | ||
initial | ||
)}` | ||
initial, | ||
)}`, | ||
); | ||
@@ -98,3 +98,3 @@ } | ||
query: Query, | ||
options?: QueryOptions | ||
options?: QueryOptions, | ||
): SetIterator<T> { | ||
@@ -106,7 +106,7 @@ return new SetIterator<T>( | ||
query, | ||
options | ||
options, | ||
); | ||
return response.data; | ||
}, | ||
options | ||
options, | ||
); | ||
@@ -125,3 +125,3 @@ } | ||
pageable: Page<T> | EmbeddedSet, | ||
options?: QueryOptions | ||
options?: QueryOptions, | ||
): SetIterator<T> { | ||
@@ -140,3 +140,5 @@ return new SetIterator<T>(client, pageable, options); | ||
/** Implement {@link AsyncGenerator.next} */ | ||
/** Implement | ||
* {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/AsyncGenerator/next| AsyncGenerator.next} | ||
* */ | ||
async next(): Promise<IteratorResult<T[], void>> { | ||
@@ -146,3 +148,5 @@ return this.#generator.next(); | ||
/** Implement {@link AsyncGenerator.return} */ | ||
/** Implement | ||
* {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/AsyncGenerator/return| AsyncGenerator.return} | ||
* */ | ||
async return(): Promise<IteratorResult<T[], void>> { | ||
@@ -152,3 +156,5 @@ return this.#generator.return(); | ||
/** Implement {@link AsyncGenerator.throw} */ | ||
/** Implement | ||
* {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/AsyncGenerator/throw| AsyncGenerator.throw} | ||
* */ | ||
async throw(e: any): Promise<IteratorResult<T[], void>> { | ||
@@ -158,3 +164,5 @@ return this.#generator.throw(e); | ||
/** Implement {@link AsyncGenerator} */ | ||
/** Implement | ||
* {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/AsyncGenerator| AsyncGenerator} | ||
* */ | ||
[Symbol.asyncIterator]() { | ||
@@ -190,3 +198,5 @@ return this; | ||
/** Implement {@link AsyncGenerator.next} */ | ||
/** Implement | ||
* {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/AsyncGenerator/next| AsyncGenerator.next} | ||
* */ | ||
async next(): Promise<IteratorResult<T, void>> { | ||
@@ -196,3 +206,5 @@ return this.#generator.next(); | ||
/** Implement {@link AsyncGenerator.return} */ | ||
/** Implement | ||
* {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/AsyncGenerator/return| AsyncGenerator.return} | ||
* */ | ||
async return(): Promise<IteratorResult<T, void>> { | ||
@@ -202,3 +214,5 @@ return this.#generator.return(); | ||
/** Implement {@link AsyncGenerator.throw} */ | ||
/** Implement | ||
* {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/AsyncGenerator/throw| AsyncGenerator.throw} | ||
* */ | ||
async throw(e: any): Promise<IteratorResult<T, void>> { | ||
@@ -208,3 +222,5 @@ return this.#generator.throw(e); | ||
/** Implement {@link AsyncGenerator} */ | ||
/** Implement | ||
* {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/AsyncGenerator| AsyncGenerator} | ||
* */ | ||
[Symbol.asyncIterator]() { | ||
@@ -222,3 +238,3 @@ return this; | ||
initial: Page<T> | EmbeddedSet, | ||
options: QueryOptions | ||
options: QueryOptions, | ||
): AsyncGenerator<T[], void, unknown> { | ||
@@ -250,3 +266,3 @@ let currentPage = initial; | ||
thunk: () => Promise<T | Page<T> | EmbeddedSet>, | ||
options: QueryOptions | ||
options: QueryOptions, | ||
): AsyncGenerator<T[], void, unknown> { | ||
@@ -259,3 +275,3 @@ const result = await thunk(); | ||
result as Page<T> | EmbeddedSet, | ||
options | ||
options, | ||
)) { | ||
@@ -274,3 +290,3 @@ yield page; | ||
async function* generateItems<T extends QueryValue>( | ||
setIterator: SetIterator<T> | ||
setIterator: SetIterator<T>, | ||
) { | ||
@@ -277,0 +293,0 @@ for await (const page of setIterator) { |
@@ -0,5 +1,13 @@ | ||
import { | ||
FeedSuccess, | ||
QueryValue, | ||
StreamEventData, | ||
QueryStats, | ||
} from "../wire-protocol"; | ||
import { getServiceError } from "../errors"; | ||
/** | ||
* A token used to initiate a Fauna stream at a particular snapshot in time. | ||
* A token used to initiate a Fauna event source at a particular snapshot in time. | ||
* | ||
* The example below shows how to request a stream token from Fauna and use it | ||
* The example below shows how to request an event token from Fauna and use it | ||
* to establish an event steam. | ||
@@ -12,5 +20,5 @@ * | ||
* `); | ||
* const token = response.data; | ||
* const eventSource = response.data; | ||
* | ||
* const stream = client.stream(token) | ||
* const stream = client.stream(eventSource) | ||
* .on("add", (event) => console.log("New message", event)) | ||
@@ -21,5 +29,17 @@ * | ||
*/ | ||
export class StreamToken { | ||
export interface EventSource { | ||
readonly token: string; | ||
} | ||
export function isEventSource(value: any): value is EventSource { | ||
if (typeof value.token === "string") { | ||
return true; | ||
} | ||
return false; | ||
} | ||
export class StreamToken implements EventSource { | ||
readonly token: string; | ||
constructor(token: string) { | ||
@@ -29,1 +49,33 @@ this.token = token; | ||
} | ||
/** | ||
* A class to represent a page of events from a Fauna stream. | ||
*/ | ||
export class FeedPage<T extends QueryValue> { | ||
readonly events: IterableIterator<StreamEventData<T>>; | ||
readonly cursor: string; | ||
readonly hasNext: boolean; | ||
readonly stats?: QueryStats; | ||
constructor({ events, cursor, has_next, stats }: FeedSuccess<T>) { | ||
this.events = this.#toEventIterator(events); | ||
this.cursor = cursor; | ||
this.hasNext = has_next; | ||
this.stats = stats; | ||
} | ||
*#toEventIterator( | ||
events: FeedSuccess<T>["events"], | ||
): IterableIterator<StreamEventData<T>> { | ||
// A page of events may contain an error event. These won't be reported | ||
// at a response level, so we need to check for them here. They are | ||
// considered fatal. Pages end at the first error event. | ||
for (const event of events) { | ||
if (event.type === "error") { | ||
throw getServiceError(event); | ||
} | ||
yield event; | ||
} | ||
} | ||
} |
@@ -1,3 +0,2 @@ | ||
// eslint-disable-next-line @typescript-eslint/no-unused-vars | ||
import { fql, QueryArgumentObject } from "./query-builder"; | ||
import { QueryArgumentObject } from "./query-builder"; | ||
import { | ||
@@ -137,2 +136,7 @@ DateStub, | ||
attempts: number; | ||
/** | ||
* A list of rate limits hit. | ||
* Included with QueryFailure responses when the query is rate limited. | ||
*/ | ||
rate_limits_hit?: ("read" | "write" | "compute")[]; | ||
}; | ||
@@ -386,2 +390,3 @@ | ||
start_ts?: number; | ||
cursor?: string; | ||
}; | ||
@@ -393,2 +398,3 @@ | ||
txn_ts: number; | ||
cursor: string; | ||
stats: QueryStats; | ||
@@ -399,2 +405,3 @@ }; | ||
txn_ts: number; | ||
cursor: string; | ||
stats: QueryStats; | ||
@@ -409,2 +416,15 @@ data: T; | ||
export type FeedRequest = StreamRequest & { | ||
page_size?: number; | ||
}; | ||
export type FeedSuccess<T extends QueryValue> = { | ||
events: (StreamEventData<T> | StreamEventError)[]; | ||
cursor: string; | ||
has_next: boolean; | ||
stats?: QueryStats; | ||
}; | ||
export type FeedError = QueryFailure; | ||
export type TaggedBytes = { "@bytes": string }; | ||
@@ -411,0 +431,0 @@ export type TaggedDate = { "@date": string }; |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
741932
49
8744
757
19