@deep-foundation/deeplinks
Version:
[](https://www.npmjs.com/package/@deep-foundation/deeplinks) [](https://gitpod.io/#https://github.com/deep-fo
787 lines • 42.7 kB
JavaScript
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 Debug from 'debug';
import { HasuraApi } from '@deep-foundation/hasura/api.js';
import { generateApolloClient } from '@deep-foundation/hasura/client.js';
import { gql } from '@apollo/client/index.js';
import { serializeError } from 'serialize-error';
import { DeepClient } from '../client.js';
import { ContainerController } from '../container-controller.js';
import { ALLOWED_IDS, DENIED_IDS } from '../global-ids.js';
import { reject, resolve } from '../promise.js';
import { promisify } from 'util';
import { exec } from 'child_process';
import waitOn from 'wait-on';
import { buildClientSchema, getIntrospectionQuery, printSchema } from 'graphql';
const execAsync = promisify(exec);
console.log('process.env', process.env);
const SCHEMA = 'public';
const debug = Debug('deeplinks:eh:links');
const log = debug.extend('log');
const error = debug.extend('error');
const PORT = process.env.PORT || 3006;
const DOCKER_DEEPLINKS_URL = process.env.DOCKER_DEEPLINKS_URL || 'http://host.docker.internal:3006';
const DEEPLINKS_ROUTE_HANDLERS_HOST = process.env.DEEPLINKS_ROUTE_HANDLERS_HOST || 'host.docker.internal';
const deeplinksUrl = process.env.DEEPLINKS_PUBLIC_URL;
export const DOCKER = process.env.DOCKER || '0';
const delay = time => new Promise(res => setTimeout(res, time));
const toJSON = (data) => JSON.stringify(data, Object.getOwnPropertyNames(data), 2);
export const api = new HasuraApi({
path: process.env.DEEPLINKS_HASURA_PATH,
ssl: !!+process.env.DEEPLINKS_HASURA_SSL,
secret: process.env.DEEPLINKS_HASURA_SECRET,
});
const client = generateApolloClient({
path: `${process.env.DEEPLINKS_HASURA_PATH}/v1/graphql`,
ssl: !!+process.env.DEEPLINKS_HASURA_SSL,
secret: process.env.DEEPLINKS_HASURA_SECRET,
});
const deep = new DeepClient({
apolloClient: client,
});
let mainPort;
const getMainPort = () => __awaiter(void 0, void 0, void 0, function* () {
try {
if (!mainPort)
mainPort = yield deep.id('@deep-foundation/main-port', 'port');
return mainPort;
}
catch (error) { }
});
export function makePromiseResult(promiseId, resolvedTypeId, promiseResultTypeId, result, promiseReasonTypeId, handleInsertId) {
if (typeof handleInsertId === 'number' || typeof handleInsertId === 'string') {
return {
from: {
data: {
from_id: promiseId,
type_id: resolvedTypeId,
to: {
data: {
type_id: promiseResultTypeId,
object: { data: { value: result } },
}
}
}
},
type_id: promiseReasonTypeId,
to_id: handleInsertId
};
}
else {
return {
from_id: promiseId,
type_id: resolvedTypeId,
to: {
data: {
type_id: promiseResultTypeId,
object: { data: { value: result } },
}
}
};
}
}
;
export function processPromises(promises, handleOperationsIds, promiseId, promiseResultTypeId, promiseReasonTypeId, resolvedTypeId, rejectedTypeId, log) {
return __awaiter(this, void 0, void 0, function* () {
log("promises.length: ", promises.length);
yield Promise.allSettled(promises.map((p) => p()))
.then((values) => __awaiter(this, void 0, void 0, function* () {
log("values: ", values);
const promiseResults = [];
for (let i = 0; i < values.length; i++) {
const value = values[i];
const handleInsertId = handleOperationsIds[i];
let resultTypeId = null;
let result = null;
if (value.status == 'fulfilled') {
result = value.value;
resultTypeId = resolvedTypeId;
}
if (value.status == 'rejected') {
result = value.reason;
resultTypeId = rejectedTypeId;
}
log("result: ", result);
log("resultTypeId: ", resultTypeId);
promiseResults.push(makePromiseResult(promiseId, resultTypeId, promiseResultTypeId, result, promiseReasonTypeId, handleInsertId));
}
try {
yield deep.insert(promiseResults, { name: 'IMPORT_PROMISES_RESULTS' });
log("inserted promiseResults: ", JSON.stringify(promiseResults, null, 2));
}
catch (e) {
const serializedError = serializeError(e);
log('promiseResults insert error: ', JSON.stringify(serializedError, null, 2));
}
}));
});
}
export const containerController = new ContainerController({
gql_docker_domain: +DOCKER ? 'deep-links' : 'host.docker.internal',
handlersHash: {}
});
export function getJwt(handlerId, useRunnerDebug) {
return __awaiter(this, void 0, void 0, function* () {
const getJwtDebug = Debug('deeplinks:eh:links:getJwt');
const userTypeId = deep.idLocal('@deep-foundation/core', 'User');
getJwtDebug("userTypeId: ", JSON.stringify(userTypeId, null, 2));
const packageTypeId = deep.idLocal('@deep-foundation/core', 'Package');
getJwtDebug("packageTypeId: ", JSON.stringify(packageTypeId, null, 2));
const queryString = `query {
mpUp: mp(where: {
item_id: {_eq: "${handlerId}"},
path_item: {type_id: {_in: ["${userTypeId}", "${packageTypeId}"]}}
}) {
id
path_item {
id
type_id
value
}
path_item_depth
position_id
}
mpMe: mp(where: {item_id: {_eq: "${handlerId}"}, path_item_id: { _eq: "${handlerId}" }}) {
id
path_item_depth
position_id
}
}`;
const ownerResults = yield client.query({ query: gql `${queryString}` });
getJwtDebug("ownerResults: ", JSON.stringify(ownerResults, null, 2));
const mpUp = ownerResults.data.mpUp;
const mpMe = ownerResults.data.mpMe;
const possibleOwners = mpMe.map((me) => {
const getDepthDifference = (depth) => me.path_item_depth - depth;
const up = mpUp.filter((up) => up.position_id == me.position_id);
const closestUp = up.sort((a, b) => getDepthDifference(a.path_item_depth) - getDepthDifference(b.path_item_depth))[0];
return closestUp === null || closestUp === void 0 ? void 0 : closestUp.path_item;
}).filter(r => !!r);
getJwtDebug("possibleOwners: ", JSON.stringify(possibleOwners, null, 2));
const ownerPackage = possibleOwners.find(r => r.type_id == packageTypeId);
const ownerUser = possibleOwners.find(r => r.type_id == userTypeId);
let ownerId;
if (ownerPackage) {
ownerId = ownerPackage.id;
getJwtDebug("owner is package");
}
else if (ownerUser) {
ownerId = ownerUser.id;
getJwtDebug("owner is user");
}
else {
throw new Error("No handler owner found.");
}
getJwtDebug("ownerId: ", ownerId);
const jwt = (yield deep.jwt({ linkId: ownerId })).token;
useRunnerDebug('jwt', jwt);
return { token: jwt, linkId: ownerId };
});
}
export const useRunner = ({ code, isolationProviderImageName, handlerId, data, }) => __awaiter(void 0, void 0, void 0, function* () {
const useRunnerDebug = Debug('deeplinks:eh:links:useRunner');
useRunnerDebug("handler4: ");
const { token: jwt, linkId: ownerId } = yield getJwt(handlerId, useRunnerDebug);
let secret;
try {
const Unsafe = yield deep.id('@deep-foundation/unsafe', 'AllowUnsafe');
const isUnsafe = yield deep.can(ownerId, ownerId, Unsafe);
if (isUnsafe)
secret = process.env.DEEPLINKS_HASURA_SECRET;
}
catch (error) { }
const container = yield containerController.newContainer({ publish: +DOCKER ? false : true, forceRestart: true, handler: isolationProviderImageName });
useRunnerDebug('newContainerResult', container);
const initResult = yield containerController.initHandler(container);
useRunnerDebug('initResult', initResult);
const callResult = yield containerController.callHandler({ code, container, jwt, secret, path: process.env.DEEPLINKS_HASURA_PATH, ssl: process.env.DEEPLINKS_HASURA_SSL, data });
useRunnerDebug('callResult', callResult);
return callResult;
});
export const handlerOperations = {
Insert: 'HandleInsert',
Update: 'HandleUpdate',
Delete: 'HandleDelete',
};
export function handleOperation(operation, triggeredByLinkId, oldLink, newLink, valuesOperation) {
var _a;
return __awaiter(this, void 0, void 0, function* () {
const handleOperationDebug = Debug('deeplinks:eh:links:handleOperation');
handleOperationDebug('handleOperation', operation);
const handleOperationTypeId = deep.idLocal('@deep-foundation/core', handlerOperations[operation]);
handleOperationDebug('handleOperationTypeId', handleOperationTypeId);
const promiseLinksQueryString = `query SELECT_PROMISE_LINKS {
promise_links(where: {
${!!(oldLink === null || oldLink === void 0 ? void 0 : oldLink.id) ? `old_link_id: { _eq: ${oldLink === null || oldLink === void 0 ? void 0 : oldLink.id} }` : "old_link_id: { _is_null: true }"},
${!!(newLink === null || newLink === void 0 ? void 0 : newLink.id) ? `new_link_id: { _eq: ${newLink === null || newLink === void 0 ? void 0 : newLink.id} }` : "new_link_id: { _is_null: true }"},
${typeof (valuesOperation) !== 'undefined' ? `values_operation: { _eq: "${valuesOperation}" }` : "values_operation: { _is_null: true }"},
handle_operation_type_id: { _eq: ${handleOperationTypeId} },
selector_id: { _is_null: true }
}) {
id
promise_id
handle_operation_id
handler_id
isolation_provider_image_name
code
}
}`;
handleOperationDebug('promiseLinksQueryString', promiseLinksQueryString);
const promiseLinksQuery = gql `${promiseLinksQueryString}`;
const promiseLinksResult = yield client.query({ query: promiseLinksQuery });
const promiseLinks = (_a = promiseLinksResult === null || promiseLinksResult === void 0 ? void 0 : promiseLinksResult.data) === null || _a === void 0 ? void 0 : _a.promise_links;
handleOperationDebug("promiseLinks", JSON.stringify(promiseLinks, null, 2));
handleOperationDebug("promiseLinks?.length", promiseLinks === null || promiseLinks === void 0 ? void 0 : promiseLinks.length);
if (!(promiseLinks === null || promiseLinks === void 0 ? void 0 : promiseLinks.length)) {
return;
}
const resolvedTypeId = deep.idLocal('@deep-foundation/core', 'Resolved');
const rejectedTypeId = deep.idLocal('@deep-foundation/core', 'Rejected');
const promiseResultTypeId = deep.idLocal('@deep-foundation/core', 'PromiseResult');
const promiseReasonTypeId = deep.idLocal('@deep-foundation/core', 'PromiseReason');
for (const promiseLink of promiseLinks) {
const code = promiseLink === null || promiseLink === void 0 ? void 0 : promiseLink.code;
const isolationProviderImageName = promiseLink === null || promiseLink === void 0 ? void 0 : promiseLink.isolation_provider_image_name;
const handlerId = promiseLink === null || promiseLink === void 0 ? void 0 : promiseLink.handler_id;
const handleOperationId = promiseLink === null || promiseLink === void 0 ? void 0 : promiseLink.handle_operation_id;
const promiseId = promiseLink === null || promiseLink === void 0 ? void 0 : promiseLink.promise_id;
const promises = [];
const handleOperationsIds = [];
if (code && isolationProviderImageName && handlerId && handleOperationId) {
try {
promises.push(() => __awaiter(this, void 0, void 0, function* () { return useRunner({ code, handlerId, isolationProviderImageName, data: { triggeredByLinkId, oldLink, newLink, promiseId: promiseId, deeplinksUrl } }); }));
handleOperationsIds.push(handleOperationId);
}
catch (error) {
const serializedError = serializeError(error);
handleOperationDebug('error', JSON.stringify(serializedError, null, 2));
}
}
else {
promises.push(() => __awaiter(this, void 0, void 0, function* () { return Promise.reject(new Error('Id, operation id, code, or image of a handler are not loaded.')); }));
handleOperationsIds.push(handleOperationId);
}
yield processPromises(promises, handleOperationsIds, promiseId, promiseResultTypeId, promiseReasonTypeId, resolvedTypeId, rejectedTypeId, handleOperationDebug);
yield deep.delete(promiseLink === null || promiseLink === void 0 ? void 0 : promiseLink.id, { name: 'DELETE_PROMISE_LINK', table: 'promise_links' });
}
});
}
export function handleSelectorOperation(operation, triggeredByLinkId, oldLink, newLink, valuesOperation) {
var _a;
return __awaiter(this, void 0, void 0, function* () {
const handleSelectorDebug = debug.extend('handleSelector').extend('log');
handleSelectorDebug('handleOperation', operation);
const handleOperationTypeId = deep.idLocal('@deep-foundation/core', handlerOperations[operation]);
handleSelectorDebug('handleOperationTypeId', handleOperationTypeId);
const promiseLinksQueryString = `query SELECT_PROMISE_LINKS {
promise_links(where: {
${!!(oldLink === null || oldLink === void 0 ? void 0 : oldLink.id) ? `old_link_id: { _eq: ${oldLink === null || oldLink === void 0 ? void 0 : oldLink.id} }` : "old_link_id: { _is_null: true }"},
${!!(newLink === null || newLink === void 0 ? void 0 : newLink.id) ? `new_link_id: { _eq: ${newLink === null || newLink === void 0 ? void 0 : newLink.id} }` : "new_link_id: { _is_null: true }"},
${operation == "Update" ? `values_operation: { _eq: "${valuesOperation}" }` : "values_operation: { _is_null: true }"},
handle_operation_type_id: { _eq: ${handleOperationTypeId} },
selector_id: { _is_null: false }
}) {
id
promise_id
selector_id
handle_operation_id
handler_id
isolation_provider_image_name
code
}
}`;
handleSelectorDebug('promiseLinksQueryString', promiseLinksQueryString);
const promiseLinksQuery = gql `${promiseLinksQueryString}`;
const promiseLinksResult = yield client.query({ query: promiseLinksQuery });
const promiseLinks = (_a = promiseLinksResult === null || promiseLinksResult === void 0 ? void 0 : promiseLinksResult.data) === null || _a === void 0 ? void 0 : _a.promise_links;
handleSelectorDebug('promiseLinks', JSON.stringify(promiseLinks, null, 2));
handleSelectorDebug('promiseLinks.length', promiseLinks === null || promiseLinks === void 0 ? void 0 : promiseLinks.length);
if (!(promiseLinks === null || promiseLinks === void 0 ? void 0 : promiseLinks.length)) {
return;
}
const resolvedTypeId = deep.idLocal('@deep-foundation/core', 'Resolved');
const rejectedTypeId = deep.idLocal('@deep-foundation/core', 'Rejected');
const promiseResultTypeId = deep.idLocal('@deep-foundation/core', 'PromiseResult');
const promiseReasonTypeId = deep.idLocal('@deep-foundation/core', 'PromiseReason');
for (const promiseLink of promiseLinks) {
const code = promiseLink === null || promiseLink === void 0 ? void 0 : promiseLink.code;
const isolationProviderImageName = promiseLink === null || promiseLink === void 0 ? void 0 : promiseLink.isolation_provider_image_name;
const handlerId = promiseLink === null || promiseLink === void 0 ? void 0 : promiseLink.handler_id;
const handleOperationId = promiseLink === null || promiseLink === void 0 ? void 0 : promiseLink.handle_operation_id;
const selectorId = promiseLink === null || promiseLink === void 0 ? void 0 : promiseLink.selector_id;
const promiseId = promiseLink === null || promiseLink === void 0 ? void 0 : promiseLink.promise_id;
const promises = [];
const handleOperationsIds = [];
if (code && isolationProviderImageName && handlerId && handleOperationId) {
try {
promises.push(() => __awaiter(this, void 0, void 0, function* () { return useRunner({ code, handlerId, isolationProviderImageName, data: { triggeredByLinkId, oldLink, newLink, promiseId, selectorId, deeplinksUrl } }); }));
handleOperationsIds.push(handleOperationId);
}
catch (error) {
const serializedError = serializeError(error);
handleSelectorDebug('error', JSON.stringify(serializedError, null, 2));
}
}
else {
promises.push(() => __awaiter(this, void 0, void 0, function* () { return Promise.reject(new Error('Id, operation id, code, or image of a handler are not loaded.')); }));
handleOperationsIds.push(handleOperationId);
}
yield processPromises(promises, handleOperationsIds, promiseId, promiseResultTypeId, promiseReasonTypeId, resolvedTypeId, rejectedTypeId, handleSelectorDebug);
yield deep.delete(promiseLink === null || promiseLink === void 0 ? void 0 : promiseLink.id, { name: 'DELETE_PROMISE_LINK', table: 'promise_links' });
}
});
}
export function handleSchedule(handleScheduleLink, operation) {
var _a, _b, _c, _d;
return __awaiter(this, void 0, void 0, function* () {
const handleScheduleDebug = Debug('deeplinks:eh:links:handleSchedule');
handleScheduleDebug('handleScheduleLink', handleScheduleLink);
handleScheduleDebug('operation', operation);
if (operation == 'INSERT') {
const schedule = yield deep.select({
type_id: deep.idLocal('@deep-foundation/core', 'Schedule'),
out: {
id: { _eq: handleScheduleLink.id },
},
}, {
table: 'links',
returning: 'id value',
});
handleScheduleDebug(schedule);
const scheduleId = (_b = (_a = schedule === null || schedule === void 0 ? void 0 : schedule.data) === null || _a === void 0 ? void 0 : _a[0]) === null || _b === void 0 ? void 0 : _b.id;
const scheduleValue = (_d = (_c = schedule === null || schedule === void 0 ? void 0 : schedule.data) === null || _c === void 0 ? void 0 : _c[0]) === null || _d === void 0 ? void 0 : _d.value.value;
handleScheduleDebug('scheduleId', scheduleId);
handleScheduleDebug('scheduleValue', scheduleValue);
yield api.query({
type: 'create_cron_trigger',
args: {
name: `handle_schedule_${handleScheduleLink === null || handleScheduleLink === void 0 ? void 0 : handleScheduleLink.id}`,
webhook: `${DOCKER_DEEPLINKS_URL}/api/scheduler`,
schedule: scheduleValue,
include_in_metadata: true,
payload: {
scheduleId,
schedule: scheduleValue,
handleScheduleLinkId: handleScheduleLink === null || handleScheduleLink === void 0 ? void 0 : handleScheduleLink.id,
},
retry_conf: {
num_retries: 3,
timeout_seconds: 120,
tolerance_seconds: 21675,
retry_interval_seconds: 12
},
comment: `Event trigger for handle schedule link ${handleScheduleLink === null || handleScheduleLink === void 0 ? void 0 : handleScheduleLink.id} with cron schedule definition ${scheduleValue} of ${scheduleId} schedule.`,
}
});
handleScheduleDebug('cron trigger created');
}
else if (operation == 'DELETE') {
yield api.query({
type: 'delete_cron_trigger',
args: {
name: `handle_schedule_${handleScheduleLink === null || handleScheduleLink === void 0 ? void 0 : handleScheduleLink.id}`,
}
});
handleScheduleDebug('cron trigger deleted');
}
});
}
export function handleGql(handleGqlLink, operation) {
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r;
return __awaiter(this, void 0, void 0, function* () {
const handleGqlDebug = Debug('deeplinks:eh:links:handleGql');
handleGqlDebug('handleGqlLink', handleGqlLink);
handleGqlDebug('operation', operation);
if (operation == 'INSERT') {
const portTypeId = deep.idLocal('@deep-foundation/core', 'Port');
const routerStringUseTypeId = deep.idLocal('@deep-foundation/core', 'RouterStringUse');
const routerListeningTypeId = deep.idLocal('@deep-foundation/core', 'RouterListening');
const handleRouteTypeId = deep.idLocal('@deep-foundation/core', 'HandleRoute');
const mainPort = yield getMainPort();
const routesResult = yield client.query({
query: gql `
query {
ports: links(where: {
type_id: { _eq: ${portTypeId} },
in: {
type_id: { _eq: ${routerListeningTypeId} }
from: {
in: {
type_id: { _eq: ${routerStringUseTypeId} }
from: {
out: {
type_id: { _eq: ${handleRouteTypeId} },
in: {
id: { _eq: ${handleGqlLink === null || handleGqlLink === void 0 ? void 0 : handleGqlLink.id} }
}
}
}
}
}
}
}) {
id
port: value
routerListening: in(where: {
type_id: { _eq: ${routerListeningTypeId} }
}) {
id
router: from {
id
routerStringUse: in(where: {
type_id: { _eq: ${routerStringUseTypeId} }
}) {
id
routeString: value
route: from {
id
handleRoute: out(where: {
type_id: { _eq: ${handleRouteTypeId} },
in: {
id: { _eq: ${handleGqlLink === null || handleGqlLink === void 0 ? void 0 : handleGqlLink.id} }
}
}) {
id
handleGql: in(where: {
id: { _eq: ${handleGqlLink === null || handleGqlLink === void 0 ? void 0 : handleGqlLink.id} }
}) {
id
}
}
}
}
}
}
}
}
`, variables: {}
});
const portsResult = routesResult.data.ports;
handleGqlDebug('portsResult', JSON.stringify(portsResult, null, 2));
const urls = {};
for (const port of portsResult) {
const portValue = (port === null || port === void 0 ? void 0 : port.id) === mainPort ? PORT : (_a = port === null || port === void 0 ? void 0 : port.port) === null || _a === void 0 ? void 0 : _a.value;
const baseUrl = `http://${DEEPLINKS_ROUTE_HANDLERS_HOST}:${portValue}`;
for (const routerListening of port === null || port === void 0 ? void 0 : port.routerListening) {
for (const routerStringUse of (_b = routerListening === null || routerListening === void 0 ? void 0 : routerListening.router) === null || _b === void 0 ? void 0 : _b.routerStringUse) {
const url = `${baseUrl}${(_c = routerStringUse === null || routerStringUse === void 0 ? void 0 : routerStringUse.routeString) === null || _c === void 0 ? void 0 : _c.value}`;
if ((_f = (_e = (_d = routerStringUse === null || routerStringUse === void 0 ? void 0 : routerStringUse.route) === null || _d === void 0 ? void 0 : _d.handleRoute) === null || _e === void 0 ? void 0 : _e[0]) === null || _f === void 0 ? void 0 : _f.id)
urls[url] = (_j = (_h = (_g = routerStringUse === null || routerStringUse === void 0 ? void 0 : routerStringUse.route) === null || _g === void 0 ? void 0 : _g.handleRoute) === null || _h === void 0 ? void 0 : _h[0]) === null || _j === void 0 ? void 0 : _j.id;
}
}
}
handleGqlDebug('urls', JSON.stringify(urls, null, 2));
for (const url of Object.keys(urls)) {
const handleRouteId = urls[url];
const remote_schema_name = `handle_gql_handler_${handleGqlLink === null || handleGqlLink === void 0 ? void 0 : handleGqlLink.id}`;
const options = {
type: 'add_remote_schema',
args: {
name: remote_schema_name,
definition: {
url,
headers: [{ name: 'x-hasura-client', value: 'deeplinks-gql-handler' }],
forward_client_headers: true,
timeout_seconds: 60
}
}
};
handleGqlDebug('options', JSON.stringify(options, null, 2));
const handler_path = `${url.replace(DEEPLINKS_ROUTE_HANDLERS_HOST, "localhost").replace('http://', '')}`;
const waitOnUrl = `${url.replace(DEEPLINKS_ROUTE_HANDLERS_HOST, "localhost").replace('http://', 'http-get://')}?query=%7B__typename%7D`;
handleGqlDebug('waitOnUrl', waitOnUrl);
yield waitOn({ resources: [waitOnUrl] });
try {
const response = yield api.query(options);
handleGqlDebug('remote schema addition response', JSON.stringify(JSON.parse(toJSON(response)), null, 2));
if (response.data.error) {
throw response;
}
handleGqlDebug('remote schema is added');
const remote_schema_client = generateApolloClient({
secret: process.env.DEEPLINKS_HASURA_SECRET,
path: handler_path,
});
const __schema = yield remote_schema_client.query({ query: gql `${getIntrospectionQuery()}` });
const _schema = buildClientSchema(__schema.data);
const schema = printSchema(_schema);
handleGqlDebug(`remote schema loaded
${schema}`);
yield api.query({
type: "add_remote_schema_permissions",
args: {
remote_schema: remote_schema_name,
role: "link",
definition: { schema },
comment: "remote schema permissions for role: link"
}
}, { route: '/v1/metadata' });
handleGqlDebug('remote schema permission for "link" added');
yield api.query({
type: "add_remote_schema_permissions",
args: {
remote_schema: remote_schema_name,
role: "undefined",
definition: { schema },
comment: "remote schema permissions for role: undefined"
}
}, { route: '/v1/metadata' });
handleGqlDebug('remote schema permission for "undefined" added');
}
catch (rejected) {
const processedRejection = serializeError(rejected);
handleGqlDebug('rejected', JSON.stringify(processedRejection, null, 2));
const handlingErrorTypeId = deep.idLocal('@deep-foundation/core', 'HandlingError');
handleGqlDebug('handlingErrorTypeId', handlingErrorTypeId);
const error = ((_k = processedRejection === null || processedRejection === void 0 ? void 0 : processedRejection.data) === null || _k === void 0 ? void 0 : _k.error) || '';
if (error.includes('remote schema with name') && error.includes('already exists'))
return;
const insertResult = yield deep.insert({
type_id: handlingErrorTypeId,
object: { data: { value: processedRejection } },
out: { data: [
{
type_id: deep.idLocal('@deep-foundation/core', 'HandlingErrorReason'),
to_id: handleRouteId,
},
] },
}, {
name: 'INSERT_HANDLING_ERROR',
});
handleGqlDebug('remote schema addition error is inserted');
}
}
}
else if (operation == 'DELETE') {
const reasonResult = yield client.query({
query: gql `
query {
handleGql: links(where: {
id: { _eq: ${handleGqlLink === null || handleGqlLink === void 0 ? void 0 : handleGqlLink.id} }
}) {
id
}
handleRoute: links(where: {
id: { _eq: ${handleGqlLink === null || handleGqlLink === void 0 ? void 0 : handleGqlLink.to_id} }
}) {
id
}
}
`, variables: {}
});
const data = reasonResult.data;
const reasonId = (_o = (_m = (_l = data === null || data === void 0 ? void 0 : data.handleGql) === null || _l === void 0 ? void 0 : _l[0]) === null || _m === void 0 ? void 0 : _m.id) !== null && _o !== void 0 ? _o : (_q = (_p = data === null || data === void 0 ? void 0 : data.handleRoute) === null || _p === void 0 ? void 0 : _p[0]) === null || _q === void 0 ? void 0 : _q.id;
handleGqlDebug('reasonId', reasonId);
try {
const response = yield api.query({
type: 'remove_remote_schema',
args: {
name: `handle_gql_handler_${handleGqlLink === null || handleGqlLink === void 0 ? void 0 : handleGqlLink.id}`,
},
});
handleGqlDebug('remote schema removal response', JSON.stringify(JSON.parse(toJSON(response)), null, 2));
if (response.data.error) {
throw response;
}
handleGqlDebug('remote schema is removed');
}
catch (rejected) {
const processedRejection = serializeError(rejected);
handleGqlDebug('rejected', JSON.stringify(processedRejection, null, 2));
const handlingErrorTypeId = deep.idLocal('@deep-foundation/core', 'HandlingError');
handleGqlDebug('handlingErrorTypeId', handlingErrorTypeId);
const error = ((_r = processedRejection === null || processedRejection === void 0 ? void 0 : processedRejection.data) === null || _r === void 0 ? void 0 : _r.error) || '';
if (error.includes('remote schema with name') && error.includes('already exists'))
return;
const insertResult = yield deep.insert({
type_id: handlingErrorTypeId,
object: { data: { value: processedRejection } },
out: { data: [
{
type_id: deep.idLocal('@deep-foundation/core', 'HandlingErrorReason'),
to_id: reasonId,
},
] },
}, {
name: 'INSERT_HANDLING_ERROR',
});
handleGqlDebug('remote schema removal error is inserted');
}
}
});
}
export function handlePort(handlePortLink, operation) {
var _a, _b, _c, _d, _e, _f;
return __awaiter(this, void 0, void 0, function* () {
const handlePortDebug = Debug('deeplinks:eh:links:handlePort');
handlePortDebug('handlePortLink', handlePortLink);
handlePortDebug('operation', operation);
const port = yield deep.select({
id: { _eq: handlePortLink.from_id },
}, {
table: 'links',
returning: 'id value',
});
handlePortDebug(port);
const portId = (_b = (_a = port === null || port === void 0 ? void 0 : port.data) === null || _a === void 0 ? void 0 : _a[0]) === null || _b === void 0 ? void 0 : _b.id;
const portValue = (_d = (_c = port === null || port === void 0 ? void 0 : port.data) === null || _c === void 0 ? void 0 : _c[0]) === null || _d === void 0 ? void 0 : _d.value.value;
handlePortDebug('portId', portId);
handlePortDebug('portValue', portValue);
if (operation == 'INSERT') {
const isolationProvider = yield deep.select({
in: {
id: { _eq: handlePortLink.id },
},
}, {
table: 'links',
returning: 'id value',
});
handlePortDebug('INSERT', isolationProvider);
const dockerImage = (_f = (_e = isolationProvider === null || isolationProvider === void 0 ? void 0 : isolationProvider.data) === null || _e === void 0 ? void 0 : _e[0]) === null || _f === void 0 ? void 0 : _f.value.value;
handlePortDebug('INSERT dockerImage', dockerImage);
const containerName = `deep-handle-port-${portValue}`;
handlePortDebug('INSERT containerName', containerName);
const container = yield containerController.newContainer({ publish: true, forcePort: portValue, forceName: containerName, handler: dockerImage });
handlePortDebug('INSERT newContainer result', container);
if (container.error)
return handlePortDebug('portResult.error', container.error);
handlePortDebug(`INSERT port handler container ${JSON.stringify(container)} created`);
}
else if (operation == 'DELETE') {
const containerName = `deep-handle-port-${portValue}`;
handlePortDebug('DELETE containerName', containerName);
const container = yield containerController.findContainer(containerName);
handlePortDebug('DELETE container', container);
yield containerController.dropContainer(container);
handlePortDebug('DELETE port handler container deleted');
}
});
}
export default (req, res) => __awaiter(void 0, void 0, void 0, function* () {
var _a, _b, _c, _d, _e, _f, _g;
try {
let handlePortId;
try {
handlePortId = deep.idLocal('@deep-foundation/core', 'HandlePort');
}
catch (_h) {
return res.status(500).json({ error: '@deep-foundation/core package is not ready to support links handlers.' });
}
const event = (_a = req === null || req === void 0 ? void 0 : req.body) === null || _a === void 0 ? void 0 : _a.event;
const triggeredByLinkId = parseInt(event.session_variables["x-hasura-user-id"]);
log('triggeredByLinkId', triggeredByLinkId);
const operation = event === null || event === void 0 ? void 0 : event.op;
if (operation === 'INSERT' || operation === 'UPDATE' || operation === 'DELETE') {
const oldRow = (_b = event === null || event === void 0 ? void 0 : event.data) === null || _b === void 0 ? void 0 : _b.old;
if (oldRow) {
const queryResult = yield deep.select({
id: { _eq: oldRow.id },
}, {
returning: `value`,
});
oldRow.value = (_d = (_c = queryResult.data) === null || _c === void 0 ? void 0 : _c[0]) === null || _d === void 0 ? void 0 : _d.value;
}
const newRow = (_e = event === null || event === void 0 ? void 0 : event.data) === null || _e === void 0 ? void 0 : _e.new;
if (newRow) {
const queryResult = yield deep.select({
id: { _eq: newRow.id },
}, {
returning: `value`,
});
newRow.value = (_g = (_f = queryResult.data) === null || _f === void 0 ? void 0 : _f[0]) === null || _g === void 0 ? void 0 : _g.value;
}
const current = operation === 'DELETE' ? oldRow : newRow;
log(`Processing ${current.id} link.`);
log('operation', operation);
log('current', current);
try {
if (operation === 'INSERT') {
yield handleOperation('Insert', triggeredByLinkId, oldRow, newRow);
yield handleSelectorOperation('Insert', triggeredByLinkId, oldRow, newRow);
}
else if (operation === 'DELETE') {
yield handleOperation('Delete', triggeredByLinkId, oldRow, newRow);
yield handleSelectorOperation('Delete', triggeredByLinkId, oldRow, newRow);
}
else if (operation === 'UPDATE') {
yield handleOperation('Update', triggeredByLinkId, oldRow, newRow);
yield handleSelectorOperation('Update', triggeredByLinkId, oldRow, newRow);
}
const typeId = current.type_id;
const handleScheduleId = deep.idLocal('@deep-foundation/core', 'HandleSchedule');
if (typeId === handleScheduleId && (operation === 'INSERT' || operation === 'DELETE')) {
yield handleSchedule(current, operation);
}
const handleGqlTypeId = deep.idLocal('@deep-foundation/core', 'HandleGql');
if (typeId === handleGqlTypeId && (operation === 'INSERT' || operation === 'DELETE')) {
yield handleGql(current, operation);
}
if (typeId === handlePortId && (operation === 'INSERT' || operation === 'DELETE')) {
yield handlePort(current, operation);
}
log(`Link ${current.id} is proccessed.`);
if (operation === 'INSERT' && !DENIED_IDS.includes(current.type_id) && ALLOWED_IDS.includes(current.type_id)) {
log('resolve', current.id);
yield resolve({
id: current.id, client,
Then: deep.idLocal('@deep-foundation/core', 'Then'),
Promise: deep.idLocal('@deep-foundation/core', 'Promise'),
Resolved: deep.idLocal('@deep-foundation/core', 'Resolved'),
Rejected: deep.idLocal('@deep-foundation/core', 'Rejected'),
Results: false,
});
}
return res.status(200).json({});
}
catch (e) {
const serializedError = serializeError(e);
error('error', JSON.stringify(serializedError, null, 2));
if (operation === 'INSERT' && !DENIED_IDS.includes(current.type_id) && ALLOWED_IDS.includes(current.type_id)) {
log('reject', current.id);
yield reject({
id: current.id, client,
Then: deep.idLocal('@deep-foundation/core', 'Then'),
Promise: deep.idLocal('@deep-foundation/core', 'Promise'),
Resolved: deep.idLocal('@deep-foundation/core', 'Resolved'),
Rejected: deep.idLocal('@deep-foundation/core', 'Rejected'),
Results: false,
});
}
}
return res.status(500).json({ error: 'notexplained' });
}
return res.status(500).json({ error: 'operation can be only INSERT or UPDATE' });
}
catch (e) {
const serializedError = serializeError(e);
return res.status(500).json({ error: serializedError });
}
});
export const handleGqlLinks = () => __awaiter(void 0, void 0, void 0, function* () {
const handleGqlLinksDebug = Debug('deeplinks:eh:links:handleGqlLinks');
try {
const HandleGql = deep.idLocal('@deep-foundation/core', 'HandleGql');
const { data: handles } = yield deep.select({
type_id: HandleGql
});
for (let h in handles) {
yield handleGql(handles[h], 'INSERT');
}
}
catch (e) {
const serializedError = serializeError(e);
handleGqlLinksDebug('IGNORED ERROR (handleGqlLinks):', JSON.stringify(serializedError, null, 2));
}
});
const startGqlHandling = () => __awaiter(void 0, void 0, void 0, function* () {
setInterval(handleGqlLinks, 5000);
});
startGqlHandling();
//# sourceMappingURL=links.js.map