commit 0554eaa05fc9719fc19c24cd5571614fee15a8cc Author: Yorick van Pelt Date: Tue Apr 18 18:14:53 2023 +0200 initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..c35014a --- /dev/null +++ b/.gitignore @@ -0,0 +1,6 @@ +/toggl-api +/credentials +/lib/ +/marvin/ +/marvin-*/ +/node_modules \ No newline at end of file diff --git a/package.json b/package.json new file mode 100644 index 0000000..2d0f14e --- /dev/null +++ b/package.json @@ -0,0 +1,20 @@ +{ + "name": "timesync", + "version": "1.0.0", + "main": "index.js", + "license": "MIT", + "type": "module", + "dependencies": { + "@tsconfig/node18": "^1.0.2", + "@types/luxon": "^3.3.0", + "@types/node": "^18.15.11", + "@types/pouchdb": "^6.4.0", + "@types/pouchdb-find": "^7.3.0", + "luxon": "^3.3.0", + "node-fetch": "2", + "pouchdb": "^8.0.1", + "pouchdb-find": "^8.0.1", + "typescript": "^5.0.4", + "xdg-basedir": "^5.1.0" + } +} diff --git a/src/Marvin.ts b/src/Marvin.ts new file mode 100644 index 0000000..150f564 --- /dev/null +++ b/src/Marvin.ts @@ -0,0 +1,208 @@ +import { readFileSync } from "node:fs" +import { DateTime, Interval, Duration } from "luxon" +import { inspect } from "node:util" +import { DurationUtil } from "./util.js" + +import PouchDB from "pouchdb" +import pouchdb_find from "pouchdb-find" +PouchDB.plugin(pouchdb_find) + +import type * as Marvin_types from "./marvin-types.js" +import type InspectOptions from "node:util" + + +interface Credentials { + apiToken: string + fullAccessToken: string + syncServer: string + syncDatabase: string + syncUser: string + syncPassword: string +} + +export class Marvin { + credentials: Credentials + remote: PouchDB.Database + db: PouchDB.Database + synced: Promise> + root: Taskset + constructor(credentials: Credentials=Marvin.parseCredentials(), dbName = "marvin") { + const c = credentials + let u = new URL(c.syncServer) + Object.assign(u, { + username: c.syncUser, + password: c.syncPassword, + pathname: "/" + c.syncDatabase + }) + this.credentials = credentials + this.remote = new PouchDB(u.href) + this.db = new PouchDB(dbName) + this.synced = new Promise((resolve, reject) => { + console.log("syncing..") + this.remote.replicate.to(this.db) + .on('complete', resolve) + .on('error', reject) + }).then(() => { + return this.db.createIndex({ + index: { + fields: ["db", "parentId"] + } + }) + }) + this.synced.then(() => { + console.log("sync complete!") + }) + this.root = new Taskset(this, 'root', null) + } + async api(url: string, data: any=null) { + const response = await fetch("https://serv.amazingmarvin.com/api/" + url, { + method: data ? "POST" : "GET", + body: data ? JSON.stringify(data) : null, + headers: { + "X-API-Token": this.credentials.apiToken, + 'Content-Type': 'application/json', + "Accept": "application/json" + // todo: full access token + } + }) + if (response.ok) { + if (response.headers.get('content-type')?.startsWith("application/json")) { + return response.json() + } + return response.text() + } else { + throw [response.status, await response.text()] + } + } + async test() { + // todo: throw? + return (await this.api("test", {})) == "OK" + } + trackedItem() { + // todo: wrap in Task? + return this.api("trackedItem") + } + todayItems() { + return this.api("todayItems") + } + dueItems() { + return this.api("dueItems") + } + categories() { + return this.api("categories") + } + labels() { + return this.api("labels") + } + me() { + return this.api("me") + } + trackInfo(taskIds: string[]) { + return this.api("tracks", { taskIds }) + } + + static parseCredentials(fileContents = readFileSync("credentials", "utf8")): Credentials { + const res: Record = {} + for(const line of fileContents.split('\n')) { + if (line.startsWith('# ') || !line) continue + const [k,v] = line.split(': ', 2) + res[k] = v + } + return res as unknown as Credentials + } +} + +type Tuple = N extends N ? number extends N ? T[] : _TupleOf : never; +type _TupleOf = R['length'] extends N ? R : _TupleOf; +function chunk(xs: A[], n: N): Array> { + if ((xs.length % n) != 0) console.error("wrong chunk length") + const res = new Array(xs.length / n) + for(let i = 0; i < xs.length; i += n) { + res[i/n] = xs.slice(i, i+n) + } + return res +} + +function toInterval([start, end]: [number, number]): Interval { + return Interval.fromDateTimes(DateTime.fromMillis(start), DateTime.fromMillis(end)) +} + +class Task { + _task: Marvin_types.Task + title: string + day: string + dueDate: string | null + done: boolean + doneAt: DateTime | null + createdAt: DateTime + times: Interval[] + constructor(task: Marvin_types.Task) { + this._task = task + this.title = task.title + this.day = task.day + this.dueDate = task.dueDate + this.done = !!task.done + this.doneAt = task.doneAt ? DateTime.fromMillis(task.doneAt) : null + this.createdAt = DateTime.fromMillis(task.createdAt) + this.times = task.times ? chunk(task.times, 2).map(toInterval) : [] + } + timesInInterval(interval: Interval): Interval[] { + return this.times.map(time => time.intersection(interval)).filter(x => x !== null) as Interval[] + } + timeSpentOn(interval: Interval): Duration { + return DurationUtil.sum(this.timesInInterval(interval).map(x => x.toDuration())) + } + [inspect.custom](_depth: number, _opts: InspectOptions.InspectOptions) { + return { + title: this.title, + day: this.day, + dueDate: this.dueDate, + done: this.done, + doneAt: this.doneAt ? this.doneAt.toISO() : null, + createdAt: this.createdAt.toISO(), + times: this.times + } + } +} + +class Taskset { + marv: Marvin + _id: string + constructor(marv: Marvin, _id: string, rest: Marvin_types.DBEntry | null) { + this.marv = marv + this._id = _id + Object.assign(this, {marv, _id}, rest) + } + async category(n: string): Promise { + await this.marv.synced + const d = await this.marv.db.find({ + selector: { + db: "Categories", + title: n, + parentId: this._id + } + }) + if (d && d.docs) return new Taskset(this.marv, d.docs[0]._id, d.docs[0] as unknown as Marvin_types.DBEntry) + throw new Error("category not found") + } + async tasks(): Promise { + await this.marv.synced + const d = await this.marv.db.find({ + selector: { + db: "Tasks", + parentId: this._id + }, + }) + if (d) { + return d.docs.map(x => new Task(x as unknown as Marvin_types.Task)) + } + return [] + } + async tasksOverlapping(interval: Interval): Promise { + const tasks = await this.tasks() + return tasks.filter(task => + task.times.some(x => x.overlaps(interval)) + ) + } +} + diff --git a/src/Toggl.ts b/src/Toggl.ts new file mode 100644 index 0000000..227a2cf --- /dev/null +++ b/src/Toggl.ts @@ -0,0 +1,100 @@ +import { readFileSync } from "node:fs" +import { Buffer } from "node:buffer" +import type * as Toggl_types from "./toggl-types.js" + +function base64_encode(str: string): string { + return Buffer.from(str).toString("base64") +} + +export namespace API { + export namespace Request.GET { + export interface Me { + with_related_data?: boolean + } + export interface Workspaces { + since?: number + } + export interface TimeEntries { + since?: number; + before?: string; + start_date?: string; + end_date?: string; + }; + } + export namespace Request.POST { + export interface TimeEntry extends Toggl_types.TimeEntryBase { + created_with: string; + start_date?: string; + tag_action?: 'add' | 'delete'; + } + } + export namespace Response { + export type Workspaces = Toggl_types.Workspace[] + } +} + +import Req = API.Request +import Res = API.Response + +export class Toggl { + api_token: string + constructor(api_token=readFileSync("toggl-api", "utf8").trim()) { + this.api_token = api_token + } + async parseResponse(response: Awaited>) { + if (response.ok) { + if (response.headers.get('content-type')?.startsWith("application/json")) { + return response.json() + } + return response.text() + } else { + throw [response.status, await response.text()] + } + } + get(url: string, query: any={}) { + return fetch(`https://api.track.toggl.com/api/v9/${url}?${new URLSearchParams(query)}`, { + method: "GET", + headers: { + "Content-Type": "application/json", + "Authorization": `Basic ${base64_encode(this.api_token + ":api_token")}` + }, + }).then(resp => this.parseResponse(resp)) + } + async post(url: string, body: any={}) { + return fetch(`https://api.track.toggl.com/api/v9/${url}`, { + method: "POST", + body: JSON.stringify(body), + headers: { + "Content-Type": "application/json", + "Authorization": `Basic ${base64_encode(this.api_token + ":api_token")}` + }, + }).then(resp => this.parseResponse(resp)) + } + async me(query:API.Request.GET.Me={}): Promise { + return this.get("me", query) + } + async workspaces(query: Req.GET.Workspaces={}): Promise { + const ws = (await this.get("me/workspaces", query)) as Res.Workspaces + return ws.map(x => new Workspace(this, x)) + } + async time_entries(query: Req.GET.TimeEntries={}): Promise { + return this.get("me/time_entries", query) + } + async post_time_entry(workspace_id: number, query: Omit): Promise { + const q2: Req.POST.TimeEntry = Object.assign({ workspace_id }, query) + return this.post("workspaces/" + workspace_id + "/time_entries", q2) + } +} +export class Workspace { + toggl: Toggl + workspace: Toggl_types.Workspace + constructor(t: Toggl, w: Toggl_types.Workspace) { + this.toggl = t + this.workspace = w + } + async post_time_entry(query: Omit): Promise { + const workspace_id = this.workspace.id + const q2: Req.POST.TimeEntry = Object.assign({ workspace_id }, query) + return this.toggl.post("workspaces/" + workspace_id + "/time_entries", q2) + } +} diff --git a/src/index.ts b/src/index.ts new file mode 100644 index 0000000..65eb41e --- /dev/null +++ b/src/index.ts @@ -0,0 +1,118 @@ +import { Toggl, Workspace } from "./Toggl.js" +import { DateTime, Interval, Settings as LuxonSettings } from "luxon" +import { Marvin } from "./Marvin.js" +import { xdgData, xdgConfig } from 'xdg-basedir'; +import { mkdir, readFile } from 'node:fs/promises' +import { dirname } from 'node:path' + +LuxonSettings.throwOnInvalid = true; +declare module 'luxon' { + interface TSSettings { + throwOnInvalid: true; + } +} + +type Configuration = { + toggl: string, + marvin: string, + marvinDB: string +}; + +async function inferConfig(): Promise { + let files: Configuration + if (!xdgData || !xdgConfig) { + console.warn("xdg_data or xdg_config dir not found, defaulting to cwd") + files = { + toggl: process.cwd() + "toggl-api", + marvin: process.cwd() + "marvin-credentials", + marvinDB: process.cwd() + "db/" + } + } else { + files = { + toggl: xdgConfig + "/marvin-timesync/toggl-api", + marvin: xdgConfig + "/marvin-timesync/marvin-credentials", + marvinDB: xdgData + "/marvin-timesync/db/" + } + } + await Promise.all([ + mkdir(dirname(files.toggl), { recursive: true} ), + mkdir(dirname(files.marvin), { recursive: true} ), + mkdir(files.marvinDB, { recursive: true } ) + ]) + return { + toggl: (await readFile(files.toggl, 'utf8')).trim(), + marvin: (await readFile(files.marvin, 'utf8')).trim(), + marvinDB: files.marvinDB + } +} + +function dateToInterval(d: string = "today"): Interval { + const now = DateTime.local() + let retDate + if (d == "today") { + retDate = now.startOf('day') + } else if (d == "yesterday") { + retDate = now.startOf('day').minus({ days: 1 }) + } else { + retDate = DateTime.fromISO(d) + } + return Interval.fromDateTimes(retDate.startOf('day'), retDate.endOf('day')) +} + +function toRFC3339(d: DateTime): string { + return d.set({ millisecond: 0 }).toUTC().toISO() +} + +interface TogglTE { + description: string, + start: string, + stop: string +} +async function apply_tasks_for_range(workspace: Workspace, interval: Interval, wanted_tes: TogglTE[]) { + const existing_tes = await workspace.toggl.time_entries({ + start_date: toRFC3339(interval.start), + end_date: toRFC3339(interval.end), + }) + const existing_by_start: Map = new Map() + for (const existing of existing_tes) + existing_by_start.set(DateTime.fromISO(existing.start).toMillis(), existing) + + for (const wanted of wanted_tes) { + const matched = existing_by_start.get(DateTime.fromISO(wanted.start).toMillis()) + if (matched) { + if (matched.description === wanted.description) { + console.log("matched", wanted.description) + continue + } else { + console.log("unmatched!", wanted, matched) + continue + } + } + console.log("posting", wanted) + await workspace.post_time_entry(Object.assign({ created_with: "marvin-timesync" }, wanted)) + } +} + +void (async function () { + const config = await inferConfig() + const interval = dateToInterval(process.argv.length > 2 ? process.argv[2] : 'today') + + const marvin = new Marvin(Marvin.parseCredentials(config.marvin), config.marvinDB + "marvin") + const tasks = await (marvin.root.category('Datakami').then(datakami => datakami.tasksOverlapping(interval))) + + const toggl = new Toggl(config.toggl) + const workspaces = await toggl.workspaces() + if (workspaces.length !== 1) throw new Error("not sure which workspace to use") + + const res_tasks: TogglTE[] = [] + for (const task of tasks) + for (const task_interval of task.timesInInterval(interval)) + res_tasks.push({ + description: `${task.title}`, + start: toRFC3339(task_interval.start), + stop: toRFC3339(task_interval.end) + }) + + await apply_tasks_for_range(workspaces[0], interval, res_tasks) + +})() diff --git a/src/marvin-types.ts b/src/marvin-types.ts new file mode 100644 index 0000000..48b370a --- /dev/null +++ b/src/marvin-types.ts @@ -0,0 +1,121 @@ +export interface Task { + _id: string; + createdAt: number; + updatedAt: number; + workedOnAt: number; + title: string; + parentId: string; + dueDate: string | null; + startDate: string | null; + endDate: string | null; + day: string; + firstScheduled: string; + plannedWeek: string; + plannedMonth: string; + sprintId: string | null; + rank: number; + masterRank: number; + done: boolean; + completedAt: number | null; + duration: number; + times: number[]; + firstTracked: number; + doneAt: number; + isReward: boolean; + isStarred: boolean; + isFrogged: boolean; + isPinned: boolean; + pinId: string; + recurring: boolean; + recurringTaskId: string; + echo: boolean; + echoId: string; + link: string; + subtasks: { [id: string]: Subtask }; + colorBar: string | null; + labelIds: string[]; + timeEstimate: number; + note: string; + email: string; + dailySection: string; + bonusSection: string; + customSection: string; + timeBlockSection: string; + dependsOn: { [id: string]: boolean }; + backburner: boolean; + reviewDate: string; + itemSnoozeTime: number; + permaSnoozeTime: string; + calId: string; + calURL: string; + etag: string; + calData: string; + generatedAt: number; + echoedAt: number; + deletedAt: number; + restoredAt: number; + onboard: boolean; + imported: boolean; + marvinPoints: number; + mpNotes: string[]; + rewardPoints: number; + rewardId: number; + taskTime: string; + reminderOffset: number; + reminderTime: string; + snooze: number; + autoSnooze: number; + g_in_GOALID: boolean; + g_sec_GOALID: string; + g_rank_GOALID: number; + remindAt: string; + reminder: { + time: string; + diff: number; + }; +} + +export interface Subtask { + _id: string; + title: string; + done: boolean; + rank: number; + timeEstimate: number; +} + +interface Category { + _id: string; + title: string; // The category/project's title, like "Work". + type: "project" | "category"; + updatedAt: number; // Date.now() when updated. This includes adding a task. + workedOnAt: number; // Date.now() when last worked on. That means completing a task within it. + parentId: string; // ID of parent project or category, or "unassigned" or "root". + rank: number; // Sort rank within parent. + dayRank: number; // Sort rank within day. + day: string | null | undefined; // Schedule date or null/undefined. Only projects can be scheduled. This might also be "unassigned", so check for both. See https://github.com/amazingmarvin/MarvinAPI/issues/11 + firstScheduled: string | "unassigned"; // Which day the project was first assigned to, formatted as "YYYY-MM-DD" or "unassigned" if it was never scheduled yet. Used to calculate how many !!! in procrastination strategy. + dueDate: string; // Date when project is due, formatted as "YYYY-MM-DD". + labelIds: string[]; // The IDs of labels assigned to the Project. Any labelId that doesn't correspond to an existing label in strategySettings.labels should be ignored. + timeEstimate: number; // How long the user thinks the project will take, in ms. When shown in Marvin this is added to the child tasks' time estimates. + startDate: string; // When this task can be started, formatted as "YYYY-MM-DD". + endDate: string; // When this task should be completed (soft deadline), formatted as "YYYY-MM-DD". + plannedWeek: string; // Which week the task is planned for. Date of the Monday of the week (Mon-Sun) "YYYY-MM-DD" + plannedMonth: string; // Which month the task is planned for. "YYYY-MM" + sprintId: string; // The project's sprint. Not used yet. + done: boolean; // Whether the project has been marked as done. + doneDate: string | undefined; // If done, then this was the date the project/subproject (previously called milestone) was finished. + priority: "low" | "mid" | "high"; // Project only: one of "low", "mid", or "high". Used when priorities strategy is enabled. Why not isStarred like tasks? These used to be different strategies. + color: string; // Color chosen by clicking icon in master list "#222222" (rrggbb). + icon: string; // Icon chosen by clicking icon in master list. + note: string; // note for "notes" strategy. + recurring: boolean; // True if it's a recurring project. + recurringTaskId: string; // ID of RecurringTask creator. + echo: boolean; // True if created by RecurringTask with type="echo". + isFrogged: boolean; // True if this project has been frogged for eatThatFrog. 1=normal, 2=baby, 3=monster. + reviewDate: string; // Date when user wants to review a project. + marvinPoints: number; // How many kudos you got for this project. Always 500. + mpNotes: string[]; // Notes on how Marvin awarded you kudos when you completed the project. Always ["PROJECT"]. +} + +export type DBEntry = Task | Category + diff --git a/src/toggl-types.ts b/src/toggl-types.ts new file mode 100644 index 0000000..0128eb2 --- /dev/null +++ b/src/toggl-types.ts @@ -0,0 +1,187 @@ +namespace models { + export type CardDetails = unknown; + export type ContactDetail = unknown; + export type PaymentDetail = unknown; + export type Period = unknown; + export type RecurringPeriod = unknown; + export type RecurringProjectParameters = unknown; +} +export type Subscription = { + auto_renew: boolean; + card_details: models.CardDetails; + company_id: number; + contact_detail: models.ContactDetail; + created_at: string; + currency: string; + customer_id: number; + deleted_at: string; + last_pricing_plan_id: number; + organization_id: number; + payment_details: models.PaymentDetail; + pricing_plan_id: number; + renewal_at: string; + subscription_id: number; + subscription_period: models.Period; + workspace_id: number; +}; + +export type TimeEntryConstraints = { + description_present: boolean; + project_present: boolean; + tag_present: boolean; + task_present: boolean; + time_entry_constraints_enabled: boolean; +}; + +export type CsvUpload = { + at: string; + log_id: number; +}; + +export type Workspace = { + admin: boolean; + api_token: string; + at: string; + business_ws: boolean; + csv_upload: CsvUpload; + default_currency: string; + default_hourly_rate: number; + ical_enabled: boolean; + ical_url: string; + id: number; + logo_url: string; + name: string; + only_admins_may_create_projects: boolean; + only_admins_may_create_tags: boolean; + only_admins_see_billable_rates: boolean; + only_admins_see_team_dashboard: boolean; + organization_id: number; + premium: boolean; + profile: number; + projects_billable_by_default: boolean; + rate_last_updated: string; + reports_collapse: boolean; + rounding: number; + rounding_minutes: number; + server_deleted_at: string; + subscription: Subscription; + suspended_at: string; + te_constraints: TimeEntryConstraints; +}; +type Clients = { + archived: boolean; + at: string; + id: number; + name: string; + server_deleted_at: string | null; + wid: number; +}; + +type Projects = { + active: boolean; + actual_hours: number | null; + at: string; + auto_estimates: boolean | null; + billable: boolean | null; + cid: number; + client_id: number | null; + color: string; + created_at: string; + currency: string | null; + current_period: models.RecurringPeriod; + end_date: string; + estimated_hours: number | null; + first_time_entry: string; + fixed_fee: number; + id: number; + is_private: boolean; + name: string; + rate: number; + rate_last_updated: string | null; + recurring: boolean; + recurring_parameters: models.RecurringProjectParameters[]; + server_deleted_at: string | null; + start_date: string; + template: boolean | null; + wid: number; + workspace_id: number; +}; + +type Tags = { + at: string; + deleted_at: string; + id: number; + name: string; + workspace_id: number; +}; + +type Tasks = { + active: boolean; + at: string; + estimated_seconds: number | null; + id: number; + name: string; + project_id: number; + recurring: boolean; + server_deleted_at: string | null; + tracked_seconds: number; + user_id: number | null; + workspace_id: number; +}; + +type Options = { + additionalProperties: object; +}; +export interface TimeEntryBase { + billable?: boolean; + description?: string | null; + duration?: number; + duronly?: boolean; // Deprecated + pid?: number; // Legacy field + project_id?: number | null; + start: string; + stop?: string | null; + tag_ids?: number[] | null; + tags?: string[] | null; + task_id?: number | null; + tid?: number; // Legacy field + uid?: number; // Legacy field + user_id?: number; + wid?: number; // Legacy field + workspace_id: number; +} + +export interface TimeEntry extends TimeEntryBase { + at: string; + duronly: true; // For GET requests, always true + id: number; + server_deleted_at: string | null; +} + +export type Me = { + api_token: string; + at: string; + beginning_of_week: number; + clients: Clients[] | null; + country_id: number; + created_at: string; + default_workspace_id: number; + email: string; + fullname: string; + has_password: boolean; + id: number; + image_url: string; + intercom_hash: string | null; + oauth_providers: string[]; + openid_email: string; + openid_enabled: boolean; + options: Options | null; + password_hash: string; + projects: Projects[] | null; + tags: Tags[] | null; + tasks: Tasks[] | null; + time_entries: TimeEntry[] | null; + timezone: string; + updated_at: string; + workspaces: Workspace[]; +}; diff --git a/src/util.ts b/src/util.ts new file mode 100644 index 0000000..3c247cf --- /dev/null +++ b/src/util.ts @@ -0,0 +1,7 @@ +import { Duration } from "luxon" +export namespace DurationUtil { + export const zero = Duration.fromMillis(0) + export function sum(durs: Duration[]): Duration { + return durs.reduce((p: Duration, c: Duration) => p.plus(c), zero) + } +} diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..48dbd15 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,10 @@ +{ + "extends": "@tsconfig/node18/tsconfig.json", + "compilerOptions": { + "noImplicitAny": true, + "module": "ES2020", + "moduleResolution": "nodenext", + "outDir": "lib/" + }, + "includes": ["src/*.ts"], +} diff --git a/yarn.lock b/yarn.lock new file mode 100644 index 0000000..fb0fb6a --- /dev/null +++ b/yarn.lock @@ -0,0 +1,700 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@tsconfig/node18@^1.0.2": + version "1.0.2" + resolved "https://registry.yarnpkg.com/@tsconfig/node18/-/node18-1.0.2.tgz#d0a465fbb5ae50813ad6d91542f71a6d34a5f08c" + integrity sha512-4//KMPpqhtqw4g25Zh27ELuMD+vgcidW4VLozYWtRn8VXJEiRPm7GqrVNFwBiL3rM9/3k0a07X5NpI78DvTpfQ== + +"@types/debug@*": + version "4.1.7" + resolved "https://registry.yarnpkg.com/@types/debug/-/debug-4.1.7.tgz#7cc0ea761509124709b8b2d1090d8f6c17aadb82" + integrity sha512-9AonUzyTjXXhEOa0DnqpzZi6VHlqKMswga9EXjpXnnqxwLtdvPPtlO8evrI5D9S6asFRCQ6v+wpiUKbw+vKqyg== + dependencies: + "@types/ms" "*" + +"@types/luxon@^3.3.0": + version "3.3.0" + resolved "https://registry.yarnpkg.com/@types/luxon/-/luxon-3.3.0.tgz#a61043a62c0a72696c73a0a305c544c96501e006" + integrity sha512-uKRI5QORDnrGFYgcdAVnHvEIvEZ8noTpP/Bg+HeUzZghwinDlIS87DEenV5r1YoOF9G4x600YsUXLWZ19rmTmg== + +"@types/ms@*": + version "0.7.31" + resolved "https://registry.yarnpkg.com/@types/ms/-/ms-0.7.31.tgz#31b7ca6407128a3d2bbc27fe2d21b345397f6197" + integrity sha512-iiUgKzV9AuaEkZqkOLDIvlQiL6ltuZd9tGcW3gwpnX8JbuiuhFlEGmmFXEXkN50Cvq7Os88IY2v0dkDqXYWVgA== + +"@types/node@^18.15.11": + version "18.15.11" + resolved "https://registry.yarnpkg.com/@types/node/-/node-18.15.11.tgz#b3b790f09cb1696cffcec605de025b088fa4225f" + integrity sha512-E5Kwq2n4SbMzQOn6wnmBjuK9ouqlURrcZDVfbo9ftDDTFt3nk7ZKK4GMOzoYgnpQJKcxwQw+lGaBvvlMo0qN/Q== + +"@types/pouchdb-adapter-cordova-sqlite@*": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@types/pouchdb-adapter-cordova-sqlite/-/pouchdb-adapter-cordova-sqlite-1.0.1.tgz#49e5ee6df7cc0c23196fcb340f43a560e74eb1d6" + integrity sha512-nqlXpW1ho3KBg1mUQvZgH2755y3z/rw4UA7ZJCPMRTHofxGMY8izRVw5rHBL4/7P615or0J2udpRYxgkT3D02g== + dependencies: + "@types/pouchdb-core" "*" + +"@types/pouchdb-adapter-fruitdown@*": + version "6.1.3" + resolved "https://registry.yarnpkg.com/@types/pouchdb-adapter-fruitdown/-/pouchdb-adapter-fruitdown-6.1.3.tgz#9b140ad9645cc56068728acf08ec19ac0046658e" + integrity sha512-Wz1Z1JLOW1hgmFQjqnSkmyyfH7by/iWb4abKn684WMvQfmxx6BxKJpJ4+eulkVPQzzgMMSgU1MpnQOm9FgRkbw== + dependencies: + "@types/pouchdb-core" "*" + +"@types/pouchdb-adapter-http@*": + version "6.1.3" + resolved "https://registry.yarnpkg.com/@types/pouchdb-adapter-http/-/pouchdb-adapter-http-6.1.3.tgz#6e592d5f48deb6274a21ddac1498dd308096bcf3" + integrity sha512-9Z4TLbF/KJWy/D2sWRPBA+RNU0odQimfdvlDX+EY7rGcd3aVoH8qjD/X0Xcd/0dfBH5pKrNIMFFQgW/TylRCmA== + dependencies: + "@types/pouchdb-core" "*" + +"@types/pouchdb-adapter-idb@*": + version "6.1.4" + resolved "https://registry.yarnpkg.com/@types/pouchdb-adapter-idb/-/pouchdb-adapter-idb-6.1.4.tgz#cb9a18864585d600820cd325f007614c5c3989cd" + integrity sha512-KIAXbkF4uYUz0ZwfNEFLtEkK44mEWopAsD76UhucH92XnJloBysav+TjI4FFfYQyTjoW3S1s6V+Z14CUJZ0F6w== + dependencies: + "@types/pouchdb-core" "*" + +"@types/pouchdb-adapter-leveldb@*": + version "6.1.3" + resolved "https://registry.yarnpkg.com/@types/pouchdb-adapter-leveldb/-/pouchdb-adapter-leveldb-6.1.3.tgz#17c7e75d75b992050bca15991e97fba575c61bb3" + integrity sha512-ex8NFqQGFwEpFi7AaZ5YofmuemfZNsL3nTFZBUCAKYMBkazQij1pe2ILLStSvJr0XS0qxgXjCEW19T5Wqiiskg== + dependencies: + "@types/pouchdb-core" "*" + +"@types/pouchdb-adapter-localstorage@*": + version "6.1.3" + resolved "https://registry.yarnpkg.com/@types/pouchdb-adapter-localstorage/-/pouchdb-adapter-localstorage-6.1.3.tgz#0dde02ba6b9d6073a295a20196563942ba9a54bd" + integrity sha512-oor040tye1KKiGLWYtIy7rRT7C2yoyX3Tf6elEJRpjOA7Ja/H8lKc4LaSh9ATbptIcES6MRqZDxtp7ly9hsW3Q== + dependencies: + "@types/pouchdb-core" "*" + +"@types/pouchdb-adapter-memory@*": + version "6.1.3" + resolved "https://registry.yarnpkg.com/@types/pouchdb-adapter-memory/-/pouchdb-adapter-memory-6.1.3.tgz#9eabdbc890fcf58960ee8b68b8685f837e75c844" + integrity sha512-gVbsIMzDzgZYThFVT4eVNsmuZwVm/4jDxP1sjlgc3qtDIxbtBhGgyNfcskwwz9Zu5Lv1avkDsIWvcxQhnvRlHg== + dependencies: + "@types/pouchdb-core" "*" + +"@types/pouchdb-adapter-node-websql@*": + version "6.1.3" + resolved "https://registry.yarnpkg.com/@types/pouchdb-adapter-node-websql/-/pouchdb-adapter-node-websql-6.1.3.tgz#aa18bc68af8cf509acd12c400010dcd5fab2243d" + integrity sha512-F/P+os6Jsa7CgHtH64+Z0HfwIcj0hIRB5z8gNhF7L7dxPWoAfkopK5H2gydrP3sQrlGyN4WInF+UJW/Zu1+FKg== + dependencies: + "@types/pouchdb-adapter-websql" "*" + "@types/pouchdb-core" "*" + +"@types/pouchdb-adapter-websql@*": + version "6.1.4" + resolved "https://registry.yarnpkg.com/@types/pouchdb-adapter-websql/-/pouchdb-adapter-websql-6.1.4.tgz#359fbe42ccac0ac90b492ddb8c32fafd0aa96d79" + integrity sha512-zMJQCtXC40hBsIDRn0GhmpeGMK0f9l/OGWfLguvczROzxxcOD7REI+e6SEmX7gJKw5JuMvlfuHzkQwjmvSJbtg== + dependencies: + "@types/pouchdb-core" "*" + +"@types/pouchdb-browser@*": + version "6.1.3" + resolved "https://registry.yarnpkg.com/@types/pouchdb-browser/-/pouchdb-browser-6.1.3.tgz#8f33d6ef58d6817d1f6d36979148a1c7f63244d8" + integrity sha512-EdYowrWxW9SWBMX/rux2eq7dbHi5Zeyzz+FF/IAsgQKnUxgeCO5VO2j4zTzos0SDyJvAQU+EYRc11r7xGn5tvA== + dependencies: + "@types/pouchdb-adapter-http" "*" + "@types/pouchdb-adapter-idb" "*" + "@types/pouchdb-adapter-websql" "*" + "@types/pouchdb-core" "*" + "@types/pouchdb-mapreduce" "*" + "@types/pouchdb-replication" "*" + +"@types/pouchdb-core@*": + version "7.0.11" + resolved "https://registry.yarnpkg.com/@types/pouchdb-core/-/pouchdb-core-7.0.11.tgz#8fad7a16889dafab765415430a491eb50a54f564" + integrity sha512-KTKj0Taf8pLTj8eW3qBtCd1Fh+/yhEyVo6/1czTN46MnseobdmnqgXtzaKgHMbuLouh+SHK1vM++aMPaG1qTTA== + dependencies: + "@types/debug" "*" + "@types/pouchdb-find" "*" + +"@types/pouchdb-find@*", "@types/pouchdb-find@^7.3.0": + version "7.3.0" + resolved "https://registry.yarnpkg.com/@types/pouchdb-find/-/pouchdb-find-7.3.0.tgz#b917030e9f4bf6e56bf8c3b9fe4b2a25e989009a" + integrity sha512-sFPli5tBjGX9UfXioik1jUzPdcN84eV82n0lmEFuoPepWqkLjQcyri0eOa++HYOaNPyMDhKFBqEALEZivK2dRg== + dependencies: + "@types/pouchdb-core" "*" + +"@types/pouchdb-http@*": + version "6.1.3" + resolved "https://registry.yarnpkg.com/@types/pouchdb-http/-/pouchdb-http-6.1.3.tgz#09576c0d409da1f8dee34ec5b768415e2472ea52" + integrity sha512-0e9E5SqNOyPl/3FnEIbENssB4FlJsNYuOy131nxrZk36S+y1R/6qO7ZVRypWpGTqBWSuVd7gCsq2UDwO/285+w== + dependencies: + "@types/pouchdb-adapter-http" "*" + "@types/pouchdb-core" "*" + +"@types/pouchdb-mapreduce@*": + version "6.1.7" + resolved "https://registry.yarnpkg.com/@types/pouchdb-mapreduce/-/pouchdb-mapreduce-6.1.7.tgz#9ab32d1e0f234f1bf6d1e4c5d7e216e9e23ac0a3" + integrity sha512-WzBwm7tmO9QhfRzVaWT4v6JQSS/fG2OoUDrWrhX87rPe2Pn6laPvdK5li6myNRxCoI/l5e8Jd+oYBAFnaiFucA== + dependencies: + "@types/pouchdb-core" "*" + +"@types/pouchdb-node@*": + version "6.1.4" + resolved "https://registry.yarnpkg.com/@types/pouchdb-node/-/pouchdb-node-6.1.4.tgz#5214c0169fcfd2237d373380bbd65a934feb5dfb" + integrity sha512-wnTCH8X1JOPpNOfVhz8HW0AvmdHh6pt40MuRj0jQnK7QEHsHS79WujsKTKSOF8QXtPwpvCNSsI7ut7H7tfxxJQ== + dependencies: + "@types/pouchdb-adapter-http" "*" + "@types/pouchdb-adapter-leveldb" "*" + "@types/pouchdb-core" "*" + "@types/pouchdb-mapreduce" "*" + "@types/pouchdb-replication" "*" + +"@types/pouchdb-replication@*": + version "6.4.4" + resolved "https://registry.yarnpkg.com/@types/pouchdb-replication/-/pouchdb-replication-6.4.4.tgz#743406c90f13a988fa3e346ea74ce40acd170d00" + integrity sha512-BsE5LKpjJK4iAf6Fx5kyrMw+33V+Ip7uWldUnU2BYrrvtR+MLD22dcImm7DZN1st2wPPb91i0XEnQzvP0w1C/Q== + dependencies: + "@types/pouchdb-core" "*" + "@types/pouchdb-find" "*" + +"@types/pouchdb@^6.4.0": + version "6.4.0" + resolved "https://registry.yarnpkg.com/@types/pouchdb/-/pouchdb-6.4.0.tgz#f9c41ca64b23029f9bf2eb4bf6956e6431cb79f8" + integrity sha512-eGCpX+NXhd5VLJuJMzwe3L79fa9+IDTrAG3CPaf4s/31PD56hOrhDJTSmRELSXuiqXr6+OHzzP0PldSaWsFt7w== + dependencies: + "@types/pouchdb-adapter-cordova-sqlite" "*" + "@types/pouchdb-adapter-fruitdown" "*" + "@types/pouchdb-adapter-http" "*" + "@types/pouchdb-adapter-idb" "*" + "@types/pouchdb-adapter-leveldb" "*" + "@types/pouchdb-adapter-localstorage" "*" + "@types/pouchdb-adapter-memory" "*" + "@types/pouchdb-adapter-node-websql" "*" + "@types/pouchdb-adapter-websql" "*" + "@types/pouchdb-browser" "*" + "@types/pouchdb-core" "*" + "@types/pouchdb-http" "*" + "@types/pouchdb-mapreduce" "*" + "@types/pouchdb-node" "*" + "@types/pouchdb-replication" "*" + +abort-controller@3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/abort-controller/-/abort-controller-3.0.0.tgz#eaf54d53b62bae4138e809ca225c8439a6efb392" + integrity sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg== + dependencies: + event-target-shim "^5.0.0" + +abstract-leveldown@^6.2.1: + version "6.3.0" + resolved "https://registry.yarnpkg.com/abstract-leveldown/-/abstract-leveldown-6.3.0.tgz#d25221d1e6612f820c35963ba4bd739928f6026a" + integrity sha512-TU5nlYgta8YrBMNpc9FwQzRbiXsj49gsALsXadbGHt9CROPzX5fB0rWDR5mtdpOOKa5XqRFpbj1QroPAoPzVjQ== + dependencies: + buffer "^5.5.0" + immediate "^3.2.3" + level-concat-iterator "~2.0.0" + level-supports "~1.0.0" + xtend "~4.0.0" + +abstract-leveldown@~6.2.1, abstract-leveldown@~6.2.3: + version "6.2.3" + resolved "https://registry.yarnpkg.com/abstract-leveldown/-/abstract-leveldown-6.2.3.tgz#036543d87e3710f2528e47040bc3261b77a9a8eb" + integrity sha512-BsLm5vFMRUrrLeCcRc+G0t2qOaTzpoJQLOubq2XM72eNpjF5UdU5o/5NvlNhx95XHcAvcl8OMXr4mlg/fRgUXQ== + dependencies: + buffer "^5.5.0" + immediate "^3.2.3" + level-concat-iterator "~2.0.0" + level-supports "~1.0.0" + xtend "~4.0.0" + +base64-js@^1.3.1: + version "1.5.1" + resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" + integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== + +buffer-from@1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5" + integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ== + +buffer@^5.5.0, buffer@^5.6.0: + version "5.7.1" + resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.7.1.tgz#ba62e7c13133053582197160851a8f648e99eed0" + integrity sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ== + dependencies: + base64-js "^1.3.1" + ieee754 "^1.1.13" + +clone-buffer@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/clone-buffer/-/clone-buffer-1.0.0.tgz#e3e25b207ac4e701af721e2cb5a16792cac3dc58" + integrity sha512-KLLTJWrvwIP+OPfMn0x2PheDEP20RPUcGXj/ERegTgdmPEZylALQldygiqrPPu8P45uNuPs7ckmReLY6v/iA5g== + +core-util-is@~1.0.0: + version "1.0.3" + resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.3.tgz#a6042d3634c2b27e9328f837b965fac83808db85" + integrity sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ== + +deferred-leveldown@~5.3.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/deferred-leveldown/-/deferred-leveldown-5.3.0.tgz#27a997ad95408b61161aa69bd489b86c71b78058" + integrity sha512-a59VOT+oDy7vtAbLRCZwWgxu2BaCfd5Hk7wxJd48ei7I+nsg8Orlb9CLG0PMZienk9BSUKgeAqkO2+Lw+1+Ukw== + dependencies: + abstract-leveldown "~6.2.1" + inherits "^2.0.3" + +double-ended-queue@2.1.0-0: + version "2.1.0-0" + resolved "https://registry.yarnpkg.com/double-ended-queue/-/double-ended-queue-2.1.0-0.tgz#103d3527fd31528f40188130c841efdd78264e5c" + integrity sha512-+BNfZ+deCo8hMNpDqDnvT+c0XpJ5cUa6mqYq89bho2Ifze4URTqRkcwR399hWoTrTkbZ/XJYDgP6rc7pRgffEQ== + +encoding-down@^6.3.0: + version "6.3.0" + resolved "https://registry.yarnpkg.com/encoding-down/-/encoding-down-6.3.0.tgz#b1c4eb0e1728c146ecaef8e32963c549e76d082b" + integrity sha512-QKrV0iKR6MZVJV08QY0wp1e7vF6QbhnbQhb07bwpEyuz4uZiZgPlEGdkCROuFkUwdxlFaiPIhjyarH1ee/3vhw== + dependencies: + abstract-leveldown "^6.2.1" + inherits "^2.0.3" + level-codec "^9.0.0" + level-errors "^2.0.0" + +end-stream@~0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/end-stream/-/end-stream-0.1.0.tgz#32003f3f438a2b0143168137f8fa6e9866c81ed5" + integrity sha512-Brl10T8kYnc75IepKizW6Y9liyW8ikz1B7n/xoHrJxoVSSjoqPn30sb7XVFfQERK4QfUMYRGs9dhWwtt2eu6uA== + dependencies: + write-stream "~0.4.3" + +errno@~0.1.1: + version "0.1.8" + resolved "https://registry.yarnpkg.com/errno/-/errno-0.1.8.tgz#8bb3e9c7d463be4976ff888f76b4809ebc2e811f" + integrity sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A== + dependencies: + prr "~1.0.1" + +event-target-shim@^5.0.0: + version "5.0.1" + resolved "https://registry.yarnpkg.com/event-target-shim/-/event-target-shim-5.0.1.tgz#5d4d3ebdf9583d63a5333ce2deb7480ab2b05789" + integrity sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ== + +fetch-cookie@0.11.0: + version "0.11.0" + resolved "https://registry.yarnpkg.com/fetch-cookie/-/fetch-cookie-0.11.0.tgz#e046d2abadd0ded5804ce7e2cae06d4331c15407" + integrity sha512-BQm7iZLFhMWFy5CZ/162sAGjBfdNWb7a8LEqqnzsHFhxT/X/SVj/z2t2nu3aJvjlbQkrAlTUApplPRjWyH4mhA== + dependencies: + tough-cookie "^2.3.3 || ^3.0.1 || ^4.0.0" + +ieee754@^1.1.13: + version "1.2.1" + resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" + integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== + +immediate@3.3.0, immediate@^3.2.3: + version "3.3.0" + resolved "https://registry.yarnpkg.com/immediate/-/immediate-3.3.0.tgz#1aef225517836bcdf7f2a2de2600c79ff0269266" + integrity sha512-HR7EVodfFUdQCTIeySw+WDRFJlPcLOJbXfwwZ7Oom6tjsvZ3bOkCDJHehQC3nxJrv7+f9XecwazynjU8e4Vw3Q== + +inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.1: + version "2.0.4" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" + integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== + +isarray@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" + integrity sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ== + +level-codec@9.0.2, level-codec@^9.0.0: + version "9.0.2" + resolved "https://registry.yarnpkg.com/level-codec/-/level-codec-9.0.2.tgz#fd60df8c64786a80d44e63423096ffead63d8cbc" + integrity sha512-UyIwNb1lJBChJnGfjmO0OR+ezh2iVu1Kas3nvBS/BzGnx79dv6g7unpKIDNPMhfdTEGoc7mC8uAu51XEtX+FHQ== + dependencies: + buffer "^5.6.0" + +level-concat-iterator@~2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/level-concat-iterator/-/level-concat-iterator-2.0.1.tgz#1d1009cf108340252cb38c51f9727311193e6263" + integrity sha512-OTKKOqeav2QWcERMJR7IS9CUo1sHnke2C0gkSmcR7QuEtFNLLzHQAvnMw8ykvEcv0Qtkg0p7FOwP1v9e5Smdcw== + +level-errors@^2.0.0, level-errors@~2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/level-errors/-/level-errors-2.0.1.tgz#2132a677bf4e679ce029f517c2f17432800c05c8" + integrity sha512-UVprBJXite4gPS+3VznfgDSU8PTRuVX0NXwoWW50KLxd2yw4Y1t2JUR5In1itQnudZqRMT9DlAM3Q//9NCjCFw== + dependencies: + errno "~0.1.1" + +level-iterator-stream@~4.0.0: + version "4.0.2" + resolved "https://registry.yarnpkg.com/level-iterator-stream/-/level-iterator-stream-4.0.2.tgz#7ceba69b713b0d7e22fcc0d1f128ccdc8a24f79c" + integrity sha512-ZSthfEqzGSOMWoUGhTXdX9jv26d32XJuHz/5YnuHZzH6wldfWMOVwI9TBtKcya4BKTyTt3XVA0A3cF3q5CY30Q== + dependencies: + inherits "^2.0.4" + readable-stream "^3.4.0" + xtend "^4.0.2" + +level-js@^5.0.0: + version "5.0.2" + resolved "https://registry.yarnpkg.com/level-js/-/level-js-5.0.2.tgz#5e280b8f93abd9ef3a305b13faf0b5397c969b55" + integrity sha512-SnBIDo2pdO5VXh02ZmtAyPP6/+6YTJg2ibLtl9C34pWvmtMEmRTWpra+qO/hifkUtBTOtfx6S9vLDjBsBK4gRg== + dependencies: + abstract-leveldown "~6.2.3" + buffer "^5.5.0" + inherits "^2.0.3" + ltgt "^2.1.2" + +level-packager@^5.1.0: + version "5.1.1" + resolved "https://registry.yarnpkg.com/level-packager/-/level-packager-5.1.1.tgz#323ec842d6babe7336f70299c14df2e329c18939" + integrity sha512-HMwMaQPlTC1IlcwT3+swhqf/NUO+ZhXVz6TY1zZIIZlIR0YSn8GtAAWmIvKjNY16ZkEg/JcpAuQskxsXqC0yOQ== + dependencies: + encoding-down "^6.3.0" + levelup "^4.3.2" + +level-supports@~1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/level-supports/-/level-supports-1.0.1.tgz#2f530a596834c7301622521988e2c36bb77d122d" + integrity sha512-rXM7GYnW8gsl1vedTJIbzOrRv85c/2uCMpiiCzO2fndd06U/kUXEEU9evYn4zFggBOg36IsBW8LzqIpETwwQzg== + dependencies: + xtend "^4.0.2" + +level-write-stream@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/level-write-stream/-/level-write-stream-1.0.0.tgz#3f7fbb679a55137c0feb303dee766e12ee13c1dc" + integrity sha512-bBNKOEOMl8msO+uIM9YX/gUO6ckokZ/4pCwTm/lwvs46x6Xs8Zy0sn3Vh37eDqse4mhy4fOMIb/JsSM2nyQFtw== + dependencies: + end-stream "~0.1.0" + +level@6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/level/-/level-6.0.1.tgz#dc34c5edb81846a6de5079eac15706334b0d7cd6" + integrity sha512-psRSqJZCsC/irNhfHzrVZbmPYXDcEYhA5TVNwr+V92jF44rbf86hqGp8fiT702FyiArScYIlPSBTDUASCVNSpw== + dependencies: + level-js "^5.0.0" + level-packager "^5.1.0" + leveldown "^5.4.0" + +leveldown@5.6.0, leveldown@^5.4.0: + version "5.6.0" + resolved "https://registry.yarnpkg.com/leveldown/-/leveldown-5.6.0.tgz#16ba937bb2991c6094e13ac5a6898ee66d3eee98" + integrity sha512-iB8O/7Db9lPaITU1aA2txU/cBEXAt4vWwKQRrrWuS6XDgbP4QZGj9BL2aNbwb002atoQ/lIotJkfyzz+ygQnUQ== + dependencies: + abstract-leveldown "~6.2.1" + napi-macros "~2.0.0" + node-gyp-build "~4.1.0" + +levelup@4.4.0, levelup@^4.3.2: + version "4.4.0" + resolved "https://registry.yarnpkg.com/levelup/-/levelup-4.4.0.tgz#f89da3a228c38deb49c48f88a70fb71f01cafed6" + integrity sha512-94++VFO3qN95cM/d6eBXvd894oJE0w3cInq9USsyQzzoJxmiYzPAocNcuGCPGGjoXqDVJcr3C1jzt1TSjyaiLQ== + dependencies: + deferred-leveldown "~5.3.0" + level-errors "~2.0.0" + level-iterator-stream "~4.0.0" + level-supports "~1.0.0" + xtend "~4.0.0" + +ltgt@2.2.1, ltgt@^2.1.2: + version "2.2.1" + resolved "https://registry.yarnpkg.com/ltgt/-/ltgt-2.2.1.tgz#f35ca91c493f7b73da0e07495304f17b31f87ee5" + integrity sha512-AI2r85+4MquTw9ZYqabu4nMwy9Oftlfa/e/52t9IjtfG+mGBbTNdAoZ3RQKLHR6r0wQnwZnPIEh/Ya6XTWAKNA== + +luxon@^3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/luxon/-/luxon-3.3.0.tgz#d73ab5b5d2b49a461c47cedbc7e73309b4805b48" + integrity sha512-An0UCfG/rSiqtAIiBPO0Y9/zAnHUZxAMiCpTd5h2smgsj7GGmcenvrvww2cqNA8/4A5ZrD1gJpHN2mIHZQF+Mg== + +napi-macros@~2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/napi-macros/-/napi-macros-2.0.0.tgz#2b6bae421e7b96eb687aa6c77a7858640670001b" + integrity sha512-A0xLykHtARfueITVDernsAWdtIMbOJgKgcluwENp3AlsKN/PloyO10HtmoqnFAQAcxPkgZN7wdfPfEd0zNGxbg== + +node-fetch@2: + version "2.6.9" + resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.9.tgz#7c7f744b5cc6eb5fd404e0c7a9fec630a55657e6" + integrity sha512-DJm/CJkZkRjKKj4Zi4BsKVZh3ValV5IR5s7LVZnW+6YMh0W1BfNA8XSs6DLMGYlId5F3KnA70uu2qepcR08Qqg== + dependencies: + whatwg-url "^5.0.0" + +node-fetch@2.6.7: + version "2.6.7" + resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.7.tgz#24de9fba827e3b4ae44dc8b20256a379160052ad" + integrity sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ== + dependencies: + whatwg-url "^5.0.0" + +node-gyp-build@~4.1.0: + version "4.1.1" + resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-4.1.1.tgz#d7270b5d86717068d114cc57fff352f96d745feb" + integrity sha512-dSq1xmcPDKPZ2EED2S6zw/b9NKsqzXRE6dVr8TVQnI3FJOTteUMuqF3Qqs6LZg+mLGYJWqQzMbIjMtJqTv87nQ== + +pouchdb-abstract-mapreduce@8.0.1: + version "8.0.1" + resolved "https://registry.yarnpkg.com/pouchdb-abstract-mapreduce/-/pouchdb-abstract-mapreduce-8.0.1.tgz#f45aa1424fdd272a76ceb5722a53b38c10a0ca81" + integrity sha512-BxJRHdfiC8gID8h4DPS0Xy6wsa2VBHRHMv9hsm0BhGTWTqS4k8ivItVSeU2dMoXiTBYp+7SerYmovUQNGSX1GA== + dependencies: + pouchdb-binary-utils "8.0.1" + pouchdb-collate "8.0.1" + pouchdb-collections "8.0.1" + pouchdb-errors "8.0.1" + pouchdb-fetch "8.0.1" + pouchdb-mapreduce-utils "8.0.1" + pouchdb-md5 "8.0.1" + pouchdb-utils "8.0.1" + +pouchdb-binary-utils@8.0.1: + version "8.0.1" + resolved "https://registry.yarnpkg.com/pouchdb-binary-utils/-/pouchdb-binary-utils-8.0.1.tgz#aa77248b9c0ad2a68f75f8f7cf2b594fe3dbd559" + integrity sha512-WsuR/S0aoUlcA0Alt99czkXsfuXWcrYXAcvGiTW02zawVXOafCnb/qHjA09TUaV0oy5HeHmYaNnDckoOUqspeA== + dependencies: + buffer-from "1.1.2" + +pouchdb-collate@8.0.1: + version "8.0.1" + resolved "https://registry.yarnpkg.com/pouchdb-collate/-/pouchdb-collate-8.0.1.tgz#14b6ad9330d2831fd8ef135de680060366502a1b" + integrity sha512-DTuNz1UJjBTGZMUlWS1klSE1rPsmHy8IIDie3MFH1ZTz/C+SwGgGwkiAyUDv/n00D18EMLgXq5mu+r7L6K1BwQ== + +pouchdb-collections@8.0.1: + version "8.0.1" + resolved "https://registry.yarnpkg.com/pouchdb-collections/-/pouchdb-collections-8.0.1.tgz#d6a31ab3a917fa5da49d46a804c04761a0e19655" + integrity sha512-TlkQ2GGHJApJgL0b7bJMQcwX6eMfVenLeoK9mqHfC2fJssui+HWJJ5LYKHOWan11SeB90BQVFbO6rHN6CJQeDg== + +pouchdb-errors@8.0.1: + version "8.0.1" + resolved "https://registry.yarnpkg.com/pouchdb-errors/-/pouchdb-errors-8.0.1.tgz#d57afd57e07490d8d0b4ef19c10bfc85dbf27ae5" + integrity sha512-H+ZsQxcG/JV3Tn29gnM6c9+lRPCN91ZYOkoIICsLjVRYgOTzN1AvNUD/G5JCB+81aI/u3fxZec0LEaZh6g6NHA== + +pouchdb-fetch@8.0.1: + version "8.0.1" + resolved "https://registry.yarnpkg.com/pouchdb-fetch/-/pouchdb-fetch-8.0.1.tgz#30a27a45eb24c20f346a04d906ba82bca5a3a525" + integrity sha512-Px5HLT8MxqTujc8bpPRKoouznDTJa9XBGqCbhl95q6rhjWRfwZEvXjV92z0B5BALAM6D6avMyG0DjuNfUWnMuA== + dependencies: + abort-controller "3.0.0" + fetch-cookie "0.11.0" + node-fetch "2.6.7" + +pouchdb-find@^8.0.1: + version "8.0.1" + resolved "https://registry.yarnpkg.com/pouchdb-find/-/pouchdb-find-8.0.1.tgz#aa96efce482add3a9258e64531a807d082b7848c" + integrity sha512-i5criYXMOXlbeRrCrXonqaOY+xiMiOyTLybqvtX/NkUsiD4BxJxkq5AxdSlHdJ9703nWJ0k6S+5C8VrpEj8tsQ== + dependencies: + pouchdb-abstract-mapreduce "8.0.1" + pouchdb-collate "8.0.1" + pouchdb-errors "8.0.1" + pouchdb-fetch "8.0.1" + pouchdb-md5 "8.0.1" + pouchdb-selector-core "8.0.1" + pouchdb-utils "8.0.1" + +pouchdb-mapreduce-utils@8.0.1: + version "8.0.1" + resolved "https://registry.yarnpkg.com/pouchdb-mapreduce-utils/-/pouchdb-mapreduce-utils-8.0.1.tgz#a8acb1542aaf63a007b60f7a281dbbb94b49fcab" + integrity sha512-asZcFLy1DA3oe5CeXIRCpfVrBHaHRvSb3Tc/LPD1dZDDtpEkeCuXGtJm+praN0jl41jTBEm0uMdD/YI0J5ZFXw== + dependencies: + pouchdb-collections "8.0.1" + pouchdb-utils "8.0.1" + +pouchdb-md5@8.0.1: + version "8.0.1" + resolved "https://registry.yarnpkg.com/pouchdb-md5/-/pouchdb-md5-8.0.1.tgz#5a3df4939102423727e0594c2a9bb91b82a444ed" + integrity sha512-shVcs/K/iilrcAhDEERpLIrGm/cnDVsXiocOzs7kycJEuBqYnLD9nj58VwWDcum26wfa8T9cznvEGE1jlYVNPQ== + dependencies: + pouchdb-binary-utils "8.0.1" + spark-md5 "3.0.2" + +pouchdb-selector-core@8.0.1: + version "8.0.1" + resolved "https://registry.yarnpkg.com/pouchdb-selector-core/-/pouchdb-selector-core-8.0.1.tgz#d52119b79bd34b69c27f4596dbb9e16373bbd92e" + integrity sha512-dHWsnR+mLGyfVld1vSHJI1xKTwS1xk1G2dggjfXfUrLehI+wysjTUOwiSNytyPzG6DpT+o86wyUpwzPwsDCLBw== + dependencies: + pouchdb-collate "8.0.1" + pouchdb-utils "8.0.1" + +pouchdb-utils@8.0.1: + version "8.0.1" + resolved "https://registry.yarnpkg.com/pouchdb-utils/-/pouchdb-utils-8.0.1.tgz#3fb0c9fe00f52e4d8404278a609f277c1c155b70" + integrity sha512-pWgxdk9EHVWJmjQoEvTe+ZlPXyjcuQ/vgLITN+RjGwcYhoQYUE1M0PksQd2dUP3V8lGS4+wrg9lEM/qSJPYcpw== + dependencies: + clone-buffer "1.0.0" + immediate "3.3.0" + pouchdb-collections "8.0.1" + pouchdb-errors "8.0.1" + pouchdb-md5 "8.0.1" + uuid "8.3.2" + +pouchdb@^8.0.1: + version "8.0.1" + resolved "https://registry.yarnpkg.com/pouchdb/-/pouchdb-8.0.1.tgz#78aef57b0d58abe5e4a4581a3332c0c220e20dbd" + integrity sha512-xp5S83JOQn2NAL0ZQ5CU+DI26V9/YrYuVtkXnbGEIDrYiFfj5A8gAcfbxefXb/9O+Qn4n5RaT/19+8UBSZ42sw== + dependencies: + abort-controller "3.0.0" + buffer-from "1.1.2" + clone-buffer "1.0.0" + double-ended-queue "2.1.0-0" + fetch-cookie "0.11.0" + immediate "3.3.0" + level "6.0.1" + level-codec "9.0.2" + level-write-stream "1.0.0" + leveldown "5.6.0" + levelup "4.4.0" + ltgt "2.2.1" + node-fetch "2.6.7" + readable-stream "1.1.14" + spark-md5 "3.0.2" + through2 "3.0.2" + uuid "8.3.2" + vuvuzela "1.0.3" + +prr@~1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/prr/-/prr-1.0.1.tgz#d3fc114ba06995a45ec6893f484ceb1d78f5f476" + integrity sha512-yPw4Sng1gWghHQWj0B3ZggWUm4qVbPwPFcRG8KyxiU7J2OHFSoEHKS+EZ3fv5l1t9CyCiop6l/ZYeWbrgoQejw== + +psl@^1.1.33: + version "1.9.0" + resolved "https://registry.yarnpkg.com/psl/-/psl-1.9.0.tgz#d0df2a137f00794565fcaf3b2c00cd09f8d5a5a7" + integrity sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag== + +punycode@^2.1.1: + version "2.3.0" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.0.tgz#f67fa67c94da8f4d0cfff981aee4118064199b8f" + integrity sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA== + +querystringify@^2.1.1: + version "2.2.0" + resolved "https://registry.yarnpkg.com/querystringify/-/querystringify-2.2.0.tgz#3345941b4153cb9d082d8eee4cda2016a9aef7f6" + integrity sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ== + +readable-stream@1.1.14: + version "1.1.14" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.1.14.tgz#7cf4c54ef648e3813084c636dd2079e166c081d9" + integrity sha512-+MeVjFf4L44XUkhM1eYbD8fyEsxcV81pqMSR5gblfcLCHfZvbrqy4/qYHE+/R5HoBUT11WV5O08Cr1n3YXkWVQ== + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.1" + isarray "0.0.1" + string_decoder "~0.10.x" + +"readable-stream@2 || 3", readable-stream@^3.4.0: + version "3.6.2" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.2.tgz#56a9b36ea965c00c5a93ef31eb111a0f11056967" + integrity sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA== + dependencies: + inherits "^2.0.3" + string_decoder "^1.1.1" + util-deprecate "^1.0.1" + +readable-stream@~0.0.2: + version "0.0.4" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-0.0.4.tgz#f32d76e3fb863344a548d79923007173665b3b8d" + integrity sha512-azrivNydKRYt7zwLV5wWUK7YzKTWs3q87xSmY6DlHapPrCvaT6ZrukvM5erV+yCSSPmZT8zkSdttOHQpWWm9zw== + +requires-port@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff" + integrity sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ== + +safe-buffer@~5.2.0: + version "5.2.1" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" + integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== + +spark-md5@3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/spark-md5/-/spark-md5-3.0.2.tgz#7952c4a30784347abcee73268e473b9c0167e3fc" + integrity sha512-wcFzz9cDfbuqe0FZzfi2or1sgyIrsDwmPwfZC4hiNidPdPINjeUwNfv5kldczoEAcjl9Y1L3SM7Uz2PUEQzxQw== + +string_decoder@^1.1.1: + version "1.3.0" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e" + integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA== + dependencies: + safe-buffer "~5.2.0" + +string_decoder@~0.10.x: + version "0.10.31" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94" + integrity sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ== + +through2@3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/through2/-/through2-3.0.2.tgz#99f88931cfc761ec7678b41d5d7336b5b6a07bf4" + integrity sha512-enaDQ4MUyP2W6ZyT6EsMzqBPZaM/avg8iuo+l2d3QCs0J+6RaqkHV/2/lOwDTueBHeJ/2LG9lrLW3d5rWPucuQ== + dependencies: + inherits "^2.0.4" + readable-stream "2 || 3" + +"tough-cookie@^2.3.3 || ^3.0.1 || ^4.0.0": + version "4.1.2" + resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-4.1.2.tgz#e53e84b85f24e0b65dd526f46628db6c85f6b874" + integrity sha512-G9fqXWoYFZgTc2z8Q5zaHy/vJMjm+WV0AkAeHxVCQiEB1b+dGvWzFW6QV07cY5jQ5gRkeid2qIkzkxUnmoQZUQ== + dependencies: + psl "^1.1.33" + punycode "^2.1.1" + universalify "^0.2.0" + url-parse "^1.5.3" + +tr46@~0.0.3: + version "0.0.3" + resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a" + integrity sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw== + +typescript@^5.0.4: + version "5.0.4" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.0.4.tgz#b217fd20119bd61a94d4011274e0ab369058da3b" + integrity sha512-cW9T5W9xY37cc+jfEnaUvX91foxtHkza3Nw3wkoF4sSlKn0MONdkdEndig/qPBWXNkmplh3NzayQzCiHM4/hqw== + +universalify@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.2.0.tgz#6451760566fa857534745ab1dde952d1b1761be0" + integrity sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg== + +url-parse@^1.5.3: + version "1.5.10" + resolved "https://registry.yarnpkg.com/url-parse/-/url-parse-1.5.10.tgz#9d3c2f736c1d75dd3bd2be507dcc111f1e2ea9c1" + integrity sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ== + dependencies: + querystringify "^2.1.1" + requires-port "^1.0.0" + +util-deprecate@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" + integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw== + +uuid@8.3.2: + version "8.3.2" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2" + integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg== + +vuvuzela@1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/vuvuzela/-/vuvuzela-1.0.3.tgz#3be145e58271c73ca55279dd851f12a682114b0b" + integrity sha512-Tm7jR1xTzBbPW+6y1tknKiEhz04Wf/1iZkcTJjSFcpNko43+dFW6+OOeQe9taJIug3NdfUAjFKgUSyQrIKaDvQ== + +webidl-conversions@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871" + integrity sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ== + +whatwg-url@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-5.0.0.tgz#966454e8765462e37644d3626f6742ce8b70965d" + integrity sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw== + dependencies: + tr46 "~0.0.3" + webidl-conversions "^3.0.0" + +write-stream@~0.4.3: + version "0.4.3" + resolved "https://registry.yarnpkg.com/write-stream/-/write-stream-0.4.3.tgz#83cc8c0347d0af6057a93862b4e3ae01de5c81c1" + integrity sha512-IJrvkhbAnj89W/GAVdVgbnPiVw5Ntg/B4tc/MUCIEwj/g6JIww1DWJyB/yBMT3yw2/TkT6IUZ0+IYef3flEw8A== + dependencies: + readable-stream "~0.0.2" + +xdg-basedir@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/xdg-basedir/-/xdg-basedir-5.1.0.tgz#1efba19425e73be1bc6f2a6ceb52a3d2c884c0c9" + integrity sha512-GCPAHLvrIH13+c0SuacwvRYj2SxJXQ4kaVTT5xgL3kPrz56XxkF21IGhjSE1+W0aw7gpBWRGXLCPnPby6lSpmQ== + +xtend@^4.0.2, xtend@~4.0.0: + version "4.0.2" + resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" + integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==