UNPKG

shogun-core

Version:

SHOGUN CORE - Core library for Shogun Ecosystem

484 lines (483 loc) 17.2 kB
var __read = (this && this.__read) || function (o, n) { var m = typeof Symbol === "function" && o[Symbol.iterator]; if (!m) return o; var i = m.call(o), r, ar = [], e; try { while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value); } catch (error) { e = { error: error }; } finally { try { if (r && !r.done && (m = i["return"])) m.call(i); } finally { if (e) throw e.error; } } return ar; }; var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) { if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) { if (ar || !(i in from)) { if (!ar) ar = Array.prototype.slice.call(from, 0, i); ar[i] = from[i]; } } return to.concat(ar || Array.prototype.slice.call(from)); }; import { Observable } from 'rxjs'; import { distinctUntilChanged } from 'rxjs/operators'; /** * RxJS Integration for GunDB * Provides reactive programming capabilities for GunDB data */ var RxJS = /** @class */ (function () { /** * Initialize GunRxJS with a GunDB instance * @param gun - GunDB instance */ function RxJS(gun) { this.gun = gun; this.user = gun.user(); } /** * Get the current user * @returns The current user */ RxJS.prototype.getUser = function () { return this.user; }; /** * Get the current user's public key * @returns The current user's public key */ RxJS.prototype.getUserPub = function () { var _a; return (_a = this.user.is) === null || _a === void 0 ? void 0 : _a.pub; }; /** * Observe a Gun node for changes * @param path - Path to observe (can be a string or a Gun chain) * @returns Observable that emits whenever the node changes */ RxJS.prototype.observe = function (path) { var _this = this; return new Observable(function (subscriber) { var node; if (Array.isArray(path)) { // Support array paths by chaining get calls node = _this.gun.get(path[0]); for (var i = 1; i < path.length; i++) { node = node.get(path[i]); } } else if (typeof path === 'string') { node = _this.gun.get(path); } else { node = path; } // Subscribe to changes var unsub = node.on(function (data, key) { if (data === null || data === undefined) { subscriber.next(null); return; } // Remove Gun metadata before emitting if (typeof data === 'object' && data !== null) { var cleanData = _this.removeGunMeta(data); subscriber.next(cleanData); } else { subscriber.next(data); } }); // Return teardown logic return function () { if (unsub && typeof unsub === 'function') { unsub(); } node.off(); }; }).pipe(distinctUntilChanged(function (prev, curr) { return JSON.stringify(prev) === JSON.stringify(curr); })); }; /** * Match data based on Gun's '.map()' and convert to Observable * @param path - Path to the collection * @param matchFn - Optional function to filter results * @returns Observable array of matched items */ RxJS.prototype.match = function (path, matchFn) { var _this = this; return new Observable(function (subscriber) { if (!path) { subscriber.next([]); subscriber.complete(); return; } var node = typeof path === 'string' ? _this.gun.get(path) : path; var results = {}; var unsub = node.map().on(function (data, key) { // Skip soul key which is Gun's internal reference if (key === '_' || !data) return; if (matchFn && !matchFn(data)) { // If matchFn is provided and returns false, remove item if (results[key]) { delete results[key]; subscriber.next(Object.values(results)); } return; } var cleanData = typeof data === 'object' ? _this.removeGunMeta(data) : data; results[key] = cleanData; subscriber.next(Object.values(results)); }); // Return teardown logic return function () { if (unsub && typeof unsub === 'function') { unsub(); } node.off(); }; }); }; /** * Put data and return an Observable * @param path - Path where to put the data * @param data - Data to put * @returns Observable that completes when the put is acknowledged */ RxJS.prototype.put = function (path, data) { var _this = this; return new Observable(function (subscriber) { var performPut = function (target, value) { target.put(value, function (ack) { if (ack.err) { subscriber.error(new Error(ack.err)); } else { subscriber.next(value); subscriber.complete(); } }); }; if (typeof path === 'string' || Array.isArray(path)) { // Path-based put var node = void 0; if (Array.isArray(path)) { node = _this.gun.get(path[0]); for (var i = 1; i < path.length; i++) node = node.get(path[i]); } else { node = _this.gun.get(path); } performPut(node, data); } else { // Root-level put performPut(_this.gun, path); } }); }; /** * Backward-compatible overload that accepts optional callback like tests expect */ RxJS.prototype.putCompat = function (data, callback) { var _this = this; return new Observable(function (subscriber) { _this.gun.put(data, function (ack) { if (callback) callback(ack); if (ack.err) { subscriber.error(new Error(ack.err)); } else { subscriber.next(data); subscriber.complete(); } }); }); }; /** * Set data on a node and return an Observable * @param path - Path to the collection * @param data - Data to set * @returns Observable that completes when the set is acknowledged */ RxJS.prototype.set = function (path, data) { var _this = this; return new Observable(function (subscriber) { var performSet = function (target, value) { target.set(value, function (ack) { if (ack.err) { subscriber.error(new Error(ack.err)); } else { subscriber.next(value); subscriber.complete(); } }); }; if (typeof path === 'string' || Array.isArray(path)) { var node = void 0; if (Array.isArray(path)) { node = _this.gun.get(path[0]); for (var i = 1; i < path.length; i++) node = node.get(path[i]); } else { node = _this.gun.get(path); } performSet(node, data); } else { performSet(_this.gun, path); } }); }; RxJS.prototype.setCompat = function (data, callback) { var _this = this; return new Observable(function (subscriber) { _this.gun.set(data, function (ack) { if (callback) callback(ack); if (ack.err) { subscriber.error(new Error(ack.err)); } else { subscriber.next(data); subscriber.complete(); } }); }); }; /** * Get data once and return as Observable * @param path - Path to get data from * @returns Observable that emits the data once */ RxJS.prototype.once = function (path) { var _this = this; var node; if (typeof path === 'string') { node = this.gun.get(path); } else if (path) { node = path; } else { node = this.gun; } return new Observable(function (subscriber) { node.once(function (data) { if (data === undefined || data === null) { subscriber.next(null); subscriber.complete(); return; } var cleanData = typeof data === 'object' ? _this.removeGunMeta(data) : data; subscriber.next(cleanData); subscriber.complete(); }); }); }; /** * Compute derived values from gun data * @param sources - Array of paths or observables to compute from * @param computeFn - Function that computes a new value from the sources * @returns Observable of computed values */ RxJS.prototype.compute = function (sources, computeFn) { var _this = this; // Convert all sources to observables var observables = sources.map(function (source) { if (typeof source === 'string') { return _this.observe(source); } return source; }); // Combine the latest values from all sources return new Observable(function (subscriber) { var values = new Array(sources.length).fill(undefined); var completed = new Array(sources.length).fill(false); var subscriptions = observables.map(function (obs, index) { return obs.subscribe({ next: function (value) { values[index] = value; // Only compute if we have all values if (values.every(function (v) { return v !== undefined; })) { try { var result = computeFn.apply(void 0, __spreadArray([], __read(values), false)); subscriber.next(result); } catch (error) { subscriber.error(error); } } }, error: function (err) { return subscriber.error(err); }, complete: function () { completed[index] = true; if (completed.every(function (c) { return c; })) { subscriber.complete(); } }, }); }); // Return teardown logic return function () { subscriptions.forEach(function (sub) { return sub.unsubscribe(); }); }; }); }; /** * User put data and return an Observable (for authenticated users) * @param path - Path where to put the data * @param data - Data to put * @returns Observable that completes when the put is acknowledged */ RxJS.prototype.userPut = function (dataOrPath, maybeData, callback) { var _this = this; return new Observable(function (subscriber) { var user = _this.gun.user(); if (typeof dataOrPath === 'string') { user.get(dataOrPath).put(maybeData, function (ack) { if (callback) callback(ack); if (ack.err) { subscriber.error(new Error(ack.err)); } else { subscriber.next(maybeData); subscriber.complete(); } }); } else { user.put(dataOrPath, function (ack) { if (callback) callback(ack); if (ack.err) { subscriber.error(new Error(ack.err)); } else { subscriber.next(dataOrPath); subscriber.complete(); } }); } }); }; /** * User set data and return an Observable (for authenticated users) * @param dataOrPath - Data to set or path where to set the data * @param maybeData - Data to set (if first parameter is path) * @param callback - Optional callback function * @returns Observable that completes when the set is acknowledged */ RxJS.prototype.userSet = function (dataOrPath, maybeData, callback) { var _this = this; return new Observable(function (subscriber) { var user = _this.gun.user(); if (typeof dataOrPath === 'string') { user.get(dataOrPath).set(maybeData, function (ack) { if (callback) callback(ack); if (ack.err) { subscriber.error(new Error(ack.err)); } else { subscriber.next(maybeData); subscriber.complete(); } }); } else { user.set(dataOrPath, function (ack) { if (callback) callback(ack); if (ack.err) { subscriber.error(new Error(ack.err)); } else { subscriber.next(dataOrPath); subscriber.complete(); } }); } }); }; /** * User once data and return an Observable (for authenticated users) * @param path - Optional path to get data from * @param callback - Optional callback function * @returns Observable that emits the data once */ RxJS.prototype.userOnce = function (path, callback) { var _this = this; return new Observable(function (subscriber) { var user = _this.gun.user(); var target = path ? user.get(path) : user; target.once(function (data, ack) { if (callback) callback(ack); if (ack && ack.err) { subscriber.error(new Error(ack.err)); } else { subscriber.next(data); subscriber.complete(); } }); }); }; /** * Get user data * @param path - Path to get data from * @returns Observable that emits the data once */ RxJS.prototype.userGet = function (path) { return this.observe(this.gun.user().get(path)); }; /** * Observe user data * @param path - Path to observe in user space * @returns Observable that emits whenever the user data changes */ RxJS.prototype.observeUser = function (path) { if (path) { return this.observe(this.gun.user().get(path)); } return this.observe(this.gun.user().get('~')); }; /** * Remove Gun metadata from an object * @param obj - Object to clean * @returns Cleaned object without Gun metadata */ RxJS.prototype.removeGunMeta = function (obj) { var _this = this; if (!obj || typeof obj !== 'object') return obj; // Create a clean copy var cleanObj = Array.isArray(obj) ? [] : {}; // Copy properties, skipping Gun metadata Object.keys(obj).forEach(function (key) { // Skip Gun metadata if (key === '_' || key === '#') return; var val = obj[key]; if (val && typeof val === 'object') { cleanObj[key] = _this.removeGunMeta(val); } else { cleanObj[key] = val; } }); return cleanObj; }; return RxJS; }()); export { RxJS };