graft-react
Version:
react admin and helper components for graft-db
606 lines (605 loc) • 26.6 kB
JavaScript
"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;