{"version":3,"file":"utils.mjs","sources":["../../../src/strapi/providers/utils.ts"],"sourcesContent":["import { randomUUID } from 'crypto';\nimport { RawData, WebSocket } from 'ws';\n\nimport type { Client, Server } from '../../../types/remote/protocol';\n\nimport {\n  ProviderError,\n  ProviderTransferError,\n  ProviderInitializationError,\n  ProviderValidationError,\n  ProviderErrorDetails,\n} from '../../errors/providers';\nimport { IDiagnosticReporter } from '../../utils/diagnostic';\nimport { stringifyTransferWebSocketPayload } from '../../utils/transfer-websocket-json';\n\ninterface IDispatcherState {\n  transfer?: { kind: Client.TransferKind; id: string };\n}\n\nexport interface RetryMessageOptions {\n  retryMessageMaxRetries: number;\n  retryMessageTimeout: number;\n}\n\ninterface IDispatchOptions {\n  attachTransfer?: boolean;\n  /** Merged onto the dispatcher's default `retryMessageOptions` for this message only. */\n  retryOverrides?: Partial<RetryMessageOptions>;\n}\n\ntype Dispatch<T> = Omit<T, 'transferID' | 'uuid'>;\n\nexport const createDispatcher = (\n  ws: WebSocket,\n  retryMessageOptions: RetryMessageOptions = {\n    retryMessageMaxRetries: 5,\n    retryMessageTimeout: 30000,\n  },\n  reportInfo?: (message: string) => void\n) => {\n  const state: IDispatcherState = {};\n\n  type DispatchMessage = Dispatch<Client.Message>;\n\n  const dispatch = async <U = null>(\n    message: DispatchMessage,\n    options: IDispatchOptions = {}\n  ): Promise<U | null> => {\n    if (!ws) {\n      throw new Error('No websocket connection found');\n    }\n\n    return new Promise<U | null>((resolve, reject) => {\n      const uuid = randomUUID();\n      const payload = { ...message, uuid };\n      let numberOfTimesMessageWasSent = 0;\n\n      if (options.attachTransfer) {\n        Object.assign(payload, { transferID: state.transfer?.id });\n      }\n\n      if (message.type === 'command') {\n        reportInfo?.(\n          `dispatching message command:${(message as Client.CommandMessage).command} uuid:${uuid} sent:${numberOfTimesMessageWasSent}`\n        );\n      } else if (message.type === 'transfer') {\n        const messageToSend = message as Client.TransferMessage;\n        reportInfo?.(\n          `dispatching message action:${messageToSend.action} ${messageToSend.kind === 'step' ? `step:${messageToSend.step}` : ''} uuid:${uuid} sent:${numberOfTimesMessageWasSent}`\n        );\n      }\n      const stringifiedPayload = stringifyTransferWebSocketPayload(\n        payload as Record<string, unknown>\n      );\n      ws.send(stringifiedPayload, (error) => {\n        if (error) {\n          reject(error);\n        }\n      });\n      const { retryMessageMaxRetries, retryMessageTimeout } = {\n        ...retryMessageOptions,\n        ...options.retryOverrides,\n      };\n      const sendPeriodically = () => {\n        if (numberOfTimesMessageWasSent <= retryMessageMaxRetries) {\n          numberOfTimesMessageWasSent += 1;\n          ws.send(stringifiedPayload, (error) => {\n            if (error) {\n              reject(error);\n            }\n          });\n        } else {\n          reject(new ProviderError('error', 'Request timed out'));\n        }\n      };\n      const interval = setInterval(sendPeriodically, retryMessageTimeout);\n\n      const onResponse = (raw: RawData) => {\n        const response: Server.Message<U> = JSON.parse(raw.toString());\n        if (message.type === 'command') {\n          reportInfo?.(\n            `received response to message command: ${(message as Client.CommandMessage).command} uuid: ${uuid} sent: ${numberOfTimesMessageWasSent}`\n          );\n        } else if (message.type === 'transfer') {\n          const messageToSend = message as Client.TransferMessage;\n          reportInfo?.(\n            `received response to message action:${messageToSend.action} ${messageToSend.kind === 'step' ? `step:${messageToSend.step}` : ''} uuid:${uuid} sent:${numberOfTimesMessageWasSent}`\n          );\n        }\n        if (response.uuid === uuid) {\n          clearInterval(interval);\n          if (response.error) {\n            const message = response.error.message;\n            const details = response.error.details?.details as ProviderErrorDetails;\n            const step = response.error.details?.step;\n            let error = new ProviderError('error', message, details);\n            if (step === 'transfer') {\n              error = new ProviderTransferError(message, details);\n            } else if (step === 'validation') {\n              error = new ProviderValidationError(message, details);\n            } else if (step === 'initialization') {\n              error = new ProviderInitializationError(message);\n            }\n            return reject(error);\n          }\n          resolve(response.data ?? null);\n        } else {\n          ws.once('message', onResponse);\n        }\n      };\n\n      ws.once('message', onResponse);\n    });\n  };\n\n  const dispatchCommand = <U extends Client.Command>(\n    payload: {\n      command: U;\n    } & ([Client.GetCommandParams<U>] extends [never]\n      ? unknown\n      : { params?: Client.GetCommandParams<U> })\n  ) => {\n    return dispatch({ type: 'command', ...payload } as Client.CommandMessage);\n  };\n\n  const dispatchTransferAction = async <T>(action: Client.Action['action']) => {\n    const payload: Dispatch<Client.Action> = { type: 'transfer', kind: 'action', action };\n\n    return dispatch<T>(payload, { attachTransfer: true }) ?? Promise.resolve(null);\n  };\n\n  const dispatchTransferStep = async <\n    T,\n    A extends Client.TransferPushMessage['action'] = Client.TransferPushMessage['action'],\n    S extends Client.TransferPushStep = Client.TransferPushStep,\n  >(\n    payload: {\n      step: S;\n      action: A;\n    } & (A extends 'stream' ? { data: Client.GetTransferPushStreamData<S> } : unknown),\n    dispatchOptions?: Omit<IDispatchOptions, 'attachTransfer'>\n  ) => {\n    const message: Dispatch<Client.TransferPushMessage> = {\n      type: 'transfer',\n      kind: 'step',\n      ...payload,\n    };\n\n    return (\n      dispatch<T>(message, { attachTransfer: true, ...dispatchOptions }) ?? Promise.resolve(null)\n    );\n  };\n\n  const setTransferProperties = (\n    properties: Exclude<IDispatcherState['transfer'], undefined>\n  ): void => {\n    state.transfer = { ...properties };\n  };\n\n  return {\n    get transferID() {\n      return state.transfer?.id;\n    },\n\n    get transferKind() {\n      return state.transfer?.kind;\n    },\n\n    setTransferProperties,\n\n    dispatch,\n    dispatchCommand,\n    dispatchTransferAction,\n    dispatchTransferStep,\n  };\n};\n\ntype WebsocketParams = ConstructorParameters<typeof WebSocket>;\ntype Address = WebsocketParams[0];\ntype Options = WebsocketParams[2];\n\nexport const connectToWebsocket = (\n  address: Address,\n  options?: Options,\n  diagnostics?: IDiagnosticReporter\n): Promise<WebSocket> => {\n  return new Promise((resolve, reject) => {\n    const server = new WebSocket(address, options);\n    server.once('open', () => {\n      resolve(server);\n    });\n\n    server.on('unexpected-response', (_req, res) => {\n      if (res.statusCode === 401) {\n        return reject(\n          new ProviderInitializationError(\n            'Failed to initialize the connection: Authentication Error'\n          )\n        );\n      }\n\n      if (res.statusCode === 403) {\n        return reject(\n          new ProviderInitializationError(\n            'Failed to initialize the connection: Authorization Error'\n          )\n        );\n      }\n\n      if (res.statusCode === 404) {\n        return reject(\n          new ProviderInitializationError(\n            'Failed to initialize the connection: Data transfer is not enabled on the remote host'\n          )\n        );\n      }\n\n      return reject(\n        new ProviderInitializationError(\n          `Failed to initialize the connection: Unexpected server response ${res.statusCode}`\n        )\n      );\n    });\n\n    server.on('message', (raw: RawData) => {\n      const response: Server.Message = JSON.parse(raw.toString());\n      if (response.diagnostic) {\n        diagnostics?.report({\n          ...response.diagnostic,\n        });\n      }\n    });\n\n    server.once('error', (err) => {\n      reject(\n        new ProviderTransferError(err.message, {\n          details: {\n            error: err.message,\n          },\n        })\n      );\n    });\n  });\n};\n\nexport const trimTrailingSlash = (input: string): string => {\n  return input.replace(/\\/$/, '');\n};\n\nexport const wait = (ms: number) => {\n  return new Promise<void>((resolve) => {\n    setTimeout(resolve, ms);\n  });\n};\n\nexport const waitUntil = async (test: () => boolean, interval: number): Promise<void> => {\n  while (!test()) {\n    await wait(interval);\n  }\n\n  return Promise.resolve();\n};\n"],"names":["createDispatcher","ws","retryMessageOptions","retryMessageMaxRetries","retryMessageTimeout","reportInfo","state","dispatch","message","options","Error","Promise","resolve","reject","uuid","randomUUID","payload","numberOfTimesMessageWasSent","attachTransfer","Object","assign","transferID","transfer","id","type","command","messageToSend","action","kind","step","stringifiedPayload","stringifyTransferWebSocketPayload","send","error","retryOverrides","sendPeriodically","ProviderError","interval","setInterval","onResponse","raw","response","JSON","parse","toString","clearInterval","details","ProviderTransferError","ProviderValidationError","ProviderInitializationError","data","once","dispatchCommand","dispatchTransferAction","dispatchTransferStep","dispatchOptions","setTransferProperties","properties","transferKind","connectToWebsocket","address","diagnostics","server","WebSocket","on","_req","res","statusCode","diagnostic","report","err","trimTrailingSlash","input","replace"],"mappings":"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"}