@strapi/data-transfer
Version:
Data transfer capabilities for Strapi
1 lines • 15.1 kB
Source Map (JSON)
{"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';\n\ninterface IDispatcherState {\n transfer?: { kind: Client.TransferKind; id: string };\n}\n\ninterface IDispatchOptions {\n attachTransfer?: boolean;\n}\n\ntype Dispatch<T> = Omit<T, 'transferID' | 'uuid'>;\n\nexport const createDispatcher = (\n ws: WebSocket,\n 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 = JSON.stringify(payload);\n ws.send(stringifiedPayload, (error) => {\n if (error) {\n reject(error);\n }\n });\n const { retryMessageMaxRetries, retryMessageTimeout } = retryMessageOptions;\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 ) => {\n const message: Dispatch<Client.TransferPushMessage> = {\n type: 'transfer',\n kind: 'step',\n ...payload,\n };\n\n return dispatch<T>(message, { attachTransfer: true }) ?? Promise.resolve(null);\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","JSON","stringify","send","error","sendPeriodically","ProviderError","interval","setInterval","onResponse","raw","response","parse","toString","clearInterval","details","ProviderTransferError","ProviderValidationError","ProviderInitializationError","data","once","dispatchCommand","dispatchTransferAction","dispatchTransferStep","setTransferProperties","properties","transferKind","connectToWebsocket","address","diagnostics","server","WebSocket","on","_req","res","statusCode","diagnostic","report","err","trimTrailingSlash","input","replace"],"mappings":"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"}