deep-foundation / js-docker-isolation-provider

The Unlicense
6 stars 7 forks source link

Unexpected token 'export' #15

Open FreePhoenix888 opened 1 year ago

FreePhoenix888 commented 1 year ago

Error

Unexpected token 'export'

Source Code

import {
  DeepClient,
  SerialOperation,
  Table,
} from '@deep-foundation/deeplinks/imports/client';
import { Link } from '@deep-foundation/deeplinks/imports/minilinks';

async ({
  deep,
  data: { newLink: notifyLink, triggeredByLinkId },
}: {
  deep: DeepClient;
  data: { newLink: Link<number>, triggeredByLinkId: number };
}) => {
  const firebaseAdmin = await import('firebase-admin');
  const util = await import('util');
  const { createSerialOperation } = await import('@deep-foundation/deeplinks/imports/gql/index')
  const logs: Array<any> = [];
  const DEFAULT_LOG_DEPTH = 3;

  async function main() {
    const log = getNamespacedLogger({ namespace: main.name });
    const notificationLinkId = notifyLink.from_id!;
    log({ notificationLinkId })
    const { data: [notificationLink] } = await deep.select(notificationLinkId)
    log({ notificationLink })
    if (!notificationLink.value?.value) {
      throw new Error(`##${notificationLinkId} must have value`)
    }
    const title = notificationLink.value.value.title;
    log({ title })
    if (!title) {
      throw new Error(`Object value of ##${notificationLinkId} must have title property`)
    }

    const body = notificationLink.value.value.body;
    log({ body })
    if (!body) {
      throw new Error(`Object value of ##${notificationLinkId} must have body property`)
    }

    const deviceLinkId = notifyLink.to_id;
    log({ deviceLinkId })

    const containTypeLinkId = await deep.id('@deep-foundation/core', 'Contain');
    log({ containTypeLinkId })

    const serviceAccount = await getServiceAccount({
      containTypeLinkId,
      triggeredByLinkId,
    });
    log({ serviceAccount })

    const firebaseApplication = await getFirebaseApplication({
      firebaseAdmin,
      serviceAccount,
    });
    log({ firebaseApplication })

    const deviceRegistrationToken = await getDeviceRegistrationToken({
      containTypeLinkId,
      deviceLinkId,
    });
    log({ deviceRegistrationToken })

    const pushNotificationData = {
      token: deviceRegistrationToken,
      notification: {
        title: title,
        body: body,
      },
    };
    log({ pushNotificationData })

    await firebaseAdmin.messaging(firebaseApplication).send(pushNotificationData);
    await deep.insert({
      type_id: await deep.id(deep.linkId!, 'Notified'),
      in: {
        data: {
          type_id: containTypeLinkId,
          from_id: triggeredByLinkId,
        },
      },
      from_id: notifyLink.id,
      to_id: deviceLinkId,
    });

    firebaseApplication.delete();
  }

  async function getServiceAccount({ containTypeLinkId, triggeredByLinkId }) {
    const log = getNamespacedLogger({ namespace: getServiceAccount.name });
    const serviceAccountTypeLinkId = await deep.id(
      deep.linkId!,
      'ServiceAccount'
    );
    log({ serviceAccountTypeLinkId })
    const usesServiceAccountTypeLinkId = await deep.id(
      deep.linkId!,
      'UsesServiceAccount'
    );
    log({ usesServiceAccountTypeLinkId })
    const selectData = {
      _or: [
        {
          type_id: serviceAccountTypeLinkId,
          in: {
            type_id: containTypeLinkId,
            from_id: triggeredByLinkId,
          },
        },
        {
          type_id: usesServiceAccountTypeLinkId,
          from_id: triggeredByLinkId,
        },
      ],
    };
    const { data } = await deep.select(selectData);
    log({ data })
    if (data.length === 0) {
      throw new Error(
        `Select with data ${JSON.stringify(selectData)} returned empty result`
      );
    }
    let serviceAccountLink;
    const usesServiceAccountLinks = data.filter(
      (link) => link.type_id === usesServiceAccountTypeLinkId
    );
    if (usesServiceAccountLinks.length > 1) {
      throw new Error(
        `There must be only one link of type ${usesServiceAccountTypeLinkId} and from ${triggeredByLinkId}, instead there are ${usesServiceAccountLinks
          .map((link) => `##${link.id}`)
          .join(', ')}`
      );
    } else if (usesServiceAccountLinks.length === 1) {
      const usesServiceAccountLink = usesServiceAccountLinks[0];
      serviceAccountLink = data.find(
        (link) => link.id === usesServiceAccountLink.to_id
      );
    } else if (usesServiceAccountLinks.length === 0) {
      const serviceAccountLinks = data.filter(
        (link) => link.type_id === serviceAccountTypeLinkId
      );
      if (serviceAccountLinks.length > 1) {
        throw new Error(
          `There must be only one link of type ##${serviceAccountTypeLinkId} and contained by ##${triggeredByLinkId}, instead there are ${serviceAccountLinks
            .map((link) => `##${link.id}`)
            .join(', ')}`
        );
      } else if (serviceAccountLinks.length === 1) {
        serviceAccountLink = serviceAccountLinks[0];
      } else if (serviceAccountLinks.length === 0) {
        throw new Error(
          `A link of type ##${serviceAccountTypeLinkId} and contained by ##${triggeredByLinkId} is not found`
        );
      }
    }
    log({ serviceAccountLink })
    if (!serviceAccountLink) {
      throw new Error(
        `A link of type ##${usesServiceAccountTypeLinkId} and from ##${triggeredByLinkId} is not found`
      );
    }
    if (!serviceAccountLink.value?.value) {
      throw new Error(`##${serviceAccountLink.id} must have value`);
    }
    const result = serviceAccountLink.value.value;
    log({ result })
    return result;
  }

  async function getDeviceRegistrationToken({
    containTypeLinkId,
    deviceLinkId,
  }) {
    const log = getNamespacedLogger({ namespace: getDeviceRegistrationToken.name });
    const deviceRegistrationTokenTypeLinkId = await deep.id(
      deep.linkId!,
      'DeviceRegistrationToken'
    );
    log({ deviceRegistrationTokenTypeLinkId })
    const selectData = {
      type_id: deviceRegistrationTokenTypeLinkId,
      in: {
        type_id: containTypeLinkId,
        from_id: deviceLinkId,
      },
    };
    log({ selectData })
    const {
      data: [deviceRegistrationTokenLink],
    } = await deep.select(selectData);
    if (!deviceRegistrationTokenLink) {
      throw new Error(
        `##${deviceLinkId} must have contained a link of type ##${deviceRegistrationTokenTypeLinkId}. Select with data ${JSON.stringify(
          selectData
        )} returned empty result`
      );
    }
    log({ deviceRegistrationTokenLink })
    if (!deviceRegistrationTokenLink.value?.value) {
      throw new Error(`##${deviceRegistrationTokenLink.id} must have value`);
    }
    const result = deviceRegistrationTokenLink.value.value;
    log({ result })
    return result;
  }

  async function getFirebaseApplication({ firebaseAdmin, serviceAccount }) {
    firebaseAdmin.apps.forEach((app) => app.delete());
    return firebaseAdmin.initializeApp({
      credential: firebaseAdmin.credential.cert(serviceAccount),
    })
  }

  function getNamespacedLogger({
    namespace,
    depth = DEFAULT_LOG_DEPTH,
  }: {
    namespace: string;
    depth?: number;
  }) {
    return function (content: any) {
      const message = util.inspect(content, { depth });
      logs.push(`${namespace}: ${message}`);
    };
  }
};

