UNPKG

graft-react

Version:

react admin and helper components for graft-db

606 lines (605 loc) 26.6 kB
"use strict"; var __assign = (this && this.__assign) || Object.assign || function(t) { for (var s, i = 1, n = arguments.length; i < n; i++) { s = arguments[i]; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; } return t; }; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; var __generator = (this && this.__generator) || function (thisArg, body) { var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t; return { next: verb(0), "throw": verb(1), "return": verb(2) }; function verb(n) { return function (v) { return step([n, v]); }; } function step(op) { if (f) throw new TypeError("Generator is already executing."); while (_) try { if (f = 1, y && (t = y[op[0] & 2 ? "return" : op[0] ? "throw" : "next"]) && !(t = t.call(y, op[1])).done) return t; if (y = 0, t) op = [0, t.value]; switch (op[0]) { case 0: case 1: t = op; break; case 4: _.label++; return { value: op[1], done: false }; case 5: _.label++; y = op[1]; op = [0]; continue; case 7: op = _.ops.pop(); _.trys.pop(); continue; default: if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } if (t[2]) _.ops.pop(); _.trys.pop(); continue; } op = body.call(thisArg, _); } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; } }; var graft_db_1 = require("graft-db"); var shortid = require("shortid"); function isRollback(latest, prev) { var prevKey = prev.key(); var newKey = latest.key(); if (prevKey && newKey) { var prevAge = graft_db_1.extractTimestampFromKey(prevKey); var newAge = graft_db_1.extractTimestampFromKey(newKey); if (prevAge.isAfter(newAge)) { return true; } } return false; } var Client = (function () { function Client() { var _this = this; this.getToken = function (msg) { return __awaiter(_this, void 0, void 0, function () { var _a; return __generator(this, function (_b) { switch (_b.label) { case 0: if (!(!this.cfg.token && this.cfg.onAuthenticate)) return [3 /*break*/, 2]; _a = this.cfg; return [4 /*yield*/, this.cfg.onAuthenticate(msg)]; case 1: _a.token = _b.sent(); _b.label = 2; case 2: if (!this.cfg.token) { throw new graft_db_1.Unauthorized('failed to authenticate'); } return [2 /*return*/, this.cfg.token]; } }); }); }; this.logout = function () { return __awaiter(_this, void 0, void 0, function () { return __generator(this, function (_a) { switch (_a.label) { case 0: this.cfg.token = undefined; this.cfg.id = undefined; this.cfg.tag = undefined; return [4 /*yield*/, this.close()]; case 1: _a.sent(); this.store = undefined; this.repository = undefined; this.initializing = true; this.onUpdate(); this.init(this.cfg); return [2 /*return*/]; } }); }); }; this.close = function () { return __awaiter(_this, void 0, void 0, function () { return __generator(this, function (_a) { switch (_a.label) { case 0: if (!(this.store && this.store.close)) return [3 /*break*/, 2]; return [4 /*yield*/, this.store.close()]; case 1: _a.sent(); _a.label = 2; case 2: return [2 /*return*/, true]; } }); }); }; this.cfg = { tag: 'master' }; this.mu = new graft_db_1.Mutex(); this.initializing = true; } Client.prototype.init = function (cfg) { return __awaiter(this, void 0, void 0, function () { var _this = this; return __generator(this, function (_a) { setTimeout(function () { return _this.reload(cfg); }, 0); return [2 /*return*/]; }); }); }; Client.prototype.reload = function (cfg) { return __awaiter(this, void 0, void 0, function () { var _this = this; var claims, r, _a, _b, _c, _d, _e, _f, _g, _h, e_1; return __generator(this, function (_j) { switch (_j.label) { case 0: this.cfg = __assign({}, this.cfg, cfg); this.dirty = false; this.sync = true; this.initializing = true; if (!this.store) return [3 /*break*/, 2]; return [4 /*yield*/, this.store.close()]; case 1: _j.sent(); _j.label = 2; case 2: this.store = new graft_db_1.QueuedWriteStore(new graft_db_1.RemoteStore({ authenticate: this.getToken, endpoint: 'http://oxdi.graftdb.com' }), false); if (this.store instanceof graft_db_1.QueuedWriteStore) { this.store.onQueue = function () { _this.sync = false; _this.onUpdateSync(); _this.onUpdate(); }; this.store.onDrain = function () { console.log('drained'); _this.sync = true; _this.lastSync = new Date(); _this.onUpdateSync(); _this.onUpdate(); }; } _j.label = 3; case 3: if (!true) return [3 /*break*/, 20]; _j.label = 4; case 4: _j.trys.push([4, 11, , 19]); return [4 /*yield*/, this.getClaims()]; case 5: claims = _j.sent(); this.onUpdate(); _a = graft_db_1.Repository.bind; _c = { store: this.store }; return [4 /*yield*/, this.getRepositoryId(claims)]; case 6: r = new (_a.apply(graft_db_1.Repository, [void 0, (_c.id = _j.sent(), _c)]))(); console.log('created repo'); _d = this; return [4 /*yield*/, r.latest(true)]; case 7: _d.repository = _j.sent(); console.log('got latest'); this.onUpdate(); _e = this; _g = (_f = this.repository).checkout; return [4 /*yield*/, this.getTagName(this.repository)]; case 8: return [4 /*yield*/, _g.apply(_f, [_j.sent()])]; case 9: _e.upstream = _j.sent(); console.log('cloned repo'); this.initializing = false; this.lastSync = new Date(); return [4 /*yield*/, this.setWork(this.upstream)]; case 10: _j.sent(); console.log('set work'); return [3 /*break*/, 20]; case 11: e_1 = _j.sent(); if (!(e_1 instanceof graft_db_1.TransportErr)) return [3 /*break*/, 13]; console.warn('failed to init', e_1, 'will try again soon'); return [4 /*yield*/, graft_db_1.sleep(1000)]; case 12: _j.sent(); return [3 /*break*/, 17]; case 13: if (!(e_1 instanceof graft_db_1.Unauthorized)) return [3 /*break*/, 16]; console.warn('unauth', e_1); if (!this.cfg.onLogout) return [3 /*break*/, 15]; return [4 /*yield*/, this.cfg.onLogout()]; case 14: _j.sent(); _j.label = 15; case 15: this.cfg.token = undefined; this.repository = undefined; this.initializing = true; this.onUpdate(); return [3 /*break*/, 17]; case 16: console.error('fatal during init:', e_1, e_1.stack); _j.label = 17; case 17: return [4 /*yield*/, graft_db_1.sleep(500)]; case 18: _j.sent(); return [3 /*break*/, 19]; case 19: return [3 /*break*/, 3]; case 20: this.repositoryWatcher(); return [2 /*return*/]; } }); }); }; Client.prototype.getClaims = function () { return __awaiter(this, void 0, void 0, function () { var token, claims; return __generator(this, function (_a) { switch (_a.label) { case 0: return [4 /*yield*/, this.getToken()]; case 1: token = _a.sent(); claims = graft_db_1.Claims.fromUnverifiedToken(token); return [2 /*return*/, claims]; } }); }); }; Client.prototype.getRepositoryId = function (claims) { return __awaiter(this, void 0, void 0, function () { var _a; return __generator(this, function (_b) { switch (_b.label) { case 0: if (!(!this.cfg.id && this.cfg.onSelectRepository)) return [3 /*break*/, 2]; _a = this.cfg; return [4 /*yield*/, this.cfg.onSelectRepository(claims)]; case 1: _a.id = _b.sent(); _b.label = 2; case 2: if (!this.cfg.id) { throw new Error('no repository selected'); } return [2 /*return*/, this.cfg.id]; } }); }); }; Client.prototype.getTagName = function (r) { return __awaiter(this, void 0, void 0, function () { var _a; return __generator(this, function (_b) { switch (_b.label) { case 0: if (!(!this.cfg.tag && this.cfg.onSelectTag)) return [3 /*break*/, 2]; _a = this.cfg; return [4 /*yield*/, this.cfg.onSelectTag(r)]; case 1: _a.tag = _b.sent(); _b.label = 2; case 2: if (!this.cfg.tag) { this.cfg.tag = 'master'; } return [2 /*return*/, this.cfg.tag]; } }); }); }; Client.prototype.setWork = function (b) { return __awaiter(this, void 0, void 0, function () { var old, g; return __generator(this, function (_a) { switch (_a.label) { case 0: old = this.work; if (b === old) { return [2 /*return*/, false]; ; } return [4 /*yield*/, b.toGraph()]; case 1: g = _a.sent(); return [4 /*yield*/, g.validate()]; case 2: _a.sent(); this.work = b; this.dirty = this.work.key() !== this.upstream.key(); this.onUpdate(); return [2 /*return*/, true]; } }); }); }; Client.prototype.update = function (tx) { return __awaiter(this, void 0, void 0, function () { var unlock, res, b, _a; return __generator(this, function (_b) { switch (_b.label) { case 0: return [4 /*yield*/, this.mu.lock()]; case 1: unlock = _b.sent(); _b.label = 2; case 2: _b.trys.push([2, , 7, 8]); res = tx(this.work); if (!(res instanceof Promise)) return [3 /*break*/, 4]; return [4 /*yield*/, res]; case 3: _a = _b.sent(); return [3 /*break*/, 5]; case 4: _a = res; _b.label = 5; case 5: b = _a; if (!(b instanceof graft_db_1.Branch)) { console.warn('update:', 'update tx did not return a branch, got:', b); return [2 /*return*/]; } return [4 /*yield*/, this.setWork(b)]; case 6: _b.sent(); return [3 /*break*/, 8]; case 7: unlock(); return [7 /*endfinally*/]; case 8: return [2 /*return*/]; } }); }); }; Client.prototype.repositoryWatcher = function () { return __awaiter(this, void 0, void 0, function () { var _a, e_2; return __generator(this, function (_b) { switch (_b.label) { case 0: console.log('starting watch'); _b.label = 1; case 1: if (!true) return [3 /*break*/, 12]; _b.label = 2; case 2: _b.trys.push([2, 5, , 11]); _a = this; return [4 /*yield*/, this.repository.watch()]; case 3: _a.repository = _b.sent(); return [4 /*yield*/, this.pull()]; case 4: if (!(_b.sent())) { console.log('repo only update'); this.onUpdate(); } return [3 /*break*/, 11]; case 5: e_2 = _b.sent(); if (!(e_2 instanceof graft_db_1.TransportErr)) return [3 /*break*/, 7]; console.warn('watch', e_2, 'will try again in a sec..'); return [4 /*yield*/, graft_db_1.sleep(3000)]; case 6: _b.sent(); return [3 /*break*/, 10]; case 7: if (!(e_2 instanceof graft_db_1.Cancelled)) return [3 /*break*/, 8]; console.log('cancelled watch', e_2); return [2 /*return*/]; case 8: console.error('watch', e_2, 'looks serious, sleeping for a while'); return [4 /*yield*/, graft_db_1.sleep(10000)]; case 9: _b.sent(); _b.label = 10; case 10: return [3 /*break*/, 1]; case 11: return [3 /*break*/, 1]; case 12: return [2 /*return*/]; } }); }); }; Client.prototype.onUpdateSync = function () { if (this.cfg.onUpdateSync) { this.cfg.onUpdateSync(this); } }; Client.prototype.onUpdate = function () { if (this.cfg.onUpdate) { this.cfg.onUpdate(this); } }; Client.prototype.onError = function (err) { if (this.cfg.onError) { this.cfg.onError(err); } else { console.error(err); } }; Client.prototype.pull = function () { return __awaiter(this, void 0, void 0, function () { var upstream, _a, _b, e_3, tag, _c, _d; return __generator(this, function (_e) { switch (_e.label) { case 0: return [4 /*yield*/, this.upstream.pull()]; case 1: upstream = _e.sent(); if (this.work && this.work.key() !== upstream.key() && isRollback(upstream, this.upstream)) { alert('rollback detected: another user rollacked back, your local changes are no longer relevent and will be lost.'); this.upstream = upstream; return [2 /*return*/, this.setWork(upstream)]; } this.upstream = upstream; if (!this.work) { return [2 /*return*/, this.setWork(upstream)]; } _e.label = 2; case 2: _e.trys.push([2, 4, , 9]); _a = this.setWork; return [4 /*yield*/, this.work.rebase(upstream, { onConflict: this.cfg.onConflict })]; case 3: return [2 /*return*/, _a.apply(this, [_e.sent()])]; case 4: e_3 = _e.sent(); if (!(e_3 instanceof graft_db_1.MergeConflict)) return [3 /*break*/, 7]; console.warn(e_3, 'no onConflict handler, changes will be lost'); return [4 /*yield*/, this.getTagName(this.repository)]; case 5: tag = _e.sent(); _c = this.setWork; return [4 /*yield*/, this.repository.checkout(tag)]; case 6: return [2 /*return*/, _c.apply(this, [_e.sent()])]; case 7: throw e_3; case 8: return [3 /*break*/, 9]; case 9: return [2 /*return*/]; } }); }); }; Client.prototype.query = function (q, vars) { return __awaiter(this, void 0, void 0, function () { return __generator(this, function (_a) { return [2 /*return*/, this.work.query(q, vars)]; }); }); }; Client.prototype.push = function (opts) { return __awaiter(this, void 0, void 0, function () { var work; return __generator(this, function (_a) { switch (_a.label) { case 0: return [4 /*yield*/, this.work.push(opts)]; case 1: work = _a.sent(); return [2 /*return*/, work]; } }); }); }; Client.prototype.undo = function () { return __awaiter(this, void 0, void 0, function () { return __generator(this, function (_a) { if (this.work.prev) { this.setWork(this.work.prev); } return [2 /*return*/, this]; }); }); }; Client.prototype.newValueKey = function (id, kd) { if (!id) { id = this.generateId(); } var rd = parseInt(id.replace('_', 'aa').replace('-', 'bb'), 32); if (!rd) { throw new Error('rd should always be set'); } var ns = this.cfg.id; if (!ns) { throw new Error('cannot create value key without repository id'); } if (this.initializing) { throw new Error('cannot create value key while initializing'); } if (!this.lastSync) { throw new Error('cannot create value key without a lastSync date'); } return graft_db_1.encodeKey({ ns: ns, rd: rd, ts: this.lastSync.getTime(), kd: kd || 'value' }); }; Client.prototype.newImageKey = function (id) { return this.newValueKey(id, 'image'); }; Client.prototype.storeValue = function (valueObject, v) { return __awaiter(this, void 0, void 0, function () { var key; return __generator(this, function (_a) { switch (_a.label) { case 0: if (!this.store) { throw new Error('no store set'); } return [4 /*yield*/, this.store.setString(this.newValueKey(valueObject.id), v)]; case 1: key = _a.sent(); return [2 /*return*/, __assign({}, valueObject, { key: key })]; } }); }); }; Client.prototype.generateId = function () { return shortid.generate(); }; Client.prototype.setValue = function (value) { return __awaiter(this, void 0, void 0, function () { var args; return __generator(this, function (_a) { switch (_a.label) { case 0: args = __assign({}, value, { id: value.id || this.generateId() }); console.log('setValue', args); return [4 /*yield*/, this._setValue(args)]; case 1: _a.sent(); return [2 /*return*/]; } }); }); }; Client.prototype._setValue = function (args) { return __awaiter(this, void 0, void 0, function () { var g, data, o, p, old; return __generator(this, function (_a) { switch (_a.label) { case 0: return [4 /*yield*/, this.work.toGraph()]; case 1: g = _a.sent(); data = { kind: graft_db_1.Kind.Value, }; if (args.key && args.value) { throw new Error("cannot supply both \"key\" and \"value\""); } else if (args.key) { data.key = args.key; } else if (args.value) { data.value = args.value; } else { throw new Error("must supply a \"key\" or \"value\" arg"); } if (args.owner) { o = g.get(args.owner); if (!(o instanceof graft_db_1.ObjectEntity)) { throw new Error('invalid object'); } data.owner = o.id; } if (args.property) { p = g.get(args.property); if (p instanceof graft_db_1.PropertyEntity) { data.property = p.id; data.type = graft_db_1.propertyTypeToValueType(p.type); } else { throw new Error('invalid property'); } } old = g.all .filter(function (e) { return e instanceof graft_db_1.ValueEntity && e.id === args.id; }) .find(function (v) { return !!v; }); if (old) { data.owner = data.owner || old.owner; data.property = data.property || old.property; data.type = data.type || old.type; } this.update(function (b) { return b.set(args.id, data); }); return [2 /*return*/]; } }); }); }; return Client; }()); exports.Client = Client;