@tanstack/react-optimistic
Version:
React hooks for optimistic updates
113 lines (112 loc) • 3.83 kB
JavaScript
;
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
const client = require("@electric-sql/client");
const store = require("@tanstack/store");
function isUpToDateMessage(message) {
return client.isControlMessage(message) && message.headers.control === `up-to-date`;
}
function hasTxids(message) {
return `headers` in message && `txids` in message.headers && Array.isArray(message.headers.txids);
}
function createElectricSync(streamOptions, options) {
const { primaryKey } = options;
const seenTxids = new store.Store(/* @__PURE__ */ new Set());
const relationSchema = new store.Store(void 0);
const hasTxid = (txid) => {
return seenTxids.state.has(txid);
};
const awaitTxid = async (txid, timeout = 3e4) => {
if (hasTxid(txid)) {
return true;
}
return new Promise((resolve, reject) => {
const timeoutId = setTimeout(() => {
unsubscribe();
reject(new Error(`Timeout waiting for txid: ${txid}`));
}, timeout);
const unsubscribe = seenTxids.subscribe(() => {
if (hasTxid(txid)) {
clearTimeout(timeoutId);
unsubscribe();
resolve(true);
}
});
});
};
const generateKeyFromRow = (row) => {
if (!primaryKey || primaryKey.length === 0) {
throw new Error(`Primary key is required for Electric sync`);
}
return primaryKey.map((key) => {
const value = row[key];
if (value === void 0) {
throw new Error(`Primary key column "${key}" not found in row`);
}
return String(value);
}).join(`|`);
};
const getSyncMetadata = () => {
var _a;
const schema = relationSchema.state || `public`;
return {
primaryKey,
relation: ((_a = streamOptions.params) == null ? void 0 : _a.table) ? [schema, streamOptions.params.table] : void 0
};
};
return {
sync: ({ begin, write, commit }) => {
const stream = new client.ShapeStream(streamOptions);
let transactionStarted = false;
let newTxids = /* @__PURE__ */ new Set();
stream.subscribe((messages) => {
let hasUpToDate = false;
for (const message of messages) {
if (hasTxids(message) && message.headers.txids) {
message.headers.txids.forEach((txid) => newTxids.add(txid));
}
if (client.isChangeMessage(message) && message.headers.schema) {
if (typeof message.headers.schema === `string`) {
const schema = message.headers.schema;
relationSchema.setState(() => schema);
}
}
if (client.isChangeMessage(message)) {
if (!transactionStarted) {
begin();
transactionStarted = true;
}
const key = message.key || generateKeyFromRow(message.value);
const enhancedMetadata = {
...message.headers,
primaryKey
};
write({
key,
type: message.headers.operation,
value: message.value,
metadata: enhancedMetadata
});
} else if (isUpToDateMessage(message)) {
hasUpToDate = true;
}
}
if (hasUpToDate && transactionStarted) {
commit();
seenTxids.setState((currentTxids) => {
const clonedSeen = new Set(currentTxids);
newTxids.forEach((txid) => clonedSeen.add(txid));
newTxids = /* @__PURE__ */ new Set();
return clonedSeen;
});
transactionStarted = false;
}
});
},
// Expose the awaitTxid function
awaitTxid,
// Expose the getSyncMetadata function
getSyncMetadata
};
}
exports.createElectricSync = createElectricSync;
//# sourceMappingURL=electric.cjs.map