Dist code transpiled by @deep-foundation/tsx package

async ({ deep, data: { newLink: notifyLink, triggeredByLinkId }, }) => {
    const firebaseAdmin = await import('firebase-admin');
    const util = await import('util');
    const { createSerialOperation } = await import('@deep-foundation/deeplinks/imports/gql/index');
    const logs = [];
    const DEFAULT_LOG_DEPTH = 3;
    async function main() {
        const log = getNamespacedLogger({ namespace: main.name });
        const notificationLinkId = notifyLink.from_id;
        log({ notificationLinkId });
        const { data: [notificationLink] } = await deep.select(notificationLinkId);
        log({ notificationLink });
        if (!notificationLink.value?.value) {
            throw new Error(`##${notificationLinkId} must have value`);
        }
        const title = notificationLink.value.value.title;
        log({ title });
        if (!title) {
            throw new Error(`Object value of ##${notificationLinkId} must have title property`);
        }
        const body = notificationLink.value.value.body;
        log({ body });
        if (!body) {
            throw new Error(`Object value of ##${notificationLinkId} must have body property`);
        }
        const deviceLinkId = notifyLink.to_id;
        log({ deviceLinkId });
        const containTypeLinkId = await deep.id('@deep-foundation/core', 'Contain');
        log({ containTypeLinkId });
        const serviceAccount = await getServiceAccount({
            containTypeLinkId,
            triggeredByLinkId,
        });
        log({ serviceAccount });
        const firebaseApplication = await getFirebaseApplication({
            firebaseAdmin,
            serviceAccount,
        });
        log({ firebaseApplication });
        const deviceRegistrationToken = await getDeviceRegistrationToken({
            containTypeLinkId,
            deviceLinkId,
        });
        log({ deviceRegistrationToken });
        const pushNotificationData = {
            token: deviceRegistrationToken,
            notification: {
                title: title,
                body: body,
            },
        };
        log({ pushNotificationData });
        await firebaseAdmin.messaging(firebaseApplication).send(pushNotificationData);
        await deep.insert({
            type_id: await deep.id(deep.linkId, 'Notified'),
            in: {
                data: {
                    type_id: containTypeLinkId,
                    from_id: triggeredByLinkId,
                },
            },
            from_id: notifyLink.id,
            to_id: deviceLinkId,
        });
        firebaseApplication.delete();
    }
    async function getServiceAccount({ containTypeLinkId, triggeredByLinkId }) {
        const log = getNamespacedLogger({ namespace: getServiceAccount.name });
        const serviceAccountTypeLinkId = await deep.id(deep.linkId, 'ServiceAccount');
        log({ serviceAccountTypeLinkId });
        const usesServiceAccountTypeLinkId = await deep.id(deep.linkId, 'UsesServiceAccount');
        log({ usesServiceAccountTypeLinkId });
        const selectData = {
            _or: [
                {
                    type_id: serviceAccountTypeLinkId,
                    in: {
                        type_id: containTypeLinkId,
                        from_id: triggeredByLinkId,
                    },
                },
                {
                    type_id: usesServiceAccountTypeLinkId,
                    from_id: triggeredByLinkId,
                },
            ],
        };
        const { data } = await deep.select(selectData);
        log({ data });
        if (data.length === 0) {
            throw new Error(`Select with data ${JSON.stringify(selectData)} returned empty result`);
        }
        let serviceAccountLink;
        const usesServiceAccountLinks = data.filter((link) => link.type_id === usesServiceAccountTypeLinkId);
        if (usesServiceAccountLinks.length > 1) {
            throw new Error(`There must be only one link of type ${usesServiceAccountTypeLinkId} and from ${triggeredByLinkId}, instead there are ${usesServiceAccountLinks
                .map((link) => `##${link.id}`)
                .join(', ')}`);
        }
        else if (usesServiceAccountLinks.length === 1) {
            const usesServiceAccountLink = usesServiceAccountLinks[0];
            serviceAccountLink = data.find((link) => link.id === usesServiceAccountLink.to_id);
        }
        else if (usesServiceAccountLinks.length === 0) {
            const serviceAccountLinks = data.filter((link) => link.type_id === serviceAccountTypeLinkId);
            if (serviceAccountLinks.length > 1) {
                throw new Error(`There must be only one link of type ##${serviceAccountTypeLinkId} and contained by ##${triggeredByLinkId}, instead there are ${serviceAccountLinks
                    .map((link) => `##${link.id}`)
                    .join(', ')}`);
            }
            else if (serviceAccountLinks.length === 1) {
                serviceAccountLink = serviceAccountLinks[0];
            }
            else if (serviceAccountLinks.length === 0) {
                throw new Error(`A link of type ##${serviceAccountTypeLinkId} and contained by ##${triggeredByLinkId} is not found`);
            }
        }
        log({ serviceAccountLink });
        if (!serviceAccountLink) {
            throw new Error(`A link of type ##${usesServiceAccountTypeLinkId} and from ##${triggeredByLinkId} is not found`);
        }
        if (!serviceAccountLink.value?.value) {
            throw new Error(`##${serviceAccountLink.id} must have value`);
        }
        const result = serviceAccountLink.value.value;
        log({ result });
        return result;
    }
    async function getDeviceRegistrationToken({ containTypeLinkId, deviceLinkId, }) {
        const log = getNamespacedLogger({ namespace: getDeviceRegistrationToken.name });
        const deviceRegistrationTokenTypeLinkId = await deep.id(deep.linkId, 'DeviceRegistrationToken');
        log({ deviceRegistrationTokenTypeLinkId });
        const selectData = {
            type_id: deviceRegistrationTokenTypeLinkId,
            in: {
                type_id: containTypeLinkId,
                from_id: deviceLinkId,
            },
        };
        log({ selectData });
        const { data: [deviceRegistrationTokenLink], } = await deep.select(selectData);
        if (!deviceRegistrationTokenLink) {
            throw new Error(`##${deviceLinkId} must have contained a link of type ##${deviceRegistrationTokenTypeLinkId}. Select with data ${JSON.stringify(selectData)} returned empty result`);
        }
        log({ deviceRegistrationTokenLink });
        if (!deviceRegistrationTokenLink.value?.value) {
            throw new Error(`##${deviceRegistrationTokenLink.id} must have value`);
        }
        const result = deviceRegistrationTokenLink.value.value;
        log({ result });
        return result;
    }
    async function getFirebaseApplication({ firebaseAdmin, serviceAccount }) {
        firebaseAdmin.apps.forEach((app) => app.delete());
        return firebaseAdmin.initializeApp({
            credential: firebaseAdmin.credential.cert(serviceAccount),
        });
    }
    function getNamespacedLogger({ namespace, depth = DEFAULT_LOG_DEPTH, }) {
        return function (content) {
            const message = util.inspect(content, { depth });
            logs.push(`${namespace}: ${message}`);
        };
    }
};
export {};
//# sourceMappingURL=module.js.map

