@veltdev/sdk-dev 6.0.16-beta.1 → 6.0.17-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/app/models/element/comment-element.model.d.ts +25 -0
- package/app/utils/constants.d.ts +7 -0
- package/{chunk-L5SOVVIR.js → chunk-2BXOD5Z7.js} +1 -1
- package/{chunk-CSN6ATAA.js → chunk-44HAZKIE.js} +1 -1
- package/{chunk-HALPIS6O.js → chunk-5H4ODM5U.js} +1 -1
- package/chunk-5ZUX3AU3.js +1 -0
- package/{chunk-KBXVJ2AO.js → chunk-6P3LPEPY.js} +1 -1
- package/chunk-A52PJCIA.js +1 -0
- package/{chunk-TJT3IIS7.js → chunk-AWSU4IMS.js} +1 -1
- package/chunk-B3U3OLF6.js +1 -0
- package/{chunk-O3CLK76M.js → chunk-BB2UXAYE.js} +1 -1
- package/chunk-BTNNHMUJ.js +1 -0
- package/{chunk-PHGOP6XJ.js → chunk-CYAQOX2W.js} +1 -1
- package/{chunk-LUXKOQSC.js → chunk-D24LAR5L.js} +1 -1
- package/{chunk-TAOBMSMM.js → chunk-DFQFM4NV.js} +1 -1
- package/chunk-EPQLN2EE.js +1 -0
- package/{chunk-H57PY57T.js → chunk-F5REFWTQ.js} +1 -1
- package/{chunk-HRU6STNE.js → chunk-FEA5HRMI.js} +1 -1
- package/{chunk-ZSCDUVYV.js → chunk-FFTR7QJM.js} +1 -1
- package/{chunk-U4L2FEIW.js → chunk-FPEVLQAP.js} +1 -1
- package/{chunk-FS6KTSNQ.js → chunk-HEFEC6O6.js} +1 -1
- package/{chunk-2XFRSBAE.js → chunk-IUD3QEEM.js} +1 -1
- package/{chunk-NM32S6ZH.js → chunk-KHL24R7O.js} +1 -1
- package/{chunk-LTKCIADR.js → chunk-LEIUFK3K.js} +1 -1
- package/{chunk-SC3WVEMZ.js → chunk-MVVXZ2D6.js} +1 -1
- package/{chunk-C7NBAS5V.js → chunk-ND3RYLBW.js} +1 -1
- package/{chunk-FWPOKU7S.js → chunk-NSGBIR4C.js} +2 -2
- package/{chunk-CEZ7IT67.js → chunk-OLHFUO6O.js} +1 -1
- package/{chunk-XCOVQJPR.js → chunk-QZ5UHEP2.js} +1 -1
- package/{chunk-OBDK4TJR.js → chunk-RGBU7P5H.js} +1 -1
- package/{chunk-DEQNXKWW.js → chunk-SKNIB72F.js} +1 -1
- package/chunk-SMANT45B.js +1 -0
- package/chunk-TAGMM5ED.js +174 -0
- package/{chunk-3MNQES2P.js → chunk-UCURXRPI.js} +1 -1
- package/{chunk-OCCE2UTF.js → chunk-VECW5ME3.js} +1 -1
- package/{chunk-6HNU2FG2.js → chunk-XZD6KKXD.js} +1 -1
- package/{chunk-YNFDUIYD.js → chunk-ZPO5AK7X.js} +1 -1
- package/package.json +1 -1
- package/velt-activity-log.js +1 -1
- package/velt-area.js +1 -1
- package/velt-arrow.js +2 -2
- package/velt-comment.js +6 -6
- package/velt-crdt.js +1 -1
- package/velt-cursor.js +2 -2
- package/velt-huddle.js +1 -1
- package/velt-live-state-sync.js +1 -1
- package/velt-notification.js +1 -1
- package/velt-portable.js +1 -1
- package/velt-presence.js +1 -1
- package/velt-reaction.js +1 -1
- package/velt-recorder.js +1 -1
- package/velt-rewriter.js +3 -3
- package/velt-selection.js +1 -1
- package/velt-tag.js +1 -1
- package/velt-user-invite.js +1 -1
- package/velt-user-request.js +1 -1
- package/velt-video-player.js +1 -1
- package/velt-views.js +2 -2
- package/velt.js +3 -3
- package/chunk-FUR2EFO6.js +0 -1
- package/chunk-GUHU4CU5.js +0 -1
- package/chunk-H6ZQEQFJ.js +0 -1
- package/chunk-I6ELSCG4.js +0 -1
- package/chunk-RV7ZJ7J2.js +0 -174
- package/chunk-VOMZ73T5.js +0 -1
package/velt-portable.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{$i as T,Vi as W,Yd as o,Zi as O,_i as p,a as b,aj as M,c as _,g as m,l as C,qj as q,sj as L}from"./chunk-RV7ZJ7J2.js";var B=["hello","subscribe","unsubscribe","publish","presence","onDisconnect","onDisconnectCancel","ping"],H=["welcome","snapshot","delta","result","error","pong"],J=[...B,...H],y=3e4,D=2,k=2e4,I=1e3,N=3e4,x=1;function v(i){if(typeof i!="string")return NaN;let e=Number(i.split(".")[0]);return Number.isInteger(e)?e:NaN}function g(i){try{let e=i.apiKey??"",s=i.instanceId?`${i.feature}/${i.instanceId}`:i.feature;switch(i.scope){case"doc":return`${e}:${i.organizationId??""}:doc:${i.documentId??""}:${s}`;case"user":return i.organizationId?`${e}:${i.organizationId}:user:${i.userIdHash??""}:${s}`:`${e}:user:${i.userIdHash??""}:${s}`;case"org":return`${e}:${i.organizationId??""}:${s}`;default:return`${e}:${s}`}}catch(e){return o.catch("Error in buildPortableWireKey: ",e),`${i?.apiKey??""}:${i?.feature??""}`}}var V={presence:"updatePresence",liveState:"publishLiveState",cursor:"updateCursor",selection:"updateSelection",huddle:"updateHuddle",syncVideoPlayer:"updateSyncVideoPlayer",flockSession:"updateFlock"};function U(i,e){if(i==="crdt"){let s=e?.uptoSeq;return Number.isInteger(s)?"writeCrdtSnapshot":"writeCrdtUpdate"}return V[i]}var P=class{constructor(e){this.session=e}whenReady(){return new Promise(e=>{try{let s=!1,t=null,n=null,r=()=>{s||(s=!0,n!==null&&(clearTimeout(n),n=null),setTimeout(()=>{try{t?.unsubscribe()}catch{}},0),e())};n=setTimeout(r,k),t=this.session.getAuthState$().subscribe(a=>{a?.signedIn&&r()})}catch(s){o.catch("Error in PortableRealtimeAdapter whenReady: ",s),e()}})}subscribe(e,s,t,n){try{let r=this.session.getTransport();if(!r)return{unsubscribe:()=>{}};let a=g(e),l=!1,c=r.subscribeChannel(a,s,d=>{try{if(d.kind==="denied"){o.catch(`Velt [portable backend]: subscribe denied on channel ${a}: ${d.code??"unknown"}${L(d)}`,b({ok:!1,code:d.code},d.reasonCode?{reasonCode:d.reasonCode}:{})),n?.onError&&!l&&(l=!0,n.onError(d.code??"permission-denied"));return}if(d.kind==="delta"){t({type:d.change??"modified",id:d.id??"",data:d.data,seq:d.seq});return}if(d.kind==="snapshot-end"){n?.onSnapshotComplete?.();return}t({type:"added",id:d.id??"",data:d.data})}catch(h){o.catch("Error in PortableRealtimeAdapter subscribe callback: ",h)}},n?.since);return{unsubscribe:()=>c.unsubscribe()}}catch(r){return o.catch("Error in PortableRealtimeAdapter subscribe: ",r),{unsubscribe:()=>{}}}}publish(e,s,t){try{let n=U(e.feature,t);if(!n)return Promise.resolve({ok:!1,code:"unimplemented",message:`no realtime publish operation for feature '${e.feature}'`});let r=this.session.getTransport();return r?r.request("publish",g(e),n,t):Promise.resolve({ok:!1,code:"failed-precondition",message:"portable transport not connected"})}catch(n){return o.catch("Error in PortableRealtimeAdapter publish: ",n),Promise.resolve({ok:!1,code:"failed-precondition"})}}presence(e,s){try{let t=this.session.getTransport();return t?t.request("presence",g(e),"updatePresence",s):Promise.resolve({ok:!1,code:"failed-precondition",message:"portable transport not connected"})}catch(t){return o.catch("Error in PortableRealtimeAdapter presence: ",t),Promise.resolve({ok:!1,code:"failed-precondition"})}}onDisconnect(e,s){return m(this,null,function*(){try{let t=this.session.getTransport();return t?yield t.registerOnDisconnect(g(e),s):()=>{}}catch(t){return o.catch("Error in PortableRealtimeAdapter onDisconnect: ",t),()=>{}}})}getServerTimeOffset(){try{return Promise.resolve(this.session.getTransport()?.getServerTimeOffset()??0)}catch(e){return o.catch("Error in PortableRealtimeAdapter getServerTimeOffset: ",e),Promise.resolve(0)}}onServerTimeOffset(e){try{return this.session.getTransport()?.onServerTimeOffset(e)??(()=>{})}catch(s){return o.catch("Error in PortableRealtimeAdapter onServerTimeOffset: ",s),()=>{}}}};var S=class{constructor(e,s){this.rest=e,this.session=s}read(e){return m(this,null,function*(){let s=yield this.rest.call("read",e);return s.ok?{data:s.data}:{data:void 0,errorCode:s.code}})}runTransaction(e){return e()}op(e,s){if(s&&typeof s=="object"&&"channel"in s){let t=s,{channel:n}=t,r=_(t,["channel"]);return this.rest.call(e,r)}return this.rest.call(e,s)}publishOp(e,s,t){if(!s.channel)return Promise.resolve({ok:!1,code:"failed-precondition",message:`portable publish op '${e}' requires a channel on the OperationRequest`});let n=this.session?.getTransport();return n?n.request("publish",g(s.channel),e,t):Promise.resolve({ok:!1,code:"failed-precondition",message:"portable transport not connected"})}notificationWirePayload(e,s){let t=e.resourceId??(typeof e.data?.notificationId=="string"?e.data.notificationId:void 0),n={};if(t!=null&&String(t).length>0&&(n.notificationId=String(t)),s&&e.data!==void 0){let r=e.data;r&&typeof r=="object"&&r.data!==void 0&&r.notificationId!==void 0?n.data=r.data:n.data=e.data}return n}annotationWirePayload(e,s,t=!1){let n=e.resourceId??(typeof e.data?.annotationId=="string"?e.data.annotationId:void 0),r={};return n!=null&&String(n).length>0&&(r.annotationId=String(n)),s&&e.data!==void 0&&(r.data=e.data),t&&e.notificationData!==void 0&&(r.notificationData=e.notificationData),r}addComment(e){return this.publishOp("addComment",e,this.annotationWirePayload(e,!0,!0))}editComment(e){return this.publishOp("editComment",e,this.annotationWirePayload(e,!0))}deleteComment(e){return this.publishOp("deleteComment",e,this.annotationWirePayload(e,!1))}addReaction(e){return this.publishOp("addReaction",e,this.annotationWirePayload(e,!0))}editReaction(e){return this.publishOp("editReaction",e,this.annotationWirePayload(e,!0))}deleteReaction(e){return this.publishOp("deleteReaction",e,this.annotationWirePayload(e,!1))}recordDocumentView(e){return this.publishOp("recordDocumentView",e,{})}getActivitiesForDocuments(e){return this.rest.call("getActivitiesForDocuments",e.data)}getActivitiesForEntity(e){return this.rest.call("getActivitiesForEntity",e.data)}setCommentResolved(e){return this.op("setCommentResolved",e)}setCommentMetadata(e){return this.op("setCommentMetadata",e)}bumpCommentViews(e){return this.op("bumpCommentViews",e)}markCommentThreadRead(e){return this.publishOp("markCommentThreadRead",e,this.notificationWirePayload(e,!1))}markNotificationRead(e){return this.publishOp("markNotificationRead",e,this.notificationWirePayload(e,!1))}addNotification(e){return this.op("addNotification",e)}deleteNotification(e){return this.publishOp("deleteNotification",e,this.notificationWirePayload(e,!1))}updateNotification(e){return this.publishOp("updateNotification",e,this.notificationWirePayload(e,!0))}updatePresence(e){return this.op("updatePresence",e)}grantAccess(e){return this.op("grantAccess",e)}revokeAccess(e){return this.rest.call("revokeAccess",{data:e.data})}getAccess(e){return this.rest.call("getAccess",{data:e.data})}upsertOrgUserProfile(e){return this.rest.call("addUserInfoToOrganization",e.data)}upsertDocMetadata(e){return this.op("upsertDocMetadata",e)}upsertOrgMetadata(e){return this.op("upsertOrgMetadata",e)}createActivity(e){return this.rest.call("createActivity",e.data)}};var K={fetch:(i,e)=>fetch(i,e)},F={400:"invalid-argument",401:"unauthenticated",403:"permission-denied",404:"not-found",412:"failed-precondition",429:"resource-exhausted"};function j(i){return!!i&&typeof i=="object"&&typeof i.ok=="boolean"}var w=class{constructor(e){this.session=e,this.insecureEndpointReported=new Set}call(e,s){return m(this,null,function*(){try{let t=this.session.getApiEndpoint(),n=this.session.getToken();if(!t||!n)return{ok:!1,code:"failed-precondition",message:"portable session not established"};if(!W(t))return this.insecureEndpointReported.has(t)||(this.insecureEndpointReported.add(t),console.error(`Velt [portable backend]: refusing to send the session token to insecure apiEndpoint '${t}' (https required; http is loopback-only). Portable REST operations are disabled until identify returns a secure endpoint.`)),{ok:!1,code:"failed-precondition",message:"portable apiEndpoint is not a secure URL; request not sent"};let r=yield K.fetch(`${t}/operations/${e}`,{method:"POST",headers:{Authorization:`Bearer ${n}`,"Content-Type":"application/json"},body:JSON.stringify(s??{})}),a;try{a=yield r.json()}catch{a=void 0}if(j(a)){if(a.ok)return r.ok?a:{ok:!1,code:F[r.status]??"permission-denied",message:`HTTP ${r.status} on operation '${e}' contradicted an ok:true envelope`};let c=a.code;return c&&M.includes(c)?a:{ok:!1,code:"permission-denied",message:`unrecognized denial code '${c}'`}}return r.ok?{ok:!0,data:a}:{ok:!1,code:F[r.status]??"permission-denied",message:`HTTP ${r.status} on operation '${e}'`}}catch(t){return o.catch(`Error in PortableRestClient call '${e}': `,t),{ok:!1,code:"permission-denied",message:"portable operation request failed"}}})}};function z(i){if(!i)return!1;try{let e=new URL(i);return e.protocol==="wss:"?!0:e.protocol==="ws:"&&["localhost","127.0.0.1","[::1]"].includes(e.hostname)}catch{return!1}}var E=class{constructor(e){this.transportFactory=e,this.token=null,this.wsEndpoint=null,this.apiEndpoint=null,this.transport=null,this.authState$=new C(null),this.nullTokenWarned=!1,this.insecureEndpointWarned=!1,this.offOffset=null,this.offTerminal=null}establish(e){try{if(!e)return;if(this.wsEndpoint=e.wsEndpoint??null,this.apiEndpoint=e.apiEndpoint??null,this.token=typeof e.token=="string"&&e.token.length>0?e.token:null,!this.token){this.transport&&this.teardown(),this.nullTokenWarned||(this.nullTokenWarned=!0,console.warn("Velt [portable backend]: identify() returned no session token (token: null). Portable transport will not connect on this page load; portable features are disabled."));return}if(!z(this.wsEndpoint)){this.transport&&this.teardown(),this.insecureEndpointWarned||(this.insecureEndpointWarned=!0,console.warn("Velt [portable backend]: refusing to connect to a non-wss:// gateway endpoint ("+this.wsEndpoint+"). The session token would travel in cleartext; portable features are disabled. (Plain ws:// is permitted for localhost only.)"));return}this.transport||(this.transport=this.transportFactory(this),this.offOffset=this.transport.onServerTimeOffset(()=>{this.authState$.value?.signedIn||this.authState$.next({signedIn:!0})}),this.offTerminal=this.transport.onTerminal(()=>{this.authState$.value!==null&&this.authState$.next(null)})),this.transport.connect()}catch(s){o.catch("Error in PortableSession establish: ",s)}}refreshToken(e){try{if(typeof e!="string"||!e.length)return;this.token=e,this.transport?.refreshAuth()}catch(s){o.catch("Error in PortableSession refreshToken: ",s)}}teardown(){try{this.offOffset?.(),this.offOffset=null,this.offTerminal?.(),this.offTerminal=null,this.transport?.close(),this.transport=null,this.authState$.value!==null&&this.authState$.next(null)}catch(e){o.catch("Error in PortableSession teardown: ",e)}}getToken(){return this.token}getWsEndpoint(){return this.wsEndpoint}getApiEndpoint(){return this.apiEndpoint}getTransport(){return this.transport}getAuthState$(){return this.authState$.asObservable()}};var f=1,R=class{constructor(e){this.deps=e,this.state="idle",this.socket=null,this.channels=new Map,this.pendingRequests=new Map,this.nextRequestId=1,this.serverTimeOffsetMs=0,this.offsetListeners=new Set,this.lastInboundAtMs=0,this.heartbeatTimer=null,this.pongDeadlineTimer=null,this.reconnectTimer=null,this.reconnectAttempts=0,this.authRecoveryAttempts=0,this.terminalListeners=new Set}onTerminal(e){return this.terminalListeners.add(e),()=>{this.terminalListeners.delete(e)}}notifyTerminal(e){this.terminalListeners.forEach(s=>{try{s(e)}catch(t){o.catch("Error in PortableWsTransport terminal listener: ",t)}})}getState(){return this.state}connect(){try{if(this.state==="connecting"||this.state==="open"||this.state==="reauthing"||this.state==="unsupported")return;let e=this.deps.getUrl(),s=this.deps.getToken();if(!e||!s)return;this.state="connecting";let t=this.deps.wsFactory(e);this.socket=t,t.onopen=()=>this.onSocketOpen(t),t.onmessage=n=>this.onFrame(t,n.data),t.onclose=()=>this.onSocketClosed(t),t.onerror=()=>{}}catch(e){o.catch("Error in PortableWsTransport connect: ",e)}}close(){try{this.state="closed",this.notifyTerminal("closed"),this.clearTimers();let e=this.socket;this.socket=null,e&&e.readyState<=f&&e.close(1e3,"client close"),this.failPendingRequests()}catch(e){o.catch("Error in PortableWsTransport close: ",e)}}checkLivenessOnResume(e=y*2){try{if(this.state!=="open"&&this.state!=="reauthing")return;let s=this.lastInboundAtMs?this.now()-this.lastInboundAtMs:Number.POSITIVE_INFINITY;if(s<=e)return;p("liveness.stale-on-resume",`silentFor=${Math.round(s/1e3)}s state=${this.state}`),T("the realtime connection was silent while the tab was in the background","Nothing had been received for longer than two heartbeats when this tab came back, so the connection is treated as dead and re-established. Data shown before this point may have been stale \u2014 the UI keeps what it already had, so this is invisible without this message."),this.handleDeadSocket()}catch(s){o.catch("Error in PortableWsTransport checkLivenessOnResume: ",s)}}refreshAuth(){try{if(this.state==="open"&&this.socket&&this.socket.readyState===f){this.state="reauthing",this.sendHello();return}(this.state==="closed"||this.state==="idle")&&(this.state="idle",this.connect())}catch(e){o.catch("Error in PortableWsTransport refreshAuth: ",e)}}subscribeChannel(e,s,t,n){let r=this.ensureChannel(e,s),a={onEvent:t,active:!0};if(r.subscribers.add(a),r.lastSeq===void 0&&typeof n=="number"&&(r.lastSeq=n),r.hasState){for(let[l,c]of r.lastKnown)try{a.onEvent({kind:"snapshot-item",id:l,data:c})}catch(d){o.catch("Error in PortableWsTransport cached-state replay: ",d)}try{a.onEvent({kind:"snapshot-end"})}catch(l){o.catch("Error in PortableWsTransport cached-state snapshot-end: ",l)}}return this.wireSubscribeIfNeeded(e,r),{unsubscribe:()=>{try{if(!a.active)return;a.active=!1,r.subscribers.delete(a),r.subscribers.size===0&&(this.clearSnapshotWatchdog(r),this.channels.delete(e),r.wired&&this.socket&&this.socket.readyState===f&&this.sendFrame({type:"unsubscribe",channel:e,requestId:`r${this.nextRequestId++}`}))}catch(l){o.catch("Error in PortableWsTransport unsubscribe: ",l)}}}}request(e,s,t,n){try{if(this.state!=="open"&&this.state!=="reauthing")return Promise.resolve({ok:!1,code:"failed-precondition",message:"portable transport not connected"});let r=`r${this.nextRequestId++}`,a=new Promise(d=>{this.pendingRequests.set(r,d)}),l={type:e,channel:s,op:t,requestId:r};e==="presence"?l.state=n:l.payload=n;let c=!1;try{c=this.sendFrame(l)}catch(d){throw this.pendingRequests.delete(r),d}return c?a:(this.pendingRequests.delete(r),Promise.resolve({ok:!1,code:"failed-precondition",message:"portable transport not connected"}))}catch(r){return o.catch("Error in PortableWsTransport request: ",r),Promise.resolve({ok:!1,code:"failed-precondition",message:"portable transport send failed"})}}registerOnDisconnect(e,s){return m(this,null,function*(){if(this.state!=="open"&&this.state!=="reauthing")return()=>{};let t=`r${this.nextRequestId++}`,n=new Promise(c=>{this.pendingRequests.set(t,c)}),r=!1;try{r=this.sendFrame({type:"onDisconnect",channel:e,cleanup:s,requestId:t})}catch(c){return this.pendingRequests.delete(t),o.catch("Error in PortableWsTransport registerOnDisconnect send: ",c),()=>{}}if(!r)return this.pendingRequests.delete(t),()=>{};let a=yield n,l=a.ok?a.id:void 0;return()=>{try{l&&this.socket&&this.socket.readyState===f&&this.sendFrame({type:"onDisconnectCancel",intentId:l,requestId:`r${this.nextRequestId++}`})}catch(c){o.catch("Error in PortableWsTransport onDisconnect cancel: ",c)}}})}getServerTimeOffset(){return this.serverTimeOffsetMs}onServerTimeOffset(e){return this.offsetListeners.add(e),()=>this.offsetListeners.delete(e)}now(){return this.deps.now?this.deps.now():Date.now()}ensureChannel(e,s){let t=this.channels.get(e);return t||(t={mode:s,subscribers:new Set,lastSeq:void 0,denied:!1,wired:!1,snapshotWatchdog:null,lastKnown:new Map,hasState:!1,resumeRequested:!1},this.channels.set(e,t)),t}wireSubscribeIfNeeded(e,s){if(s.wired||s.denied||this.state!=="open"&&this.state!=="reauthing"||!this.socket||this.socket.readyState!==f)return;let t={type:"subscribe",channel:e,mode:s.mode,requestId:`r${this.nextRequestId++}`};s.resumeRequested=!1,s.mode==="persistent"&&s.lastSeq!==void 0&&(t.since=s.lastSeq,s.resumeRequested=!0);try{s.wired=this.sendFrame(t),s.wired&&(p("channel.subscribe",`${e}${t.since!==void 0?" since="+t.since:" (full)"}`),this.armSnapshotWatchdog(e,s))}catch(n){o.catch("Error in PortableWsTransport wireSubscribeIfNeeded: ",n)}}sendHello(){this.sendFrame({type:"hello",protocolVersion:"1.0",token:this.deps.getToken(),capabilities:[]})}sendFrame(e){return!this.socket||this.socket.readyState!==f?!1:(this.socket.send(JSON.stringify(e)),!0)}onSocketOpen(e){e===this.socket&&(p("socket.open"),this.sendHello())}onWelcome(e){let s=v(e.protocolVersion),t=v("1.0");if(s!==t){this.state!=="unsupported"&&console.error(`Velt [portable backend]: gateway speaks WS protocol '${e.protocolVersion}' but this SDK speaks '${"1.0"}' (incompatible MAJOR). Portable features are disabled. Align the deployed gateway and SDK versions (see docs/self-hosting-portable-protocol.md).`),this.state="unsupported",this.notifyTerminal("unsupported"),this.clearTimers();try{this.socket?.close(1e3,"protocol-version")}catch{}this.socket=null;return}let n=this.state==="reauthing";if(p("handshake.welcome",`reauth=${n}`),this.state="open",this.reconnectAttempts=0,typeof e.serverTimeMs=="number"){this.serverTimeOffsetMs=e.serverTimeMs-this.now();for(let r of this.offsetListeners)try{r(this.serverTimeOffsetMs)}catch(a){o.catch("Error in PortableWsTransport offset listener: ",a)}}if(this.startHeartbeat(),!n)for(let[r,a]of this.channels)a.wired=!1,this.wireSubscribeIfNeeded(r,a)}onFrame(e,s){if(e!==this.socket)return;this.lastInboundAtMs=this.now();let t;try{t=JSON.parse(s)}catch{o.log("Velt [portable backend]: dropped unparseable WS frame");return}try{switch(t.type){case"welcome":this.onWelcome(t);return;case"pong":this.clearPongDeadline(),O("pong"),this.authRecoveryAttempts=0;return;case"delta":{let n=this.channels.get(t.channel);if(!n)return;typeof t.seq=="number"&&(n.lastSeq=t.seq),n.hasState=!0,t.change==="removed"?n.lastKnown.delete(t.id):t.id!==void 0&&n.lastKnown.set(t.id,t.data),this.emit(n,{kind:"delta",change:t.change,id:t.id,data:t.data,seq:t.seq});return}case"snapshot":{let n=this.channels.get(t.channel);if(!n)return;this.clearSnapshotWatchdog(n),p("channel.snapshot",`${t.channel} items=${Array.isArray(t.items)?t.items.length:"?"}${t.full?" full":""}${t.truncated?" truncated":""}`),typeof t.seq=="number"&&(n.lastSeq=t.seq);let r=Array.isArray(t.items)?t.items:[],a=t.truncated===!0,l=!a&&(t.full===!0||!n.resumeRequested);if(n.hasState=!0,a){for(let c of r)c?.id!==void 0&&n.lastKnown.set(c.id,c?.data),this.emit(n,{kind:"snapshot-item",id:c?.id,data:c?.data});this.emit(n,{kind:"snapshot-end"})}else if(l){let c=new Set;for(let h of r)h?.id!==void 0&&c.add(h.id);let d=[];for(let h of n.lastKnown.keys())c.has(h)||d.push(h);n.lastKnown.clear();for(let h of d)this.emit(n,{kind:"delta",change:"removed",id:h,data:void 0});for(let h of r)h?.id!==void 0&&n.lastKnown.set(h.id,h?.data),this.emit(n,{kind:"snapshot-item",id:h?.id,data:h?.data});this.emit(n,{kind:"snapshot-end"})}else{for(let c of r)c?.id!==void 0&&(c.data===void 0?(n.lastKnown.delete(c.id),this.emit(n,{kind:"delta",change:"removed",id:c.id,data:void 0})):(n.lastKnown.set(c.id,c.data),this.emit(n,{kind:"snapshot-item",id:c.id,data:c.data})));this.emit(n,{kind:"snapshot-end"})}return}case"result":{let n=this.pendingRequests.get(t.requestId);if(!n){o.log(`Velt [portable backend]: uncorrelated result frame (requestId ${t.requestId}, ok=${!!t.ok}${t.code?`, code=${t.code}`:""}) \u2014 no pending request. Expected for unsubscribe / onDisconnectCancel, which are fire-and-forget.`);return}this.pendingRequests.delete(t.requestId),t.ok?n(b({ok:!0,id:t.id,data:t.data},typeof t.seq=="number"?{seq:t.seq}:{})):n(b({ok:!1,code:t.code??"permission-denied",message:t.message},typeof t.reasonCode=="string"?{reasonCode:t.reasonCode}:{}));return}case"error":{let n=t.channel;if(n&&this.channels.has(n)){let r=this.channels.get(n);r.denied=!0,r.wired=!1,this.emit(r,{kind:"denied",code:t.code,reasonCode:t.reasonCode});return}if(t.requestId&&this.pendingRequests.has(t.requestId)){let r=this.pendingRequests.get(t.requestId);this.pendingRequests.delete(t.requestId),r(b({ok:!1,code:t.code??"permission-denied"},typeof t.reasonCode=="string"?{reasonCode:t.reasonCode}:{}));return}if(t.code==="unauthenticated"){if(this.state==="open"&&this.authRecoveryAttempts<x){this.authRecoveryAttempts++,console.warn("Velt [portable backend]: the gateway dropped an authenticated session (unauthenticated on a live connection). Reconnecting once to re-establish it."),this.clearHeartbeat();let a=this.socket;this.socket=null;try{a&&a.readyState<=f&&a.close(4401,"session-lost")}catch{}this.failPendingRequests(),this.markAllChannelsUnwired(),this.scheduleReconnect();return}console.warn("Velt [portable backend]: the gateway rejected authentication. Portable transport is fail-closed for this session; a fresh identify()/token is required to reconnect."),this.state="closed",this.notifyTerminal("closed"),this.clearTimers();let r=this.socket;this.socket=null;try{r&&r.readyState<=f&&r.close(4401,"unauthenticated")}catch{}this.failPendingRequests();return}return}default:return}}catch(n){o.catch("Error in PortableWsTransport onFrame: ",n)}}emit(e,s){for(let t of e.subscribers)if(t.active)try{t.onEvent(s)}catch(n){o.catch("Error in PortableWsTransport subscriber callback: ",n)}}onSocketClosed(e){p("socket.close",`stale=${e!==this.socket} state=${this.state}`),e===this.socket&&(this.socket=null,this.clearTimers(),this.failPendingRequests(),!(this.state==="closed"||this.state==="unsupported")&&(this.markAllChannelsUnwired(),this.scheduleReconnect()))}markAllChannelsUnwired(){for(let e of this.channels.values())e.wired=!1}failPendingRequests(){for(let[,e]of this.pendingRequests)e({ok:!1,code:"failed-precondition",message:"portable transport disconnected"});this.pendingRequests.clear()}scheduleReconnect(){if(this.reconnectTimer)return;this.state="reconnecting";let e=Math.min(N,I*Math.pow(2,this.reconnectAttempts)),s=Math.max(I,e*(.5+Math.random()*.5));this.reconnectAttempts++,this.reconnectTimer=setTimeout(()=>{this.reconnectTimer=null,this.state==="reconnecting"&&(this.state="idle",this.connect())},s)}startHeartbeat(){this.clearHeartbeat(),this.heartbeatTimer=setInterval(()=>{try{if(this.state!=="open"&&this.state!=="reauthing")return;if(!this.socket||this.socket.readyState!==f){p("socket.dead-without-close",`state=${this.state} readyState=${this.socket?this.socket.readyState:"no-socket"}`),T("the realtime socket stopped without reporting it (recovering)","The connection was closed by the browser or the network without delivering a close event \u2014 most often a backgrounded/frozen tab. The SDK is reconnecting; if realtime features stay stuck after this, the reconnect is the thing to look at."),this.handleDeadSocket();return}O("ping"),this.sendFrame({type:"ping"}),this.armPongDeadline()}catch(e){o.catch("Error in PortableWsTransport heartbeat: ",e)}},y)}handleDeadSocket(){try{let e=this.socket;this.socket=null,this.clearHeartbeat(),this.clearPongDeadline();try{e?.close(4e3,"socket dead without close event")}catch{}this.failPendingRequests(),this.markAllChannelsUnwired(),this.state!=="closed"&&this.state!=="unsupported"&&this.scheduleReconnect()}catch(e){o.catch("Error in PortableWsTransport handleDeadSocket: ",e)}}armSnapshotWatchdog(e,s){this.clearSnapshotWatchdog(s),s.snapshotWatchdog=setTimeout(()=>{s.snapshotWatchdog=null,p("channel.snapshot-missing",`${e} after ${k}ms`),T("a realtime channel was subscribed but never delivered its first snapshot","Anything waiting on that first emission \u2014 a sidebar skeleton, an empty comment list \u2014 will stay in its loading state. The trail below shows whether the socket handshook, whether the credential was refreshed, and how long the tab was away.",`snapshot-missing:${e}`)},k)}clearSnapshotWatchdog(e){e?.snapshotWatchdog&&(clearTimeout(e.snapshotWatchdog),e.snapshotWatchdog=null)}armPongDeadline(){this.pongDeadlineTimer||(this.pongDeadlineTimer=setTimeout(()=>{this.pongDeadlineTimer=null;let e=this.socket;this.socket=null,this.clearHeartbeat();try{e?.close(4e3,"pong timeout")}catch{}this.failPendingRequests();for(let s of this.channels.values())s.wired=!1;this.state!=="closed"&&this.state!=="unsupported"&&this.scheduleReconnect()},y*D))}clearPongDeadline(){this.pongDeadlineTimer&&(clearTimeout(this.pongDeadlineTimer),this.pongDeadlineTimer=null)}clearHeartbeat(){this.heartbeatTimer&&(clearInterval(this.heartbeatTimer),this.heartbeatTimer=null),this.clearPongDeadline()}clearTimers(){this.clearHeartbeat();for(let e of this.channels.values())this.clearSnapshotWatchdog(e);this.reconnectTimer&&(clearTimeout(this.reconnectTimer),this.reconnectTimer=null)}};var u=null,A=null;function Y(){try{u?.teardown()}catch{}}function Ae(){try{u?.getTransport()?.checkLivenessOnResume()}catch(i){o.catch("Error in checkPortableBackendLiveness: ",i)}}function Oe(){Y(),u=null,A=null}function G(i){let e=!u;if(u||(u=new E(s=>new R({wsFactory:t=>new WebSocket(t),getUrl:()=>s.getWsEndpoint(),getToken:()=>s.getToken()}))),i?.token&&u.getToken()&&u.getTransport()?u.refreshToken(i.token):u.establish(i),e){let s=new w(u);A={db:new S(s,u),realtime:new P(u)}}return A&&q(A),u}export{Ae as checkPortableBackendLiveness,G as default,Oe as resetPortableBackendEntryForTest,Y as teardownPortableBackend};
|
|
1
|
+
import{$i as H,Bj as V,Yd as a,a as p,b as k,c as B,dj as L,ej as h,fj as y,g,gj as U,l as F,zj as K}from"./chunk-TAGMM5ED.js";var he=["hello","subscribe","unsubscribe","publish","presence","onDisconnect","onDisconnectCancel","ping"],ue=["welcome","snapshot","delta","result","error","pong"],fe=["draining"],Oe=[...he,...ue,...fe],A=3e4,Y=2,E=2e4,S=1e3,q=3e4,z=1,P="ordered-deltas",j="shutting_down",G=new Set(["resource-exhausted"]),M=5,X=3e4,Q=6e4,J=5e3,Z=250,v=1e4,ee=3e4,te=256;function N(o){if(typeof o!="string")return NaN;let e=Number(o.split(".")[0]);return Number.isInteger(e)?e:NaN}function pe(o){let e=ie(o)?.apiKey;return typeof e=="string"&&e.length>0?e:null}function R(o){let e=ie(o),s=e?.apiKey,t=e?.userIdHash;return typeof s!="string"||!s.length||typeof t!="string"||!t.length?null:JSON.stringify([s,t])}function ie(o){try{if(typeof o!="string")return null;let e=o.split(".");if(e.length!==3||!e[1])return null;let s=e[1].replace(/-/g,"+").replace(/_/g,"/"),t=s+"=".repeat((4-s.length%4)%4),n=atob(t),r=new Uint8Array(n.length);for(let c=0;c<n.length;c++)r[c]=n.charCodeAt(c);let i=JSON.parse(new TextDecoder().decode(r));return i&&typeof i=="object"?i:null}catch{return null}}var se=null,ne=null,re=!1;function $(o){try{let e=o&&o===se?ne:pe(o);if(typeof o=="string"&&(se=o,ne=e),e)return e;re||(re=!0,a.catch("Velt [portable backend]: the session token carries no readable apiKey claim, so channel names use the API key from the SDK init. If the gateway names channels differently, subscriptions will not receive updates."));return}catch(e){a.catch("Error in resolvePortableChannelApiKey: ",e);return}}function W(o,e){try{let s=e||(o.apiKey??""),t=o.instanceId?`${o.feature}/${o.instanceId}`:o.feature;switch(o.scope){case"doc":return`${s}:${o.organizationId??""}:doc:${o.documentId??""}:${t}`;case"user":return o.organizationId?`${s}:${o.organizationId}:user:${o.userIdHash??""}:${t}`:`${s}:user:${o.userIdHash??""}:${t}`;case"org":return`${s}:${o.organizationId??""}:${t}`;default:return`${s}:${t}`}}catch(s){return a.catch("Error in buildPortableWireKey: ",s),`${e||(o?.apiKey??"")}:${o?.feature??""}`}}var me={presence:"updatePresence",liveState:"publishLiveState",cursor:"updateCursor",selection:"updateSelection",huddle:"updateHuddle",syncVideoPlayer:"updateSyncVideoPlayer",flockSession:"updateFlock"};function ge(o,e){if(o==="crdt"){let s=e?.uptoSeq;return Number.isInteger(s)?"writeCrdtSnapshot":"writeCrdtUpdate"}return me[o]}var w=class{constructor(e){this.session=e,this.foldDeferredLogged=!1}wireKey(e){return W(e,$(this.session.getToken()))}hasCapability(e){try{return this.session.getTransport()?.hasCapability(e)??!1}catch(s){return a.catch("Error in PortableRealtimeAdapter hasCapability: ",s),!1}}whenReady(){return new Promise(e=>{try{let s=!1,t=null,n=null,r=()=>{s||(s=!0,n!==null&&(clearTimeout(n),n=null),setTimeout(()=>{try{t?.unsubscribe()}catch{}},0),e())};n=setTimeout(r,E),t=this.session.getAuthState$().subscribe(i=>{i?.signedIn&&r()})}catch(s){a.catch("Error in PortableRealtimeAdapter whenReady: ",s),e()}})}subscribe(e,s,t,n){try{let r=this.session.getTransport();if(!r)return{unsubscribe:()=>{}};let i=this.wireKey(e),c=!1,d=r.subscribeChannel(i,s,l=>{try{if(l.kind==="denied"){a.catch(`Velt [portable backend]: subscribe denied on channel ${i}: ${l.code??"unknown"}${V(l)}`,p({ok:!1,code:l.code},l.reasonCode?{reasonCode:l.reasonCode}:{})),n?.onError&&!c&&(c=!0,n.onError(l.code??"permission-denied"));return}if(l.kind==="delta"){t(p({type:l.change??"modified",id:l.id??"",data:l.data,seq:l.seq},l.snapshot?{snapshot:l.snapshot}:{}));return}if(l.kind==="snapshot-end"){n?.onSnapshotComplete?.(k(p({},typeof l.seq=="number"?{seq:l.seq}:{}),{full:l.full===!0}));return}t(p({type:"added",id:l.id??"",data:l.data},l.snapshot?{snapshot:l.snapshot}:{}))}catch(m){a.catch("Error in PortableRealtimeAdapter subscribe callback: ",m)}},n?.since);return{unsubscribe:()=>d.unsubscribe()}}catch(r){return a.catch("Error in PortableRealtimeAdapter subscribe: ",r),{unsubscribe:()=>{}}}}publish(e,s,t){try{let n=ge(e.feature,t);if(!n)return Promise.resolve({ok:!1,code:"unimplemented",message:`no realtime publish operation for feature '${e.feature}'`});if(n==="writeCrdtSnapshot"&&!this.hasCapability(P))return this.foldDeferredLogged||(this.foldDeferredLogged=!0,a.log("Velt [portable backend]: crdt snapshot fold deferred \u2014 the gateway does not announce ordered-deltas on this connection (compaction pauses; content is unaffected).")),Promise.resolve({ok:!0});let r=this.session.getTransport();return r?r.request("publish",this.wireKey(e),n,t):Promise.resolve({ok:!1,code:"failed-precondition",message:"portable transport not connected"})}catch(n){return a.catch("Error in PortableRealtimeAdapter publish: ",n),Promise.resolve({ok:!1,code:"failed-precondition",message:"portable transport send failed"})}}presence(e,s){try{let t=this.session.getTransport();return t?t.request("presence",this.wireKey(e),"updatePresence",s):Promise.resolve({ok:!1,code:"failed-precondition",message:"portable transport not connected"})}catch(t){return a.catch("Error in PortableRealtimeAdapter presence: ",t),Promise.resolve({ok:!1,code:"failed-precondition",message:"portable transport send failed"})}}onDisconnect(e,s,t){return g(this,null,function*(){let n=!1,r=i=>{if(!n){n=!0;try{t?.onResult?.(i)}catch(c){a.catch("Error in PortableRealtimeAdapter onDisconnect onResult: ",c)}}};try{let i=this.session.getTransport();return i?yield i.registerOnDisconnect(this.wireKey(e),s,t?.onResult?r:void 0):(r({ok:!1,code:"failed-precondition",message:"portable transport not connected"}),()=>{})}catch(i){return a.catch("Error in PortableRealtimeAdapter onDisconnect: ",i),r({ok:!1,code:"failed-precondition",message:"portable transport send failed"}),()=>{}}})}getServerTimeOffset(){try{return Promise.resolve(this.session.getTransport()?.getServerTimeOffset()??0)}catch(e){return a.catch("Error in PortableRealtimeAdapter getServerTimeOffset: ",e),Promise.resolve(0)}}onServerTimeOffset(e){try{return this.session.getTransport()?.onServerTimeOffset(e)??(()=>{})}catch(s){return a.catch("Error in PortableRealtimeAdapter onServerTimeOffset: ",s),()=>{}}}};var _=class{constructor(e,s){this.rest=e,this.session=s}read(e){return g(this,null,function*(){let s=yield this.rest.call("read",e);return s.ok?{data:s.data}:{data:void 0,errorCode:s.code}})}runTransaction(e){return e()}op(e,s){if(s&&typeof s=="object"&&"channel"in s){let t=s,{channel:n}=t,r=B(t,["channel"]);return this.rest.call(e,r)}return this.rest.call(e,s)}publishOp(e,s,t){if(!s.channel)return Promise.resolve({ok:!1,code:"failed-precondition",message:`portable publish op '${e}' requires a channel on the OperationRequest`});let n=this.session?.getTransport();return n?n.request("publish",W(s.channel,$(this.session?.getToken())),e,t):Promise.resolve({ok:!1,code:"failed-precondition",message:"portable transport not connected"})}notificationWirePayload(e,s){let t=e.resourceId??(typeof e.data?.notificationId=="string"?e.data.notificationId:void 0),n={};if(t!=null&&String(t).length>0&&(n.notificationId=String(t)),s&&e.data!==void 0){let r=e.data;r&&typeof r=="object"&&r.data!==void 0&&r.notificationId!==void 0?n.data=r.data:n.data=e.data}return n}annotationWirePayload(e,s,t=!1){let n=e.resourceId??(typeof e.data?.annotationId=="string"?e.data.annotationId:void 0),r={};return n!=null&&String(n).length>0&&(r.annotationId=String(n)),s&&e.data!==void 0&&(r.data=e.data),t&&e.notificationData!==void 0&&(r.notificationData=e.notificationData),t&&typeof e.isPermissionProviderUsed=="boolean"&&(r.isPermissionProviderUsed=e.isPermissionProviderUsed),r}addComment(e){return this.publishOp("addComment",e,this.annotationWirePayload(e,!0,!0))}editComment(e){return this.publishOp("editComment",e,this.annotationWirePayload(e,!0))}deleteComment(e){return this.publishOp("deleteComment",e,this.annotationWirePayload(e,!1))}addReaction(e){return this.publishOp("addReaction",e,this.annotationWirePayload(e,!0))}editReaction(e){return this.publishOp("editReaction",e,this.annotationWirePayload(e,!0))}deleteReaction(e){return this.publishOp("deleteReaction",e,this.annotationWirePayload(e,!1))}recordDocumentView(e){return this.publishOp("recordDocumentView",e,{})}getActivitiesForDocuments(e){return this.rest.call("getActivitiesForDocuments",e.data)}getActivitiesForEntity(e){return this.rest.call("getActivitiesForEntity",e.data)}setCommentResolved(e){return this.op("setCommentResolved",e)}setCommentMetadata(e){return this.op("setCommentMetadata",e)}bumpCommentViews(e){return this.op("bumpCommentViews",e)}markCommentThreadRead(e){return this.publishOp("markCommentThreadRead",e,this.notificationWirePayload(e,!1))}markNotificationRead(e){return this.publishOp("markNotificationRead",e,this.notificationWirePayload(e,!1))}addNotification(e){return this.op("addNotification",e)}deleteNotification(e){return this.publishOp("deleteNotification",e,this.notificationWirePayload(e,!1))}updateNotification(e){return this.publishOp("updateNotification",e,this.notificationWirePayload(e,!0))}updatePresence(e){return this.op("updatePresence",e)}grantAccess(e){return this.op("grantAccess",e)}revokeAccess(e){return this.rest.call("revokeAccess",{data:e.data})}getAccess(e){return this.rest.call("getAccess",{data:e.data})}upsertOrgUserProfile(e){return this.rest.call("addUserInfoToOrganization",e.data)}upsertDocMetadata(e){return this.op("upsertDocMetadata",e)}upsertOrgMetadata(e){return this.op("upsertOrgMetadata",e)}createActivity(e){return this.rest.call("createActivity",e.data)}saveCrdtVersion(e){return this.rest.call("saveCrdtVersion",e.data)}getCrdtVersion(e){return this.rest.call("getCrdtVersion",e.data)}listCrdtVersions(e){return this.rest.call("listCrdtVersions",e.data)}getOrganizationUsers(e){return this.rest.call("getOrganizationUsers",e.data)}setLocationMetadata(e){return this.rest.call("setLocationMetadata",e.data)}fetchLocations(e){return this.rest.call("fetchLocations",e.data)}createFolder(e){return this.rest.call("createFolder",e.data)}setDocumentMetadata(e){return this.rest.call("setDocumentMetadata",e.data)}getDocuments(e){return this.rest.call("getDocuments",e.data)}getNotificationsForDocuments(e){return this.rest.call("getNotificationsForDocuments",e.data)}getDocumentMetadataFromIds(e){return this.rest.call("getDocumentMetadataFromIds",e.data)}getCrossOrgUserNotifications(e){return this.rest.call("getCrossOrgUserNotifications",e.data)}};var Te=7e4,oe=Object.freeze({getNotificationsForDocuments:1200*1e3});function be(o){return Object.prototype.hasOwnProperty.call(oe,o)?oe[o]:Te}var ae="portable request timed out",le="portable request failed in transport",ye=new Set(["read","getAccess","getActivitiesForDocuments","getActivitiesForEntity","getCrdtVersion","listCrdtVersions","getOrganizationUsers","fetchLocations","getDocuments","getNotificationsForDocuments","getDocumentMetadataFromIds","getCrossOrgUserNotifications","createFolder","setDocumentMetadata"]),Ee=500;function Re(o){let e=o;return!!e&&e.ok===!1&&e.code==="failed-precondition"&&e.message===le}var ke={fetch:(o,e)=>fetch(o,e)},ce={400:"invalid-argument",401:"unauthenticated",403:"permission-denied",404:"not-found",412:"failed-precondition",429:"resource-exhausted"};function Ae(o){return!!o&&typeof o=="object"&&typeof o.ok=="boolean"}var O=class{constructor(e){this.session=e,this.insecureEndpointReported=new Set}call(e,s){return g(this,null,function*(){let t=this.session.getToken(),n=this.session.getGeneration?.(),r=yield this.send(e,s);if(!Re(r)||!ye.has(e)||(yield new Promise(c=>setTimeout(c,Ee)),this.session.getGeneration?.()!==n))return r;let i=this.session.getToken();if(i!==t){let c=R(t);if(c===null||R(i)!==c)return r}return this.send(e,s)})}send(e,s){return g(this,null,function*(){try{let t=this.session.getApiEndpoint(),n=this.session.getToken();if(!t||!n)return{ok:!1,code:"failed-precondition",message:"portable session not established"};if(!H(t))return this.insecureEndpointReported.has(t)||(this.insecureEndpointReported.add(t),console.error(`Velt [portable backend]: refusing to send the session token to insecure apiEndpoint '${t}' (https required; http is loopback-only). Portable REST operations are disabled until identify returns a secure endpoint.`)),{ok:!1,code:"failed-precondition",message:"portable apiEndpoint is not a secure URL; request not sent"};let r=typeof AbortController=="function"?new AbortController:null,i=null,c=new Promise(d=>{i=setTimeout(()=>{r?.abort(),d({ok:!1,code:"permission-denied",message:ae})},be(e))});try{return yield Promise.race([this.exchange(e,s,t,n,r?.signal),c])}finally{i!==null&&clearTimeout(i)}}catch(t){return a.catch(`Error in PortableRestClient call '${e}': `,t),{ok:!1,code:"permission-denied",message:"portable operation request failed"}}})}exchange(e,s,t,n,r){return g(this,null,function*(){let i;try{i=JSON.stringify(s??{})}catch(c){return a.catch(`PortableRestClient '${e}': the request body could not be serialized; not sent: `,c),{ok:!1,code:"failed-precondition",message:"portable request body could not be serialized; request not sent"}}try{let c=yield ke.fetch(`${t}/operations/${e}`,p({method:"POST",headers:{Authorization:`Bearer ${n}`,"Content-Type":"application/json"},body:i},r?{signal:r}:{})),d;try{d=yield c.json()}catch{d=void 0}if(Ae(d)){if(d.ok)return c.ok?d:{ok:!1,code:ce[c.status]??"permission-denied",message:`HTTP ${c.status} on operation '${e}' contradicted an ok:true envelope`};let m=d.code;return m&&U.includes(m)?d:{ok:!1,code:"permission-denied",message:`unrecognized denial code '${m}'`}}return c.ok?{ok:!0,data:d}:{ok:!1,code:ce[c.status]??"permission-denied",message:`HTTP ${c.status} on operation '${e}'`}}catch(c){return r?.aborted?{ok:!1,code:"permission-denied",message:ae}:(a.catch(`Error in PortableRestClient call '${e}': `,c),{ok:!1,code:"failed-precondition",message:le})}})}};function Se(o){if(!o)return!1;try{let e=new URL(o);return e.protocol==="wss:"?!0:e.protocol==="ws:"&&["localhost","127.0.0.1","[::1]"].includes(e.hostname)}catch{return!1}}var D=class{constructor(e){this.transportFactory=e,this.token=null,this.wsEndpoint=null,this.apiEndpoint=null,this.transport=null,this.authState$=new F(null),this.nullTokenWarned=!1,this.insecureEndpointWarned=!1,this.offOffset=null,this.offTerminal=null,this.generation=0}establish(e){try{if(!e)return;if(this.generation++,this.wsEndpoint=e.wsEndpoint??null,this.apiEndpoint=e.apiEndpoint??null,this.token=typeof e.token=="string"&&e.token.length>0?e.token:null,!this.token){this.transport&&this.teardown(),this.nullTokenWarned||(this.nullTokenWarned=!0,console.warn("Velt [portable backend]: identify() returned no session token (token: null). Portable transport will not connect on this page load; portable features are disabled."));return}if(!Se(this.wsEndpoint)){this.transport&&this.teardown(),this.insecureEndpointWarned||(this.insecureEndpointWarned=!0,console.warn("Velt [portable backend]: refusing to connect to a non-wss:// gateway endpoint ("+this.wsEndpoint+"). The session token would travel in cleartext; portable features are disabled. (Plain ws:// is permitted for localhost only.)"));return}this.transport||(this.transport=this.transportFactory(this),this.offOffset=this.transport.onServerTimeOffset(()=>{this.authState$.value?.signedIn||this.authState$.next({signedIn:!0})}),this.offTerminal=this.transport.onTerminal(()=>{this.authState$.value!==null&&this.authState$.next(null)})),this.transport.connect()}catch(s){a.catch("Error in PortableSession establish: ",s)}}refreshToken(e){try{if(typeof e!="string"||!e.length)return;this.token=e,this.transport?.refreshAuth()}catch(s){a.catch("Error in PortableSession refreshToken: ",s)}}teardown(){try{this.generation++,this.offOffset?.(),this.offOffset=null,this.offTerminal?.(),this.offTerminal=null,this.transport?.close(),this.transport=null,this.authState$.value!==null&&this.authState$.next(null)}catch(e){a.catch("Error in PortableSession teardown: ",e)}}getToken(){return this.token}getGeneration(){return this.generation}getWsEndpoint(){return this.wsEndpoint}getApiEndpoint(){return this.apiEndpoint}getTransport(){return this.transport}getAuthState$(){return this.authState$.asObservable()}};function de(o,e,s){let t=Number.isFinite(s)?Math.min(Math.max(s,0),1):0;if(e==="fast")return t*Z;let n=Number.isFinite(o)?Math.max(0,Math.floor(o)):0,r=Math.min(q,S*Math.pow(2,n+1)),i=e==="shutdown"?Math.min(q,Math.max(r,J)):r;return S+t*(i-S)}function T(){return{ok:!1,code:"failed-precondition",message:"portable transport not connected"}}function Pe(){return{ok:!1,code:"failed-precondition",message:"portable transport disconnected"}}var b=1,C=class{constructor(e){this.deps=e,this.state="idle",this.socket=null,this.channels=new Map,this.pendingRequests=new Map,this.nextRequestId=1,this.nextRequestOrder=0,this.orderedDeltas=!1,this.capabilities=new Set,this.pendingReconnectKind=null,this.drain=null,this.onlineListenerAttached=!1,this.onBrowserOnline=()=>{try{if(h("network.online",`state=${this.state}`),this.state==="reconnecting"){this.expediteReconnect("online");return}(this.state==="open"||this.state==="reauthing")&&this.checkLivenessOnResume()}catch(s){a.catch("Error in PortableWsTransport online handler: ",s)}},this.serverTimeOffsetMs=0,this.offsetListeners=new Set,this.lastInboundAtMs=0,this.heartbeatTimer=null,this.pongDeadlineTimer=null,this.reconnectTimer=null,this.reconnectAttempts=0,this.authRecoveryAttempts=0,this.terminalListeners=new Set}onTerminal(e){return this.terminalListeners.add(e),()=>{this.terminalListeners.delete(e)}}notifyTerminal(e){this.terminalListeners.forEach(s=>{try{s(e)}catch(t){a.catch("Error in PortableWsTransport terminal listener: ",t)}})}getState(){return this.state}hasCapability(e){return(this.state==="open"||this.state==="reauthing")&&this.capabilities.has(e)}connect(){try{if(this.state==="connecting"||this.state==="open"||this.state==="reauthing"||this.state==="unsupported")return;let e=this.deps.getUrl(),s=this.deps.getToken();if(!e||!s)return;this.attachOnlineListener(),this.state="connecting";let t=this.deps.wsFactory(e);this.socket=t,t.onopen=()=>this.onSocketOpen(t),t.onmessage=n=>this.onFrame(t,n.data),t.onclose=n=>this.onSocketClosed(t,n?.code),t.onerror=()=>{}}catch(e){a.catch("Error in PortableWsTransport connect: ",e)}}close(){try{this.state="closed",this.notifyTerminal("closed"),this.clearTimers(),this.detachOnlineListener();let e=this.socket;this.socket=null,e&&e.readyState<=b&&e.close(1e3,"client close"),this.failPendingRequests(),this.endDrain(!0)}catch(e){a.catch("Error in PortableWsTransport close: ",e)}}checkLivenessOnResume(e=A*2){try{if(this.state==="reconnecting"){this.expediteReconnect("resume");return}if(this.state!=="open"&&this.state!=="reauthing")return;let s=this.lastInboundAtMs?this.now()-this.lastInboundAtMs:Number.POSITIVE_INFINITY;if(s<=e)return;h("liveness.stale-on-resume",`silentFor=${Math.round(s/1e3)}s state=${this.state}`),y("the realtime connection was silent while the tab was in the background","Nothing had been received for longer than two heartbeats when this tab came back, so the connection is treated as dead and re-established. Data shown before this point may have been stale \u2014 the UI keeps what it already had, so this is invisible without this message."),this.handleDeadSocket()}catch(s){a.catch("Error in PortableWsTransport checkLivenessOnResume: ",s)}}refreshAuth(){try{if(this.isDrainingCurrentSocket()){h("auth.refresh-deferred","draining");return}if(this.state==="open"&&this.socket&&this.socket.readyState===b){this.state="reauthing",this.sendHello();return}(this.state==="closed"||this.state==="idle")&&(this.state="idle",this.connect())}catch(e){a.catch("Error in PortableWsTransport refreshAuth: ",e)}}subscribeChannel(e,s,t,n){let r=this.ensureChannel(e,s),i={onEvent:t,active:!0};if(r.subscribers.add(i),r.lastSeq===void 0&&typeof n=="number"&&(r.lastSeq=n),r.hasState){for(let[c,d]of r.lastKnown)try{i.onEvent({kind:"snapshot-item",id:c,data:d,snapshot:r.cacheComplete?"full":"partial"})}catch(l){a.catch("Error in PortableWsTransport cached-state replay: ",l)}try{i.onEvent({kind:"snapshot-end"})}catch(c){a.catch("Error in PortableWsTransport cached-state snapshot-end: ",c)}}return this.wireSubscribeIfNeeded(e,r),{unsubscribe:()=>{try{if(!i.active)return;i.active=!1,r.subscribers.delete(i),r.subscribers.size===0&&(this.clearSnapshotWatchdog(r),this.clearRetryTimer(r),this.clearHealthyTimer(r),this.channels.delete(e),r.wired&&this.socket&&this.socket.readyState===b&&!this.isDrainingCurrentSocket()&&this.sendFrame({type:"unsubscribe",channel:e,requestId:`r${this.nextRequestId++}`}))}catch(c){a.catch("Error in PortableWsTransport unsubscribe: ",c)}}}}request(e,s,t,n){try{let r={type:e,channel:s,op:t,requestId:""};return e==="presence"?r.state=n:r.payload=n,this.drain?this.enqueueDuringDrain(r):this.state!=="open"&&this.state!=="reauthing"?Promise.resolve(T()):this.sendRequest(r)}catch(r){return a.catch("Error in PortableWsTransport request: ",r),Promise.resolve({ok:!1,code:"failed-precondition",message:"portable transport send failed"})}}registerOnDisconnect(e,s,t){return g(this,null,function*(){let n={type:"onDisconnect",channel:e,cleanup:s,requestId:""},r;if(this.drain)r=this.enqueueDuringDrain(n);else{if(this.state!=="open"&&this.state!=="reauthing")return t?.(T()),()=>{};let d=this.newPendingRequest(n);r=d.promise;let l=!1;try{l=this.dispatch(d.request)}catch(m){return a.catch("Error in PortableWsTransport registerOnDisconnect send: ",m),t?.({ok:!1,code:"failed-precondition",message:"portable transport send failed"}),()=>{}}if(!l)return t?.(T()),()=>{}}let i=yield r;t?.(i);let c=i.ok?i.id:void 0;return()=>{try{c&&this.socket&&this.socket.readyState===b&&!this.isDrainingCurrentSocket()&&this.sendFrame({type:"onDisconnectCancel",intentId:c,requestId:`r${this.nextRequestId++}`})}catch(d){a.catch("Error in PortableWsTransport onDisconnect cancel: ",d)}}})}getServerTimeOffset(){return this.serverTimeOffsetMs}onServerTimeOffset(e){return this.offsetListeners.add(e),()=>this.offsetListeners.delete(e)}now(){return this.deps.now?this.deps.now():Date.now()}random(){return this.deps.random?this.deps.random():Math.random()}ensureChannel(e,s){let t=this.channels.get(e);return t||(t={mode:s,subscribers:new Set,lastSeq:void 0,denied:!1,wired:!1,snapshotWatchdog:null,lastKnown:new Map,hasState:!1,resumeRequested:!1,retryAttempts:0,retryTimer:null,healthyTimer:null,repeatDropLogged:!1,cacheComplete:!1},this.channels.set(e,t)),t}wireSubscribeIfNeeded(e,s){if(s.wired||s.denied||s.retryTimer||this.state!=="open"&&this.state!=="reauthing"||!this.socket||this.socket.readyState!==b||this.isDrainingCurrentSocket())return;let t={type:"subscribe",channel:e,mode:s.mode,requestId:`r${this.nextRequestId++}`};s.subscribeRequestId=t.requestId,s.resumeRequested=!1,s.mode==="persistent"&&s.lastSeq!==void 0&&(t.since=s.lastSeq,s.resumeRequested=!0),s.wired=!0,this.armSnapshotWatchdog(e,s);let n=!1;try{n=this.sendFrame(t)}catch(r){a.catch("Error in PortableWsTransport wireSubscribeIfNeeded: ",r)}if(!n){s.wired=!1,this.clearSnapshotWatchdog(s);return}h("channel.subscribe",`${e}${t.since!==void 0?" since="+t.since:" (full)"}`)}sendHello(){this.sendFrame({type:"hello",protocolVersion:"1.0",token:this.deps.getToken(),capabilities:[]})}sendFrame(e){return!this.socket||this.socket.readyState!==b?!1:(this.socket.send(JSON.stringify(e)),!0)}onSocketOpen(e){e===this.socket&&(h("socket.open"),this.sendHello())}onWelcome(e){let s=N(e.protocolVersion),t=N("1.0");if(s!==t){this.state!=="unsupported"&&console.error(`Velt [portable backend]: gateway speaks WS protocol '${e.protocolVersion}' but this SDK speaks '${"1.0"}' (incompatible MAJOR). Portable features are disabled. Align the deployed gateway and SDK versions (see docs/self-hosting-portable-protocol.md).`),this.state="unsupported",this.notifyTerminal("unsupported"),this.clearTimers();try{this.socket?.close(1e3,"protocol-version")}catch{}this.socket=null,this.failPendingRequests(),this.endDrain(!0);return}let n=this.state==="reauthing";if(this.capabilities=new Set(Array.isArray(e.capabilities)?e.capabilities.filter(r=>typeof r=="string"):[]),this.orderedDeltas=this.capabilities.has(P),h("handshake.welcome",`reauth=${n}${this.orderedDeltas?" ordered-deltas":""}`),this.state="open",this.reconnectAttempts=0,typeof e.serverTimeMs=="number"){this.serverTimeOffsetMs=e.serverTimeMs-this.now();for(let r of this.offsetListeners)try{r(this.serverTimeOffsetMs)}catch(i){a.catch("Error in PortableWsTransport offset listener: ",i)}}if(this.startHeartbeat(),!n){for(let[r,i]of this.channels)i.wired=!1,this.clearRetryTimer(i),this.wireSubscribeIfNeeded(r,i);this.drain&&!this.isDrainingCurrentSocket()&&this.flushDrainQueue(this.endDrain(!1))}}onFrame(e,s){if(e!==this.socket)return;this.lastInboundAtMs=this.now();let t;try{t=JSON.parse(s)}catch{a.log("Velt [portable backend]: dropped unparseable WS frame");return}try{switch(t.type){case"welcome":this.onWelcome(t);return;case"pong":this.clearPongDeadline(),L("pong"),this.authRecoveryAttempts=0;return;case"delta":{let n=this.channels.get(t.channel);if(!n||!n.wired)return;if(typeof t.seq=="number"){if(this.orderedDeltas&&n.lastSeq!==void 0&&t.seq<=n.lastSeq){n.repeatDropLogged||(n.repeatDropLogged=!0,a.log(`Velt [portable backend]: dropped a repeated delta on ${t.channel} (seq ${t.seq} <= ${n.lastSeq}); further repeats on this channel are dropped without a log line.`));return}n.lastSeq=t.seq}this.noteChannelHealthy(n),n.hasState=!0,t.change==="removed"?n.lastKnown.delete(t.id):t.id!==void 0&&n.lastKnown.set(t.id,t.data),this.emit(n,{kind:"delta",change:t.change,id:t.id,data:t.data,seq:t.seq});return}case"snapshot":{let n=this.channels.get(t.channel);if(!n||!n.wired)return;this.clearSnapshotWatchdog(n),this.noteChannelHealthy(n),h("channel.snapshot",`${t.channel} items=${Array.isArray(t.items)?t.items.length:"?"}${t.full?" full":""}${t.truncated?" truncated":""}`);let r=Array.isArray(t.items)?t.items:[],i=t.truncated===!0,c=!i&&(t.full===!0||!n.resumeRequested);typeof t.seq=="number"?n.lastSeq=t.seq:this.orderedDeltas&&c&&(n.lastSeq=void 0),n.hasState=!0;let d=p({kind:"snapshot-end",full:c},typeof t.seq=="number"?{seq:t.seq}:{});if(i?n.cacheComplete=!1:c&&(n.cacheComplete=!0),i){for(let l of r)l?.id!==void 0&&n.lastKnown.set(l.id,l?.data),this.emit(n,{kind:"snapshot-item",id:l?.id,data:l?.data,snapshot:"partial"});this.emit(n,d)}else if(c){let l=new Set;for(let f of r)f?.id!==void 0&&l.add(f.id);let m=[];for(let f of n.lastKnown.keys())l.has(f)||m.push(f);n.lastKnown.clear();for(let f of m)this.emit(n,{kind:"delta",change:"removed",id:f,data:void 0,snapshot:"full"});for(let f of r)f?.id!==void 0&&n.lastKnown.set(f.id,f?.data),this.emit(n,{kind:"snapshot-item",id:f?.id,data:f?.data,snapshot:"full"});this.emit(n,d)}else{for(let l of r)l?.id!==void 0&&(l.data===void 0?(n.lastKnown.delete(l.id),this.emit(n,{kind:"delta",change:"removed",id:l.id,data:void 0})):(n.lastKnown.set(l.id,l.data),this.emit(n,{kind:"snapshot-item",id:l.id,data:l.data,snapshot:"partial"})));this.emit(n,d)}return}case"result":{let n=this.pendingRequests.get(t.requestId);if(!n){a.log(`Velt [portable backend]: uncorrelated result frame (requestId ${t.requestId}, ok=${!!t.ok}${t.code?`, code=${t.code}`:""}) \u2014 no pending request. Expected for unsubscribe / onDisconnectCancel, which are fire-and-forget.`);return}if(this.pendingRequests.delete(t.requestId),!t.ok&&t.reasonCode===j&&!n.resent){n.resent=!0,h("request.refused-shutting-down",String(n.frame.op??n.frame.type)),this.beginDrain(void 0),this.drain?.queue.push(n),this.maybeFinishDrain();return}let r=n.resolve;t.ok?r(p({ok:!0,id:t.id,data:t.data},typeof t.seq=="number"?{seq:t.seq}:{})):r(p({ok:!1,code:t.code??"permission-denied",message:t.message},typeof t.reasonCode=="string"?{reasonCode:t.reasonCode}:{})),this.maybeFinishDrain();return}case"draining":{if(this.state!=="open"&&this.state!=="reauthing")return;this.beginDrain(t.deadlineMs),this.maybeFinishDrain();return}case"error":{let n=t.channel,r=typeof t.code=="string"&&G.has(t.code);if(n&&this.channels.has(n)){let i=this.channels.get(n);if(r){this.retryChannelAfterLoad(n,i,t.code);return}i.denied=!0,i.wired=!1,this.clearSnapshotWatchdog(i),this.clearRetryTimer(i),this.clearHealthyTimer(i),this.emit(i,{kind:"denied",code:t.code,reasonCode:t.reasonCode});return}if(t.requestId&&this.pendingRequests.has(t.requestId)){let i=this.pendingRequests.get(t.requestId).resolve;this.pendingRequests.delete(t.requestId),i(p({ok:!1,code:t.code??"permission-denied"},typeof t.reasonCode=="string"?{reasonCode:t.reasonCode}:{})),this.maybeFinishDrain();return}if(r&&t.requestId){let i=this.findChannelBySubscribeRequestId(t.requestId);if(i){this.retryChannelAfterLoad(i[0],i[1],t.code);return}}if(t.code==="unauthenticated"){if(this.state==="open"&&this.authRecoveryAttempts<z){this.authRecoveryAttempts++,console.warn("Velt [portable backend]: the gateway dropped an authenticated session (unauthenticated on a live connection). Reconnecting once to re-establish it."),this.clearHeartbeat();let c=this.socket;this.socket=null;try{c&&c.readyState<=b&&c.close(4401,"session-lost")}catch{}this.failPendingRequests(),this.markAllChannelsUnwired(),this.scheduleReconnect(this.drain?"shutdown":"backoff");return}console.warn("Velt [portable backend]: the gateway rejected authentication. Portable transport is fail-closed for this session; a fresh identify()/token is required to reconnect."),this.state="closed",this.notifyTerminal("closed"),this.clearTimers();let i=this.socket;this.socket=null;try{i&&i.readyState<=b&&i.close(4401,"unauthenticated")}catch{}this.failPendingRequests(),this.endDrain(!0);return}return}default:return}}catch(n){a.catch("Error in PortableWsTransport onFrame: ",n)}}emit(e,s){for(let t of e.subscribers)if(t.active)try{t.onEvent(s)}catch(n){a.catch("Error in PortableWsTransport subscriber callback: ",n)}}onSocketClosed(e,s){if(h("socket.close",`stale=${e!==this.socket} state=${this.state} code=${s??"?"}`),e!==this.socket||(this.socket=null,this.drain&&this.drain.socket===e&&(this.clearDrainWaitTimer(),this.drain.socket=null),this.clearTimers(),this.failPendingRequests(),this.state==="closed"||this.state==="unsupported"))return;this.markAllChannelsUnwired();let t=s===1001||s===1012||!!this.drain;this.scheduleReconnect(t?"shutdown":"backoff")}markAllChannelsUnwired(){for(let e of this.channels.values())e.wired=!1}failPendingRequests(){let e=[...this.pendingRequests.values()];this.pendingRequests.clear();for(let s of e)s.resolve(Pe())}scheduleReconnect(e="backoff"){if(this.reconnectTimer)return;this.state="reconnecting";let s=de(this.reconnectAttempts,e,this.random());e!=="fast"&&this.reconnectAttempts++,this.pendingReconnectKind=e,this.reconnectTimer=setTimeout(()=>{this.reconnectTimer=null,this.pendingReconnectKind=null,this.state==="reconnecting"&&(this.state="idle",this.connect())},s)}expediteReconnect(e){this.state!=="reconnecting"||!this.reconnectTimer||this.pendingReconnectKind==="fast"||(clearTimeout(this.reconnectTimer),this.reconnectTimer=null,this.pendingReconnectKind=null,this.reconnectAttempts=0,h("reconnect.expedited",e),this.scheduleReconnect("fast"))}attachOnlineListener(){try{if(this.onlineListenerAttached||typeof window>"u"||typeof window.addEventListener!="function")return;window.addEventListener("online",this.onBrowserOnline),this.onlineListenerAttached=!0}catch(e){a.catch("Error in PortableWsTransport attachOnlineListener: ",e)}}detachOnlineListener(){try{if(!this.onlineListenerAttached||typeof window>"u")return;window.removeEventListener("online",this.onBrowserOnline),this.onlineListenerAttached=!1}catch(e){a.catch("Error in PortableWsTransport detachOnlineListener: ",e)}}newPendingRequest(e){let s,t=new Promise(n=>{s=n});return{request:{resolve:s,frame:e,order:this.nextRequestOrder++,resent:!1,token:this.deps.getToken(),identity:this.currentIdentity()},promise:t}}sendRequest(e){let{request:s,promise:t}=this.newPendingRequest(e);return this.dispatch(s)?t:Promise.resolve(T())}dispatch(e){let s=`r${this.nextRequestId++}`;this.pendingRequests.set(s,e);let t=!1;try{t=this.sendFrame(k(p({},e.frame),{requestId:s}))}catch(n){throw this.pendingRequests.delete(s),n}return t||this.pendingRequests.delete(s),t}enqueueDuringDrain(e){let s=this.drain;if(!s||s.queue.length>=te)return h("drain.queue-full",`${s?.queue.length??0}`),Promise.resolve(T());let{request:t,promise:n}=this.newPendingRequest(e);return s.queue.push(t),n}beginDrain(e){if(this.isDrainingCurrentSocket())return;let s=typeof e=="number"&&Number.isFinite(e)&&e>=0?Math.min(e,v):v;h("socket.draining",`wait=${Math.round(s)}ms inFlight=${this.pendingRequests.size}`),this.drain||(this.drain={socket:null,waitTimer:null,queueTimer:null,queue:[]});let t=this.drain;t.socket=this.socket,this.clearDrainWaitTimer(),t.waitTimer=setTimeout(()=>{t.waitTimer=null,this.finishDrain("deadline")},s),t.queueTimer&&clearTimeout(t.queueTimer),t.queueTimer=setTimeout(()=>{t.queueTimer=null,this.expireDrainQueue()},s+ee)}maybeFinishDrain(){this.isDrainingCurrentSocket()&&this.pendingRequests.size===0&&this.finishDrain("results-in")}finishDrain(e){try{let s=this.drain;if(!s||!s.socket||s.socket!==this.socket)return;this.clearDrainWaitTimer();let t=s.socket;s.socket=null,this.socket=null,h("socket.drain-close",`${e} queued=${s.queue.length}`),this.clearHeartbeat();for(let n of this.channels.values())this.clearSnapshotWatchdog(n);try{t.close(1e3,"client closing: server draining")}catch{}this.failPendingRequests(),this.markAllChannelsUnwired(),this.state!=="closed"&&this.state!=="unsupported"&&this.scheduleReconnect("shutdown")}catch(s){a.catch("Error in PortableWsTransport finishDrain: ",s)}}expireDrainQueue(){let e=this.drain?.queue.length??0;h("drain.expired",`queued=${e}`),e>0&&y("writes queued during a gateway shutdown could not be sent","The gateway announced it was shutting down and no replacement connection came up in time, so requests held for it were failed as not sent. They did not run on the server.","drain-queue-expired"),this.endDrain(!0)}endDrain(e){let s=this.drain;if(!s)return[];this.drain=null,s.waitTimer&&(clearTimeout(s.waitTimer),s.waitTimer=null),s.queueTimer&&(clearTimeout(s.queueTimer),s.queueTimer=null);let t=s.queue;if(s.queue=[],e){for(let n of t)n.resolve(T());return[]}return t}flushDrainQueue(e){e.length>0&&h("drain.resend",`${e.length}`);let s=this.deps.getToken(),t=this.currentIdentity();for(let n of e.sort((r,i)=>r.order-i.order))try{if(this.drain){this.drain.queue.push(n);continue}if(!(n.identity!==null&&t!==null?n.identity===t:n.token===s)){h("drain.credential-changed",String(n.frame.op??n.frame.type)),n.resolve(T());continue}this.dispatch(n)||n.resolve(T())}catch(r){a.catch("Error in PortableWsTransport drain resend: ",r),n.resolve(T())}}currentIdentity(){try{return this.deps.getIdentity?.()??null}catch{return null}}clearDrainWaitTimer(){this.drain?.waitTimer&&(clearTimeout(this.drain.waitTimer),this.drain.waitTimer=null)}isDrainingCurrentSocket(){return!!this.drain&&!!this.drain.socket&&this.drain.socket===this.socket}retryChannelAfterLoad(e,s,t){if(s.wired=!1,this.clearSnapshotWatchdog(s),this.clearHealthyTimer(s),s.retryTimer)return;let n;s.retryAttempts>=M?(y("a realtime channel stayed refused for load after every fast retry",`The gateway answered '${t}' ${M} times in a row for one channel, so the SDK now retries it about every 30 seconds for as long as it is subscribed. The channel keeps the data it already had. This is gateway load, not a permission problem.`,`channel-retry-exhausted:${e}`),n=X*(.75+.5*Math.min(Math.max(this.random()||0,0),1)),h("channel.retry-slow",`${e} code=${t} in=${Math.round(n)}ms`)):(s.retryAttempts++,n=de(s.retryAttempts-1,"backoff",this.random()),h("channel.retry",`${e} code=${t} attempt=${s.retryAttempts} in=${Math.round(n)}ms`)),s.retryTimer=setTimeout(()=>{s.retryTimer=null;try{if(this.channels.get(e)!==s||s.denied)return;this.wireSubscribeIfNeeded(e,s)}catch(r){a.catch("Error in PortableWsTransport channel retry: ",r)}},n)}clearRetryTimer(e){e.retryTimer&&(clearTimeout(e.retryTimer),e.retryTimer=null)}noteChannelHealthy(e){e.retryAttempts===0||e.healthyTimer||(e.healthyTimer=setTimeout(()=>{e.healthyTimer=null,e.retryAttempts=0},Q))}clearHealthyTimer(e){e.healthyTimer&&(clearTimeout(e.healthyTimer),e.healthyTimer=null)}findChannelBySubscribeRequestId(e){for(let s of this.channels)if(s[1].subscribeRequestId===e)return s;return null}startHeartbeat(){this.clearHeartbeat(),this.heartbeatTimer=setInterval(()=>{try{if(this.state!=="open"&&this.state!=="reauthing")return;if(!this.socket||this.socket.readyState!==b){h("socket.dead-without-close",`state=${this.state} readyState=${this.socket?this.socket.readyState:"no-socket"}`),y("the realtime socket stopped without reporting it (recovering)","The connection was closed by the browser or the network without delivering a close event \u2014 most often a backgrounded/frozen tab. The SDK is reconnecting; if realtime features stay stuck after this, the reconnect is the thing to look at."),this.handleDeadSocket();return}L("ping"),this.sendFrame({type:"ping"}),this.armPongDeadline()}catch(e){a.catch("Error in PortableWsTransport heartbeat: ",e)}},A)}handleDeadSocket(){try{let e=this.socket;this.socket=null,this.clearHeartbeat(),this.clearPongDeadline();try{e?.close(4e3,"socket dead without close event")}catch{}this.failPendingRequests(),this.markAllChannelsUnwired(),this.state!=="closed"&&this.state!=="unsupported"&&this.scheduleReconnect(this.drain?"shutdown":"backoff")}catch(e){a.catch("Error in PortableWsTransport handleDeadSocket: ",e)}}armSnapshotWatchdog(e,s){this.clearSnapshotWatchdog(s),s.snapshotWatchdog=setTimeout(()=>{s.snapshotWatchdog=null,h("channel.snapshot-missing",`${e} after ${E}ms`),y("a realtime channel was subscribed but never delivered its first snapshot","Anything waiting on that first emission \u2014 a sidebar skeleton, an empty comment list \u2014 will stay in its loading state. The trail below shows whether the socket handshook, whether the credential was refreshed, and how long the tab was away.",`snapshot-missing:${e}`)},E)}clearSnapshotWatchdog(e){e?.snapshotWatchdog&&(clearTimeout(e.snapshotWatchdog),e.snapshotWatchdog=null)}armPongDeadline(){this.pongDeadlineTimer||(this.pongDeadlineTimer=setTimeout(()=>{this.pongDeadlineTimer=null;let e=this.socket;this.socket=null,this.clearHeartbeat();try{e?.close(4e3,"pong timeout")}catch{}this.failPendingRequests();for(let s of this.channels.values())s.wired=!1;this.state!=="closed"&&this.state!=="unsupported"&&this.scheduleReconnect(this.drain?"shutdown":"backoff")},A*Y))}clearPongDeadline(){this.pongDeadlineTimer&&(clearTimeout(this.pongDeadlineTimer),this.pongDeadlineTimer=null)}clearHeartbeat(){this.heartbeatTimer&&(clearInterval(this.heartbeatTimer),this.heartbeatTimer=null),this.clearPongDeadline()}clearTimers(){this.clearHeartbeat();for(let e of this.channels.values())this.clearSnapshotWatchdog(e),this.clearRetryTimer(e),this.clearHealthyTimer(e);this.reconnectTimer&&(clearTimeout(this.reconnectTimer),this.reconnectTimer=null,this.pendingReconnectKind=null)}};var u=null,I=null;function we(){try{u?.teardown()}catch{}}function it(){try{u?.getTransport()?.checkLivenessOnResume()}catch(o){a.catch("Error in checkPortableBackendLiveness: ",o)}}function ot(){we(),u=null,I=null}function _e(o){let e=!u;if(u||(u=new D(s=>new C({wsFactory:t=>new WebSocket(t),getUrl:()=>s.getWsEndpoint(),getToken:()=>s.getToken(),getIdentity:()=>R(s.getToken())}))),o?.token&&u.getToken()&&u.getTransport()?u.refreshToken(o.token):u.establish(o),e){let s=new O(u);I={db:new _(s,u),realtime:new w(u)}}return I&&K(I),u}export{it as checkPortableBackendLiveness,_e as default,ot as resetPortableBackendEntryForTest,we as teardownPortableBackend};
|