Unable to Load Forge App | Entry point resolver not found

Hi everyone,

Recently I was trying to find out how migrate a connect app to forge, and so during that process, I created a branch from my previous codebase completed the following.

  1. Installed forge cli, and logged in on forge.
  2. Registered the app on Forge using a manifest file.

I found out that in my case, it would be better to create new forge modules rather then using connectModules, so i created a issue panel which was just displaying hello world and successfully deployed & installed the application to marketplace(development).

Finally I used this example app to add an issue panel to the app after successfully installing it, the loader did not load and got the following error on console.

Uncaught (in promise) Error: Entry point "resolver" for extension "<key>" could not be invoked as it does not exist or does not reference a function or endpoint. 

Error: Entry point "resolver" for extension "<key>" could not be invoked as it does not exist or does not reference a function or endpoint

This is the rehauled folder structure that I am using.

- src 
   - index.js
- static 
   - spa
      - build
      - node_modules
      - public 
      - src
      - .gitignore
      - package.json 
- manifest.yml

This is manifest file

app:
  id: <id> 
modules: 
  jira:issuePanel:
    - key: <key>
      resource: <res>
      title: Title
      viewportSize: medium
      resolver:
        function: resolver
      tooltip: Tooltip
      icon: <url-of-icon>
  function:
    - key: resolver
      handler: index.handler
permissions:
  scopes:
    - storage:app
  content:
    styles:
      - 'unsafe-inline'  
resources: 
  - key: <res>
    path: ../src/static/spa/build

and this is the index.js file

import Resolver from '@forge/resolver';
import { storage } from '@forge/api';

const resolver = new Resolver();

const getUniqueId = () => '_' + Math.random().toString(36).substr(2, 9);

const getListKeyFromContext = (context) => {
  console.log(context);
  const { localId: id } = context;
  return id.split('/')[id.split('/').length - 1];
}

const getAll = async (listId) => {
  return await storage.get(listId) || [];
}

resolver.define('get-all', ({ context }) => {
  return getAll(getListKeyFromContext(context));
});

resolver.define('create', async ({ payload, context }) => {
  const listId = getListKeyFromContext(context);
  const records = await getAll(listId);
  const id = getUniqueId();

  const newRecord = {
    id,
    ...payload,
  };

  await storage.set(getListKeyFromContext(context), [...records, newRecord]);

  return newRecord;
});

resolver.define('update', async ({ payload, context }) => {
  const listId = getListKeyFromContext(context);
  let records = await getAll(listId);

  records = records.map(item => {
    if (item.id === payload.id) {
      return payload;
    }
    return item;
  })

  await storage.set(getListKeyFromContext(context), records);

  return payload;
});

resolver.define('delete', async ({ payload, context }) => {
  const listId = getListKeyFromContext(context);
  let records = await getAll(listId);

  records = records.filter(item => item.id !== payload.id)

  await storage.set(getListKeyFromContext(context), records);

  return payload;
});

resolver.define('delete-all', ({ context }) => {
  return storage.set(getListKeyFromContext(context), []);
});

export const handler = resolver.getDefinitions();

Any help in what I am doing wrong would be much appreciated!!

This line in your manifest makes me think your folder structure is wrong.

There should be no need to use “…/” from the manifest since it should be in the root folder of your project. The folder structure you put in the post looks correct but are you sure that it represents the actual structure? You may want to check. I can’t see why you would have put that path in there unless it’s just an unrelated mistake.

I can’t find anything that is obviously wrong with your setup as written in the post.