convex
Version:
Client for the Convex Cloud
228 lines (227 loc) • 6.38 kB
JavaScript
"use strict";
import { convexToJson } from "../../values/index.js";
import {
canonicalizeUdfPath,
serializePathAndArgs
} from "./udf_path_utils.js";
export class LocalSyncState {
constructor() {
this.nextQueryId = 0;
this.querySetVersion = 0;
this.identityVersion = 0;
this.querySet = /* @__PURE__ */ new Map();
this.queryIdToToken = /* @__PURE__ */ new Map();
this.outstandingQueriesOlderThanRestart = /* @__PURE__ */ new Set();
this.outstandingAuthOlderThanRestart = false;
}
hasSyncedPastLastReconnect() {
return this.outstandingQueriesOlderThanRestart.size === 0 && !this.outstandingAuthOlderThanRestart;
}
markAuthCompletion() {
this.outstandingAuthOlderThanRestart = false;
}
subscribe(udfPath, args, journal) {
const canonicalizedUdfPath = canonicalizeUdfPath(udfPath);
const queryToken = serializePathAndArgs(canonicalizedUdfPath, args);
const existingEntry = this.querySet.get(queryToken);
if (existingEntry !== void 0) {
existingEntry.numSubscribers += 1;
return {
queryToken,
modification: null,
unsubscribe: () => this.removeSubscriber(queryToken)
};
} else {
const queryId = this.nextQueryId++;
const query = {
id: queryId,
canonicalizedUdfPath,
args,
numSubscribers: 1,
journal
};
this.querySet.set(queryToken, query);
this.queryIdToToken.set(queryId, queryToken);
const baseVersion = this.querySetVersion;
const newVersion = ++this.querySetVersion;
const add = {
type: "Add",
queryId,
udfPath: canonicalizedUdfPath,
args: [convexToJson(args)],
journal
};
const modification = {
type: "ModifyQuerySet",
baseVersion,
newVersion,
modifications: [add]
};
return {
queryToken,
modification,
unsubscribe: () => this.removeSubscriber(queryToken)
};
}
}
transition(transition) {
for (const modification of transition.modifications) {
switch (modification.type) {
case "QueryUpdated":
case "QueryFailed": {
this.outstandingQueriesOlderThanRestart.delete(modification.queryId);
const journal = modification.journal;
if (journal !== void 0) {
const queryToken = this.queryIdToToken.get(modification.queryId);
if (queryToken !== void 0) {
this.querySet.get(queryToken).journal = journal;
}
}
break;
}
case "QueryRemoved": {
this.outstandingQueriesOlderThanRestart.delete(modification.queryId);
break;
}
default: {
const _ = modification;
throw new Error(`Invalid modification ${modification.type}`);
}
}
}
}
queryId(udfPath, args) {
const canonicalizedUdfPath = canonicalizeUdfPath(udfPath);
const queryToken = serializePathAndArgs(canonicalizedUdfPath, args);
const existingEntry = this.querySet.get(queryToken);
if (existingEntry !== void 0) {
return existingEntry.id;
}
return null;
}
isCurrentOrNewerAuthVersion(version) {
return version >= this.identityVersion;
}
setAuth(value) {
this.auth = {
tokenType: "User",
value
};
const baseVersion = this.identityVersion++;
return {
type: "Authenticate",
baseVersion,
...this.auth
};
}
setAdminAuth(value, actingAs) {
const auth = {
tokenType: "Admin",
value,
impersonating: actingAs
};
this.auth = auth;
const baseVersion = this.identityVersion++;
return {
type: "Authenticate",
baseVersion,
...auth
};
}
clearAuth() {
this.auth = void 0;
this.markAuthCompletion();
const baseVersion = this.identityVersion++;
return {
type: "Authenticate",
tokenType: "None",
baseVersion
};
}
hasAuth() {
return !!this.auth;
}
isNewAuth(value) {
return this.auth?.value !== value;
}
queryPath(queryId) {
const pathAndArgs = this.queryIdToToken.get(queryId);
if (pathAndArgs) {
return this.querySet.get(pathAndArgs).canonicalizedUdfPath;
}
return null;
}
queryArgs(queryId) {
const pathAndArgs = this.queryIdToToken.get(queryId);
if (pathAndArgs) {
return this.querySet.get(pathAndArgs).args;
}
return null;
}
queryToken(queryId) {
return this.queryIdToToken.get(queryId) ?? null;
}
queryJournal(queryToken) {
return this.querySet.get(queryToken)?.journal;
}
restart(oldRemoteQueryResults) {
this.outstandingQueriesOlderThanRestart.clear();
const modifications = [];
for (const localQuery of this.querySet.values()) {
const add = {
type: "Add",
queryId: localQuery.id,
udfPath: localQuery.canonicalizedUdfPath,
args: [convexToJson(localQuery.args)],
journal: localQuery.journal
};
modifications.push(add);
if (!oldRemoteQueryResults.has(localQuery.id)) {
this.outstandingQueriesOlderThanRestart.add(localQuery.id);
}
}
this.querySetVersion = 1;
const querySet = {
type: "ModifyQuerySet",
baseVersion: 0,
newVersion: 1,
modifications
};
if (!this.auth) {
this.identityVersion = 0;
return [querySet, void 0];
}
this.outstandingAuthOlderThanRestart = true;
const authenticate = {
type: "Authenticate",
baseVersion: 0,
...this.auth
};
this.identityVersion = 1;
return [querySet, authenticate];
}
removeSubscriber(queryToken) {
const localQuery = this.querySet.get(queryToken);
if (localQuery.numSubscribers > 1) {
localQuery.numSubscribers -= 1;
return null;
} else {
this.querySet.delete(queryToken);
this.queryIdToToken.delete(localQuery.id);
this.outstandingQueriesOlderThanRestart.delete(localQuery.id);
const baseVersion = this.querySetVersion;
const newVersion = ++this.querySetVersion;
const remove = {
type: "Remove",
queryId: localQuery.id
};
return {
type: "ModifyQuerySet",
baseVersion,
newVersion,
modifications: [remove]
};
}
}
}
//# sourceMappingURL=local_state.js.map