Question

Is this the problem of js-docker-isolation-provider or @deep-foundation/tsx package? What should we do? The scariest thing is that I have been using handler code transpiled by that version of tsx package and everything was working. I do not know what is changed the way to brake it

FreePhoenix888 commented 1 year ago

I had conversation about this with chatgpt: https://chat.openai.com/share/452fcec7-ae51-49ab-9e0e-b22bd9c0e059

FreePhoenix888 commented 1 year ago

If I run this file (test.ts):

async ({ deep, data: { newLink: notifyLink, triggeredByLinkId }, }) => {
};
export {};
//# sourceMappingURL=module.js.map

by using

npx ts-node --esm test.ts 

It will run without problem

FreePhoenix888 commented 1 year ago

If I run this file (test.ts):

eval(`
async ({ deep, data: { newLink: notifyLink, triggeredByLinkId }, }) => {
};
export {};
//# sourceMappingURL=module.js.map
`)

by using

npx ts-node --esm test.ts 

It will throw the error:

freephoenix888@FreePhoenix:~/Programming/deep/deep-memo-app$ npx ts-node --esm test.ts 
SyntaxError: Unexpected token 'export'
    at file:///home/freephoenix888/Programming/deep/deep-memo-app/test.ts:1:1
    at ModuleJob.run (node:internal/modules/esm/module_job:194:25)
FreePhoenix888 commented 1 year ago

I have talked about this with GPT-4: https://chat.openai.com/share/5bbda39d-1ad5-4eb7-93f1-59061fe47a59

Konard commented 7 months ago

@FreePhoenix888 did you try to put export before the function? Our code expects that the last expression of the code string will be function expression.

FreePhoenix888 commented 7 months ago

@FreePhoenix888 did you try to put export before the function? Our code expects that the last expression of the code string will be function expression.

The reason is - tsx now transpiles ts to esnext (or smth like that) but code is executed by eval by js provider

Eval does not know what export is

As workaround I remove this export

Konard commented 7 months ago

@FreePhoenix888 I think we can close this issue in favor of https://github.com/deep-foundation/js-docker-isolation-provider/issues/19

What do you think? Or what is the specific reason to use export? Even if handler supports ts, why would you need to export anything from it?

FreePhoenix888 commented 7 months ago

@FreePhoenix888 I think we can close this issue in favor of #19

What do you think? Or what is the specific reason to use export? Even if handler supports ts, why would you need to export anything from it?

I do not export smth manually, export is added itself when tsx bundles to jsx