{"version":3,"file":"generations.mjs","names":[],"sources":["../../src/lib/promises.ts","../../src/helpers/generations/index.ts"],"sourcesContent":["// oxlint-disable-next-line prefer-node-protocol\nimport { EventEmitter } from 'native-events';\n\n// oxlint-disable-next-line no-explicit-any\ntype EventMap = Record<string, any[]>;\n\ninterface EventfulListener<Events extends EventMap> {\n  on: <Name extends keyof Events>(\n    eventName: Name,\n    listener: (...args: Events[Name]) => void\n  ) => this;\n  once: <Name extends keyof Events>(\n    eventName: Name,\n    listener: (...args: Events[Name]) => void\n  ) => this;\n  off: <Name extends keyof Events>(\n    eventName: Name,\n    listener: (...args: Events[Name]) => void\n  ) => this;\n}\ninterface EventfulEmitter<Events extends EventMap> {\n  emit: <Name extends keyof Events>(\n    eventName: Name,\n    ...args: Events[Name]\n  ) => this;\n}\n\nexport type EventfulPromise<Data, Events extends EventMap> = Promise<Data> &\n  EventfulListener<Events>;\n\n/**\n * Attach a `EventEmitter` to a `Promise` returned by the `executor`\n *\n * @param executor Executor returning the promise. The `emitter` is passed to the executor as param.\n * @param emitter `EventEmitter` attached. By default it's a new instance.\n *\n * @returns The EventfulPromise\n */\nconst createEventfulPromise = <Data, Events extends EventMap = EventMap>(\n  executor: (\n    emitter: EventfulEmitter<Events>,\n    resolve: (value: Data) => void\n  ) => Promise<void>,\n  // oxlint-disable-next-line unicorn/prefer-event-target\n  emitter: EventEmitter = new EventEmitter()\n): EventfulPromise<Data, Events> => {\n  const customEmitter: EventfulEmitter<Events> = {\n    emit: (eventName, ...args) => {\n      emitter.emit(eventName.toString(), ...args);\n      return customEmitter;\n    },\n  };\n\n  // oxlint-disable-next-line promise/avoid-new\n  const promise = new Promise<Data>((resolve, reject) => {\n    executor(customEmitter, resolve)\n      // oxlint-disable-next-line prefer-await-to-then\n      .catch(reject);\n  });\n\n  const res: EventfulPromise<Data, Events> = Object.assign<\n    Promise<Data>,\n    EventfulListener<Events>\n  >(promise, {\n    off: (eventName, listener) => {\n      emitter.off(eventName.toString(), (...params) =>\n        // oxlint-disable-next-line no-explicit-any\n        listener(...(params as any))\n      );\n      return res;\n    },\n    on: (eventName, listener) => {\n      emitter.on(eventName.toString(), (...params) =>\n        // oxlint-disable-next-line no-explicit-any\n        listener(...(params as any))\n      );\n      return res;\n    },\n    once: (eventName, listener) => {\n      emitter.once(eventName.toString(), (...params) =>\n        // oxlint-disable-next-line no-explicit-any\n        listener(...(params as any))\n      );\n      return res;\n    },\n  });\n  return res;\n};\n\n// oxlint-disable-next-line no-default-export\nexport default createEventfulPromise;\n","import { client } from '~/lib/fetch';\nimport createEventfulPromise, { type EventfulPromise } from '~/lib/promises';\n\nimport type {\n  GenerationStatus,\n  Generation,\n  RawGeneration,\n} from '~/modules/generations/types';\nimport type { ReportResult } from '~/modules/reports/types';\nimport type { Task } from '~/modules/tasks/types';\nimport {\n  assignDependencies,\n  assignPermission,\n} from '~/helpers/permissions/decorator';\nimport { transformGeneration } from '~/modules/generations/methods';\nimport { generateReportOfTask, getFileAsJson } from '~/modules/reports/methods';\nimport { getTask } from '~/modules/tasks/methods';\n\nexport interface GenerationStartedEvent {\n  id: string;\n}\n\nexport type GenerationProgressEvent = Omit<Generation, 'task'>;\n\n// oxlint-disable-next-line no-explicit-any\ninterface GenerationEvents extends Record<string, any[]> {\n  started: [GenerationStartedEvent];\n  progress: [GenerationProgressEvent];\n}\n\nconst GEN_END_STATES = new Set<GenerationStatus>([\n  'SUCCESS',\n  'ERROR',\n  'ABORTED',\n]);\n\nexport const isGenerationEnded = (gen: Generation): boolean =>\n  GEN_END_STATES.has(gen.status);\n\ntype ReportGenerationPromise = EventfulPromise<ReportResult, GenerationEvents>;\n\n/**\n * Start generation of a report and track progress\n *\n * @param taskOrId Task or Task's id\n * @param targets Override targets, also enable first level of debugging\n *\n * @fires #started When generation started. See `GenerationStartedEvent`.\n * @fires #progress When generation progress. See `GenerationProgressEvent`. Job's progress is\n * between 0 and 1\n *\n * @throws If job's fails. **Not if generation fails !**\n *\n * @returns When the report is ready, returns the report result\n */\nexport const generateAndListenReportOfTask = (\n  taskOrId: Omit<Task, 'template'> | string,\n  period?: { start: Date; end: Date },\n  targets?: string[]\n): ReportGenerationPromise =>\n  createEventfulPromise<ReportResult, GenerationEvents>(\n    async (events, resolve) => {\n      const task = await getTask(taskOrId);\n      const websocket = client.socket('/generations', [task.namespaceId]);\n      if (!websocket) {\n        throw new Error('Unable to get socket');\n      }\n\n      websocket.on(\n        'generation:updated',\n        function onGenerationUpdated(gen: Omit<RawGeneration, 'task'>) {\n          const generation: Omit<Generation, 'task'> = transformGeneration(gen);\n          // Notify progress if it's the correct task\n          if (generation.taskId !== task.id) {\n            return;\n          }\n          events.emit('progress', generation);\n\n          // If generation ended, stop listening\n          if (!isGenerationEnded(generation)) {\n            return;\n          }\n          websocket.off('generation:updated', onGenerationUpdated);\n\n          // And resolve result\n          getFileAsJson(taskOrId, `${generation.reportId}.det.json`)\n            // oxlint-disable-next-line prefer-await-to-then\n            .then((result) => resolve(result))\n            // oxlint-disable-next-line prefer-await-to-then\n            .catch((_err) => {\n              /** */\n            });\n        }\n      );\n\n      // Once events are registered, start generation\n      const { id } = await generateReportOfTask(taskOrId, period, targets);\n      events.emit('started', { id });\n    }\n  );\nassignDependencies(generateAndListenReportOfTask, [\n  getTask,\n  generateReportOfTask,\n  getFileAsJson,\n]);\n\n/**\n * Listen to all generations\n *\n * @param onUpdate Function to call when a generation is updated\n * @param namespaces Namespaces to listen to\n *\n * @returns Function to remove listener\n */\nexport function listenAllGenerations(\n  onUpdate: (generation: Omit<Generation, 'task'>) => void,\n  namespaces?: string[]\n): { stop: () => void } {\n  const websocket = client.socket('/generations', namespaces);\n  if (!websocket) {\n    throw new Error('Unable to get socket');\n  }\n\n  const updated = (gen: Omit<RawGeneration, 'task'>): void =>\n    onUpdate(transformGeneration(gen));\n\n  websocket.on('generation:updated', updated);\n\n  return {\n    stop: (): void => {\n      websocket.off('generation:updated', updated);\n    },\n  };\n}\n// Applies same permissions as `GET /generations/:id`\nassignPermission(listenAllGenerations, 'GET /generations/:id', true);\n"],"mappings":";;;;;;;;;;;;;;;;;AAsCA,MAAM,yBACJ,UAKA,UAAwB,IAAI,aAAa,MACP;CAClC,MAAM,gBAAyC,EAC7C,OAAO,WAAW,GAAG,SAAS;EAC5B,QAAQ,KAAK,UAAU,SAAS,GAAG,GAAG,IAAI;EAC1C,OAAO;CACT,EACF;CAGA,MAAM,UAAU,IAAI,SAAe,SAAS,WAAW;EACrD,SAAS,eAAe,OAAO,CAAC,CAE7B,MAAM,MAAM;CACjB,CAAC;CAED,MAAM,MAAqC,OAAO,OAGhD,SAAS;EACT,MAAM,WAAW,aAAa;GAC5B,QAAQ,IAAI,UAAU,SAAS,IAAI,GAAG,WAEpC,SAAS,GAAI,MAAc,CAC7B;GACA,OAAO;EACT;EACA,KAAK,WAAW,aAAa;GAC3B,QAAQ,GAAG,UAAU,SAAS,IAAI,GAAG,WAEnC,SAAS,GAAI,MAAc,CAC7B;GACA,OAAO;EACT;EACA,OAAO,WAAW,aAAa;GAC7B,QAAQ,KAAK,UAAU,SAAS,IAAI,GAAG,WAErC,SAAS,GAAI,MAAc,CAC7B;GACA,OAAO;EACT;CACF,CAAC;CACD,OAAO;AACT;;;;ACzDA,MAAM,iCAAiB,IAAI,IAAsB;CAC/C;CACA;CACA;AACF,CAAC;AAED,MAAa,qBAAqB,QAChC,eAAe,IAAI,IAAI,MAAM;;;;;;;;;;;;;;;AAkB/B,MAAa,iCACX,UACA,QACA,YAEA;yCACS,QAAQ,SAAY;EACzB,MAAM,OAAO,MAAM,QAAQ,QAAQ;EACnC,MAAM,YAAY,OAAO,OAAO,gBAAgB,CAAC,KAAK,WAAW,CAAC;EAClE,IAAI,CAAC,WACH,MAAM,IAAI,MAAM,sBAAsB;EAGxC,UAAU,GACR,sBACA,SAAS,oBAAoB,KAAkC;GAC7D,MAAM,aAAuC,oBAAoB,GAAG;GAEpE,IAAI,WAAW,WAAW,KAAK,IAC7B;GAEF,OAAO,KAAK,YAAY,UAAU;GAGlC,IAAI,CAAC,kBAAkB,UAAU,GAC/B;GAEF,UAAU,IAAI,sBAAsB,mBAAmB;GAGvD,cAAc,UAAU,GAAG,WAAW,SAAS,UAAU,CAAC,CAEvD,MAAM,WAAW,QAAQ,MAAM,CAAC,CAAC,CAEjC,OAAO,SAAS;;GAEjB,CAAC;EACL,CACF;EAGA,MAAM,EAAE,OAAO,MAAM,qBAAqB,UAAU,QAAQ,OAAO;EACnE,OAAO,KAAK,WAAW,EAAE,GAAG,CAAC;CAC/B;iBArCO,IAAQ;;;EAqCf,CACF;AACF,mBAAmB,+BAA+B;CAChD;CACA;CACA;AACF,CAAC;;;;;;;;;AAUD,SAAgB,qBACd,UACA,YACsB;CACtB,MAAM,YAAY,OAAO,OAAO,gBAAgB,UAAU;CAC1D,IAAI,CAAC,WACH,MAAM,IAAI,MAAM,sBAAsB;CAGxC,MAAM,WAAW,QACf,SAAS,oBAAoB,GAAG,CAAC;CAEnC,UAAU,GAAG,sBAAsB,OAAO;CAE1C,OAAO,EACL,YAAkB;EAChB,UAAU,IAAI,sBAAsB,OAAO;CAC7C,EACF;AACF;AAEA,iBAAiB,sBAAsB,wBAAwB,IAAI"}