UNPKG

@deep-foundation/deeplinks

Version:

[![npm](https://img.shields.io/npm/v/@deep-foundation/deeplinks.svg)](https://www.npmjs.com/package/@deep-foundation/deeplinks) [![Gitpod](https://img.shields.io/badge/Gitpod-ready--to--code-blue?logo=gitpod)](https://gitpod.io/#https://github.com/deep-fo

787 lines 42.7 kB
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