UNPKG

convex

Version:

Client for the Convex Cloud

242 lines (241 loc) 9.28 kB
"use strict"; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __hasOwnProp = Object.prototype.hasOwnProperty; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); var client_exports = {}; __export(client_exports, { InternalConvexClient: () => InternalConvexClient }); module.exports = __toCommonJS(client_exports); var import__ = require("../../index.js"); var import_local_state = require("./local_state.js"); var import_mutation_manager = require("./mutation_manager.js"); var import_optimistic_updates_impl = require("./optimistic_updates_impl.js"); var import_remote_query_set = require("./remote_query_set.js"); var import_udf_path_utils = require("./udf_path_utils.js"); var import_web_socket_manager = require("./web_socket_manager.js"); var import_uuid = require("uuid"); var import_logging = require("../logging.js"); var import_action_manager = require("./action_manager.js"); const DEFAULT_OPTIONS = { unsavedChangesWarning: true }; class InternalConvexClient { constructor(clientConfig, onTransition, options) { options = { ...DEFAULT_OPTIONS, ...options }; let webSocketConstructor = options.webSocketConstructor; if (!webSocketConstructor && typeof WebSocket === "undefined") { throw new Error( "No WebSocket global variable defined! To use Convex in an environment without WebSocket try the HTTP client: https://docs.convex.dev/api/classes/browser.ConvexHttpClient" ); } webSocketConstructor = webSocketConstructor || WebSocket; const address = clientConfig.address; const i = address.search("://"); if (i == -1) { throw new Error("Provided address was not an absolute URL."); } const origin = address.substring(i + 3); const protocol = address.substring(0, i); let wsProtocol; if (protocol === "http") { wsProtocol = "ws"; } else if (protocol === "https") { wsProtocol = "wss"; } else { throw new Error(`Unknown parent protocol ${protocol}`); } const wsUri = `${wsProtocol}://${origin}/api/${import__.version}/sync`; this.state = new import_local_state.LocalSyncState(); this.remoteQuerySet = new import_remote_query_set.RemoteQuerySet( (queryId) => this.state.queryPath(queryId) ); this.mutationManager = new import_mutation_manager.MutationManager(); this.actionManager = new import_action_manager.ActionManager(); this.optimisticQueryResults = new import_optimistic_updates_impl.OptimisticQueryResults(); this.onTransition = onTransition; this.nextMutationId = 0; this.nextActionId = 0; this.sessionId = (0, import_uuid.v4)(); const { unsavedChangesWarning } = options; if (typeof window === "undefined" && unsavedChangesWarning) { throw new Error( "unsavedChangesWarning enabled, but no window object found! Navigating away from the page could cause in-flight mutations to be dropped. Pass {unsavedChangesWarning: false} in Convex client options to disable this feature." ); } unsavedChangesWarning && window.addEventListener("beforeunload", (e) => { if (this.mutationManager.hasUncommittedMutations() || this.actionManager.hasInflightActions()) { e.preventDefault(); const confirmationMessage = "Are you sure you want to leave? Your changes may not be saved."; (e || window.event).returnValue = confirmationMessage; return confirmationMessage; } }); this.webSocketManager = new import_web_socket_manager.WebSocketManager( wsUri, (reconnectMetadata) => { this.webSocketManager.sendMessage({ ...reconnectMetadata, type: "Connect", sessionId: this.sessionId }); this.remoteQuerySet = new import_remote_query_set.RemoteQuerySet( (queryId) => this.state.queryPath(queryId) ); const [querySetModification, authModification] = this.state.restart(); if (authModification) { this.webSocketManager.sendMessage(authModification); } this.webSocketManager.sendMessage(querySetModification); this.actionManager.restart(); for (const message of this.mutationManager.restart()) { this.webSocketManager.sendMessage(message); } }, (serverMessage) => { if (serverMessage.type == "Transition") { this.remoteQuerySet.transition(serverMessage); this.state.saveQueryJournals(serverMessage); const completedMutations = this.mutationManager.removeCompletedMutations( this.remoteQuerySet.timestamp() ); this.notifyOnQueryResultChanges(completedMutations); } else if (serverMessage.type == "MutationResponse") { const completedMutationId = this.mutationManager.onResponse(serverMessage); if (completedMutationId) { this.notifyOnQueryResultChanges(/* @__PURE__ */ new Set([completedMutationId])); } } else if (serverMessage.type == "ActionResponse") { this.actionManager.onResponse(serverMessage); } else if (serverMessage.type == "FatalError") { const error = (0, import_logging.logFatalError)(serverMessage.error); void this.webSocketManager.stop(); throw error; } }, webSocketConstructor ); } notifyOnQueryResultChanges(completedMutations) { const remoteQueryResults = this.remoteQuerySet.remoteQueryResults(); const queryTokenToValue = /* @__PURE__ */ new Map(); for (const [queryId, result] of remoteQueryResults) { const queryToken = this.state.queryToken(queryId); if (queryToken !== null) { const query = { result, udfPath: this.state.queryPath(queryId), args: this.state.queryArgs(queryId) }; queryTokenToValue.set(queryToken, query); } } this.onTransition( this.optimisticQueryResults.ingestQueryResultsFromServer( queryTokenToValue, completedMutations ) ); } setAuth(value) { const message = this.state.setAuth(value); this.webSocketManager.sendMessage(message); } setAdminAuth(value) { const message = this.state.setAdminAuth(value); this.webSocketManager.sendMessage(message); } clearAuth() { const message = this.state.clearAuth(); this.webSocketManager.sendMessage(message); } subscribe(name, args, journal) { if (!Array.isArray(args)) { throw new Error( `Query arguments to \`InternalConvexClient.subcribe\` must be an array. Received ${args}.` ); } const { modification, queryToken, unsubscribe } = this.state.subscribe( name, args, journal ); if (modification !== null) { this.webSocketManager.sendMessage(modification); } return { queryToken, unsubscribe: () => { const modification2 = unsubscribe(); if (modification2) { this.webSocketManager.sendMessage(modification2); } } }; } localQueryResult(udfPath, args) { const queryToken = (0, import_udf_path_utils.serializePathAndArgs)(udfPath, args); return this.optimisticQueryResults.queryResult(queryToken); } queryJournal(name, args) { const queryToken = (0, import_udf_path_utils.serializePathAndArgs)(name, args); return this.state.queryJournal(queryToken); } connectionState() { return { hasInflightMutation: this.mutationManager.hasInflightMutation(), hasInflightAction: this.actionManager.hasInflightActions(), isWebSocketConnected: this.webSocketManager.socketState() === "ready" }; } async mutate(udfPath, args, optimisticUpdate = null) { const mutationId = this.nextMutationId; this.nextMutationId++; if (optimisticUpdate !== null) { const wrappedUpdate = (localQueryStore) => { optimisticUpdate(localQueryStore, ...args); }; const changedQueries = this.optimisticQueryResults.applyOptimisticUpdate( wrappedUpdate, mutationId ); this.onTransition(changedQueries); } const { message, result } = this.mutationManager.request( udfPath, args, mutationId ); this.webSocketManager.sendMessage(message); return result; } async action(udfPath, args) { const actionId = this.nextActionId; this.nextActionId++; const { message, result } = this.actionManager.request( udfPath, args, actionId ); this.webSocketManager.sendMessage(message); return result; } async close() { return this.webSocketManager.stop(); } } //# sourceMappingURL=client.js.map