kinto
Version:
An Offline-First JavaScript client for Kinto.
2,835 lines • 88.7 kB
JavaScript
!(function (e, t) {
"object" == typeof exports && "undefined" != typeof module
? t(exports)
: "function" == typeof define && define.amd
? define(["exports"], t)
: t(
((e =
"undefined" != typeof globalThis ? globalThis : e || self).Kinto =
{})
);
})(this, function (e) {
"use strict";
function t(e, t, s, r) {
var i,
a = arguments.length,
n =
a < 3
? t
: null === r
? (r = Object.getOwnPropertyDescriptor(t, s))
: r;
if ("object" == typeof Reflect && "function" == typeof Reflect.decorate)
n = Reflect.decorate(e, t, s, r);
else
for (var o = e.length - 1; o >= 0; o--)
(i = e[o]) && (n = (a < 3 ? i(n) : a > 3 ? i(t, s, n) : i(t, s)) || n);
return (a > 3 && n && Object.defineProperty(t, s, n), n);
}
"function" == typeof SuppressedError && SuppressedError;
const s = /^[a-zA-Z0-9][a-zA-Z0-9_-]*$/;
function r(e) {
return void 0 === e;
}
function i(e, t) {
return Object.keys(e).every((s) => {
const r = e[s];
return Array.isArray(r)
? r.some((e) => e === t[s])
: "object" == typeof r
? i(r, t[s])
: Object.prototype.hasOwnProperty.call(t, s)
? t[s] === r
: (console.error(`The property ${s} does not exist`), !1);
});
}
function a(e, t) {
return e.length
? e.reduce((e, t) => e.then(t), Promise.resolve(t))
: Promise.resolve(t);
}
function n(e, t) {
if (e === t) return !0;
if (typeof e != typeof t) return !1;
if (!e || "object" != typeof e || !t || "object" != typeof t) return !1;
if (Object.keys(e).length !== Object.keys(t).length) return !1;
for (const s in e) if (!n(e[s], t[s])) return !1;
return !0;
}
function o(e, t = []) {
const s = Object.assign({}, e);
for (const e of t) delete s[e];
return s;
}
function c(e, t, s) {
const r = e.length - 1;
return e.reduce(
(e, s, i) =>
i === r
? (e[s] = t)
: Object.prototype.hasOwnProperty.call(e, s)
? e[s]
: (e[s] = {}),
s
);
}
function d(e) {
if (p(e)) return e;
if ("string" == typeof e) return { id: e };
throw new Error("Invalid argument.");
}
function h(e) {
const t = (e) => encodeURIComponent("boolean" == typeof e ? String(e) : e),
s = g(e);
return Object.keys(s)
.map((e) => {
const r = t(e) + "=";
return Array.isArray(s[e])
? r + s[e].map((e) => t(e)).join(",")
: r + t(s[e]);
})
.join("&");
}
function l(e) {
return function (t, s, r) {
const i = r.value;
return {
configurable: !0,
get() {
const t = (...t) =>
(this.client ? this.client : this)
.fetchServerCapabilities()
.then((t) => {
const s = e.filter((e) => !(e in t));
if (s.length) {
const e = s.join(", ");
throw new Error(
`Required capabilities ${e} not present on server`
);
}
})
.then(() => i.apply(this, t));
return (
Object.defineProperty(this, s, {
value: t,
configurable: !0,
writable: !0,
}),
t
);
},
};
};
}
function u(e) {
return function (t, s, r) {
const i = r.value;
return {
configurable: !0,
get() {
const t = (...t) => {
if (this._isBatch) throw new Error(e);
return i.apply(this, t);
};
return (
Object.defineProperty(this, s, {
value: t,
configurable: !0,
writable: !0,
}),
t
);
},
};
};
}
function p(e) {
return "object" == typeof e && null !== e && !Array.isArray(e);
}
function f(e) {
const {
name: t,
type: s,
base64: r,
} = (function (e) {
const t = e.match(/^data:(.*);base64,(.*)/);
if (!t)
throw new Error(`Invalid data-url: ${String(e).substring(0, 32)}...`);
const s = t[1],
r = t[2],
[i, ...a] = s.split(";"),
n = a.reduce((e, t) => {
const [s, r] = t.split("=");
return Object.assign(Object.assign({}, e), { [s]: r });
}, {});
return Object.assign(Object.assign({}, n), { type: i, base64: r });
})(e),
i = atob(r),
a = [];
for (let e = 0; e < i.length; e++) a.push(i.charCodeAt(e));
return { blob: new Blob([new Uint8Array(a)], { type: s }), name: t };
}
function g(e) {
const t = {};
for (const s in e) void 0 !== e[s] && (t[s] = e[s]);
return t;
}
function m(e) {
const t = new Headers(e);
t.has("authorization") && t.set("authorization", "**** (suppressed)");
const s = {};
for (const [e, r] of t.entries()) s[e] = r;
return s;
}
const y = {
104: "Missing Authorization Token",
105: "Invalid Authorization Token",
106: "Request body was not valid JSON",
107: "Invalid request parameter",
108: "Missing request parameter",
109: "Invalid posted data",
110: "Invalid Token / id",
111: "Missing Token / id",
112: "Content-Length header was not provided",
113: "Request body too large",
114: "Resource was created, updated or deleted meanwhile",
115: "Method not allowed on this end point (hint: server may be readonly)",
116: "Requested version not available on this server",
117: "Client has sent too many requests",
121: "Resource access is forbidden for this user",
122: "Another resource violates constraint",
201: "Service Temporary unavailable due to high load",
202: "Service deprecated",
999: "Internal Server Error",
};
class _ extends Error {
constructor(e, t) {
(super(`Timeout while trying to access ${e} with ${JSON.stringify(t)}`),
Error.captureStackTrace && Error.captureStackTrace(this, _),
(this.url = e),
(this.options = t));
}
}
class b extends Error {
constructor(e, t, s) {
const { status: r } = e;
(super(`Response from server unparseable (HTTP ${r || 0}; ${s}): ${t}`),
Error.captureStackTrace && Error.captureStackTrace(this, b),
(this.status = r),
(this.response = e),
(this.stack = s.stack),
(this.error = s));
}
}
class w extends Error {
constructor(e, t) {
const { status: s } = e;
let r,
{ statusText: i } = e;
t &&
((i = t.error || i),
t.errno && t.errno in y
? (r = y[t.errno])
: t.message && (r = t.message),
r && t.message && t.message !== r && (r += ` (${t.message})`));
let a = `HTTP ${s} ${i}`;
(r && (a += `: ${r}`),
super(a.trim()),
Error.captureStackTrace && Error.captureStackTrace(this, w),
(this.response = e),
(this.data = t));
}
}
class v {
static get DEFAULT_REQUEST_HEADERS() {
return { Accept: "application/json", "Content-Type": "application/json" };
}
static get defaultOptions() {
return { timeout: null, requestMode: "cors" };
}
constructor(e, t = {}) {
((this.events = e),
(this.requestMode = t.requestMode || v.defaultOptions.requestMode),
(this.timeout = t.timeout || v.defaultOptions.timeout),
(this.fetchFunc = t.fetchFunc || globalThis.fetch.bind(globalThis)));
}
timedFetch(e, t) {
let s = !1;
return new Promise((r, i) => {
let a;
function n(e) {
return (t) => {
s || (a && clearTimeout(a), e(t));
};
}
(this.timeout &&
(a = setTimeout(() => {
((s = !0),
t &&
t.headers &&
(t = Object.assign(Object.assign({}, t), {
headers: m(t.headers),
})),
i(new _(e, t)));
}, this.timeout)),
this.fetchFunc(e, t).then(n(r)).catch(n(i)));
});
}
async processResponse(e) {
const { status: t, headers: s } = e,
r = await e.text();
let i;
if (0 !== r.length)
try {
i = JSON.parse(r);
} catch (t) {
throw new b(e, r, t);
}
if (t >= 400) throw new w(e, i);
return { status: t, json: i, headers: s };
}
async retry(e, t, s, r) {
var i;
return (
await ((i = t), new Promise((e) => setTimeout(e, i))),
this.request(
e,
s,
Object.assign(Object.assign({}, r), { retry: r.retry - 1 })
)
);
}
async request(e, t = { headers: {} }, s = { retry: 0 }) {
((t.headers = Object.assign(
Object.assign({}, v.DEFAULT_REQUEST_HEADERS),
t.headers
)),
t.body &&
t.body instanceof FormData &&
(t.headers instanceof Headers
? t.headers.delete("Content-Type")
: Array.isArray(t.headers) || delete t.headers["Content-Type"]),
(t.mode = this.requestMode));
const r = await this.timedFetch(e, t),
{ headers: i } = r;
(this._checkForDeprecationHeader(i), this._checkForBackoffHeader(i));
const a = this._checkForRetryAfterHeader(i);
return a && s.retry > 0
? this.retry(e, a, t, s)
: this.processResponse(r);
}
_checkForDeprecationHeader(e) {
const t = e.get("Alert");
if (!t) return;
let s;
try {
s = JSON.parse(t);
} catch (e) {
return void console.warn("Unable to parse Alert header message", t);
}
(console.warn(s.message, s.url),
this.events && this.events.emit("deprecated", s));
}
_checkForBackoffHeader(e) {
let t;
const s = e.get("Backoff"),
r = s ? parseInt(s, 10) : 0;
((t = r > 0 ? new Date().getTime() + 1e3 * r : 0),
this.events && this.events.emit("backoff", t));
}
_checkForRetryAfterHeader(e) {
const t = e.get("Retry-After");
if (!t) return null;
const s = 1e3 * parseInt(t, 10),
r = new Date().getTime() + s;
return (this.events && this.events.emit("retry-after", r), s);
}
}
const j = {
root: () => "/",
batch: () => "/batch",
permissions: () => "/permissions",
bucket: (e) => "/buckets" + (e ? `/${e}` : ""),
history: (e) => `${j.bucket(e)}/history`,
snapshot: (e, t, s) => `${j.bucket(e)}/snapshot/collections/${t}@${s}`,
collection: (e, t) => `${j.bucket(e)}/collections` + (t ? `/${t}` : ""),
group: (e, t) => `${j.bucket(e)}/groups` + (t ? `/${t}` : ""),
record: (e, t, s) => `${j.collection(e, t)}/records` + (s ? `/${s}` : ""),
attachment: (e, t, s) => `${j.record(e, t, s)}/attachment`,
},
O = { safe: !1, headers: {}, patch: !1 };
function k(e, t) {
return e ? (t ? { "If-Match": `"${t}"` } : { "If-None-Match": "*" }) : {};
}
function E(e, { data: t, permissions: s }, r = {}) {
const { headers: i, safe: a } = Object.assign(Object.assign({}, O), r);
return {
method: r.method || (t && t.id) ? "PUT" : "POST",
path: e,
headers: Object.assign(Object.assign({}, i), k(a)),
body: { data: t, permissions: s },
};
}
function R(e, { data: t, permissions: s }, r = {}) {
const {
headers: i,
safe: a,
patch: n,
} = Object.assign(Object.assign({}, O), r),
{ last_modified: o } = Object.assign(Object.assign({}, t), r);
return (
t &&
0 ===
Object.keys(t).filter((e) => "id" !== e && "last_modified" !== e)
.length &&
(t = void 0),
{
method: n ? "PATCH" : "PUT",
path: e,
headers: Object.assign(Object.assign({}, i), k(a, o)),
body: { data: t, permissions: s },
}
);
}
function S(e, t, s, r = {}) {
const {
headers: i,
safe: a,
last_modified: n,
} = Object.assign(Object.assign({}, O), r),
o = [];
for (const [e, r] of Object.entries(t))
if (r)
for (const t of r) o.push({ op: s, path: `/permissions/${e}/${t}` });
return {
method: "PATCH",
path: e,
headers: Object.assign(Object.assign(Object.assign({}, i), k(a, n)), {
"Content-Type": "application/json-patch+json",
}),
body: o,
};
}
function A(e, t = {}) {
const {
headers: s,
safe: r,
last_modified: i,
} = Object.assign(Object.assign({}, O), t);
if (r && !i)
throw new Error("Safe concurrency check requires a last_modified value.");
return {
method: "DELETE",
path: e,
headers: Object.assign(Object.assign({}, s), k(r, i)),
};
}
function T(e, t, { data: s, permissions: r } = {}, i = {}) {
const { headers: a, safe: n } = Object.assign(Object.assign({}, O), i),
{ last_modified: o } = Object.assign(Object.assign({}, s), i),
c = (function (e, t, s = {}) {
const { filename: r = "untitled" } = s,
{ blob: i, name: a } = f(e),
n = new FormData();
n.append("attachment", i, a || r);
for (const e in t) void 0 !== t[e] && n.append(e, JSON.stringify(t[e]));
return n;
})(t, { data: s, permissions: r }, i);
return {
method: "POST",
path: e,
headers: Object.assign(Object.assign({}, a), k(n, o)),
body: c,
};
}
const x = [];
for (let e = 0; e < 256; ++e) x.push((e + 256).toString(16).slice(1));
let I;
const H = new Uint8Array(16);
var P = {
randomUUID:
"undefined" != typeof crypto &&
crypto.randomUUID &&
crypto.randomUUID.bind(crypto),
};
function M(e, t, s) {
const r =
(e = e || {}).random ??
e.rng?.() ??
(function () {
if (!I) {
if ("undefined" == typeof crypto || !crypto.getRandomValues)
throw new Error(
"crypto.getRandomValues() not supported. See https://github.com/uuidjs/uuid#getrandomvalues-not-supported"
);
I = crypto.getRandomValues.bind(crypto);
}
return I(H);
})();
if (r.length < 16) throw new Error("Random bytes length must be >= 16");
return (
(r[6] = (15 & r[6]) | 64),
(r[8] = (63 & r[8]) | 128),
(function (e, t = 0) {
return (
x[e[t + 0]] +
x[e[t + 1]] +
x[e[t + 2]] +
x[e[t + 3]] +
"-" +
x[e[t + 4]] +
x[e[t + 5]] +
"-" +
x[e[t + 6]] +
x[e[t + 7]] +
"-" +
x[e[t + 8]] +
x[e[t + 9]] +
"-" +
x[e[t + 10]] +
x[e[t + 11]] +
x[e[t + 12]] +
x[e[t + 13]] +
x[e[t + 14]] +
x[e[t + 15]]
).toLowerCase();
})(r)
);
}
function q(e, t, s) {
return P.randomUUID && !e ? P.randomUUID() : M(e);
}
let D = class {
constructor(e, t, s, r = {}) {
((this.client = e),
(this.bucket = t),
(this.name = s),
(this._endpoints = e.endpoints),
(this._retry = r.retry || 0),
(this._safe = !!r.safe),
(this._headers = Object.assign(
Object.assign({}, this.bucket.headers),
r.headers
)));
}
get execute() {
return this.client.execute.bind(this.client);
}
_getHeaders(e) {
return Object.assign(Object.assign({}, this._headers), e.headers);
}
_getSafe(e) {
return Object.assign({ safe: this._safe }, e).safe;
}
_getRetry(e) {
return Object.assign({ retry: this._retry }, e).retry;
}
async getTotalRecords(e = {}) {
const t = this._endpoints.record(this.bucket.name, this.name),
s = { headers: this._getHeaders(e), path: t, method: "HEAD" },
{ headers: r } = await this.client.execute(s, {
raw: !0,
retry: this._getRetry(e),
});
return parseInt(r.get("Total-Records"), 10);
}
async getRecordsTimestamp(e = {}) {
const t = this._endpoints.record(this.bucket.name, this.name),
s = { headers: this._getHeaders(e), path: t, method: "HEAD" },
{ headers: r } = await this.client.execute(s, {
raw: !0,
retry: this._getRetry(e),
});
return r.get("ETag");
}
async getData(e = {}) {
const t = this._endpoints.collection(this.bucket.name, this.name),
s = { headers: this._getHeaders(e), path: t },
{ data: r } = await this.client.execute(s, {
retry: this._getRetry(e),
query: e.query,
fields: e.fields,
});
return r;
}
async setData(e, t = {}) {
if (!p(e)) throw new Error("A collection object is required.");
const { patch: s, permissions: r } = t,
{ last_modified: i } = Object.assign(Object.assign({}, e), t),
a = R(
this._endpoints.collection(this.bucket.name, this.name),
{ data: e, permissions: r },
{
last_modified: i,
patch: s,
headers: this._getHeaders(t),
safe: this._getSafe(t),
}
);
return this.client.execute(a, { retry: this._getRetry(t) });
}
async getPermissions(e = {}) {
const t = this._endpoints.collection(this.bucket.name, this.name),
s = { headers: this._getHeaders(e), path: t },
{ permissions: r } = await this.client.execute(s, {
retry: this._getRetry(e),
});
return r;
}
async setPermissions(e, t = {}) {
if (!p(e)) throw new Error("A permissions object is required.");
const s = R(
this._endpoints.collection(this.bucket.name, this.name),
{ data: { last_modified: t.last_modified }, permissions: e },
{ headers: this._getHeaders(t), safe: this._getSafe(t) }
);
return this.client.execute(s, { retry: this._getRetry(t) });
}
async addPermissions(e, t = {}) {
if (!p(e)) throw new Error("A permissions object is required.");
const s = this._endpoints.collection(this.bucket.name, this.name),
{ last_modified: r } = t,
i = S(s, e, "add", {
last_modified: r,
headers: this._getHeaders(t),
safe: this._getSafe(t),
});
return this.client.execute(i, { retry: this._getRetry(t) });
}
async removePermissions(e, t = {}) {
if (!p(e)) throw new Error("A permissions object is required.");
const s = this._endpoints.collection(this.bucket.name, this.name),
{ last_modified: r } = t,
i = S(s, e, "remove", {
last_modified: r,
headers: this._getHeaders(t),
safe: this._getSafe(t),
});
return this.client.execute(i, { retry: this._getRetry(t) });
}
async createRecord(e, t = {}) {
const { permissions: s } = t,
r = E(
this._endpoints.record(this.bucket.name, this.name, e.id),
{ data: e, permissions: s },
{ headers: this._getHeaders(t), safe: this._getSafe(t) }
);
return this.client.execute(r, { retry: this._getRetry(t) });
}
async addAttachment(e, t = {}, s = {}) {
const { permissions: r } = s,
i = t.id || q(),
a = this._endpoints.attachment(this.bucket.name, this.name, i),
{ last_modified: n } = Object.assign(Object.assign({}, t), s),
o = T(
a,
e,
{ data: t, permissions: r },
{
last_modified: n,
filename: s.filename,
headers: this._getHeaders(s),
safe: this._getSafe(s),
}
);
return (
await this.client.execute(o, {
stringify: !1,
retry: this._getRetry(s),
}),
this.getRecord(i)
);
}
async removeAttachment(e, t = {}) {
const { last_modified: s } = t,
r = A(this._endpoints.attachment(this.bucket.name, this.name, e), {
last_modified: s,
headers: this._getHeaders(t),
safe: this._getSafe(t),
});
return this.client.execute(r, { retry: this._getRetry(t) });
}
async updateRecord(e, t = {}) {
if (!p(e)) throw new Error("A record object is required.");
if (!e.id) throw new Error("A record id is required.");
const { permissions: s } = t,
{ last_modified: r } = Object.assign(Object.assign({}, e), t),
i = R(
this._endpoints.record(this.bucket.name, this.name, e.id),
{ data: e, permissions: s },
{
headers: this._getHeaders(t),
safe: this._getSafe(t),
last_modified: r,
patch: !!t.patch,
}
);
return this.client.execute(i, { retry: this._getRetry(t) });
}
async deleteRecord(e, t = {}) {
const s = d(e);
if (!s.id) throw new Error("A record id is required.");
const { id: r } = s,
{ last_modified: i } = Object.assign(Object.assign({}, s), t),
a = A(this._endpoints.record(this.bucket.name, this.name, r), {
last_modified: i,
headers: this._getHeaders(t),
safe: this._getSafe(t),
});
return this.client.execute(a, { retry: this._getRetry(t) });
}
async deleteRecords(e = {}) {
const t = this._endpoints.record(this.bucket.name, this.name);
return this.client.paginatedDelete(t, e, {
headers: this._getHeaders(e),
retry: this._getRetry(e),
});
}
async getRecord(e, t = {}) {
const s = this._endpoints.record(this.bucket.name, this.name, e),
r = { headers: this._getHeaders(t), path: s };
return this.client.execute(r, {
retry: this._getRetry(t),
query: t.query,
fields: t.fields,
});
}
async listRecords(e = {}) {
const t = this._endpoints.record(this.bucket.name, this.name);
return e.at
? this.getSnapshot(e.at)
: this.client.paginatedList(t, e, {
headers: this._getHeaders(e),
retry: this._getRetry(e),
});
}
async isHistoryComplete() {
const {
data: [e],
} = await this.bucket.listHistory({
limit: 1,
filters: {
action: "create",
resource_name: "collection",
collection_id: this.name,
},
});
return !!e;
}
async getSnapshot(e, t = {}) {
if (!e || !Number.isInteger(e) || e <= 0)
throw new Error("Invalid argument, expected a positive integer.");
const s = this._endpoints.snapshot(this.bucket.name, this.name, e),
r = { headers: this._getHeaders(t), path: s, method: "GET" };
let i = null;
try {
const { json: e } = await this.client.execute(r, {
raw: !0,
retry: this._getRetry(t),
});
i = e;
} catch (e) {
if (!/404/.test(String(e))) throw e;
}
if (null != i)
return {
last_modified: String(e),
data: i.data,
next: () => {
throw new Error("Snapshots don't support pagination");
},
hasNextPage: !1,
totalRecords: i.data.length,
};
if (!(await this.isHistoryComplete()))
throw new Error(
"Computing a snapshot is only possible when the full history for a collection is available. Here, the history plugin seems to have been enabled after the creation of the collection."
);
const { data: a } = await this.bucket.listHistory({
pages: 1 / 0,
sort: "last_modified",
filters: { resource_name: "record", collection_id: this.name },
}),
n = new Map(),
o = new Map();
for (const t of a)
(t.target.data.last_modified <= e && o.set(t.record_id, t),
n.set(t.record_id, t));
const { data: c } = await this.listRecords({
pages: 1 / 0,
fields: ["id"],
}),
d = new Set(c.map((e) => e.id)),
h = new Set();
for (const e of n.values())
"delete" == e.action || d.has(e.record_id) || h.add(e.record_id);
const l = [];
for (const e of o.values())
"delete" == e.action || h.has(e.record_id) || l.push(e.target.data);
return {
last_modified: String(e),
data: Array.from(l).sort((e, t) => t.last_modified - e.last_modified),
next: () => {
throw new Error("Snapshots don't support pagination");
},
hasNextPage: !1,
totalRecords: l.length,
};
}
async batch(e, t = {}) {
return this.client.batch(e, {
bucket: this.bucket.name,
collection: this.name,
headers: this._getHeaders(t),
retry: this._getRetry(t),
safe: this._getSafe(t),
aggregate: !!t.aggregate,
});
}
};
(t([l(["attachments"])], D.prototype, "addAttachment", null),
t([l(["attachments"])], D.prototype, "removeAttachment", null),
t([l(["history"])], D.prototype, "getSnapshot", null));
class $ {
constructor(e, t, s = {}) {
((this.client = e),
(this.name = t),
(this._endpoints = e.endpoints),
(this._headers = s.headers || {}),
(this._retry = s.retry || 0),
(this._safe = !!s.safe));
}
get execute() {
return this.client.execute.bind(this.client);
}
get headers() {
return this._headers;
}
_getHeaders(e) {
return Object.assign(Object.assign({}, this._headers), e.headers);
}
_getSafe(e) {
return Object.assign({ safe: this._safe }, e).safe;
}
_getRetry(e) {
return Object.assign({ retry: this._retry }, e).retry;
}
collection(e, t = {}) {
return new D(this.client, this, e, {
headers: this._getHeaders(t),
retry: this._getRetry(t),
safe: this._getSafe(t),
});
}
async getCollectionsTimestamp(e = {}) {
const t = this._endpoints.collection(this.name),
s = { headers: this._getHeaders(e), path: t, method: "HEAD" },
{ headers: r } = await this.client.execute(s, {
raw: !0,
retry: this._getRetry(e),
});
return r.get("ETag");
}
async getGroupsTimestamp(e = {}) {
const t = this._endpoints.group(this.name),
s = { headers: this._getHeaders(e), path: t, method: "HEAD" },
{ headers: r } = await this.client.execute(s, {
raw: !0,
retry: this._getRetry(e),
});
return r.get("ETag");
}
async getData(e = {}) {
const t = this._endpoints.bucket(this.name),
s = { headers: this._getHeaders(e), path: t },
{ data: r } = await this.client.execute(s, {
retry: this._getRetry(e),
query: e.query,
fields: e.fields,
});
return r;
}
async setData(e, t = {}) {
if (!p(e)) throw new Error("A bucket object is required.");
const s = Object.assign(Object.assign({}, e), { id: this.name }),
r = s.id;
"default" === s.id && delete s.id;
const i = this._endpoints.bucket(r),
{ patch: a, permissions: n } = t,
{ last_modified: o } = Object.assign(Object.assign({}, e), t),
c = R(
i,
{ data: s, permissions: n },
{
last_modified: o,
patch: a,
headers: this._getHeaders(t),
safe: this._getSafe(t),
}
);
return this.client.execute(c, { retry: this._getRetry(t) });
}
async listHistory(e = {}) {
const t = this._endpoints.history(this.name);
return this.client.paginatedList(t, e, {
headers: this._getHeaders(e),
retry: this._getRetry(e),
});
}
async listCollections(e = {}) {
const t = this._endpoints.collection(this.name);
return this.client.paginatedList(t, e, {
headers: this._getHeaders(e),
retry: this._getRetry(e),
});
}
async createCollection(e, t = {}) {
const { permissions: s, data: r = {} } = t;
r.id = e;
const i = E(
this._endpoints.collection(this.name, e),
{ data: r, permissions: s },
{ headers: this._getHeaders(t), safe: this._getSafe(t) }
);
return this.client.execute(i, { retry: this._getRetry(t) });
}
async deleteCollection(e, t = {}) {
const s = d(e);
if (!s.id) throw new Error("A collection id is required.");
const { id: r } = s,
{ last_modified: i } = Object.assign(Object.assign({}, s), t),
a = A(this._endpoints.collection(this.name, r), {
last_modified: i,
headers: this._getHeaders(t),
safe: this._getSafe(t),
});
return this.client.execute(a, { retry: this._getRetry(t) });
}
async deleteCollections(e = {}) {
const t = this._endpoints.collection(this.name);
return this.client.paginatedDelete(t, e, {
headers: this._getHeaders(e),
retry: this._getRetry(e),
});
}
async listGroups(e = {}) {
const t = this._endpoints.group(this.name);
return this.client.paginatedList(t, e, {
headers: this._getHeaders(e),
retry: this._getRetry(e),
});
}
async getGroup(e, t = {}) {
const s = this._endpoints.group(this.name, e),
r = { headers: this._getHeaders(t), path: s };
return this.client.execute(r, {
retry: this._getRetry(t),
query: t.query,
fields: t.fields,
});
}
async createGroup(e, t = [], s = {}) {
const r = Object.assign(Object.assign({}, s.data), { id: e, members: t }),
i = this._endpoints.group(this.name, e),
{ permissions: a } = s,
n = E(
i,
{ data: r, permissions: a },
{ headers: this._getHeaders(s), safe: this._getSafe(s) }
);
return this.client.execute(n, { retry: this._getRetry(s) });
}
async updateGroup(e, t = {}) {
if (!p(e)) throw new Error("A group object is required.");
if (!e.id) throw new Error("A group id is required.");
const s = Object.assign(Object.assign({}, t.data), e),
r = this._endpoints.group(this.name, e.id),
{ patch: i, permissions: a } = t,
{ last_modified: n } = Object.assign(Object.assign({}, s), t),
o = R(
r,
{ data: s, permissions: a },
{
last_modified: n,
patch: i,
headers: this._getHeaders(t),
safe: this._getSafe(t),
}
);
return this.client.execute(o, { retry: this._getRetry(t) });
}
async deleteGroup(e, t = {}) {
const s = d(e),
{ id: r } = s,
{ last_modified: i } = Object.assign(Object.assign({}, s), t),
a = A(this._endpoints.group(this.name, r), {
last_modified: i,
headers: this._getHeaders(t),
safe: this._getSafe(t),
});
return this.client.execute(a, { retry: this._getRetry(t) });
}
async deleteGroups(e = {}) {
const t = this._endpoints.group(this.name);
return this.client.paginatedDelete(t, e, {
headers: this._getHeaders(e),
retry: this._getRetry(e),
});
}
async getPermissions(e = {}) {
const t = {
headers: this._getHeaders(e),
path: this._endpoints.bucket(this.name),
},
{ permissions: s } = await this.client.execute(t, {
retry: this._getRetry(e),
});
return s;
}
async setPermissions(e, t = {}) {
if (!p(e)) throw new Error("A permissions object is required.");
const s = this._endpoints.bucket(this.name),
{ last_modified: r } = t,
i = R(
s,
{ data: { last_modified: r }, permissions: e },
{ headers: this._getHeaders(t), safe: this._getSafe(t) }
);
return this.client.execute(i, { retry: this._getRetry(t) });
}
async addPermissions(e, t = {}) {
if (!p(e)) throw new Error("A permissions object is required.");
const s = this._endpoints.bucket(this.name),
{ last_modified: r } = t,
i = S(s, e, "add", {
last_modified: r,
headers: this._getHeaders(t),
safe: this._getSafe(t),
});
return this.client.execute(i, { retry: this._getRetry(t) });
}
async removePermissions(e, t = {}) {
if (!p(e)) throw new Error("A permissions object is required.");
const s = this._endpoints.bucket(this.name),
{ last_modified: r } = t,
i = S(s, e, "remove", {
last_modified: r,
headers: this._getHeaders(t),
safe: this._getSafe(t),
});
return this.client.execute(i, { retry: this._getRetry(t) });
}
async batch(e, t = {}) {
return this.client.batch(e, {
bucket: this.name,
headers: this._getHeaders(t),
retry: this._getRetry(t),
safe: this._getSafe(t),
aggregate: !!t.aggregate,
});
}
}
t([l(["history"])], $.prototype, "listHistory", null);
class C {
constructor(e, t) {
if ("string" != typeof e || !e.length)
throw new Error("Invalid remote URL: " + e);
("/" === e[e.length - 1] && (e = e.slice(0, -1)),
(this._backoffReleaseTime = null),
(this._requests = []),
(this._isBatch = !!t.batch),
(this._retry = t.retry || 0),
(this._safe = !!t.safe),
(this._headers = t.headers || {}),
(this.remote = e),
(this.serverInfo = null),
(this.events = t.events),
(this.endpoints = j));
const { fetchFunc: s, requestMode: r, timeout: i } = t;
((this.http = new v(this.events, {
fetchFunc: s,
requestMode: r,
timeout: i,
})),
this._registerHTTPEvents());
}
get remote() {
return this._remote;
}
set remote(e) {
let t;
try {
t = e.match(/\/(v\d+)\/?$/)[1];
} catch (t) {
throw new Error("The remote URL must contain the version: " + e);
}
((this._remote = e), (this._version = t));
}
get version() {
return this._version;
}
get backoff() {
const e = new Date().getTime();
return this._backoffReleaseTime && e < this._backoffReleaseTime
? this._backoffReleaseTime - e
: 0;
}
_registerHTTPEvents() {
!this._isBatch &&
this.events &&
this.events.on("backoff", (e) => {
this._backoffReleaseTime = e;
});
}
bucket(e, t = {}) {
return new $(this, e, {
headers: this._getHeaders(t),
safe: this._getSafe(t),
retry: this._getRetry(t),
});
}
setHeaders(e) {
((this._headers = Object.assign(Object.assign({}, this._headers), e)),
(this.serverInfo = null));
}
_getHeaders(e) {
return Object.assign(Object.assign({}, this._headers), e.headers);
}
_getSafe(e) {
return Object.assign({ safe: this._safe }, e).safe;
}
_getRetry(e) {
return Object.assign({ retry: this._retry }, e).retry;
}
async _getHello(e = {}) {
const t = this.remote + j.root(),
{ json: s } = await this.http.request(
t,
{ headers: this._getHeaders(e) },
{ retry: this._getRetry(e) }
);
return s;
}
async fetchServerInfo(e = {}) {
return (
this.serverInfo ||
(this.serverInfo = await this._getHello({
retry: this._getRetry(e),
})),
this.serverInfo
);
}
async fetchServerSettings(e = {}) {
const { settings: t } = await this.fetchServerInfo(e);
return t;
}
async fetchServerCapabilities(e = {}) {
const { capabilities: t } = await this.fetchServerInfo(e);
return t;
}
async fetchUser(e = {}) {
const { user: t } = await this._getHello(e);
return t;
}
async fetchHTTPApiVersion(e = {}) {
const { http_api_version: t } = await this.fetchServerInfo(e);
return t;
}
async _batchRequests(e, t = {}) {
const s = this._getHeaders(t);
if (!e.length) return [];
const r = (await this.fetchServerSettings({ retry: this._getRetry(t) }))
.batch_max_requests;
if (r && e.length > r) {
const s =
((i = e),
(a = r) <= 0
? [i]
: i.reduce(
(e, t, s) => (
0 === s || s % a == 0
? e.push([t])
: e[e.length - 1].push(t),
e
),
[]
)),
n = [];
for (const e of s) {
const s = await this._batchRequests(e, t);
n.push(...s);
}
return n;
}
var i, a;
const { responses: n } = await this.execute(
{
headers: s,
path: j.batch(),
method: "POST",
body: { defaults: { headers: s }, requests: e },
},
{ retry: this._getRetry(t) }
);
return n;
}
async batch(e, t = {}) {
const s = new C(this.remote, {
events: this.events,
batch: !0,
safe: this._getSafe(t),
retry: this._getRetry(t),
});
t.bucket && t.collection
? e(s.bucket(t.bucket).collection(t.collection))
: t.bucket
? e(s.bucket(t.bucket))
: e(s);
const r = await this._batchRequests(s._requests, t);
return t.aggregate
? (function (e = [], t = []) {
if (e.length !== t.length)
throw new Error("Responses length should match requests one.");
return e.reduce(
(e, s, r) => {
const { status: i } = s,
a = t[r];
if (i >= 200 && i < 400) e.published.push(s.body);
else if (404 === i) {
const t = /(buckets|groups|collections|records)\/([^/]+)$/,
r = a.path.match(t),
i = r && 3 === r.length ? r[2] : void 0;
e.skipped.push({ id: i, path: a.path, error: s.body });
} else
412 === i
? e.conflicts.push({
type: "outgoing",
local: a.body,
remote:
(s.body.details && s.body.details.existing) || null,
})
: e.errors.push({ path: a.path, sent: a, error: s.body });
return e;
},
{ errors: [], published: [], conflicts: [], skipped: [] }
);
})(r, s._requests)
: r;
}
async execute(e, t = {}) {
const { raw: s = !1, stringify: r = !0 } = t;
if (this._isBatch) {
this._requests.push(e);
const t =
"This result is generated from within a batch operation and should not be consumed.";
return s ? { status: 0, json: t, headers: new Headers() } : t;
}
const i =
this.remote +
(function (e, t = {}) {
const s = Object.assign({}, t.query);
t.fields && (s._fields = t.fields);
const r = h(s);
return r ? e + "?" + r : e;
})(e.path, t),
a = await this.http.request(
i,
g({
method: e.method,
headers: e.headers,
body: r ? JSON.stringify(e.body) : e.body,
}),
{ retry: this._getRetry(t) }
);
return s ? a : a.json;
}
async paginatedOperation(e, t = {}, s = {}) {
const {
sort: r,
filters: i,
limit: a,
pages: n,
since: o,
fields: c,
} = Object.assign({ sort: "-last_modified" }, t);
if (o && "string" != typeof o)
throw new Error(
`Invalid value for since (${o}), should be ETag value.`
);
const d = Object.assign(Object.assign({}, i), {
_sort: r,
_limit: a,
_since: o,
});
c && (d._fields = c);
const l = h(d);
let u = [],
p = 0;
const f = async function (e) {
if (!e) throw new Error("Pagination exhausted.");
return g(e);
},
g = async (e) => {
const { headers: t } = s;
return y(await this.http.request(e, { headers: t }));
},
m = (e, t, s) => ({
last_modified: s ? s.replace(/"/g, "") : s,
data: e,
next: f.bind(null, t),
hasNextPage: !!t,
totalRecords: -1,
}),
y = async function ({ headers: e = new Headers(), json: t = {} }) {
const s = e.get("Next-Page"),
r = e.get("ETag");
return n
? ((u = u.concat(t.data)),
(p += 1),
p >= n || !s ? m(u, s, r) : g(s))
: m(t.data, s, r);
};
return y(
await this.execute(
{
headers: s.headers ? s.headers : {},
path: e + "?" + l,
method: s.method,
},
{ raw: !0, retry: s.retry || 0 }
)
);
}
async paginatedList(e, t = {}, s = {}) {
return this.paginatedOperation(e, t, s);
}
paginatedDelete(e, t = {}, s = {}) {
const { headers: r, safe: i, last_modified: a } = s,
n = A(e, { headers: r, safe: i || !1, last_modified: a });
return this.paginatedOperation(
e,
t,
Object.assign(Object.assign({}, s), {
headers: n.headers,
method: "DELETE",
})
);
}
async listPermissions(e = {}) {
const t = j.permissions(),
s = Object.assign({ sort: "id" }, e);
return this.paginatedList(t, s, {
headers: this._getHeaders(e),
retry: this._getRetry(e),
});
}
async listBuckets(e = {}) {
const t = j.bucket();
return this.paginatedList(t, e, {
headers: this._getHeaders(e),
retry: this._getRetry(e),
});
}
async createBucket(e, t = {}) {
const { data: s, permissions: r } = t,
i = Object.assign(Object.assign({}, s), { id: e || void 0 }),
a = i.id ? j.bucket(i.id) : j.bucket();
return this.execute(
E(
a,
{ data: i, permissions: r },
{ headers: this._getHeaders(t), safe: this._getSafe(t) }
),
{ retry: this._getRetry(t) }
);
}
async deleteBucket(e, t = {}) {
const s = d(e);
if (!s.id) throw new Error("A bucket id is required.");
const r = j.bucket(s.id),
{ last_modified: i } = Object.assign(Object.assign({}, s), t);
return this.execute(
A(r, {
last_modified: i,
headers: this._getHeaders(t),
safe: this._getSafe(t),
}),
{ retry: this._getRetry(t) }
);
}
async deleteBuckets(e = {}) {
const t = j.bucket();
return this.paginatedDelete(t, e, {
headers: this._getHeaders(e),
retry: this._getRetry(e),
safe: e.safe,
last_modified: e.last_modified,
});
}
async createAccount(e, t) {
return this.execute(
E(`/accounts/${e}`, { data: { password: t } }, { method: "PUT" })
);
}
}
var L, N;
(t(
[u("This operation is not supported within a batch operation.")],
C.prototype,
"fetchServerSettings",
null
),
t(
[u("This operation is not supported within a batch operation.")],
C.prototype,
"fetchServerCapabilities",
null
),
t(
[u("This operation is not supported within a batch operation.")],
C.prototype,
"fetchUser",
null
),
t(
[u("This operation is not supported within a batch operation.")],
C.prototype,
"fetchHTTPApiVersion",
null
),
t([u("Can't use batch within a batch!")], C.prototype, "batch", null),
t([l(["permissions_endpoint"])], C.prototype, "listPermissions", null),
t(
[
((L = "1.4"),
(N = "2.0"),
function (e, t, s) {
const r = s.value;
return {
configurable: !0,
get() {
const e = (...e) =>
(this.client ? this.client : this)
.fetchHTTPApiVersion()
.then((e) =>
(function (e, t, s) {
const r = (e) => e.split(".").map((e) => parseInt(e, 10)),
[i, a] = r(e),
[n, o] = r(t),
[c, d] = r(s);
if (
[
i < n,
i === n && a < o,
i > c,
i === c && a >= d,
].some((e) => e)
)
throw new Error(
`Version ${e} doesn't satisfy ${t} <= x < ${s}`
);
})(e, L, N)
)
.then(() => r.apply(this, e));
return (
Object.defineProperty(this, t, {
value: e,
configurable: !0,
writable: !0,
}),
e
);
},
};
}),
],
C.prototype,
"deleteBuckets",
null
),
t([l(["accounts"])], C.prototype, "createAccount", null));
class B extends C {
constructor(e, t = {}) {
const s = t.events;
super(e, Object.assign({ events: s }, t));
}
}
class U {
clear() {
throw new Error("Not Implemented.");
}
execute(e, t = { preload: [] }) {
throw new Error("Not Implemented.");
}
get(e) {
throw new Error("Not Implemented.");
}
list(e = { filters: {}, order: "" }) {
throw new Error("Not Implemented.");
}
saveLastModified(e) {
throw new Error("Not Implemented.");
}
getLastModified() {
throw new Error("Not Implemented.");
}
importBulk(e) {
throw new Error("Not Implemented.");
}
loadDump(e) {
throw new Error("Not Implemented.");
}
saveMetadata(e) {
throw new Error("Not Implemented.");
}
getMetadata() {
throw new Error("Not Implemented.");
}
}
const F = ["id", "_status", "last_modified"];
async function K(e, { version: t, onupgradeneeded: s }) {
return new Promise((r, i) => {
const a = indexedDB.open(e, t);
((a.onupgradeneeded = (e) => {
a.result.onerror = (e) => i(a.error);
const t = a.transaction;
return (
(t.onabort = (e) => {
const s =
a.error ||
t.error ||
new DOMException("The operation has been aborted", "AbortError");
i(s);
}),
s(e)
);
}),
(a.onerror = (e) => {
i(e.target.error);
}),
(a.onsuccess = (e) => {
const t = a.result;
r(t);
}));
});
}
async function V(e, t, s, r = {}) {
const { mode: i } = r;
return new Promise((r, a) => {
const n = i ? e.transaction([t], i) : e.transaction([t]),
o = n.objectStore(t),
c = (e) => {
(n.abort(), console.error(e), a(e));
};
let d;
try {
d = s(o, c);
} catch (e) {
c(e);
}
((n.onerror = (e) => a(e.target.error)),
(n.oncomplete = (e) => r(d)),
(n.onabort = (e) => {
const t =
e.target.error ||
n.error ||
new DOMException("The operation has been aborted", "AbortError");
a(t);
}));
});
}
async function J(e) {
return new Promise((t, s) => {
const r = indexedDB.deleteDatabase(e);
((r.onsuccess = (e) => t(e.target)),
(r.onerror = (e) => s(e.target.error)));
});
}
const G = {
all(e, t) {
const s = [];
return (r) => {
const a = r.target.result;
if (a) {
const { value: t } = a;
(i(e, t) && s.push(t), a.continue());
} else t(s);
};
},
in(e, t, s) {
const r = [];
let a = 0;
return function (n) {
const o = n.target.result;
if (!o) return void s(r);
const { key: c, value: d } = o;
for (; c > e[a]; ) if ((++a, a === e.length)) return void s(r);
const h = Array.isArray(c)
? (function (e, t) {
if (e.length !== t.length) return !1;
for (let s = e.length; s--; ) if (e[s] !== t[s]) return !1;
return !0;
})(c, e[a])
: c === e[a];
h ? (i(t, d) && r.push(d), o.continue()) : o.continue(e[a]);
};
},
};
function z(e, t, s, r) {
const i = Object.keys(s);
if (0 === i.length) {
const s = t.index("cid").getAll(IDBKeyRange.only(e));
return ((s.onsuccess = (e) => r(e.target.result)), s);
}
const a = i.find((e) => F.includes(e));
if (!a) {
if (Object.keys(s).some((e) => e.includes("."))) {
const i = (function (e) {
const t = {};
for (const s in e) c(s.split("."), e[s], t);
return t;
})(s),
a = t.index("cid").openCursor(IDBKeyRange.only(e));
return ((a.onsuccess = G.all(i, r)), a);
}
const i = t.index("cid").openCursor(IDBKeyRange.only(e));
return ((i.onsuccess = G.all(s, r)), i);
}
const n = o(s, [a]),
d = s[a],
h = "id" === a ? t : t.index(a);
if (Array.isArray(d)) {
if (0 === d.length) return r([]);
const t = d.map((t) => [e, t]).sort(),
s = IDBKeyRange.bound(t[0], t[t.length - 1]),
i = h.openCursor(s);
return ((i.onsuccess = G.in(t, n, r)), i);
}
if (0 === Object.keys(n).length) {
const t = h.getAll(IDBKeyRange.only([e, d]));
return ((t.onsuccess = (e) => r(e.target.result)), t);
}
const l = h.openCursor(IDBKeyRange.only([e, d]));
return ((l.onsuccess = G.all(n, r)), l);
}
class W extends Error {
constructor(e, t) {
(super(`IndexedDB ${e}() ${t.message}`),
(this.name = t.name),
(this.stack = t.stack));
}
}
class Y extends U {
static get IDBError() {
return W;
}
constructor(e, t = {}) {
(super(),
(this.cid = e),
(this.dbName = t.dbName || "KintoDB"),
(this._options = t),
(this._db = null));
}
_handleError(e, t) {
throw new W(e, t);
}
async open() {
if (this._db) return this;
const e = this._options.migrateOldData
? await (async function (e) {
let t = !0;
const s = await K(e, {
version: 1,
onupgradeneeded: (e) => {
t = !1;
},
});
if (
((t =
s.objectStoreNames.contains("__meta__") &&
s.objectStoreNames.contains(e)),
!t)
)
return (s.close(), await J(e), null);
console.warn(`${e}: old IndexedDB database found.`);
try {
let t;
(await V(s, e, (e) => {
e.openCursor().onsuccess = G.all({}, (e) => (t = e));
}),
console.log(`${e}: found ${t.length} records.`));
let r = null;
return (
await V(s, "__meta__", (t) => {
t.get(`${e}-lastModified`).onsuccess = (e) => {
r = e.target.result ? e.target.result.value : null;
};
}),
r ||
(await V(s, "__meta__", (e) => {
e.get("lastModified").onsuccess = (e) => {
r = e.target.result ? e.target.result.value : null;
};
})),
console.log(`${e}: ${r ? "found" : "no"} timestamp.`),
{ records: t, timestamp: r }
);
} catch (e) {
return (console.error("Error occured during migration", e), null);
} finally {
s.close();
}
})(this.cid)
: null;
if (
((this._db = await K(this.dbName, {
version: 2,
onupgradeneeded: (e) => {
const t = e.target.result;
if (e.oldVersion < 1) {
const e = t.createObjectStore("records", {
keyPath: ["_cid", "id"],
});
(e.createIndex("cid", "_cid"),
e.createIndex("_status", ["_cid", "_status"]),
e.createIndex("last_modified", ["_cid", "last_modified"]),
t.createObjectStore("timestamps", { keyPath: "cid" }));
}
e.oldVersion < 2 &&
t.createObjectStore("collections", { keyPath: "cid" });
},
})),
e)
) {
const { records: t, timestamp: s } = e;
(await this.importBulk(t),
await this.saveLastModified(null != s ? s : 0),
console.log(`${this.cid}: data was migrated successfully.`),
await J(this.cid),
console.warn(`${this.cid}: old database was deleted.`));
}
return this;
}
close() {
return (
this._db && (this._db.close(), (this._db = null)),
Promise.resolve()
);
}
async prepare(e, t, s) {
(await this.open(), await V(this._db, e, t, s));
}
async clear() {
try {
await this.prepare(
"records",
(e) => {
const t = IDBKeyRange.only(this.cid),
s = e.index("cid").openKeyCursor(t);
return (
(s.onsuccess = (t) => {
const s = t.target.result;
s && (e.delete(s.primaryKey), s.continue());
}),
s
);
},
{ mode: "readwrite" }
);
} catch (e) {
this._handleError("clear", e);
}
}
async execute(e, t = { preload: [] }) {
let s;
return (
await this.prepare(
"records",
(r, i) => {
const a = (t = {}) => {
const a = (function (e, t, s = {}) {
const r = e.cid;
return {
create(e) {
t.add(Object.assign(Object.assign({}, e), { _cid: r }));
},
update: (e) =>
t.put(Object.assign(Object.assign({}, e), { _cid: r })),
delete(e) {
t.delete([r, e]);
},
get: (e) => s[e],
};
})(this, r, t);
try {
const t = e(a);
if (t instanceof Promise)
throw new Error(
"execute() callback should not return a Promise."
);
s = t;
} catch (e) {
i && i(e);
}
};
if (!t.preload) return void a();
const n = { id: t.preload };
z(this.cid, r, n, (e) => {
const t = {};
for (const s of e) (delete s._cid, (t[s.id] = s));
a(t);
});
},
{ mode: "readwrite" }
),
s
);
}
async get(e) {
try {
let t;
return (
await this.prepare("records", (s) => {
s.get([this.cid, e]).onsuccess = (e) => (t = e.target.result);
}),
t
);
} catch (e) {
this._handleError("get", e);
}
return null;
}
async list(e = { filters: {} }) {
const { filters: t } = e;
try {
let s = [];
return (
await this.prepare("records", (e) => {
z(this.cid, e, t, (e) => {
for (const t of e) delete t._cid;
s = e;
});
}),
e.order
? (function (e, t) {
const s = "-" === e[0],
i = s ? e.slice(1) : e,
a = s ? -1 : 1;
return t
.slice()
.sort((e, t) =>
e[i] && r(t[i])
? a
: t[i] && r(e[i])
? -a
: r(e[i]) && r(t[i])
? 0
: e[i] > t[i]
? a
: -a
);
})(e.order, s)
: s
);
} catch (e) {
this._handleError("list", e);
}
return [];
}
async saveLastModified(e) {
const t = e || null;
try {
return (
await this.prepare(
"timestamps",
(e) => {
null === t
? e.delete(this.cid)
: e.put({ cid: this.cid, value: t });
},
{ mode: "readwrite" }
),
t
);
} catch (e) {
this._handleError("saveLastModified", e);
}
return null;
}
async getLastModified() {
try {
let e = null;
return (
await this.prepare("timestamps", (t) => {
t.get(this.cid).onsuccess = (t) => {
e = t.target.result;
};
}),
e ? e.value : null
);
} catch (e) {
this._handleError("getLastModified", e);
}
return null;
}
async loadDump(e) {
return this.importBulk(e);
}
async importBulk(e) {
try {
await this.execute((t) => {
let s = 0;
!(function r() {
if (s === e.length) return;
((t.update(e[s]).onsuccess = r), ++s);
})();
});
const t = await this.getLastModified(),
s = Math.max(...e.map((e) => e.last_modified));
return (t && s > t && (await this.saveLastModified(s)), e);
} catch (e) {
this._handleError("importBulk", e);
}
return [];
}
async saveMetadata(e) {
try {
return (
await this.prepare(
"collections",
(t) => t.put({ cid: this.cid, metadata: e }),
{ mode: "readwrite" }
),
e
);
} catch (e) {
return (this._handleError("saveMetadata", e), null);
}
}
async getMetadata() {
try {
let e = null;
return (
await this.prepare("collections", (t) => {
t.get(this.cid).onsuccess = (t) => (e = t.target.result);
}),
e ? e.metadata : null
);
} catch (e) {
return (this._handleError("getMetadata", e), null);
}
}
}
const Q = ["_status"],
Z = ["incoming-changes"];
function X(e, t, s = []) {
const r = [...Q, "last_modified", ...s],
i = (e) => o(e, r);
return n(i(e), i(t));
}
class ee {
constructor() {
((this.lastModified = null),
(this._lists = {
errors: [],
created: [],
updated: [],
deleted: [],
published: [],
conflicts: [],
skipped: [],
resolved: [],
void: [],
}),
(this._cached = {}));
}
add(e, t) {
return Array.isArray(this._lists[e])
? (Array.isArray(t) || (t = [t]),
(this._lists[e] = [...this._lists[e], ...t]),
delete this._cached[e],
this)
: (console.warn(`Unknown type "${e}"`), this);
}
get ok() {
return this.errors.length + this.conflicts.length === 0;
}
get errors() {
return this._lists.errors;
}
get conflicts() {
return this._lists.conflicts;
}
get skipped() {
return this._deduplicate("skipped");
}
get resolved() {
return this._deduplicate("resolved");
}
get created() {
return this._deduplicate("created");
}
get updated() {
return this._deduplicate("updated");
}
get deleted() {
return this._deduplicate("deleted");
}
get published() {
return this._deduplicate("published");
}
_deduplicate(e) {
if (!(e in this._cached)) {
const t = new Set(),
s = new Map();
(this._lists[e].forEach((e) => {
e.id ? s.set(e.id, e) : t.add(e);
}),
(this._cached[e] = Array.from(s.values()).concat(Array.from(t))));
}
return this._cached[e];
}
reset(e) {
return ((this._lists[e] = []), delete this._cached[e], this);
}
toObject() {
return {
ok: this.ok,
lastModified: this.lastModified,
errors: this.errors,
created: this.created,
updated: this.updated,
deleted: this.deleted,
skipped: this.skipped,
published: this.published,
conflicts: this.conflicts,
resolved: this.resolved,
};
}
}
class te extends Error {
constructor(e, t, s) {
(super(s),
Error.captureStackTrace && Error.captureStackTrace(this, te),
(this.clientTimestamp = e),
(this.serverTimestamp = t));
}
}
function se(e, t) {
return Object.assign(Object.assign({}, e), { _status: t });
}
function re(e) {
return se(e, "deleted");
}
function ie(e) {
return se(e, "synced");
}
function ae(e, t, s, r) {
const i = e.get(t.id);
if (!i) {
if (t.deleted) return { type: "skipped", data: t };
const s = ie(t);
return (e.create(s), { type: "created", data: s });
}
const a = Object.assign(Object.assign({}, i), ie(t));
if (r === ne.strategy.PULL_ONLY)
return t.deleted
? (e.delete(t.id), { type: "deleted", data: i })
: (e.update(a), { type: "updated", data: { old: i, new: a } });
const n = X(i, t, s);
return "synced" !== i._status
? "deleted" === i._status
? { type: "skipped", data: i }
: n
? (e.update(a), { type: "updated", data: { old: i, new: a } })
: void 0 !== i.last_modified && i.last_modified === t.last_modified
? { type: "void" }
: {
type: "conflicts",
data: { type: "incoming", local: i, remote: t },
}
: t.deleted
? (e.delete(t.id), { type: "deleted", data: i })
: (e.update(a),
n ? { type: "void" } : { type: "updated", data: { old: i, new: a } });
}
class ne {
constructor(e, t, s, r = {}) {
((this._bucket = e), (this._name = t), (this._lastModified = null));
const i = r.adapter
? r.adapter(`${e}/${t}`, r.adapterOptions)
: new Y(`${e}/${t}`, r.adapterOptions);
if (!(i instanceof U)) throw new Error("Unsupported adapter.");
((this.db = i),
(this.kinto = s),
(this.events = r.events),
(this.idSchema = this._validateIdSchema(r.idSchema)),
(this.remoteTransformers = this._validateRemoteTransformers(
r.remoteTransformers
)),
(this.hooks = this._validateHooks(r.hooks)),
(this.localFields = r.localFields || []));
}
get api() {
return this.kinto.api;
}
get name() {
return this._name;
}
get bucket() {
return this._bucket;
}
get lastModified() {
return this._lastModified;
}
static get strategy() {
return {
CLIENT_WINS: "client_wins",
SERVER_WINS: "server_wins",
PULL_ONLY: "pull_only",
MANUAL: "manual",
};
}
_validateIdSchema(e) {
if (void 0 === e)
return {
generate: () => q(),
validate: (e) => "string" == typeof e && s.test(e),
};
if ("object" != typeof e) throw new Error("idSchema must be an object.");
if ("function" != typeof e.generate)
throw new Error("idSchema must provide a generate function.");
if ("function" != typeof e.validate)
throw new Error("idSchema must provide a validate function.");
return e;
}
_validateRemoteTransformers(e) {
if (void 0 === e) return [];
if (!Array.isArray(e))
throw new Error("remoteTransformers should be an array.");
return e.map((e) => {
if ("object" != typeof e)
throw new Error("A transformer must be an object.");
if ("function" != typeof e.encode)
throw new Error("A transformer must provide an encode function.");
if ("function" != typeof e.decode)
throw new Error("A transformer must provide a decode function.");
return e;
});
}
_validateHook(e) {
if (!Array.isArray(e))
throw new Error("A hook definition should be an array of functions.");
return e.map((e) => {
if ("function" != typeof e)
throw new Error("A hook definition should be an array of functions.");
return e;
});
}
_validateHooks(e) {
if (void 0 === e) return {};
if (Array.isArray(e))
throw new Error("hooks should be an object, not an array.");
if ("object" != typeof e) throw new Error("hooks should be an object.");
const t = {};
for (const s in e) {
if (!Z.includes(s))
throw new Error("The hook should be one of " + Z.join(", "));
t[s] = this._validateHook(e[s]);
}
return t;
}
async clear() {
return (
await this.db.clear(),
await this.db.saveMetadata(null),
await this.db.saveLastModified(null),
{ data: [], permissions: {} }
);
}
_encodeRecord(e, t) {
const s = "remote" === e ? this.remoteTransformers : [];
return s.length
? a(
s.map((e) => (t) => e.encode(t)),
t
)
: Promise.resolve(t);
}
_decodeRecord(e, t) {
const s = "remote" === e ? this.remoteTransformers : [];
return s.length
? a(
s.reverse().map((e) => (t) => e.decode(t)),
t
)
: Promise.resolve(t);
}
create(e, t = { useRecordId: !1, synced: !1 }) {
const s = (e) => Promise.reject(new Error(e));
if ("object" != typeof e) return s("Record is not an object.");
if (
(t.synced || t.useRecordId) &&
!Object.prototype.hasOwnProperty.call(e, "id")
)
return s(
"Missing required Id; synced and useRecordId options require one"
);
if (
!t.synced &&
!t.useRecordId &&
Object.prototype.hasOwnProperty.call(e, "id")
)
return s("Extraneous Id; can't create a record having one set.");
const r = Object.assign(Object.assign({}, e), {
id: t.synced || t.useRecordId ? e.id : this.idSchema.generate(e),
_status: t.synced ? "synced" : "created",
});
return this.idSchema.validate(r.id)
? this.execute((e) => e.create(r), { preloadIds: [r.id] }).catch(
(e) => {
if (t.useRecordId)
throw new Error(
"Couldn't create record. It may have been virtually deleted."
);
throw e;
}
)
: s(`Invalid Id: ${r.id}`);
}
update(e, t = { synced: !1, patch: !1 }) {
return "object" != typeof e
? Promise.reject(new Error("Record is not an object."))
: Object.prototype.hasOwnProperty.call(e, "id")
? this.idSchema.validate(e.id)
? this.execute(
(s) => {
var r, i;
return s.update(e, {
synced: null !== (r = t.synced) && void 0 !== r && r,
patch: null !== (i = t.patch) && void 0 !== i && i,
});
},
{ preloadIds: [e.id] }
)
: Promise.reject(new Error(`Invalid Id: ${e.id}`))
: Promise.reject(new Error("Cannot update a record missing id."));
}
upsert(e) {
return "object" != typeof e
? Promise.reject(new Error("Record is not an object."))
: Object.prototype.hasOwnProperty.call(e, "id")
? this.idSchema.validate(e.id)
? this.execute((t) => t.upsert(e), { preloadIds: [e.id] })
: Promise.reject(new Error(`Invalid Id: ${e.id}`))
: Promise.reject(new Error("Cannot update a record missing id."));
}
get(e, t = { includeDeleted: !1 }) {
return this.execute((s) => s.get(e, t), { preloadIds: [e] });
}
getAny(e) {
return this.execute((t) => t.getAny(e), { preloadIds: [e] });
}
delete(e, t = { virtual: !0 }) {
return this.execute((s) => s.delete(e, t), { preloadIds: [e] });
}
async deleteAll() {
const { data: e } = await this.list({}, { includeDeleted: !1 }),
t = e.map((e) => e.id);
return this.execute((e) => e.deleteAll(t), { preloadIds: t });
}
deleteAny(e) {
return this.execute((t) => t.deleteAny(e), { preloadIds: [e] });
}
async list(e = {}, t = { includeDeleted: !1 }) {
e = Object.assign({ order: "-last_modified", filters: {} }, e);
const s = await this.db.list(e);
let r = s;
return (
t.includeDeleted || (r = s.filter((e) => "deleted" !== e._status)),
{ data: r, permissions: {} }
);
}
async importChanges(e, t, s = ne.strategy.MANUAL) {
try {
for (let r = 0; r < t.length; r += 200) {
const i = t.slice(r, r + 200),
{ imports: a, resolved: n } = await this.db.execute(
(e) => {
const t = i.map((t) => ae(e, t, this.localFields, s)),
r = t
.filter((e) => "conflicts" === e.type)
.map((e) => e.data);
return { imports: t, resolved: this._handleConflicts(e, r, s) };
},
{ preload: i.map((e) => e.id) }
);
(a.forEach(({ type: t, data: s }) => e.add(t, s)),
n.length > 0 && e.reset("conflicts").add("resolved", n));
}
} catch (t) {
const s = { type: "incoming", message: t.message, stack: t.stack };
e.add("errors", s);
}
return e;
}
async _applyPushedResults(e, t, s, r = ne.strategy.MANUAL) {
const i = t.filter((e) => e.deleted),
a = t.filter((e) => !e.deleted),
{ published: n, resolved: o } = await this.db.execute((e) => {
const t = a.map((t) => {
const s = ie(t);
return (e.update(s), s);
}),
n = i.map((t) => (e.delete(t.id), { id: t.id, deleted: !0 }));
return {
published: t.concat(n),
resolved: this._handleConflicts(e, s, r),
};
});
return (
e.add("published", n),
o.length > 0 &&
e.reset("conflicts").reset("resolved").add("resolved", o),
e
);
}
_handleConflicts(e, t, s) {
return s === ne.strategy.MANUAL
? []
: t.map((t) => {
const r = s === ne.strategy.CLIENT_WINS ? t.local : t.remote,
i = s === ne.strategy.CLIENT_WINS ? t.remote : t.local;
let a, n, o;
if (null === r)
(e.delete(t.local.id),
(a = null),
(n = "synced"),
(o = t.local.id));
else {
const s = this._resolveRaw(t, r);
(e.update(s), (a = s), (n = s._status), (o = s.id));
}
return { rejected: i, accepted: a, id: o, _status: n };
});
}
execute(e, { preloadIds: t = [] } = {}) {
for (const e of t)
if (!this.idSchema.validate(e))
return Promise.reject(Error(`Invalid Id: ${e}`));
return this.db.execute(
(t) => {
const s = new oe(this, t),
r = e(s);
return (s.emitEvents(), r);
},
{ preload: t }
);
}
async resetSyncStatus() {
const e = await this.list(
{ filters: { _status: ["deleted", "synced"] }, order: "" },
{ includeDeleted: !0 }
);
return (
await this.db.execute((t) => {
e.data.forEach((e) => {
"deleted" === e._status
? t.delete(e.id)
: t.update(
Object.assign(Object.assign({}, e), {
last_modified: void 0,
_status: "created",
})
);
});
}),
(this._lastModified = null),
await this.db.saveLastModified(null),
e.data.length
);
}
async gatherLocalChanges() {
const e = await this.list({
filters: { _status: ["created", "updated"] },
order: "",
}),
t = await this.list(
{ filters: { _status: "deleted" }, order: "" },
{ includeDeleted: !0 }
);
return await Promise.all(
e.data.concat(t.data).map(this._encodeRecord.bind(this, "remote"))
);
}
async pullChanges(e, t, s = {}) {
if (!t.ok) return t;
const r = this.lastModified
? this.lastModified
: await this.db.getLastModified();
let i;
if (
(s = Object.assign(
{ strategy: ne.strategy.MANUAL, lastModified: r, headers: {} },
s
)).exclude
) {
i = {
exclude_id: s.exclude
.slice(0, 50)
.map((e) => e.id)
.join(","),
};
}
s.expectedTimestamp &&
(i = Object.assign(Object.assign({}, i), {
_expected: s.expectedTimestamp,
}));
const { data: a, last_modified: n } = await e.listRecords({
since: s.lastModified ? `${s.lastModified}` : void 0,
headers: s.headers,
retry: s.retry,
pages: 1 / 0,
filters: i,
}),
o = n ? parseInt(n, 10) : void 0,
c = s.lastModified,
d = o && o > s.lastModified,
h = 0 === a.length;
if (!s.exclude && c && d && h) {
throw new te(
c,
o,
"Server has been flushed. Client Side Timestamp: " +
c +
" Server Side Timestamp: " +
o
);
}
t.lastModified = o;
const l = {
lastModified: o,
changes: await Promise.all(
a.map((e) => this._decodeRecord("remote", e))
),
},
u = await this.applyHook("incoming-changes", l);
return (
u.changes.length > 0 &&
(await this.importChanges(t, u.changes, s.strategy)),
t
);
}
applyHook(e, t) {
return void 0 === this.hooks[e]
? Promise.resolve(t)
: a(
this.hooks[e].map((e) => (s) => {
const r = e(t, this),
i = r && "function" == typeof r.then,
a = r && Object.prototype.hasOwnProperty.call(r, "changes");
if (!i && !a)
throw new Error(
`Invalid return value for hook: ${JSON.stringify(r)} has no 'then()' or 'changes' properties`
);
return r;
}),
t
);
}
async pushChanges(e, t, s, r = {}) {
if (!s.ok) return s;
const i = !r.strategy || void 0 !== r.strategy,
a = t.filter((e) => "deleted" === e._status),
n = t.filter((e) => "deleted" != e._status),
o = await e.batch(
(e) => {
(a.forEach((t) => {
t.last_modified && e.deleteRecord(t);
}),
n.forEach((t) => {
const s = this.cleanLocalFields(t);
"created" === t._status ? e.createRecord(s) : e.updateRecord(s);
}));
},
{ headers: r.headers, retry: r.retry, safe: i, aggregate: !0 }
);
s.add(
"errors",
o.errors.map((e) =>
Object.assign(Object.assign({}, e), { type: "outgoing" })
)
);
const c = [];
for (const { type: e, local: t, remote: s } of o.conflicts) {
const r = (t && t.data) || { id: s.id },
i = {
type: e,
local: await this._decodeRecord("remote", r),
remote: s && (await this._decodeRecord("remote", s)),
};
c.push(i);
}
s.add("conflicts", c);
const d = o.skipped.map((e) =>
Object.assign(Object.assign({}, e), { deleted: !0 })
),
h = o.published.map((e) => e.data).concat(d),
l = await Promise.all(h.map((e) => this._decodeRecord("remote", e)));
return (
(l.length > 0 || c.length > 0) &&
(await this._applyPushedResults(s, l, c, r.strategy)),
s
);
}
cleanLocalFields(e) {
return o(e, [...Q, ...this.localFields]);
}
resolve(e, t) {
return this.db.execute((s) => {
const r = this._resolveRaw(e, t);
return (s.update(r), { data: r, permissions: {} });
});
}
_resolveRaw(e, t) {
const s = Object.assign(Object.assign({}, t), {
last_modified: e.remote && e.remote.last_modified,
});
return se(s, n(s, e.remote) ? "synced" : "updated");
}
async sync(
e = {
strategy: ne.strategy.MANUAL,
headers: {},
retry: 1,
ignoreBackoff: !1,
bucket: null,
collection: null,
remote: null,
expectedTimestamp: null,
}
) {
var t, s;
e = Object.assign(Object.assign({}, e), {
bucket: e.bucket || this.bucket,
collection: e.collection || this.name,
});
const r = this.api.remote;
if (
(e.remote && (this.api.remote = e.remote),
!e.ignoreBackoff && this.api.backoff > 0)
) {
const e = Math.ceil(this.api.backoff / 1e3);
return Promise.reject(
new Error(
`Server is asking clients to back off; retry in ${e}s or use the ignoreBackoff option.`
)
);
}
const i = this.api.bucket(e.bucket).collection(e.collection),
a = new ee();
try {
(await this.pullMetadata(i, e), await this.pullChanges(i, a, e));
const { lastModified: t } = a;
if (e.strategy !== ne.strategy.PULL_ONLY) {
const s = await this.gatherLocalChanges();
await this.pushChanges(i, s, a, e);
const r = a.resolved.filter((e) => "synced" !== e._status);
if (r.length > 0) {
const t = await Promise.all(
r.map((e) => {
let t = e.accepted;
return (
null === t && (t = { id: e.id, _status: e._status }),
this._encodeRecord("remote", t)
);
})
);
await this.pushChanges(i, t, a, e);
}
if (a.published.length > 0) {
const s = Object.assign(Object.assign({}, e), {
lastModified: t,
exclude: a.published,
});
await this.pullChanges(i, a, s);
}
}
a.ok &&
(this._lastModified = await this.db.saveLastModified(a.lastModified));
} catch (s) {
throw (
null === (t = this.events) ||
void 0 === t ||
t.emit(
"sync:error",
Object.assign(Object.assign({}, e), { error: s })
),
s
);
} finally {
this.api.remote = r;
}
return (
null === (s = this.events) ||
void 0 === s ||
s.emit(
"sync:success",
Object.assign(Object.assign({}, e), { result: a })
),
a
);
}
async loadDump(e) {
return this.importBulk(e);
}
async importBulk(e) {
if (!Array.isArray(e)) throw new Error("Records is not an array.");
for (const t of e) {
if (
!Object.prototype.hasOwnProperty.call(t, "id") ||
!this.idSchema.validate(t.id)
)
throw new Error("Record has invalid ID: " + JSON.stringify(t));
if (!t.last_modified)
throw new Error(
"Record has no last_modified value: " + JSON.stringify(t)
);
}
const { data: t } = await this.list({}, { includeDeleted: !0 }),
s = t.reduce((e, t) => ((e[t.id] = t), e), {}),
r = e.filter((e) => {
const t = s[e.id];
return (
void 0 === t ||
("synced" === t._status &&
void 0 !== t.last_modified &&
e.last_modified > t.last_modified)
);
});
return await this.db.importBulk(r.map(ie));
}
async pullMetadata(e, t = {}) {
const { expectedTimestamp: s, headers: r } = t,
i = s ? { query: { _expected: s.toString() } } : void 0,
a = await e.getData(
Object.assign(Object.assign({}, i), { headers: r })
);
return this.db.saveMetadata(a);
}
async metadata() {
return this.db.getMetadata();
}
}
class oe {
constructor(e, t) {
((this.collection = e),
(this.adapterTransaction = t),
(this._events = []));
}
_queueEvent(e, t) {
this._events.push({ action: e, payload: t });
}
emitEvents() {
var e, t;
for (const { action: t, payload: s } of this._events)
null === (e = this.collection.events) || void 0 === e || e.emit(t, s);
if (this._events.length > 0) {
const e = this._events.map(({ action: e, payload: t }) =>
Object.assign({ action: e }, t)
);
null === (t = this.collection.events) ||
void 0 === t ||
t.emit("change", { targets: e });
}
this._events = [];
}
getAny(e) {
return { data: this.adapterTransaction.get(e), permissions: {} };
}
get(e, t = { includeDeleted: !1 }) {
const s = this.getAny(e);
if (!s.data || (!t.includeDeleted && "deleted" === s.data._status))
throw new Error(`Record with id=${e} not found.`);
return s;
}
delete(e, t = { virtual: !0 }) {
const s = this.adapterTransaction.get(e),
r = s && "deleted" === s._status;
if (!s || (r && t.virtual))
throw new Error(`Record with id=${e} not found.`);
return (
t.virtual
? this.adapterTransaction.update(re(s))
: this.adapterTransaction.delete(e),
this._queueEvent("delete", { data: s }),
{ data: s, permissions: {} }
);
}
deleteAll(e) {
const t = [];
return (
e.forEach((e) => {
(t.push(this.adapterTransaction.get(e)), this.delete(e));
}),
this._queueEvent("deleteAll", { data: t }),
{ data: t, permissions: {} }
);
}
deleteAny(e) {
const t = this.adapterTransaction.get(e);
return (
t &&
(this.adapterTransaction.update(re(t)),
this._queueEvent("delete", { data: t })),
{ data: Object.assign({ id: e }, t), deleted: !!t, permissions: {} }
);
}
create(e) {
if ("object" != typeof e) throw new Error("Record is not an object.");
if (!Object.prototype.hasOwnProperty.call(e, "id"))
throw new Error("Cannot create a record missing id");
if (!this.collection.idSchema.validate(e.id))
throw new Error(`Invalid Id: ${e.id}`);
return (
this.adapterTransaction.create(e),
this._queueEvent("create", { data: e }),
{ data: e, permissions: {} }
);
}
update(e, t = { synced: !1, patch: !1 }) {
if ("object" != typeof e) throw new Error("Record is not an object.");
if (!Object.prototype.hasOwnProperty.call(e, "id"))
throw new Error("Cannot update a record missing id.");
if (!this.collection.idSchema.validate(e.id))
throw new Error(`Invalid Id: ${e.id}`);
const s = this.adapterTransaction.get(e.id);
if (!s) throw new Error(`Record with id=${e.id} not found.`);
const r = t.patch ? Object.assign(Object.assign({}, s), e) : e,
i = this._updateRaw(s, r, t);
return (
this.adapterTransaction.update(i),
this._queueEvent("update", { data: i, oldRecord: s }),
{ data: i, oldRecord: s, permissions: {} }
);
}
_updateRaw(e, t, { synced: s = !1 } = {}) {
const r = Object.assign({}, t);
e &&
e.last_modified &&
!r.last_modified &&
(r.last_modified = e.last_modified);
const i =
e && X(e, r, this.collection.localFields) && "synced" === e._status,
a = !e || (e && "created" === e._status);
return se(r, i || s ? "synced" : a ? "created" : "updated");
}
upsert(e) {
if ("object" != typeof e) throw new Error("Record is not an object.");
if (!Object.prototype.hasOwnProperty.call(e, "id"))
throw new Error("Cannot update a record missing id.");
if (!this.collection.idSchema.validate(e.id))
throw new Error(`Invalid Id: ${e.id}`);
let t = this.adapterTransaction.get(e.id);
const s = this._updateRaw(t, e);
return (
this.adapterTransaction.update(s),
t && "deleted" === t._status && (t = void 0),
t
? this._queueEvent("update", { data: s, oldRecord: t })
: this._queueEvent("create", { data: s }),
{ data: s, oldRecord: t, permissions: {} }
);
}
}
class ce {
static get adapters() {
return { BaseAdapter: U };
}
static get syncStrategy() {
return ne.strategy;
}
constructor(e = {}) {
const t = {
bucket: "default",
remote: "http://localhost:8888/v1",
retry: 1,
};
if (
((this._options = Object.assign(Object.assign({}, t), e)),
!this._options.adapter)
)
throw new Error("No adapter provided");
((this._api = null), (this.events = this._options.events));
}
get ApiClass() {
throw new Error("ApiClass() must be implemented by subclasses.");
}
get api() {
const {
events: e,
headers: t,
remote: s,
requestMode: r,
retry: i,
timeout: a,
} = this._options;
return (
this._api ||
(this._api = new this.ApiClass(s, {
events: e,
headers: t,
requestMode: r,
retry: i,
timeout: a,
})),
this._api
);
}
collection(e, t = {}) {
if (!e) throw new Error("missing collection name");
const {
bucket: s,
events: r,
adapter: i,
adapterOptions: a,
} = Object.assign(Object.assign({}, this._options), t),
{ idSchema: n, remoteTransformers: o, hooks: c, localFields: d } = t;
return new ne(s, e, this, {
events: r,
adapter: i,
adapterOptions: a,
idSchema: n,
remoteTransformers: o,
hooks: c,
localFields: d,
});
}
}
class de extends ce {
static get adapters() {
return { BaseAdapter: U, IDB: Y };
}
get ApiClass() {
return B;
}
constructor(e = {}) {
const t = { adapter: (e, t) => new de.adapters.IDB(e, t) };
super(Object.assign(Object.assign({}, t), e));
}
}
((e.AbstractBaseAdapter = class {}),
(e.BaseAdapter = U),
(e.KintoBase = ce),
(e.KintoClient = B),
(e.default = de),
(e.getDeepKey = function (e, t) {
const s = t.split(".");
let r = e;
for (let e = 0; e < s.length; e++) r = r ? r[s[e]] : void 0;
return null != r ? r : void 0;
}),
Object.defineProperty(e, "__esModule", { value: !0 }));
});
//# sourceMappingURL=kinto.min.js.map