var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
import { gql, useQuery, useSubscription, useApolloClient, Observable } from '@apollo/client/index.js';
import { generateApolloClient } from '@deep-foundation/hasura/client.js';
import { useLocalStore } from '@deep-foundation/store/local.js';
import React, { createContext, useContext, useMemo, useState } from "react";
import { deleteMutation, generateQuery, generateQueryData, generateSerial, insertMutation, updateMutation } from './gql/index.js';
import { MinilinkCollection, useMinilinksApply, useMinilinksQuery, useMinilinksSubscription } from './minilinks.js';
import { awaitPromise } from './promise.js';
import { useTokenController } from './react-token.js';
import { reserve } from './reserve.js';
import { corePckg } from './core.js';
import get from 'get-value';
import { debug } from './debug.js';
import { Traveler as NativeTraveler } from './traveler.js';
const moduleLog = debug.extend('client');
import { _ids, pathToWhere, serializeWhere, serializeQuery, parseJwt } from './client.js';
const log = debug.extend('log');
const error = debug.extend('error');
const corePckgIds = {};
corePckg.data.filter(l => !!l.type).forEach((l, i) => {
    corePckgIds[l.id] = i + 1;
});
export function checkAndFillShorts(obj) {
    var _a, _b, _c;
    for (var i in obj) {
        if (!obj.hasOwnProperty(i))
            continue;
        if ((typeof obj[i]) == 'object' && obj[i] !== null) {
            if (typeof obj[i] === 'object' && i === 'object' && ((_b = (_a = obj[i]) === null || _a === void 0 ? void 0 : _a.data) === null || _b === void 0 ? void 0 : _b.value) === undefined) {
                obj[i] = { data: { value: obj[i] } };
                continue;
            }
            if (typeof obj[i] === 'object' && (i === 'to' || i === 'from' || i === 'in' || i === 'out') && ((_c = obj[i]) === null || _c === void 0 ? void 0 : _c.data) === undefined)
                obj[i] = { data: obj[i] };
            checkAndFillShorts(obj[i]);
        }
        else if (i === 'string' && typeof obj[i] === 'string' || i === 'number' && typeof obj[i] === 'number')
            obj[i] = { data: { value: obj[i] } };
    }
}
export class DeepClient {
    _silent(options = {}) {
        return typeof (options.silent) === 'boolean' ? options.silent : this.silent;
    }
    constructor(options) {
        var _a, _b, _c;
        this.useDeepSubscription = useDeepSubscription;
        this.useDeepQuery = useDeepQuery;
        this.useMinilinksQuery = (query) => useMinilinksQuery(this.minilinks, query);
        this.useMinilinksSubscription = (query) => useMinilinksSubscription(this.minilinks, query);
        this.useDeep = useDeep;
        this.DeepProvider = DeepProvider;
        this.DeepContext = DeepContext;
        this.serializeQuery = serializeQuery;
        this.serializeWhere = serializeWhere;
        this.deep = options.deep;
        if (!this.apolloClient)
            this.apolloClient = options.apolloClient;
        if (!this.deep && !options.apolloClient)
            throw new Error('options.apolloClient or options.deep is required');
        if (this.deep && !this.apolloClient && !options.apolloClient && options.token) {
            this.apolloClient = generateApolloClient({
                path: (_a = this.deep.apolloClient) === null || _a === void 0 ? void 0 : _a.path,
                ssl: (_b = this.deep.apolloClient) === null || _b === void 0 ? void 0 : _b.ssl,
                token: options.token,
            });
        }
        if (!this.apolloClient)
            throw new Error('apolloClient is invalid');
        this.client = this.apolloClient;
        this.minilinks = options.minilinks || new MinilinkCollection();
        this.table = options.table || 'links';
        this.token = options.token;
        if (this.token) {
            const decoded = parseJwt(this.token);
            const linkId = decoded === null || decoded === void 0 ? void 0 : decoded.userId;
            if (!linkId) {
                throw new Error(`Unable to parse linkId from jwt token.`);
            }
            if (options.linkId && options.linkId !== linkId) {
                throw new Error(`linkId (${linkId}) parsed from jwt token is not the same as linkId passed via options (${options.linkId}).`);
            }
            this.linkId = linkId;
        }
        else {
            this.linkId = options.linkId;
        }
        this.handleAuth = (options === null || options === void 0 ? void 0 : options.handleAuth) || ((_c = options === null || options === void 0 ? void 0 : options.deep) === null || _c === void 0 ? void 0 : _c.handleAuth);
        this.linksSelectReturning = options.linksSelectReturning || options.selectReturning || 'id type_id from_id to_id value';
        this.selectReturning = options.selectReturning || this.linksSelectReturning;
        this.valuesSelectReturning = options.valuesSelectReturning || 'id link_id value';
        this.selectorsSelectReturning = options.selectorsSelectReturning || 'item_id selector_id';
        this.filesSelectReturning = options.filesSelectReturning || 'id link_id name mimeType';
        this.insertReturning = options.insertReturning || 'id';
        this.updateReturning = options.updateReturning || 'id';
        this.deleteReturning = options.deleteReturning || 'id';
        this.defaultSelectName = options.defaultSelectName || 'SELECT';
        this.defaultInsertName = options.defaultInsertName || 'INSERT';
        this.defaultUpdateName = options.defaultUpdateName || 'UPDATE';
        this.defaultDeleteName = options.defaultDeleteName || 'DELETE';
        this.silent = options.silent || false;
        this.unsafe = options.unsafe || {};
    }
    stringify(any) {
        if (typeof (any) === 'string') {
            let json;
            try {
                json = JSON.parse(any);
            }
            catch (e) { }
            return json ? JSON.stringify(json, null, 2) : any.toString();
        }
        else if (typeof (any) === 'object') {
            return JSON.stringify(any, null, 2);
        }
        return any;
    }
    select(exp, options) {
        var _a, _b, _c, _d, _e, _f, _g;
        return __awaiter(this, void 0, void 0, function* () {
            if (!exp) {
                return { error: { message: '!exp' }, data: undefined, loading: false, networkStatus: undefined };
            }
            const query = serializeQuery(exp, (options === null || options === void 0 ? void 0 : options.table) || 'links');
            const table = (options === null || options === void 0 ? void 0 : options.table) || this.table;
            const returning = (_a = options === null || options === void 0 ? void 0 : options.returning) !== null && _a !== void 0 ? _a : (table === 'links' ? this.linksSelectReturning :
                ['strings', 'numbers', 'objects'].includes(table) ? this.valuesSelectReturning :
                    table === 'selectors' ? this.selectorsSelectReturning :
                        table === 'files' ? this.filesSelectReturning : `id`);
            const tableNamePostfix = options === null || options === void 0 ? void 0 : options.tableNamePostfix;
            const aggregate = options === null || options === void 0 ? void 0 : options.aggregate;
            const variables = options === null || options === void 0 ? void 0 : options.variables;
            const name = (options === null || options === void 0 ? void 0 : options.name) || this.defaultSelectName;
            try {
                const q = yield this.apolloClient.query(generateQuery({
                    queries: [
                        generateQueryData({
                            tableName: table,
                            tableNamePostfix: tableNamePostfix || aggregate ? '_aggregate' : '',
                            returning: aggregate ? `aggregate { ${aggregate} }` : returning,
                            variables: Object.assign(Object.assign({}, variables), query)
                        }),
                    ],
                    name: name,
                }));
                return Object.assign(Object.assign({}, q), { data: aggregate ? (_e = (_d = (_c = (_b = (q)) === null || _b === void 0 ? void 0 : _b.data) === null || _c === void 0 ? void 0 : _c.q0) === null || _d === void 0 ? void 0 : _d.aggregate) === null || _e === void 0 ? void 0 : _e[aggregate] : (_g = (_f = (q)) === null || _f === void 0 ? void 0 : _f.data) === null || _g === void 0 ? void 0 : _g.q0 });
            }
            catch (e) {
                console.log(generateQueryData({
                    tableName: table,
                    tableNamePostfix: tableNamePostfix || aggregate ? '_aggregate' : '',
                    returning: aggregate ? `aggregate { ${aggregate} }` : returning,
                    variables: Object.assign(Object.assign({}, variables), query)
                })('a', 0));
                throw new Error(`DeepClient Select Error: ${e.message}`, { cause: e });
            }
        });
    }
    ;
    subscribe(exp, options) {
        var _a;
        if (!exp) {
            return new Observable((observer) => {
                observer.error('!exp');
            });
        }
        const query = serializeQuery(exp, (options === null || options === void 0 ? void 0 : options.table) || 'links');
        const table = (options === null || options === void 0 ? void 0 : options.table) || this.table;
        const returning = (_a = options === null || options === void 0 ? void 0 : options.returning) !== null && _a !== void 0 ? _a : (table === 'links' ? this.linksSelectReturning :
            ['strings', 'numbers', 'objects'].includes(table) ? this.valuesSelectReturning :
                table === 'selectors' ? this.selectorsSelectReturning :
                    table === 'files' ? this.filesSelectReturning : `id`);
        const tableNamePostfix = options === null || options === void 0 ? void 0 : options.tableNamePostfix;
        const aggregate = options === null || options === void 0 ? void 0 : options.aggregate;
        const variables = options === null || options === void 0 ? void 0 : options.variables;
        const name = (options === null || options === void 0 ? void 0 : options.name) || this.defaultSelectName;
        try {
            const apolloObservable = this.apolloClient.subscribe(Object.assign({}, generateQuery({
                operation: 'subscription',
                queries: [
                    generateQueryData({
                        tableName: table,
                        tableNamePostfix: tableNamePostfix || aggregate ? '_aggregate' : '',
                        returning: returning || aggregate ? `aggregate { ${aggregate} }` : returning,
                        variables: Object.assign(Object.assign({}, variables), query)
                    }),
                ],
                name: name,
            })));
            const observable = new Observable((observer) => {
                const subscription = apolloObservable.subscribe({
                    next: (data) => {
                        var _a, _b;
                        observer.next(aggregate ? (_b = (_a = data === null || data === void 0 ? void 0 : data.q0) === null || _a === void 0 ? void 0 : _a.aggregate) === null || _b === void 0 ? void 0 : _b[aggregate] : data === null || data === void 0 ? void 0 : data.q0);
                    },
                    error: (error) => observer.error(error),
                });
                return () => subscription.unsubscribe();
            });
            return observable;
        }
        catch (e) {
            throw new Error(`DeepClient Subscription Error: ${e.message}`, { cause: e });
        }
    }
    ;
    insert(objects, options) {
        var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
        return __awaiter(this, void 0, void 0, function* () {
            const _objects = Object.prototype.toString.call(objects) === '[object Array]' ? objects : [objects];
            checkAndFillShorts(_objects);
            const table = (options === null || options === void 0 ? void 0 : options.table) || this.table;
            const returning = (options === null || options === void 0 ? void 0 : options.returning) || this.insertReturning;
            const variables = options === null || options === void 0 ? void 0 : options.variables;
            const name = (options === null || options === void 0 ? void 0 : options.name) || this.defaultInsertName;
            let q = {};
            try {
                q = yield this.apolloClient.mutate(generateSerial({
                    actions: [insertMutation(table, Object.assign(Object.assign({}, variables), { objects: _objects }), { tableName: table, operation: 'insert', returning })],
                    name: name,
                }));
            }
            catch (e) {
                const sqlError = (_d = (_c = (_b = (_a = e === null || e === void 0 ? void 0 : e.graphQLErrors) === null || _a === void 0 ? void 0 : _a[0]) === null || _b === void 0 ? void 0 : _b.extensions) === null || _c === void 0 ? void 0 : _c.internal) === null || _d === void 0 ? void 0 : _d.error;
                if (sqlError === null || sqlError === void 0 ? void 0 : sqlError.message)
                    e.message = sqlError.message;
                if (!this._silent(options))
                    throw new Error(`DeepClient Insert Error: ${e.message}`, { cause: e });
                return Object.assign(Object.assign({}, q), { data: (_g = (_f = (_e = (q)) === null || _e === void 0 ? void 0 : _e.data) === null || _f === void 0 ? void 0 : _f.m0) === null || _g === void 0 ? void 0 : _g.returning, error: e });
            }
            return Object.assign(Object.assign({}, q), { data: (_k = (_j = (_h = (q)) === null || _h === void 0 ? void 0 : _h.data) === null || _j === void 0 ? void 0 : _j.m0) === null || _k === void 0 ? void 0 : _k.returning });
        });
    }
    ;
    update(exp, value, options) {
        var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
        return __awaiter(this, void 0, void 0, function* () {
            if (exp === null)
                return this.insert([value], options);
            if (value === null)
                return this.delete(exp, options);
            const query = serializeQuery(exp, (options === null || options === void 0 ? void 0 : options.table) === this.table || !(options === null || options === void 0 ? void 0 : options.table) ? 'links' : 'value');
            const table = (options === null || options === void 0 ? void 0 : options.table) || this.table;
            const returning = (options === null || options === void 0 ? void 0 : options.returning) || this.updateReturning;
            const variables = options === null || options === void 0 ? void 0 : options.variables;
            const name = (options === null || options === void 0 ? void 0 : options.name) || this.defaultUpdateName;
            let q;
            try {
                q = yield this.apolloClient.mutate(generateSerial({
                    actions: [updateMutation(table, Object.assign(Object.assign(Object.assign({}, variables), query), { _set: value }), { tableName: table, operation: 'update', returning })],
                    name: name,
                }));
            }
            catch (e) {
                const sqlError = (_d = (_c = (_b = (_a = e === null || e === void 0 ? void 0 : e.graphQLErrors) === null || _a === void 0 ? void 0 : _a[0]) === null || _b === void 0 ? void 0 : _b.extensions) === null || _c === void 0 ? void 0 : _c.internal) === null || _d === void 0 ? void 0 : _d.error;
                if (sqlError === null || sqlError === void 0 ? void 0 : sqlError.message)
                    e.message = sqlError.message;
                if (!this._silent(options))
                    throw new Error(`DeepClient Update Error: ${e.message}`, { cause: e });
                return Object.assign(Object.assign({}, q), { data: (_g = (_f = (_e = (q)) === null || _e === void 0 ? void 0 : _e.data) === null || _f === void 0 ? void 0 : _f.m0) === null || _g === void 0 ? void 0 : _g.returning, error: e });
            }
            return Object.assign(Object.assign({}, q), { data: (_k = (_j = (_h = (q)) === null || _h === void 0 ? void 0 : _h.data) === null || _j === void 0 ? void 0 : _j.m0) === null || _k === void 0 ? void 0 : _k.returning });
        });
    }
    ;
    delete(exp, options) {
        var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
        return __awaiter(this, void 0, void 0, function* () {
            if (!exp)
                throw new Error('!exp');
            const query = serializeQuery(exp, (options === null || options === void 0 ? void 0 : options.table) === this.table || !(options === null || options === void 0 ? void 0 : options.table) ? 'links' : 'value');
            const table = (options === null || options === void 0 ? void 0 : options.table) || this.table;
            const returning = (options === null || options === void 0 ? void 0 : options.returning) || this.deleteReturning;
            const variables = options === null || options === void 0 ? void 0 : options.variables;
            const name = (options === null || options === void 0 ? void 0 : options.name) || this.defaultDeleteName;
            let q;
            try {
                q = yield this.apolloClient.mutate(generateSerial({
                    actions: [deleteMutation(table, Object.assign(Object.assign(Object.assign({}, variables), query), { returning }), { tableName: table, operation: 'delete', returning })],
                    name: name,
                }));
            }
            catch (e) {
                const sqlError = (_d = (_c = (_b = (_a = e === null || e === void 0 ? void 0 : e.graphQLErrors) === null || _a === void 0 ? void 0 : _a[0]) === null || _b === void 0 ? void 0 : _b.extensions) === null || _c === void 0 ? void 0 : _c.internal) === null || _d === void 0 ? void 0 : _d.error;
                if (sqlError === null || sqlError === void 0 ? void 0 : sqlError.message)
                    e.message = sqlError.message;
                if (!this._silent(options))
                    throw new Error(`DeepClient Delete Error: ${e.message}`, { cause: e });
                return Object.assign(Object.assign({}, q), { data: (_g = (_f = (_e = (q)) === null || _e === void 0 ? void 0 : _e.data) === null || _f === void 0 ? void 0 : _f.m0) === null || _g === void 0 ? void 0 : _g.returning, error: e });
            }
            return Object.assign(Object.assign({}, q), { data: (_k = (_j = (_h = (q)) === null || _h === void 0 ? void 0 : _h.data) === null || _j === void 0 ? void 0 : _j.m0) === null || _k === void 0 ? void 0 : _k.returning });
        });
    }
    ;
    serial({ name, operations, returning, silent }) {
        var _a, _b, _c, _d, _e, _f, _g, _h, _j;
        return __awaiter(this, void 0, void 0, function* () {
            let operationsGroupedByTypeAndTable = {};
            operationsGroupedByTypeAndTable = operations.reduce((acc, operation) => {
                if (!acc[operation.type]) {
                    acc[operation.type] = {};
                }
                if (!acc[operation.type][operation.table]) {
                    acc[operation.type][operation.table] = [];
                }
                acc[operation.type][operation.table].push(operation);
                return acc;
            }, operationsGroupedByTypeAndTable);
            let serialActions = [];
            Object.keys(operationsGroupedByTypeAndTable).map((operationType) => {
                const operationsGroupedByTable = operationsGroupedByTypeAndTable[operationType];
                Object.keys(operationsGroupedByTable).map((table) => {
                    const operations = operationsGroupedByTable[table];
                    if (operationType === 'insert') {
                        const insertOperations = operations;
                        const serialAction = insertMutation(table, { objects: insertOperations.map(operation => Array.isArray(operation.objects) ? operation.objects : [operation.objects]).flat() }, { tableName: table, operation: operationType, returning });
                        serialActions.push(serialAction);
                    }
                    else if (operationType === 'update') {
                        const updateOperations = operations;
                        const newSerialActions = updateOperations.map(operation => {
                            const exp = operation.exp;
                            const value = operation.value;
                            const query = serializeQuery(exp, table === this.table || !table ? 'links' : 'value');
                            return updateMutation(table, Object.assign(Object.assign({}, query), { _set: value }), { tableName: table, operation: operationType, returning });
                        });
                        serialActions = [...serialActions, ...newSerialActions];
                    }
                    else if (operationType === 'delete') {
                        const deleteOperations = operations;
                        ;
                        const newSerialActions = deleteOperations.map(operation => {
                            const exp = operation.exp;
                            const query = serializeQuery(exp, table === this.table || !table ? 'links' : 'value');
                            return deleteMutation(table, Object.assign({}, query), { tableName: table, operation: operationType, returning });
                        });
                        serialActions = [...serialActions, ...newSerialActions];
                    }
                });
            });
            let result;
            try {
                result = yield this.apolloClient.mutate(generateSerial({
                    actions: serialActions,
                    name: name !== null && name !== void 0 ? name : 'Name',
                }));
            }
            catch (e) {
                const sqlError = (_d = (_c = (_b = (_a = e === null || e === void 0 ? void 0 : e.graphQLErrors) === null || _a === void 0 ? void 0 : _a[0]) === null || _b === void 0 ? void 0 : _b.extensions) === null || _c === void 0 ? void 0 : _c.internal) === null || _d === void 0 ? void 0 : _d.error;
                if (sqlError === null || sqlError === void 0 ? void 0 : sqlError.message)
                    e.message = sqlError.message;
                if (!silent)
                    throw new Error(`DeepClient Serial Error: ${e.message}`, { cause: e });
                return Object.assign(Object.assign({}, result), { data: (_g = (_f = (_e = (result)) === null || _e === void 0 ? void 0 : _e.data) === null || _f === void 0 ? void 0 : _f.m0) === null || _g === void 0 ? void 0 : _g.returning, error: e });
            }
            return Object.assign(Object.assign({}, result), { data: ((_h = (result)) === null || _h === void 0 ? void 0 : _h.data) && Object.values((_j = (result)) === null || _j === void 0 ? void 0 : _j.data).flatMap(m => m.returning) });
        });
    }
    ;
    reserve(count) {
        return reserve({ count, client: this.apolloClient });
    }
    ;
    await(id, options = { results: false }) {
        return __awaiter(this, void 0, void 0, function* () {
            return awaitPromise({
                id, client: this.apolloClient,
                Then: yield this.id('@deep-foundation/core', 'Then'),
                Promise: yield this.id('@deep-foundation/core', 'Promise'),
                Resolved: yield this.id('@deep-foundation/core', 'Resolved'),
                Rejected: yield this.id('@deep-foundation/core', 'Rejected'),
                Results: options.results
            });
        });
    }
    ;
    id(start, ...path) {
        var _a, _b, _c, _d, _e, _f, _g;
        return __awaiter(this, void 0, void 0, function* () {
            if (typeof (start) === 'object') {
                return (_c = (_b = (_a = ((yield this.select(start)))) === null || _a === void 0 ? void 0 : _a.data) === null || _b === void 0 ? void 0 : _b[0]) === null || _c === void 0 ? void 0 : _c.id;
            }
            if ((_d = _ids === null || _ids === void 0 ? void 0 : _ids[start]) === null || _d === void 0 ? void 0 : _d[path[0]]) {
                return _ids[start][path[0]];
            }
            const q = yield this.select(pathToWhere(start, ...path));
            if (q.error) {
                throw q.error;
            }
            const result = (((_f = (_e = q === null || q === void 0 ? void 0 : q.data) === null || _e === void 0 ? void 0 : _e[0]) === null || _f === void 0 ? void 0 : _f.id) | ((_g = _ids === null || _ids === void 0 ? void 0 : _ids[start]) === null || _g === void 0 ? void 0 : _g[path === null || path === void 0 ? void 0 : path[0]]) | 0);
            if (!result && path[path.length - 1] !== true) {
                throw new Error(`Id not found by [${JSON.stringify([start, ...path])}]`);
            }
            return result;
        });
    }
    ;
    ids(...paths) {
        return __awaiter(this, void 0, void 0, function* () {
            const appendPath = (accumulator, keys, value) => {
                const lastKey = keys.pop();
                const lastObject = keys.reduce((obj, key) => obj[key] = obj[key] || {}, accumulator);
                lastObject[lastKey] = value;
            };
            const result = {};
            yield Promise.all(paths.map(([start, ...path]) => __awaiter(this, void 0, void 0, function* () {
                const id = yield this.id(start, ...path);
                appendPath(result, [start, ...path], id);
            })));
            return result;
        });
    }
    idLocal(start, ...path) {
        const paths = [start, ...path];
        if (get(_ids, paths.join('.'))) {
            return get(_ids, paths.join('.'));
        }
        const [link] = this.minilinks.query({
            id: {
                _id: paths
            }
        });
        const result = link === null || link === void 0 ? void 0 : link.id;
        if (!result) {
            throw new Error(`Id not found by ${JSON.stringify([start, ...path])}`);
        }
        else {
            return result;
        }
    }
    ;
    guest(options = {}) {
        var _a;
        return __awaiter(this, void 0, void 0, function* () {
            const relogin = typeof (options.relogin) === 'boolean' ? options.relogin : true;
            const result = yield this.apolloClient.query({ query: GUEST });
            const { linkId, token, error } = ((_a = result === null || result === void 0 ? void 0 : result.data) === null || _a === void 0 ? void 0 : _a.guest) || {};
            if (!error && !!token && relogin) {
                if (this === null || this === void 0 ? void 0 : this.handleAuth)
                    setTimeout(() => this === null || this === void 0 ? void 0 : this.handleAuth(+linkId, token), 0);
            }
            return { linkId, token, error: !error && (!linkId || !token) ? 'unexepted' : error };
        });
    }
    ;
    jwt(options) {
        var _a;
        return __awaiter(this, void 0, void 0, function* () {
            const relogin = typeof (options.relogin) === 'boolean' ? options.relogin : false;
            if (options === null || options === void 0 ? void 0 : options.token) {
                try {
                    const token = options === null || options === void 0 ? void 0 : options.token;
                    const decoded = parseJwt(token);
                    const linkId = decoded === null || decoded === void 0 ? void 0 : decoded.userId;
                    if (!!token && relogin) {
                        if (this === null || this === void 0 ? void 0 : this.handleAuth)
                            setTimeout(() => this === null || this === void 0 ? void 0 : this.handleAuth(+linkId, token), 0);
                    }
                    return { linkId, token, error: (!linkId || !token) ? 'unexepted' : undefined };
                }
                catch (e) {
                    return { error: e };
                }
            }
            else if (options === null || options === void 0 ? void 0 : options.linkId) {
                const result = yield this.apolloClient.query({ query: JWT, variables: { linkId: +options.linkId } });
                const { linkId, token, error } = ((_a = result === null || result === void 0 ? void 0 : result.data) === null || _a === void 0 ? void 0 : _a.jwt) || {};
                if (!error && !!token && relogin) {
                    if (this === null || this === void 0 ? void 0 : this.handleAuth)
                        setTimeout(() => this === null || this === void 0 ? void 0 : this.handleAuth(+linkId, token), 0);
                }
                return { linkId, token, error: error ? error : (!linkId) ? 'unexepted' : undefined };
            }
            else
                return { error: `linkId or token must be provided` };
        });
    }
    ;
    whoami() {
        var _a, _b, _c, _d;
        return __awaiter(this, void 0, void 0, function* () {
            const result = yield this.apolloClient.query({ query: WHOISME });
            this.linkId = (_b = (_a = result === null || result === void 0 ? void 0 : result.data) === null || _a === void 0 ? void 0 : _a.jwt) === null || _b === void 0 ? void 0 : _b.linkId;
            return (_d = (_c = result === null || result === void 0 ? void 0 : result.data) === null || _c === void 0 ? void 0 : _c.jwt) === null || _d === void 0 ? void 0 : _d.linkId;
        });
    }
    login(options) {
        return __awaiter(this, void 0, void 0, function* () {
            const jwtResult = yield this.jwt(Object.assign(Object.assign({}, options), { relogin: true }));
            this.token = jwtResult.token;
            this.linkId = jwtResult.linkId;
            return jwtResult;
        });
    }
    ;
    logout() {
        return __awaiter(this, void 0, void 0, function* () {
            if (this === null || this === void 0 ? void 0 : this.handleAuth)
                setTimeout(() => this === null || this === void 0 ? void 0 : this.handleAuth(0, ''), 0);
            return { linkId: 0, token: '' };
        });
    }
    ;
    can(objectIds, subjectIds, actionIds, userIds = this.linkId) {
        var _a;
        return __awaiter(this, void 0, void 0, function* () {
            const where = {};
            if (objectIds)
                where.object_id = typeof (objectIds) === 'number' ? { _eq: +objectIds } : { _in: objectIds };
            if (subjectIds)
                where.subject_id = typeof (subjectIds) === 'number' ? { _eq: +subjectIds } : { _in: subjectIds };
            if (actionIds)
                where.action_id = typeof (actionIds) === 'number' ? { _eq: +actionIds } : { _in: actionIds };
            const result = yield this.select(where, { table: 'can', returning: 'rule_id' });
            return !!((_a = result === null || result === void 0 ? void 0 : result.data) === null || _a === void 0 ? void 0 : _a.length);
        });
    }
    name(input) {
        var _a, _b, _c;
        return __awaiter(this, void 0, void 0, function* () {
            const id = typeof (input) === 'number' ? input : input.id;
            const { data: [containLink] } = yield this.select({
                type_id: { _id: ['@deep-foundation/core', 'Contain'] },
                to_id: id,
            });
            if (!((_a = containLink === null || containLink === void 0 ? void 0 : containLink.value) === null || _a === void 0 ? void 0 : _a.value)) {
                const { data: [packageLink] } = yield this.select(id);
                if ((packageLink === null || packageLink === void 0 ? void 0 : packageLink.type_id) === this.idLocal('@deep-foundation/core', 'Package'))
                    return (_b = packageLink === null || packageLink === void 0 ? void 0 : packageLink.value) === null || _b === void 0 ? void 0 : _b.value;
            }
            return (_c = containLink === null || containLink === void 0 ? void 0 : containLink.value) === null || _c === void 0 ? void 0 : _c.value;
        });
    }
    ;
    nameLocal(input) {
        var _a, _b, _c, _d, _e, _f;
        const id = typeof (input) === 'number' ? input : input === null || input === void 0 ? void 0 : input.id;
        if (!id)
            return;
        if (((_a = this.minilinks.byId[id]) === null || _a === void 0 ? void 0 : _a.type_id) === this.idLocal('@deep-foundation/core', 'Package'))
            return (_c = (_b = this.minilinks.byId[id]) === null || _b === void 0 ? void 0 : _b.value) === null || _c === void 0 ? void 0 : _c.value;
        return (_f = (_e = (_d = this.minilinks.byType[this.idLocal('@deep-foundation/core', 'Contain')]) === null || _d === void 0 ? void 0 : _d.find((c) => (c === null || c === void 0 ? void 0 : c.to_id) === id)) === null || _e === void 0 ? void 0 : _e.value) === null || _f === void 0 ? void 0 : _f.value;
    }
    import(path) {
        return __awaiter(this, void 0, void 0, function* () {
            if (typeof DeepClient.resolveDependency !== 'undefined') {
                try {
                    return yield DeepClient.resolveDependency(path);
                }
                catch (e) {
                    console.log(`IGNORED ERROR: Call to DeepClient.resolveDependency is failed with`, e);
                }
            }
            if (typeof require !== 'undefined') {
                try {
                    return yield require(path);
                }
                catch (e) {
                    console.log(`IGNORED ERROR: Call to require is failed with`, e);
                }
            }
            return yield import(path);
        });
    }
    Traveler(links) {
        return new NativeTraveler(this, links);
    }
    ;
}
export const JWT = gql `query JWT($linkId: Int) {
  jwt(input: {linkId: $linkId}) {
    linkId
    token
  }
}`;
export const WHOISME = gql `query WHOISME {
  jwt(input: {}) {
    linkId
  }
}`;
export const GUEST = gql `query GUEST {
  guest {
    linkId
    token
  }
}`;
export function useAuthNode() {
    return useLocalStore('use_auth_link_id', 0);
}
export const DeepContext = createContext(undefined);
export function useDeepGenerator(apolloClientProps) {
    const log = debug.extend(useDeepGenerator.name);
    const apolloClientHook = useApolloClient();
    log({ apolloClientHook });
    const apolloClient = apolloClientProps || apolloClientHook;
    log({ apolloClient });
    const [linkId, setLinkId] = useAuthNode();
    log({ linkId, setLinkId });
    const [token, setToken] = useTokenController();
    log({ token, setToken });
    const deep = useMemo(() => {
        if (!(apolloClient === null || apolloClient === void 0 ? void 0 : apolloClient.jwt_token)) {
            log({ token, apolloClient });
        }
        return new DeepClient({
            apolloClient, linkId, token,
            handleAuth: (linkId, token) => {
                setToken(token);
                setLinkId(linkId);
            },
        });
    }, [apolloClient]);
    log({ deep });
    return deep;
}
export function DeepProvider({ apolloClient: apolloClientProps, children, }) {
    const deep = useDeepGenerator(apolloClientProps);
    return React.createElement(DeepContext.Provider, { value: deep }, children);
}
export function useDeep() {
    return useContext(DeepContext);
}
export function useDeepQuery(query, options) {
    var _a, _b, _c;
    const [miniName] = useState((options === null || options === void 0 ? void 0 : options.mini) || Math.random().toString(36).slice(2, 7));
    debug('useDeepQuery', miniName, query, options);
    const deep = useDeep();
    const wq = useMemo(() => {
        const sq = serializeQuery(query);
        return generateQuery({
            operation: 'query',
            queries: [generateQueryData(Object.assign(Object.assign({ tableName: 'links', returning: `
          id type_id from_id to_id value
          string { id value }
          number { id value }
          object { id value }
        ` }, options), { variables: Object.assign(Object.assign({}, sq), options === null || options === void 0 ? void 0 : options.variables) }))],
            name: (options === null || options === void 0 ? void 0 : options.name) || 'USE_DEEP_QUERY',
        });
    }, [query, options]);
    const result = useQuery(wq.query, { variables: wq === null || wq === void 0 ? void 0 : wq.variables });
    useMinilinksApply(deep.minilinks, miniName, ((_a = result === null || result === void 0 ? void 0 : result.data) === null || _a === void 0 ? void 0 : _a.q0) || []);
    const mlResult = deep.useMinilinksSubscription({ id: { _in: (_c = (_b = result === null || result === void 0 ? void 0 : result.data) === null || _b === void 0 ? void 0 : _b.q0) === null || _c === void 0 ? void 0 : _c.map(l => l.id) } });
    return Object.assign(Object.assign({}, result), { data: mlResult });
}
export function useDeepSubscription(query, options) {
    var _a, _b, _c;
    const [miniName] = useState((options === null || options === void 0 ? void 0 : options.mini) || Math.random().toString(36).slice(2, 7));
    debug('useDeepSubscription', miniName, query, options);
    const deep = useDeep();
    const wq = useMemo(() => {
        const sq = serializeQuery(query);
        return generateQuery({
            operation: 'subscription',
            queries: [generateQueryData(Object.assign(Object.assign({ tableName: 'links', returning: `
          id type_id from_id to_id value
          string { id value }
          number { id value }
          object { id value }
        ` }, options), { variables: Object.assign(Object.assign({}, sq), options === null || options === void 0 ? void 0 : options.variables) }))],
            name: (options === null || options === void 0 ? void 0 : options.name) || 'USE_DEEP_SUBSCRIPTION',
        });
    }, [query, options]);
    const result = useSubscription(wq.query, { variables: wq === null || wq === void 0 ? void 0 : wq.variables });
    useMinilinksApply(deep.minilinks, miniName, ((_a = result === null || result === void 0 ? void 0 : result.data) === null || _a === void 0 ? void 0 : _a.q0) || []);
    const mlResult = useMinilinksSubscription(deep.minilinks, { id: { _in: (_c = (_b = result === null || result === void 0 ? void 0 : result.data) === null || _b === void 0 ? void 0 : _b.q0) === null || _c === void 0 ? void 0 : _c.map(l => l.id) } });
    return Object.assign(Object.assign({}, result), { data: mlResult });
}
export function useDeepId(start, ...path) {
    var _a, _b;
    const result = useDeepQuery({ id: { _id: [start, ...path] } });
    return { data: (_b = (_a = result === null || result === void 0 ? void 0 : result.data) === null || _a === void 0 ? void 0 : _a[0]) === null || _b === void 0 ? void 0 : _b.id, loading: result === null || result === void 0 ? void 0 : result.loading, error: result === null || result === void 0 ? void 0 : result.error };
}
//# sourceMappingURL=cyber.js.map