in packages/database/src/core/Repo.ts [208:328]
export function repoStart(
repo: Repo,
appId: string,
authOverride?: object
): void {
repo.stats_ = statsManagerGetCollection(repo.repoInfo_);
if (repo.forceRestClient_ || beingCrawled()) {
repo.server_ = new ReadonlyRestClient(
repo.repoInfo_,
(
pathString: string,
data: unknown,
isMerge: boolean,
tag: number | null
) => {
repoOnDataUpdate(repo, pathString, data, isMerge, tag);
},
repo.authTokenProvider_,
repo.appCheckProvider_
);
// Minor hack: Fire onConnect immediately, since there's no actual connection.
setTimeout(() => repoOnConnectStatus(repo, /* connectStatus= */ true), 0);
} else {
// Validate authOverride
if (typeof authOverride !== 'undefined' && authOverride !== null) {
if (typeof authOverride !== 'object') {
throw new Error(
'Only objects are supported for option databaseAuthVariableOverride'
);
}
try {
stringify(authOverride);
} catch (e) {
throw new Error('Invalid authOverride provided: ' + e);
}
}
repo.persistentConnection_ = new PersistentConnection(
repo.repoInfo_,
appId,
(
pathString: string,
data: unknown,
isMerge: boolean,
tag: number | null
) => {
repoOnDataUpdate(repo, pathString, data, isMerge, tag);
},
(connectStatus: boolean) => {
repoOnConnectStatus(repo, connectStatus);
},
(updates: object) => {
repoOnServerInfoUpdate(repo, updates);
},
repo.authTokenProvider_,
repo.appCheckProvider_,
authOverride
);
repo.server_ = repo.persistentConnection_;
}
repo.authTokenProvider_.addTokenChangeListener(token => {
repo.server_.refreshAuthToken(token);
});
repo.appCheckProvider_.addTokenChangeListener(result => {
repo.server_.refreshAppCheckToken(result.token);
});
// In the case of multiple Repos for the same repoInfo (i.e. there are multiple Firebase.Contexts being used),
// we only want to create one StatsReporter. As such, we'll report stats over the first Repo created.
repo.statsReporter_ = statsManagerGetOrCreateReporter(
repo.repoInfo_,
() => new StatsReporter(repo.stats_, repo.server_)
);
// Used for .info.
repo.infoData_ = new SnapshotHolder();
repo.infoSyncTree_ = new SyncTree({
startListening: (query, tag, currentHashFn, onComplete) => {
let infoEvents: Event[] = [];
const node = repo.infoData_.getNode(query._path);
// This is possibly a hack, but we have different semantics for .info endpoints. We don't raise null events
// on initial data...
if (!node.isEmpty()) {
infoEvents = syncTreeApplyServerOverwrite(
repo.infoSyncTree_,
query._path,
node
);
setTimeout(() => {
onComplete('ok');
}, 0);
}
return infoEvents;
},
stopListening: () => {}
});
repoUpdateInfo(repo, 'connected', false);
repo.serverSyncTree_ = new SyncTree({
startListening: (query, tag, currentHashFn, onComplete) => {
repo.server_.listen(query, currentHashFn, tag, (status, data) => {
const events = onComplete(status, data);
eventQueueRaiseEventsForChangedPath(
repo.eventQueue_,
query._path,
events
);
});
// No synchronous events for network-backed sync trees
return [];
},
stopListening: (query, tag) => {
repo.server_.unlisten(query, tag);
}
});
}