{"version":3,"file":"node.mjs","names":[],"sources":["../node.mts"],"sourcesContent":["import {\n  baseLoadFromInput,\n  createMinimalZip,\n  createZip,\n  type Attachment,\n  type AttachmentInput,\n  type MinimalBackupData,\n  type PHBaseState,\n  type PHDocument,\n  type Reducer,\n  type ReplayDocumentOptions,\n} from \"@powerhousedao/shared/document-model\";\nimport mime from \"mime/lite\";\nimport type { BinaryLike } from \"node:crypto\";\nimport { createHash } from \"node:crypto\";\nimport fs from \"node:fs\";\nimport https from \"node:https\";\nimport { join } from \"node:path\";\n\nfunction getFileAttributes(\n  file: string,\n): Omit<Attachment, \"data\" | \"mimeType\"> {\n  const extension = file.replace(/^.*\\./, \"\") || undefined;\n  const fileName = file.replace(/^.*[/\\\\]/, \"\") || undefined;\n  return { extension, fileName };\n}\n\n/**\n * Reads an attachment from a file and returns its base64-encoded data and MIME type.\n * @param path - The path of the attachment file to read.\n * @returns A Promise that resolves to an object containing the base64-encoded data and MIME type of the attachment.\n */\nexport async function getLocalFile(path: string): Promise<AttachmentInput> {\n  const buffer = await getFileNode(path);\n  const mimeType = mime.getType(path) || \"application/octet-stream\";\n  const attributes = getFileAttributes(path);\n  const data = buffer.toString(\"base64\");\n  return { data, hash: hashNode(data), mimeType, ...attributes };\n}\n\n/**\n * Fetches an attachment from a URL and returns its base64-encoded data and MIME type.\n * @param url - The URL of the attachment to fetch.\n * @returns A Promise that resolves to an object containing the base64-encoded data and MIME type of the attachment.\n */\nexport async function getRemoteFile(url: string): Promise<AttachmentInput> {\n  const { buffer, mimeType = \"application/octet-stream\" } =\n    await fetchFileNode(url);\n  const attributes = getFileAttributes(url);\n  const data = buffer.toString(\"base64\");\n  return {\n    data,\n    hash: hashNode(data),\n    mimeType,\n    ...attributes,\n  };\n}\n\nexport function writeFileNode(\n  path: string,\n  name: string,\n  data: Uint8Array,\n): Promise<string> {\n  const filePath = join(path, name);\n  fs.mkdirSync(path, { recursive: true });\n\n  return new Promise((resolve, reject) => {\n    try {\n      fs.writeFile(filePath, data, {}, (err) => {\n        if (err) {\n          reject(err);\n        } else {\n          resolve(filePath);\n        }\n      });\n    } catch (error: unknown) {\n      if (error instanceof Error) {\n        reject(error);\n      } else {\n        reject(new Error(String(error)));\n      }\n    }\n  });\n}\n\nexport function readFileNode(path: string) {\n  return fs.readFileSync(path);\n}\n\nexport function fetchFileNode(\n  url: string,\n): Promise<{ buffer: Buffer; mimeType?: string }> {\n  return new Promise((resolve, reject) => {\n    https\n      .get(url, (resp) => {\n        const data: Uint8Array[] = [];\n        const mimeType = resp.headers[\"content-type\"];\n        resp.on(\"data\", (chunk: Uint8Array) => {\n          data.push(chunk);\n        });\n\n        resp.on(\"end\", () => {\n          resolve({ buffer: Buffer.concat(data), mimeType });\n        });\n      })\n      .on(\"error\", (err) => {\n        reject(err);\n      });\n  });\n}\n\nexport const getFileNode = (file: string) => {\n  return Promise.resolve(readFileNode(file));\n};\n\nexport const hashNode = (\n  data: BinaryLike,\n  algorithm = \"sha1\",\n  encoding: \"base64\" | \"hex\" = \"base64\",\n  _params?: Record<string, unknown>,\n) => {\n  if (![\"sha1\", \"sha256\", \"sha512\"].includes(algorithm)) {\n    throw new Error(\n      `Hashing algorithm not supported: \"${algorithm}\". Available: sha1, sha256, sha512`,\n    );\n  }\n\n  if (![\"base64\", \"hex\"].includes(encoding)) {\n    throw new Error(\n      `Hash encoding not supported: \"${encoding}\". Available: base64, hex`,\n    );\n  }\n\n  return createHash(algorithm).update(data).digest(encoding);\n};\n\n/**\n * Loads a document from a ZIP file.\n *\n * @remarks\n * This function reads a ZIP file and returns the document state after\n * applying all the operations. The reducer is used to apply the operations.\n *\n * @typeParam S - The type of the state object.\n * @typeParam A - The type of the actions that can be applied to the state object.\n *\n * @param path - The path to the ZIP file.\n * @param reducer - The reducer to apply the operations to the state object.\n * @returns A promise that resolves to the document state after applying all the operations.\n * @throws An error if the initial state or the operations history is not found in the ZIP file.\n */\nexport async function baseLoadFromFile<\n  TState extends PHBaseState = PHBaseState,\n>(\n  path: string,\n  reducer: Reducer<TState>,\n  options?: ReplayDocumentOptions,\n): Promise<PHDocument<TState>> {\n  const file = readFileNode(path);\n  return baseLoadFromInput(file, reducer, options);\n}\n\n/**\n * Saves a minimal document backup to a .phd file.\n * Used when the full document is not available (e.g., in onOperations handler).\n * Creates a file with minimal header and empty operations.\n */\nexport async function baseMinimalSaveToFile(\n  data: MinimalBackupData,\n  path: string,\n  extension: string,\n) {\n  const file = await createMinimalZip(data);\n  const fileExtension = extension ? `.${extension}.phd` : \".phd\";\n\n  return writeFileNode(\n    path,\n    data.name.endsWith(fileExtension)\n      ? data.name\n      : `${data.name}${fileExtension}`,\n    file,\n  );\n}\n\n/**\n * Saves a document to a ZIP file.\n *\n * @remarks\n * This function creates a ZIP file containing the document's state, operations,\n * and file attachments. The file is saved to the specified path.\n *\n * @param document - The document to save to the file.\n * @param path - The path to save the file to.\n * @param extension - The extension to use for the file.\n * @returns A promise that resolves to the path of the saved file.\n */\nexport async function baseSaveToFile(\n  document: PHDocument,\n  path: string,\n  extension: string,\n  name?: string,\n) {\n  const file = await createZip(document);\n  const fileName = name ?? document.header.name;\n  const fileExtension = extension ? `.${extension}.phd` : \".phd\";\n\n  return writeFileNode(\n    path,\n    fileName.endsWith(fileExtension) ? fileName : `${fileName}${fileExtension}`,\n    file,\n  );\n}\n"],"mappings":"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"}