@nhtio/adk 0.1.0-master-e6c58205 → 0.1.0-master-89b47bec

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (290) hide show
  1. package/CHANGELOG.md +94 -0
  2. package/__vite-browser-external-CU7uua8b.mjs +9 -0
  3. package/__vite-browser-external-CU7uua8b.mjs.map +1 -0
  4. package/__vite-browser-external-DAHxjh-D.js +13 -0
  5. package/__vite-browser-external-DAHxjh-D.js.map +1 -0
  6. package/batteries/embeddings/openai/adapter.cjs +1 -1
  7. package/batteries/embeddings/openai/adapter.mjs +1 -1
  8. package/batteries/embeddings/webllm/adapter.cjs +1 -1
  9. package/batteries/embeddings/webllm/adapter.mjs +1 -1
  10. package/batteries/llm/ollama/adapter.cjs +5 -5
  11. package/batteries/llm/ollama/adapter.mjs +5 -5
  12. package/batteries/llm/ollama/helpers.cjs +2 -2
  13. package/batteries/llm/ollama/helpers.mjs +2 -2
  14. package/batteries/llm/ollama/validation.cjs +1 -1
  15. package/batteries/llm/ollama/validation.mjs +1 -1
  16. package/batteries/llm/openai_chat_completions/adapter.cjs +5 -5
  17. package/batteries/llm/openai_chat_completions/adapter.mjs +5 -5
  18. package/batteries/llm/openai_chat_completions/helpers.cjs +2 -2
  19. package/batteries/llm/openai_chat_completions/helpers.mjs +2 -2
  20. package/batteries/llm/openai_chat_completions/validation.cjs +1 -1
  21. package/batteries/llm/openai_chat_completions/validation.mjs +1 -1
  22. package/batteries/llm/webllm_chat_completions/adapter.cjs +5 -5
  23. package/batteries/llm/webllm_chat_completions/adapter.mjs +5 -5
  24. package/batteries/llm/webllm_chat_completions/validation.cjs +1 -1
  25. package/batteries/llm/webllm_chat_completions/validation.mjs +1 -1
  26. package/batteries/media/contracts.cjs +38 -8
  27. package/batteries/media/contracts.cjs.map +1 -1
  28. package/batteries/media/contracts.d.ts +86 -6
  29. package/batteries/media/contracts.mjs +37 -9
  30. package/batteries/media/contracts.mjs.map +1 -1
  31. package/batteries/media/engines/audio_decode.cjs +46 -6
  32. package/batteries/media/engines/audio_decode.cjs.map +1 -1
  33. package/batteries/media/engines/audio_decode.d.ts +9 -5
  34. package/batteries/media/engines/audio_decode.mjs +47 -7
  35. package/batteries/media/engines/audio_decode.mjs.map +1 -1
  36. package/batteries/media/engines/data.cjs +159 -0
  37. package/batteries/media/engines/data.cjs.map +1 -0
  38. package/batteries/media/engines/data.d.ts +36 -0
  39. package/batteries/media/engines/data.mjs +157 -0
  40. package/batteries/media/engines/data.mjs.map +1 -0
  41. package/batteries/media/engines/exceljs.cjs +290 -0
  42. package/batteries/media/engines/exceljs.cjs.map +1 -0
  43. package/batteries/media/engines/exceljs.d.ts +41 -0
  44. package/batteries/media/engines/exceljs.mjs +288 -0
  45. package/batteries/media/engines/exceljs.mjs.map +1 -0
  46. package/batteries/media/engines/execa_executor.cjs +1 -1
  47. package/batteries/media/engines/execa_executor.mjs +1 -1
  48. package/batteries/media/engines/fs_workspace.cjs +1 -1
  49. package/batteries/media/engines/fs_workspace.mjs +1 -1
  50. package/batteries/media/engines/jimp.cjs +24 -2
  51. package/batteries/media/engines/jimp.cjs.map +1 -1
  52. package/batteries/media/engines/jimp.d.ts +3 -1
  53. package/batteries/media/engines/jimp.mjs +24 -2
  54. package/batteries/media/engines/jimp.mjs.map +1 -1
  55. package/batteries/media/engines/sharp.cjs +37 -4
  56. package/batteries/media/engines/sharp.cjs.map +1 -1
  57. package/batteries/media/engines/sharp.d.ts +5 -3
  58. package/batteries/media/engines/sharp.mjs +37 -4
  59. package/batteries/media/engines/sharp.mjs.map +1 -1
  60. package/batteries/media/engines/sheetjs.cjs +438 -0
  61. package/batteries/media/engines/sheetjs.cjs.map +1 -0
  62. package/batteries/media/engines/sheetjs.d.ts +51 -0
  63. package/batteries/media/engines/sheetjs.mjs +436 -0
  64. package/batteries/media/engines/sheetjs.mjs.map +1 -0
  65. package/batteries/media/engines/soffice.cjs +37 -3
  66. package/batteries/media/engines/soffice.cjs.map +1 -1
  67. package/batteries/media/engines/soffice.mjs +38 -4
  68. package/batteries/media/engines/soffice.mjs.map +1 -1
  69. package/batteries/media/engines/tesseract_js.cjs +1 -1
  70. package/batteries/media/engines/tesseract_js.mjs +1 -1
  71. package/batteries/media/engines/transformers_asr.cjs +1 -1
  72. package/batteries/media/engines/transformers_asr.mjs +1 -1
  73. package/batteries/media/forge.cjs +89 -20
  74. package/batteries/media/forge.cjs.map +1 -1
  75. package/batteries/media/forge.mjs +89 -20
  76. package/batteries/media/forge.mjs.map +1 -1
  77. package/batteries/media/formats.d.ts +9 -0
  78. package/batteries/media/index.d.ts +8 -6
  79. package/batteries/media/lint.cjs +270 -58
  80. package/batteries/media/lint.cjs.map +1 -1
  81. package/batteries/media/lint.d.ts +45 -0
  82. package/batteries/media/lint.mjs +267 -58
  83. package/batteries/media/lint.mjs.map +1 -1
  84. package/batteries/media/registry.d.ts +11 -2
  85. package/batteries/media/steps/data.d.ts +26 -0
  86. package/batteries/media/steps/doc.d.ts +17 -7
  87. package/batteries/media/steps/patch.d.ts +90 -0
  88. package/batteries/media/steps/sheet.d.ts +10 -6
  89. package/batteries/media/steps/text.d.ts +4 -1
  90. package/batteries/media/validate.d.ts +5 -0
  91. package/batteries/media/verbs.d.ts +12 -1
  92. package/batteries/media.cjs +869 -448
  93. package/batteries/media.cjs.map +1 -1
  94. package/batteries/media.mjs +829 -409
  95. package/batteries/media.mjs.map +1 -1
  96. package/batteries/storage/flydrive.cjs +3 -6
  97. package/batteries/storage/flydrive.cjs.map +1 -1
  98. package/batteries/storage/flydrive.mjs +3 -6
  99. package/batteries/storage/flydrive.mjs.map +1 -1
  100. package/batteries/storage/in_memory.cjs +1 -1
  101. package/batteries/storage/in_memory.mjs +1 -1
  102. package/batteries/storage/opfs.cjs +1 -1
  103. package/batteries/storage/opfs.mjs +1 -1
  104. package/batteries/tools/_shared.cjs +2 -2
  105. package/batteries/tools/_shared.mjs +2 -2
  106. package/batteries/tools/color.cjs +2 -2
  107. package/batteries/tools/color.mjs +2 -2
  108. package/batteries/tools/comparison.cjs +3 -3
  109. package/batteries/tools/comparison.mjs +3 -3
  110. package/batteries/tools/data_structure.cjs +3 -3
  111. package/batteries/tools/data_structure.mjs +3 -3
  112. package/batteries/tools/datetime_extended.cjs +3 -3
  113. package/batteries/tools/datetime_extended.mjs +3 -3
  114. package/batteries/tools/datetime_math.cjs +3 -3
  115. package/batteries/tools/datetime_math.mjs +3 -3
  116. package/batteries/tools/encoding.cjs +3 -3
  117. package/batteries/tools/encoding.mjs +3 -3
  118. package/batteries/tools/formatting.cjs +3 -3
  119. package/batteries/tools/formatting.mjs +3 -3
  120. package/batteries/tools/geo_basics.cjs +2 -2
  121. package/batteries/tools/geo_basics.mjs +2 -2
  122. package/batteries/tools/math.cjs +3 -3
  123. package/batteries/tools/math.mjs +3 -3
  124. package/batteries/tools/memory.cjs +6 -6
  125. package/batteries/tools/memory.mjs +6 -6
  126. package/batteries/tools/parsing.cjs +4 -4
  127. package/batteries/tools/parsing.mjs +4 -4
  128. package/batteries/tools/retrievables.cjs +5 -5
  129. package/batteries/tools/retrievables.mjs +5 -5
  130. package/batteries/tools/scrapper.cjs +1 -1
  131. package/batteries/tools/scrapper.mjs +1 -1
  132. package/batteries/tools/searxng.cjs +1 -1
  133. package/batteries/tools/searxng.mjs +1 -1
  134. package/batteries/tools/standing_instructions.cjs +4 -4
  135. package/batteries/tools/standing_instructions.mjs +4 -4
  136. package/batteries/tools/statistics.cjs +4 -4
  137. package/batteries/tools/statistics.mjs +4 -4
  138. package/batteries/tools/string_processing.cjs +3 -3
  139. package/batteries/tools/string_processing.mjs +3 -3
  140. package/batteries/tools/structured_data.cjs +3 -3
  141. package/batteries/tools/structured_data.mjs +3 -3
  142. package/batteries/tools/text_analysis.cjs +3 -3
  143. package/batteries/tools/text_analysis.mjs +3 -3
  144. package/batteries/tools/text_comparison.cjs +2 -2
  145. package/batteries/tools/text_comparison.mjs +2 -2
  146. package/batteries/tools/time.cjs +3 -3
  147. package/batteries/tools/time.mjs +3 -3
  148. package/batteries/tools/unit_conversion.cjs +2 -2
  149. package/batteries/tools/unit_conversion.mjs +2 -2
  150. package/batteries/tools/web_retrieval.cjs +1 -1
  151. package/batteries/tools/web_retrieval.mjs +1 -1
  152. package/batteries/tools.cjs +2 -2
  153. package/batteries/tools.mjs +2 -2
  154. package/batteries/vector/arangodb.cjs +1 -1
  155. package/batteries/vector/arangodb.mjs +1 -1
  156. package/batteries/vector/clickhouse.cjs +1 -1
  157. package/batteries/vector/clickhouse.mjs +1 -1
  158. package/batteries/vector/cloudflare.cjs +1 -1
  159. package/batteries/vector/cloudflare.mjs +1 -1
  160. package/batteries/vector/couchbase.cjs +1 -1
  161. package/batteries/vector/couchbase.mjs +1 -1
  162. package/batteries/vector/duckdb.cjs +1 -1
  163. package/batteries/vector/duckdb.mjs +1 -1
  164. package/batteries/vector/elasticsearch.cjs +1 -1
  165. package/batteries/vector/elasticsearch.mjs +1 -1
  166. package/batteries/vector/filters.cjs +1 -1
  167. package/batteries/vector/filters.mjs +1 -1
  168. package/batteries/vector/hnswlib.cjs +1 -1
  169. package/batteries/vector/hnswlib.mjs +1 -1
  170. package/batteries/vector/lancedb.cjs +1 -1
  171. package/batteries/vector/lancedb.mjs +1 -1
  172. package/batteries/vector/mariadb.cjs +1 -1
  173. package/batteries/vector/mariadb.mjs +1 -1
  174. package/batteries/vector/meilisearch.cjs +1 -1
  175. package/batteries/vector/meilisearch.mjs +1 -1
  176. package/batteries/vector/migrate.cjs +1 -1
  177. package/batteries/vector/migrate.mjs +1 -1
  178. package/batteries/vector/mongodb.cjs +1 -1
  179. package/batteries/vector/mongodb.mjs +1 -1
  180. package/batteries/vector/neo4j.cjs +1 -1
  181. package/batteries/vector/neo4j.mjs +1 -1
  182. package/batteries/vector/opensearch.cjs +1 -1
  183. package/batteries/vector/opensearch.mjs +1 -1
  184. package/batteries/vector/oracle23ai.cjs +1 -1
  185. package/batteries/vector/oracle23ai.mjs +1 -1
  186. package/batteries/vector/pinecone.cjs +1 -1
  187. package/batteries/vector/pinecone.mjs +1 -1
  188. package/batteries/vector/redis.cjs +1 -1
  189. package/batteries/vector/redis.mjs +1 -1
  190. package/batteries/vector/retrievable.cjs +1 -1
  191. package/batteries/vector/retrievable.mjs +1 -1
  192. package/batteries/vector/s3vectors.cjs +1 -1
  193. package/batteries/vector/s3vectors.mjs +1 -1
  194. package/batteries/vector/solr.cjs +1 -1
  195. package/batteries/vector/solr.mjs +1 -1
  196. package/batteries/vector/surrealdb.cjs +1 -1
  197. package/batteries/vector/surrealdb.mjs +1 -1
  198. package/batteries/vector/typesense.cjs +1 -1
  199. package/batteries/vector/typesense.mjs +1 -1
  200. package/batteries/vector/vespa.cjs +1 -1
  201. package/batteries/vector/vespa.mjs +1 -1
  202. package/batteries/vector/weaviate.cjs +1 -1
  203. package/batteries/vector/weaviate.mjs +1 -1
  204. package/batteries.cjs +2 -2
  205. package/batteries.mjs +2 -2
  206. package/bundled_xlsx.d.ts +1075 -0
  207. package/{common-BxoznqbX.mjs → common-BQoFv108.mjs} +7 -7
  208. package/{common-BxoznqbX.mjs.map → common-BQoFv108.mjs.map} +1 -1
  209. package/{common-BBK2e5ro.js → common-DmDn4Gfl.js} +7 -7
  210. package/{common-BBK2e5ro.js.map → common-DmDn4Gfl.js.map} +1 -1
  211. package/common.cjs +7 -7
  212. package/common.mjs +7 -7
  213. package/{dispatch_runner-Hn5idJYx.js → dispatch_runner-BwplbCPr.js} +3 -3
  214. package/{dispatch_runner-Hn5idJYx.js.map → dispatch_runner-BwplbCPr.js.map} +1 -1
  215. package/{dispatch_runner-DUrpj0xR.mjs → dispatch_runner-C1ar_D7W.mjs} +3 -3
  216. package/{dispatch_runner-DUrpj0xR.mjs.map → dispatch_runner-C1ar_D7W.mjs.map} +1 -1
  217. package/dispatch_runner.cjs +1 -1
  218. package/dispatch_runner.mjs +1 -1
  219. package/eslint.cjs +1 -1
  220. package/eslint.mjs +1 -1
  221. package/forge.cjs +4 -4
  222. package/forge.mjs +4 -4
  223. package/formats-CCylUHZw.mjs +161 -0
  224. package/formats-CCylUHZw.mjs.map +1 -0
  225. package/formats-DZVuqZUN.js +196 -0
  226. package/formats-DZVuqZUN.js.map +1 -0
  227. package/guards.cjs +8 -8
  228. package/guards.mjs +8 -8
  229. package/index.cjs +11 -11
  230. package/index.mjs +11 -11
  231. package/mcp/adk-docs-corpus.json +1 -1
  232. package/package.json +198 -182
  233. package/{scrapper-DLj_KkxK.mjs → scrapper-Dn2wXu0Y.mjs} +5 -5
  234. package/{scrapper-DLj_KkxK.mjs.map → scrapper-Dn2wXu0Y.mjs.map} +1 -1
  235. package/{scrapper-Cmf1CSA-.js → scrapper-mBZ0Odq7.js} +5 -5
  236. package/{scrapper-Cmf1CSA-.js.map → scrapper-mBZ0Odq7.js.map} +1 -1
  237. package/{searxng-BKs5s8Su.js → searxng-Dj-iP_Vz.js} +5 -5
  238. package/{searxng-BKs5s8Su.js.map → searxng-Dj-iP_Vz.js.map} +1 -1
  239. package/{searxng-BJ-aZcMz.mjs → searxng-DjFxtFf6.mjs} +5 -5
  240. package/{searxng-BJ-aZcMz.mjs.map → searxng-DjFxtFf6.mjs.map} +1 -1
  241. package/server.json +21 -0
  242. package/skills/adk-assembly/SKILL.md +2 -2
  243. package/{spooled_artifact-BR0IhU9y.js → spooled_artifact-BCmPrxZS.js} +3 -3
  244. package/{spooled_artifact-BR0IhU9y.js.map → spooled_artifact-BCmPrxZS.js.map} +1 -1
  245. package/{spooled_artifact-nTE6ujM8.mjs → spooled_artifact-DL36jnqA.mjs} +3 -3
  246. package/{spooled_artifact-nTE6ujM8.mjs.map → spooled_artifact-DL36jnqA.mjs.map} +1 -1
  247. package/spooled_artifact.cjs +2 -2
  248. package/spooled_artifact.mjs +2 -2
  249. package/{spooled_markdown_artifact-Dj3fNowz.js → spooled_markdown_artifact-CD4PrrpV.js} +3 -3
  250. package/{spooled_markdown_artifact-Dj3fNowz.js.map → spooled_markdown_artifact-CD4PrrpV.js.map} +1 -1
  251. package/{spooled_markdown_artifact-DIYzbQv8.mjs → spooled_markdown_artifact-Da-Xnebh.mjs} +3 -3
  252. package/{spooled_markdown_artifact-DIYzbQv8.mjs.map → spooled_markdown_artifact-Da-Xnebh.mjs.map} +1 -1
  253. package/{thought-Cde2Y_GK.mjs → thought-CtOoZUSE.mjs} +3 -3
  254. package/{thought-Cde2Y_GK.mjs.map → thought-CtOoZUSE.mjs.map} +1 -1
  255. package/{thought-BFtsnUTU.js → thought-eka4iUHa.js} +3 -3
  256. package/{thought-BFtsnUTU.js.map → thought-eka4iUHa.js.map} +1 -1
  257. package/{tool-CcxYxA5X.mjs → tool-CITF20yJ.mjs} +3 -3
  258. package/{tool-CcxYxA5X.mjs.map → tool-CITF20yJ.mjs.map} +1 -1
  259. package/{tool-B2nnkwNU.js → tool-Dhjca7rC.js} +3 -3
  260. package/{tool-B2nnkwNU.js.map → tool-Dhjca7rC.js.map} +1 -1
  261. package/{tool_call-BxL3eU1k.js → tool_call-Cyi0hUUc.js} +4 -4
  262. package/{tool_call-BxL3eU1k.js.map → tool_call-Cyi0hUUc.js.map} +1 -1
  263. package/{tool_call-B3MOog2R.mjs → tool_call-D_k36aI4.mjs} +4 -4
  264. package/{tool_call-B3MOog2R.mjs.map → tool_call-D_k36aI4.mjs.map} +1 -1
  265. package/{tool_registry-BaLUIzWz.mjs → tool_registry-CZ55mIti.mjs} +152 -143
  266. package/tool_registry-CZ55mIti.mjs.map +1 -0
  267. package/{tool_registry-BdKlPuHS.js → tool_registry-DwZ6pzN4.js} +151 -142
  268. package/tool_registry-DwZ6pzN4.js.map +1 -0
  269. package/{turn_runner-M2I8G2ok.js → turn_runner-CCZcsoDU.js} +5 -5
  270. package/{turn_runner-M2I8G2ok.js.map → turn_runner-CCZcsoDU.js.map} +1 -1
  271. package/{turn_runner-BV4BaZK9.mjs → turn_runner-DRPpVvsd.mjs} +5 -5
  272. package/{turn_runner-BV4BaZK9.mjs.map → turn_runner-DRPpVvsd.mjs.map} +1 -1
  273. package/turn_runner.cjs +1 -1
  274. package/turn_runner.mjs +1 -1
  275. package/{validate-JOHfh-BB.mjs → validate-C_hTnDBE.mjs} +95 -8
  276. package/validate-C_hTnDBE.mjs.map +1 -0
  277. package/{validate-DgDZkUKs.js → validate-gaSa9bsk.js} +95 -8
  278. package/validate-gaSa9bsk.js.map +1 -0
  279. package/xlsx-B0sTpEC2.js +30615 -0
  280. package/xlsx-B0sTpEC2.js.map +1 -0
  281. package/xlsx-DiMpn_Xv.mjs +30596 -0
  282. package/xlsx-DiMpn_Xv.mjs.map +1 -0
  283. package/xlsx.zahl-D2_Q-Xs4.mjs +6 -0
  284. package/xlsx.zahl-D2_Q-Xs4.mjs.map +1 -0
  285. package/xlsx.zahl-ZIcUQVv8.js +7 -0
  286. package/xlsx.zahl-ZIcUQVv8.js.map +1 -0
  287. package/tool_registry-BaLUIzWz.mjs.map +0 -1
  288. package/tool_registry-BdKlPuHS.js.map +0 -1
  289. package/validate-DgDZkUKs.js.map +0 -1
  290. package/validate-JOHfh-BB.mjs.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"jimp.mjs","names":[],"sources":["../../../../src/batteries/media/engines/jimp.ts"],"sourcesContent":["/**\n * A cross-environment image {@link @nhtio/adk/batteries/media/contracts!MediaEngine}\n * backed by Jimp (pure JavaScript — no native bindings, no binaries).\n *\n * @module @nhtio/adk/batteries/media/engines/jimp\n *\n * @remarks\n * The local-by-default raster engine: runs anywhere TypeScript runs. Declares one mutate\n * capability over png/jpeg/bmp/gif/tiff with resize (cover/contain approximations), rotate,\n * flip, quality, and metadata stripping (Jimp re-encodes pixels, so EXIF never survives —\n * `strip_metadata` is inherently satisfied). For webp/avif output or native-speed processing,\n * compose a sharp-backed engine instead — the capability declaration is the seam.\n *\n * `jimp` is an optional peer dependency, lazily imported on first actual use (constructing\n * the engine — and therefore the pipeline — never loads it).\n */\n\nimport { isError } from '@nhtio/adk/guards'\nimport { E_INVALID_MEDIA_PIPELINE_CONFIG } from '../exceptions'\nimport type * as JimpNS from 'jimp'\nimport type { MediaEngine, MutateRequest, EngineBytesResult } from '../contracts'\n\ntype JimpModule = typeof JimpNS\n\n/** Options for {@link jimpEngine}. */\nexport interface JimpEngineOptions {\n /** Override the module resolution (tests / custom builds). Default: `import('jimp')`. */\n jimp?: () => JimpModule | Promise<JimpModule>\n}\n\nconst SUPPORTED_OUTPUT = ['png', 'jpg', 'jpeg', 'bmp', 'gif', 'tiff'] as const\n\nconst MIME_BY_FORMAT: Record<string, string> = {\n png: 'image/png',\n jpg: 'image/jpeg',\n jpeg: 'image/jpeg',\n bmp: 'image/bmp',\n gif: 'image/gif',\n tiff: 'image/tiff',\n}\n\n/**\n * Construct the Jimp-backed image engine.\n *\n * @param options - Optional module resolver override.\n * @returns The engine.\n */\nexport const jimpEngine = (options: JimpEngineOptions = {}): MediaEngine => {\n let modPromise: Promise<JimpModule> | undefined\n const getJimp = (): Promise<JimpModule> => {\n modPromise ??= Promise.resolve(options.jimp ? options.jimp() : import('jimp')).catch((err) => {\n const detail = isError(err) ? err.message : String(err)\n throw new E_INVALID_MEDIA_PIPELINE_CONFIG([\n `the jimp engine could not load its peer dependency \"jimp\": ${detail} — install it (pnpm add jimp)`,\n ])\n })\n return modPromise\n }\n\n const mutate = async (request: MutateRequest): Promise<EngineBytesResult> => {\n const { Jimp } = await getJimp()\n const image = await Jimp.read(\n request.bytes.buffer.slice(\n request.bytes.byteOffset,\n request.bytes.byteOffset + request.bytes.byteLength\n ) as ArrayBuffer\n )\n\n if (request.resize) {\n const { width, height, fit } = request.resize\n if (width !== undefined && height !== undefined) {\n if (fit === 'cover') image.cover({ w: width, h: height })\n else if (fit === 'contain') image.contain({ w: width, h: height })\n else image.resize({ w: width, h: height })\n } else if (width !== undefined) {\n image.resize({ w: width })\n } else if (height !== undefined) {\n image.resize({ h: height })\n }\n }\n if (request.rotate) {\n image.rotate(request.rotate)\n }\n if (request.flip) {\n image.flip({\n horizontal: request.flip.horizontal === true,\n vertical: request.flip.vertical === true,\n })\n }\n\n const targetFormat = request.format?.to ?? mimeToFormat(request.mimeType)\n const mimeType = MIME_BY_FORMAT[targetFormat]\n if (!mimeType) {\n throw new Error(\n `jimp cannot encode \"${targetFormat}\"; supported: ${SUPPORTED_OUTPUT.join(', ')} (compose a sharp engine for webp/avif)`\n )\n }\n const quality = request.format?.quality\n const buffer =\n mimeType === 'image/jpeg' && quality !== undefined\n ? await image.getBuffer('image/jpeg', { quality })\n : await image.getBuffer(mimeType as 'image/png')\n return { bytes: new Uint8Array(buffer), mimeType }\n }\n\n return {\n id: 'jimp',\n mutates: [\n {\n over: ['image/png', 'image/jpeg', 'image/bmp', 'image/gif', 'image/tiff'],\n ops: ['resize', 'rotate', 'flip', 'strip_metadata'],\n encodes: SUPPORTED_OUTPUT,\n mutate,\n },\n ],\n }\n}\n\nconst mimeToFormat = (mimeType: string): string => {\n const sub = mimeType.toLowerCase().split(';')[0].trim().split('/')[1] ?? 'png'\n return sub === 'jpeg' ? 'jpg' : sub\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AA8BA,IAAM,mBAAmB;CAAC;CAAO;CAAO;CAAQ;CAAO;CAAO;AAAM;AAEpE,IAAM,iBAAyC;CAC7C,KAAK;CACL,KAAK;CACL,MAAM;CACN,KAAK;CACL,KAAK;CACL,MAAM;AACR;;;;;;;AAQA,IAAa,cAAc,UAA6B,CAAC,MAAmB;CAC1E,IAAI;CACJ,MAAM,gBAAqC;EACzC,eAAe,QAAQ,QAAQ,QAAQ,OAAO,QAAQ,KAAK,IAAI,OAAO,OAAO,EAAE,OAAO,QAAQ;GAE5F,MAAM,IAAI,gCAAgC,CACxC,8DAFa,QAAQ,GAAG,IAAI,IAAI,UAAU,OAAO,GAAG,EAEiB,8BACvE,CAAC;EACH,CAAC;EACD,OAAO;CACT;CAEA,MAAM,SAAS,OAAO,YAAuD;EAC3E,MAAM,EAAE,SAAS,MAAM,QAAQ;EAC/B,MAAM,QAAQ,MAAM,KAAK,KACvB,QAAQ,MAAM,OAAO,MACnB,QAAQ,MAAM,YACd,QAAQ,MAAM,aAAa,QAAQ,MAAM,UAC3C,CACF;EAEA,IAAI,QAAQ,QAAQ;GAClB,MAAM,EAAE,OAAO,QAAQ,QAAQ,QAAQ;GACvC,IAAI,UAAU,KAAA,KAAa,WAAW,KAAA,GACpC,IAAI,QAAQ,SAAS,MAAM,MAAM;IAAE,GAAG;IAAO,GAAG;GAAO,CAAC;QACnD,IAAI,QAAQ,WAAW,MAAM,QAAQ;IAAE,GAAG;IAAO,GAAG;GAAO,CAAC;QAC5D,MAAM,OAAO;IAAE,GAAG;IAAO,GAAG;GAAO,CAAC;QACpC,IAAI,UAAU,KAAA,GACnB,MAAM,OAAO,EAAE,GAAG,MAAM,CAAC;QACpB,IAAI,WAAW,KAAA,GACpB,MAAM,OAAO,EAAE,GAAG,OAAO,CAAC;EAE9B;EACA,IAAI,QAAQ,QACV,MAAM,OAAO,QAAQ,MAAM;EAE7B,IAAI,QAAQ,MACV,MAAM,KAAK;GACT,YAAY,QAAQ,KAAK,eAAe;GACxC,UAAU,QAAQ,KAAK,aAAa;EACtC,CAAC;EAGH,MAAM,eAAe,QAAQ,QAAQ,MAAM,aAAa,QAAQ,QAAQ;EACxE,MAAM,WAAW,eAAe;EAChC,IAAI,CAAC,UACH,MAAM,IAAI,MACR,uBAAuB,aAAa,gBAAgB,iBAAiB,KAAK,IAAI,EAAE,wCAClF;EAEF,MAAM,UAAU,QAAQ,QAAQ;EAChC,MAAM,SACJ,aAAa,gBAAgB,YAAY,KAAA,IACrC,MAAM,MAAM,UAAU,cAAc,EAAE,QAAQ,CAAC,IAC/C,MAAM,MAAM,UAAU,QAAuB;EACnD,OAAO;GAAE,OAAO,IAAI,WAAW,MAAM;GAAG;EAAS;CACnD;CAEA,OAAO;EACL,IAAI;EACJ,SAAS,CACP;GACE,MAAM;IAAC;IAAa;IAAc;IAAa;IAAa;GAAY;GACxE,KAAK;IAAC;IAAU;IAAU;IAAQ;GAAgB;GAClD,SAAS;GACT;EACF,CACF;CACF;AACF;AAEA,IAAM,gBAAgB,aAA6B;CACjD,MAAM,MAAM,SAAS,YAAY,EAAE,MAAM,GAAG,EAAE,GAAG,KAAK,EAAE,MAAM,GAAG,EAAE,MAAM;CACzE,OAAO,QAAQ,SAAS,QAAQ;AAClC"}
1
+ {"version":3,"file":"jimp.mjs","names":[],"sources":["../../../../src/batteries/media/engines/jimp.ts"],"sourcesContent":["/**\n * A cross-environment image {@link @nhtio/adk/batteries/media/contracts!MediaEngine}\n * backed by Jimp (pure JavaScript — no native bindings, no binaries).\n *\n * @module @nhtio/adk/batteries/media/engines/jimp\n *\n * @remarks\n * The local-by-default raster engine: runs anywhere TypeScript runs. Declares one mutate\n * capability over png/jpeg/bmp/gif/tiff with resize (cover/contain approximations), rotate,\n * flip, quality, and metadata stripping (Jimp re-encodes pixels, so EXIF never survives —\n * `strip_metadata` is inherently satisfied), plus a generation edge: `EMPTY_MIME` → a blank\n * 1024×1024 white canvas in any supported encoding (resize in the same statement —\n * `empty:png | image resize width=64`). For webp/avif output or native-speed processing,\n * compose a sharp-backed engine instead — the capability declaration is the seam.\n *\n * `jimp` is an optional peer dependency, lazily imported on first actual use (constructing\n * the engine — and therefore the pipeline — never loads it).\n */\n\nimport { EMPTY_MIME } from '../contracts'\nimport { isError } from '@nhtio/adk/guards'\nimport { E_INVALID_MEDIA_PIPELINE_CONFIG } from '../exceptions'\nimport type * as JimpNS from 'jimp'\nimport type {\n MediaEngine,\n MutateRequest,\n EngineBytesResult,\n ConvertRequest,\n ConvertResult,\n} from '../contracts'\n\ntype JimpModule = typeof JimpNS\n\n/** Options for {@link jimpEngine}. */\nexport interface JimpEngineOptions {\n /** Override the module resolution (tests / custom builds). Default: `import('jimp')`. */\n jimp?: () => JimpModule | Promise<JimpModule>\n}\n\nconst SUPPORTED_OUTPUT = ['png', 'jpg', 'jpeg', 'bmp', 'gif', 'tiff'] as const\n\nconst MIME_BY_FORMAT: Record<string, string> = {\n png: 'image/png',\n jpg: 'image/jpeg',\n jpeg: 'image/jpeg',\n bmp: 'image/bmp',\n gif: 'image/gif',\n tiff: 'image/tiff',\n}\n\n/**\n * Construct the Jimp-backed image engine.\n *\n * @param options - Optional module resolver override.\n * @returns The engine.\n */\nexport const jimpEngine = (options: JimpEngineOptions = {}): MediaEngine => {\n let modPromise: Promise<JimpModule> | undefined\n const getJimp = (): Promise<JimpModule> => {\n modPromise ??= Promise.resolve(options.jimp ? options.jimp() : import('jimp')).catch((err) => {\n const detail = isError(err) ? err.message : String(err)\n throw new E_INVALID_MEDIA_PIPELINE_CONFIG([\n `the jimp engine could not load its peer dependency \"jimp\": ${detail} — install it (pnpm add jimp)`,\n ])\n })\n return modPromise\n }\n\n const mutate = async (request: MutateRequest): Promise<EngineBytesResult> => {\n const { Jimp } = await getJimp()\n const image = await Jimp.read(\n request.bytes.buffer.slice(\n request.bytes.byteOffset,\n request.bytes.byteOffset + request.bytes.byteLength\n ) as ArrayBuffer\n )\n\n if (request.resize) {\n const { width, height, fit } = request.resize\n if (width !== undefined && height !== undefined) {\n if (fit === 'cover') image.cover({ w: width, h: height })\n else if (fit === 'contain') image.contain({ w: width, h: height })\n else image.resize({ w: width, h: height })\n } else if (width !== undefined) {\n image.resize({ w: width })\n } else if (height !== undefined) {\n image.resize({ h: height })\n }\n }\n if (request.rotate) {\n image.rotate(request.rotate)\n }\n if (request.flip) {\n image.flip({\n horizontal: request.flip.horizontal === true,\n vertical: request.flip.vertical === true,\n })\n }\n\n const targetFormat = request.format?.to ?? mimeToFormat(request.mimeType)\n const mimeType = MIME_BY_FORMAT[targetFormat]\n if (!mimeType) {\n throw new Error(\n `jimp cannot encode \"${targetFormat}\"; supported: ${SUPPORTED_OUTPUT.join(', ')} (compose a sharp engine for webp/avif)`\n )\n }\n const quality = request.format?.quality\n const buffer =\n mimeType === 'image/jpeg' && quality !== undefined\n ? await image.getBuffer('image/jpeg', { quality })\n : await image.getBuffer(mimeType as 'image/png')\n return { bytes: new Uint8Array(buffer), mimeType }\n }\n\n // Generation: a blank 1024×1024 white canvas, encoded to the requested format.\n const convert = async (request: ConvertRequest): Promise<ConvertResult> => {\n const mimeType = MIME_BY_FORMAT[request.to]\n if (!mimeType) {\n throw new Error(\n `jimp cannot generate \"${request.to}\"; supported: ${SUPPORTED_OUTPUT.join(', ')}`\n )\n }\n const { Jimp } = await getJimp()\n const image = new Jimp({ width: 1024, height: 1024, color: 0xffffffff })\n const buffer = await image.getBuffer(mimeType as 'image/png')\n return { outputs: [{ bytes: new Uint8Array(buffer), mimeType }] }\n }\n\n return {\n id: 'jimp',\n converts: [{ from: [EMPTY_MIME], to: SUPPORTED_OUTPUT, convert }],\n mutates: [\n {\n over: ['image/png', 'image/jpeg', 'image/bmp', 'image/gif', 'image/tiff'],\n ops: ['resize', 'rotate', 'flip', 'strip_metadata'],\n encodes: SUPPORTED_OUTPUT,\n mutate,\n },\n ],\n }\n}\n\nconst mimeToFormat = (mimeType: string): string => {\n const sub = mimeType.toLowerCase().split(';')[0].trim().split('/')[1] ?? 'png'\n return sub === 'jpeg' ? 'jpg' : sub\n}\n"],"mappings":"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"}
@@ -1,7 +1,8 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
2
  require("../../../chunk-Cek0wNdY.js");
3
- const require_tool_registry = require("../../../tool_registry-BdKlPuHS.js");
3
+ const require_tool_registry = require("../../../tool_registry-DwZ6pzN4.js");
4
4
  require("../../../guards.cjs");
5
+ const require_batteries_media_contracts = require("../contracts.cjs");
5
6
  const require_exceptions = require("../../../exceptions-D79HIKeX.js");
6
7
  //#region src/batteries/media/engines/sharp.ts
7
8
  /**
@@ -12,9 +13,11 @@ const require_exceptions = require("../../../exceptions-D79HIKeX.js");
12
13
  *
13
14
  * @remarks
14
15
  * The performance/fidelity engine for Node deployments: native speed plus webp/avif output
15
- * and the full `fit` mode set. sharp is permanently Node-only (native bindings); for a
16
- * cross-environment engine compose the jimp implementation instead the capability
17
- * declaration is the seam, and BYO instances adapt via {@link fromSharp}.
16
+ * and the full `fit` mode set, plus a generation edge `EMPTY_MIME` a blank 1024×1024
17
+ * white canvas in any supported encoding (resize in the same statement). sharp is permanently
18
+ * Node-only (native bindings); for a cross-environment engine compose the jimp implementation
19
+ * instead — the capability declaration is the seam, and BYO instances adapt via
20
+ * {@link fromSharp}.
18
21
  *
19
22
  * `sharp` is an optional peer dependency, lazily imported on first actual use.
20
23
  */
@@ -82,6 +85,34 @@ var capabilityOf = (run) => ({
82
85
  mutate: run
83
86
  });
84
87
  /**
88
+ * Build the generation capability over a sharp source: `EMPTY_MIME` → a blank 1024×1024
89
+ * white canvas (3 channels, so jpeg never trips on alpha) in any supported encoding.
90
+ */
91
+ var blankCapability = (getSharp) => ({
92
+ from: [require_batteries_media_contracts.EMPTY_MIME],
93
+ to: SUPPORTED_OUTPUT,
94
+ convert: async (request) => {
95
+ const mimeType = MIME_BY_FORMAT[request.to];
96
+ if (!mimeType) throw new Error(`sharp cannot generate "${request.to}"; supported: ${SUPPORTED_OUTPUT.join(", ")}`);
97
+ const sharp = await getSharp();
98
+ const formatKey = request.to === "jpg" ? "jpeg" : request.to;
99
+ const buffer = await sharp({ create: {
100
+ width: 1024,
101
+ height: 1024,
102
+ channels: 3,
103
+ background: {
104
+ r: 255,
105
+ g: 255,
106
+ b: 255
107
+ }
108
+ } }).toFormat(formatKey).toBuffer();
109
+ return { outputs: [{
110
+ bytes: new Uint8Array(buffer),
111
+ mimeType
112
+ }] };
113
+ }
114
+ });
115
+ /**
85
116
  * Construct the sharp-backed image engine.
86
117
  *
87
118
  * @param options - Optional module resolver override.
@@ -95,6 +126,7 @@ var sharpEngine = (options = {}) => {
95
126
  };
96
127
  return {
97
128
  id: "sharp",
129
+ converts: [blankCapability(getSharp)],
98
130
  mutates: [capabilityOf(async (request) => runTransform(await getSharp(), request))]
99
131
  };
100
132
  };
@@ -107,6 +139,7 @@ var sharpEngine = (options = {}) => {
107
139
  */
108
140
  var fromSharp = (sharp) => ({
109
141
  id: "sharp",
142
+ converts: [blankCapability(async () => sharp)],
110
143
  mutates: [capabilityOf(async (request) => runTransform(sharp, request))]
111
144
  });
112
145
  var mimeToFormat = (mimeType) => {
@@ -1 +1 @@
1
- {"version":3,"file":"sharp.cjs","names":[],"sources":["../../../../src/batteries/media/engines/sharp.ts"],"sourcesContent":["/**\n * A Node-native image {@link @nhtio/adk/batteries/media/contracts!MediaEngine}\n * backed by sharp (libvips bindings — fast, full-format).\n *\n * @module @nhtio/adk/batteries/media/engines/sharp\n *\n * @remarks\n * The performance/fidelity engine for Node deployments: native speed plus webp/avif output\n * and the full `fit` mode set. sharp is permanently Node-only (native bindings); for a\n * cross-environment engine compose the jimp implementation instead — the capability\n * declaration is the seam, and BYO instances adapt via {@link fromSharp}.\n *\n * `sharp` is an optional peer dependency, lazily imported on first actual use.\n */\n\nimport { isError } from '@nhtio/adk/guards'\nimport { default as SharpDefault } from 'sharp'\nimport { E_INVALID_MEDIA_PIPELINE_CONFIG } from '../exceptions'\nimport type { MediaEngine, MutateCapability, MutateRequest, EngineBytesResult } from '../contracts'\n\ntype SharpFn = typeof SharpDefault\n\n/** Options for {@link sharpEngine}. */\nexport interface SharpEngineOptions {\n /** Override the module resolution (electron/custom builds). Default: `import('sharp')`. */\n sharp?: () => SharpFn | { default: SharpFn } | Promise<SharpFn | { default: SharpFn }>\n}\n\nconst SUPPORTED_OUTPUT = ['png', 'jpg', 'jpeg', 'webp', 'tiff', 'avif', 'gif'] as const\n\nconst MIME_BY_FORMAT: Record<string, string> = {\n png: 'image/png',\n jpg: 'image/jpeg',\n jpeg: 'image/jpeg',\n webp: 'image/webp',\n tiff: 'image/tiff',\n avif: 'image/avif',\n gif: 'image/gif',\n}\n\nconst resolveSharp = async (supplied: SharpEngineOptions['sharp']): Promise<SharpFn> => {\n try {\n const mod = await (supplied ? supplied() : import('sharp'))\n const fn = typeof mod === 'function' ? mod : (mod as { default: SharpFn }).default\n if (typeof fn !== 'function') throw new Error('sharp did not resolve to a function')\n return fn\n } catch (err) {\n const detail = isError(err) ? err.message : String(err)\n throw new E_INVALID_MEDIA_PIPELINE_CONFIG([\n `the sharp engine could not load its peer dependency \"sharp\": ${detail} — install it (pnpm add sharp); note sharp is Node-only`,\n ])\n }\n}\n\n/** Run a fused mutate request through a sharp instance function. */\nconst runTransform = async (sharp: SharpFn, request: MutateRequest): Promise<EngineBytesResult> => {\n let img = sharp(request.bytes)\n if (request.rotate) img = img.rotate(request.rotate)\n if (request.flip?.vertical) img = img.flip()\n if (request.flip?.horizontal) img = img.flop()\n if (\n request.resize &&\n (request.resize.width !== undefined || request.resize.height !== undefined)\n ) {\n img = img.resize({\n width: request.resize.width,\n height: request.resize.height,\n fit: request.resize.fit ?? 'cover',\n })\n }\n const target = request.format?.to ?? mimeToFormat(request.mimeType)\n const mimeType = MIME_BY_FORMAT[target]\n if (!mimeType) {\n throw new Error(`sharp cannot encode \"${target}\"; supported: ${SUPPORTED_OUTPUT.join(', ')}`)\n }\n const formatKey = (target === 'jpg' ? 'jpeg' : target) as\n | 'png'\n | 'jpeg'\n | 'webp'\n | 'tiff'\n | 'avif'\n | 'gif'\n img = img.toFormat(\n formatKey,\n request.format?.quality !== undefined ? { quality: request.format.quality } : {}\n )\n if (request.stripMetadata !== true) {\n // sharp strips metadata by default; keep it when NOT asked to strip.\n img = img.keepMetadata()\n }\n const buffer = await img.toBuffer()\n return { bytes: new Uint8Array(buffer), mimeType }\n}\n\n/** Build the single mutate capability over a sharp source. */\nconst capabilityOf = (\n run: (request: MutateRequest) => Promise<EngineBytesResult>\n): MutateCapability => ({\n over: ['image/*'],\n ops: ['resize', 'rotate', 'flip', 'strip_metadata'],\n encodes: SUPPORTED_OUTPUT,\n mutate: run,\n})\n\n/**\n * Construct the sharp-backed image engine.\n *\n * @param options - Optional module resolver override.\n * @returns The engine.\n */\nexport const sharpEngine = (options: SharpEngineOptions = {}): MediaEngine => {\n let sharpPromise: Promise<SharpFn> | undefined\n const getSharp = (): Promise<SharpFn> => {\n sharpPromise ??= resolveSharp(options.sharp)\n return sharpPromise\n }\n return {\n id: 'sharp',\n mutates: [capabilityOf(async (request) => runTransform(await getSharp(), request))],\n }\n}\n\n/**\n * Adapt an already-configured sharp module (your import, your build flags) to the engine\n * contract — the BYO transformer.\n *\n * @param sharp - The sharp function you imported.\n * @returns The engine.\n */\nexport const fromSharp = (sharp: SharpFn): MediaEngine => ({\n id: 'sharp',\n mutates: [capabilityOf(async (request) => runTransform(sharp, request))],\n})\n\nconst mimeToFormat = (mimeType: string): string => {\n const sub = mimeType.toLowerCase().split(';')[0].trim().split('/')[1] ?? 'png'\n return sub === 'jpeg' ? 'jpg' : sub\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AA4BA,IAAM,mBAAmB;CAAC;CAAO;CAAO;CAAQ;CAAQ;CAAQ;CAAQ;AAAK;AAE7E,IAAM,iBAAyC;CAC7C,KAAK;CACL,KAAK;CACL,MAAM;CACN,MAAM;CACN,MAAM;CACN,MAAM;CACN,KAAK;AACP;AAEA,IAAM,eAAe,OAAO,aAA4D;CACtF,IAAI;EACF,MAAM,MAAM,OAAO,WAAW,SAAS,IAAI,OAAO;EAClD,MAAM,KAAK,OAAO,QAAQ,aAAa,MAAO,IAA6B;EAC3E,IAAI,OAAO,OAAO,YAAY,MAAM,IAAI,MAAM,qCAAqC;EACnF,OAAO;CACT,SAAS,KAAK;EAEZ,MAAM,IAAI,mBAAA,gCAAgC,CACxC,gEAFa,sBAAA,QAAQ,GAAG,IAAI,IAAI,UAAU,OAAO,GAAG,EAEmB,wDACzE,CAAC;CACH;AACF;;AAGA,IAAM,eAAe,OAAO,OAAgB,YAAuD;CACjG,IAAI,MAAM,MAAM,QAAQ,KAAK;CAC7B,IAAI,QAAQ,QAAQ,MAAM,IAAI,OAAO,QAAQ,MAAM;CACnD,IAAI,QAAQ,MAAM,UAAU,MAAM,IAAI,KAAK;CAC3C,IAAI,QAAQ,MAAM,YAAY,MAAM,IAAI,KAAK;CAC7C,IACE,QAAQ,WACP,QAAQ,OAAO,UAAU,KAAA,KAAa,QAAQ,OAAO,WAAW,KAAA,IAEjE,MAAM,IAAI,OAAO;EACf,OAAO,QAAQ,OAAO;EACtB,QAAQ,QAAQ,OAAO;EACvB,KAAK,QAAQ,OAAO,OAAO;CAC7B,CAAC;CAEH,MAAM,SAAS,QAAQ,QAAQ,MAAM,aAAa,QAAQ,QAAQ;CAClE,MAAM,WAAW,eAAe;CAChC,IAAI,CAAC,UACH,MAAM,IAAI,MAAM,wBAAwB,OAAO,gBAAgB,iBAAiB,KAAK,IAAI,GAAG;CAE9F,MAAM,YAAa,WAAW,QAAQ,SAAS;CAO/C,MAAM,IAAI,SACR,WACA,QAAQ,QAAQ,YAAY,KAAA,IAAY,EAAE,SAAS,QAAQ,OAAO,QAAQ,IAAI,CAAC,CACjF;CACA,IAAI,QAAQ,kBAAkB,MAE5B,MAAM,IAAI,aAAa;CAEzB,MAAM,SAAS,MAAM,IAAI,SAAS;CAClC,OAAO;EAAE,OAAO,IAAI,WAAW,MAAM;EAAG;CAAS;AACnD;;AAGA,IAAM,gBACJ,SACsB;CACtB,MAAM,CAAC,SAAS;CAChB,KAAK;EAAC;EAAU;EAAU;EAAQ;CAAgB;CAClD,SAAS;CACT,QAAQ;AACV;;;;;;;AAQA,IAAa,eAAe,UAA8B,CAAC,MAAmB;CAC5E,IAAI;CACJ,MAAM,iBAAmC;EACvC,iBAAiB,aAAa,QAAQ,KAAK;EAC3C,OAAO;CACT;CACA,OAAO;EACL,IAAI;EACJ,SAAS,CAAC,aAAa,OAAO,YAAY,aAAa,MAAM,SAAS,GAAG,OAAO,CAAC,CAAC;CACpF;AACF;;;;;;;;AASA,IAAa,aAAa,WAAiC;CACzD,IAAI;CACJ,SAAS,CAAC,aAAa,OAAO,YAAY,aAAa,OAAO,OAAO,CAAC,CAAC;AACzE;AAEA,IAAM,gBAAgB,aAA6B;CACjD,MAAM,MAAM,SAAS,YAAY,EAAE,MAAM,GAAG,EAAE,GAAG,KAAK,EAAE,MAAM,GAAG,EAAE,MAAM;CACzE,OAAO,QAAQ,SAAS,QAAQ;AAClC"}
1
+ {"version":3,"file":"sharp.cjs","names":[],"sources":["../../../../src/batteries/media/engines/sharp.ts"],"sourcesContent":["/**\n * A Node-native image {@link @nhtio/adk/batteries/media/contracts!MediaEngine}\n * backed by sharp (libvips bindings — fast, full-format).\n *\n * @module @nhtio/adk/batteries/media/engines/sharp\n *\n * @remarks\n * The performance/fidelity engine for Node deployments: native speed plus webp/avif output\n * and the full `fit` mode set, plus a generation edge — `EMPTY_MIME` → a blank 1024×1024\n * white canvas in any supported encoding (resize in the same statement). sharp is permanently\n * Node-only (native bindings); for a cross-environment engine compose the jimp implementation\n * instead — the capability declaration is the seam, and BYO instances adapt via\n * {@link fromSharp}.\n *\n * `sharp` is an optional peer dependency, lazily imported on first actual use.\n */\n\nimport { EMPTY_MIME } from '../contracts'\nimport { isError } from '@nhtio/adk/guards'\nimport { default as SharpDefault } from 'sharp'\nimport { E_INVALID_MEDIA_PIPELINE_CONFIG } from '../exceptions'\nimport type {\n MediaEngine,\n MutateCapability,\n MutateRequest,\n EngineBytesResult,\n ConvertCapability,\n ConvertRequest,\n ConvertResult,\n} from '../contracts'\n\ntype SharpFn = typeof SharpDefault\n\n/** Options for {@link sharpEngine}. */\nexport interface SharpEngineOptions {\n /** Override the module resolution (electron/custom builds). Default: `import('sharp')`. */\n sharp?: () => SharpFn | { default: SharpFn } | Promise<SharpFn | { default: SharpFn }>\n}\n\nconst SUPPORTED_OUTPUT = ['png', 'jpg', 'jpeg', 'webp', 'tiff', 'avif', 'gif'] as const\n\nconst MIME_BY_FORMAT: Record<string, string> = {\n png: 'image/png',\n jpg: 'image/jpeg',\n jpeg: 'image/jpeg',\n webp: 'image/webp',\n tiff: 'image/tiff',\n avif: 'image/avif',\n gif: 'image/gif',\n}\n\nconst resolveSharp = async (supplied: SharpEngineOptions['sharp']): Promise<SharpFn> => {\n try {\n const mod = await (supplied ? supplied() : import('sharp'))\n const fn = typeof mod === 'function' ? mod : (mod as { default: SharpFn }).default\n if (typeof fn !== 'function') throw new Error('sharp did not resolve to a function')\n return fn\n } catch (err) {\n const detail = isError(err) ? err.message : String(err)\n throw new E_INVALID_MEDIA_PIPELINE_CONFIG([\n `the sharp engine could not load its peer dependency \"sharp\": ${detail} — install it (pnpm add sharp); note sharp is Node-only`,\n ])\n }\n}\n\n/** Run a fused mutate request through a sharp instance function. */\nconst runTransform = async (sharp: SharpFn, request: MutateRequest): Promise<EngineBytesResult> => {\n let img = sharp(request.bytes)\n if (request.rotate) img = img.rotate(request.rotate)\n if (request.flip?.vertical) img = img.flip()\n if (request.flip?.horizontal) img = img.flop()\n if (\n request.resize &&\n (request.resize.width !== undefined || request.resize.height !== undefined)\n ) {\n img = img.resize({\n width: request.resize.width,\n height: request.resize.height,\n fit: request.resize.fit ?? 'cover',\n })\n }\n const target = request.format?.to ?? mimeToFormat(request.mimeType)\n const mimeType = MIME_BY_FORMAT[target]\n if (!mimeType) {\n throw new Error(`sharp cannot encode \"${target}\"; supported: ${SUPPORTED_OUTPUT.join(', ')}`)\n }\n const formatKey = (target === 'jpg' ? 'jpeg' : target) as\n | 'png'\n | 'jpeg'\n | 'webp'\n | 'tiff'\n | 'avif'\n | 'gif'\n img = img.toFormat(\n formatKey,\n request.format?.quality !== undefined ? { quality: request.format.quality } : {}\n )\n if (request.stripMetadata !== true) {\n // sharp strips metadata by default; keep it when NOT asked to strip.\n img = img.keepMetadata()\n }\n const buffer = await img.toBuffer()\n return { bytes: new Uint8Array(buffer), mimeType }\n}\n\n/** Build the single mutate capability over a sharp source. */\nconst capabilityOf = (\n run: (request: MutateRequest) => Promise<EngineBytesResult>\n): MutateCapability => ({\n over: ['image/*'],\n ops: ['resize', 'rotate', 'flip', 'strip_metadata'],\n encodes: SUPPORTED_OUTPUT,\n mutate: run,\n})\n\n/**\n * Build the generation capability over a sharp source: `EMPTY_MIME` → a blank 1024×1024\n * white canvas (3 channels, so jpeg never trips on alpha) in any supported encoding.\n */\nconst blankCapability = (getSharp: () => Promise<SharpFn>): ConvertCapability => ({\n from: [EMPTY_MIME],\n to: SUPPORTED_OUTPUT,\n convert: async (request: ConvertRequest): Promise<ConvertResult> => {\n const mimeType = MIME_BY_FORMAT[request.to]\n if (!mimeType) {\n throw new Error(\n `sharp cannot generate \"${request.to}\"; supported: ${SUPPORTED_OUTPUT.join(', ')}`\n )\n }\n const sharp = await getSharp()\n const formatKey = (request.to === 'jpg' ? 'jpeg' : request.to) as\n | 'png'\n | 'jpeg'\n | 'webp'\n | 'tiff'\n | 'avif'\n | 'gif'\n const buffer = await sharp({\n create: { width: 1024, height: 1024, channels: 3, background: { r: 255, g: 255, b: 255 } },\n })\n .toFormat(formatKey)\n .toBuffer()\n return { outputs: [{ bytes: new Uint8Array(buffer), mimeType }] }\n },\n})\n\n/**\n * Construct the sharp-backed image engine.\n *\n * @param options - Optional module resolver override.\n * @returns The engine.\n */\nexport const sharpEngine = (options: SharpEngineOptions = {}): MediaEngine => {\n let sharpPromise: Promise<SharpFn> | undefined\n const getSharp = (): Promise<SharpFn> => {\n sharpPromise ??= resolveSharp(options.sharp)\n return sharpPromise\n }\n return {\n id: 'sharp',\n converts: [blankCapability(getSharp)],\n mutates: [capabilityOf(async (request) => runTransform(await getSharp(), request))],\n }\n}\n\n/**\n * Adapt an already-configured sharp module (your import, your build flags) to the engine\n * contract — the BYO transformer.\n *\n * @param sharp - The sharp function you imported.\n * @returns The engine.\n */\nexport const fromSharp = (sharp: SharpFn): MediaEngine => ({\n id: 'sharp',\n converts: [blankCapability(async () => sharp)],\n mutates: [capabilityOf(async (request) => runTransform(sharp, request))],\n})\n\nconst mimeToFormat = (mimeType: string): string => {\n const sub = mimeType.toLowerCase().split(';')[0].trim().split('/')[1] ?? 'png'\n return sub === 'jpeg' ? 'jpg' : sub\n}\n"],"mappings":"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"}
@@ -6,9 +6,11 @@
6
6
  *
7
7
  * @remarks
8
8
  * The performance/fidelity engine for Node deployments: native speed plus webp/avif output
9
- * and the full `fit` mode set. sharp is permanently Node-only (native bindings); for a
10
- * cross-environment engine compose the jimp implementation instead the capability
11
- * declaration is the seam, and BYO instances adapt via {@link fromSharp}.
9
+ * and the full `fit` mode set, plus a generation edge `EMPTY_MIME` a blank 1024×1024
10
+ * white canvas in any supported encoding (resize in the same statement). sharp is permanently
11
+ * Node-only (native bindings); for a cross-environment engine compose the jimp implementation
12
+ * instead — the capability declaration is the seam, and BYO instances adapt via
13
+ * {@link fromSharp}.
12
14
  *
13
15
  * `sharp` is an optional peer dependency, lazily imported on first actual use.
14
16
  */
@@ -1,5 +1,6 @@
1
- import { o as isError } from "../../../tool_registry-BaLUIzWz.mjs";
1
+ import { o as isError } from "../../../tool_registry-CZ55mIti.mjs";
2
2
  import "../../../guards.mjs";
3
+ import { EMPTY_MIME } from "../contracts.mjs";
3
4
  import { t as E_INVALID_MEDIA_PIPELINE_CONFIG } from "../../../exceptions-BLTn4Ofs.mjs";
4
5
  //#region src/batteries/media/engines/sharp.ts
5
6
  /**
@@ -10,9 +11,11 @@ import { t as E_INVALID_MEDIA_PIPELINE_CONFIG } from "../../../exceptions-BLTn4O
10
11
  *
11
12
  * @remarks
12
13
  * The performance/fidelity engine for Node deployments: native speed plus webp/avif output
13
- * and the full `fit` mode set. sharp is permanently Node-only (native bindings); for a
14
- * cross-environment engine compose the jimp implementation instead the capability
15
- * declaration is the seam, and BYO instances adapt via {@link fromSharp}.
14
+ * and the full `fit` mode set, plus a generation edge `EMPTY_MIME` a blank 1024×1024
15
+ * white canvas in any supported encoding (resize in the same statement). sharp is permanently
16
+ * Node-only (native bindings); for a cross-environment engine compose the jimp implementation
17
+ * instead — the capability declaration is the seam, and BYO instances adapt via
18
+ * {@link fromSharp}.
16
19
  *
17
20
  * `sharp` is an optional peer dependency, lazily imported on first actual use.
18
21
  */
@@ -80,6 +83,34 @@ var capabilityOf = (run) => ({
80
83
  mutate: run
81
84
  });
82
85
  /**
86
+ * Build the generation capability over a sharp source: `EMPTY_MIME` → a blank 1024×1024
87
+ * white canvas (3 channels, so jpeg never trips on alpha) in any supported encoding.
88
+ */
89
+ var blankCapability = (getSharp) => ({
90
+ from: [EMPTY_MIME],
91
+ to: SUPPORTED_OUTPUT,
92
+ convert: async (request) => {
93
+ const mimeType = MIME_BY_FORMAT[request.to];
94
+ if (!mimeType) throw new Error(`sharp cannot generate "${request.to}"; supported: ${SUPPORTED_OUTPUT.join(", ")}`);
95
+ const sharp = await getSharp();
96
+ const formatKey = request.to === "jpg" ? "jpeg" : request.to;
97
+ const buffer = await sharp({ create: {
98
+ width: 1024,
99
+ height: 1024,
100
+ channels: 3,
101
+ background: {
102
+ r: 255,
103
+ g: 255,
104
+ b: 255
105
+ }
106
+ } }).toFormat(formatKey).toBuffer();
107
+ return { outputs: [{
108
+ bytes: new Uint8Array(buffer),
109
+ mimeType
110
+ }] };
111
+ }
112
+ });
113
+ /**
83
114
  * Construct the sharp-backed image engine.
84
115
  *
85
116
  * @param options - Optional module resolver override.
@@ -93,6 +124,7 @@ var sharpEngine = (options = {}) => {
93
124
  };
94
125
  return {
95
126
  id: "sharp",
127
+ converts: [blankCapability(getSharp)],
96
128
  mutates: [capabilityOf(async (request) => runTransform(await getSharp(), request))]
97
129
  };
98
130
  };
@@ -105,6 +137,7 @@ var sharpEngine = (options = {}) => {
105
137
  */
106
138
  var fromSharp = (sharp) => ({
107
139
  id: "sharp",
140
+ converts: [blankCapability(async () => sharp)],
108
141
  mutates: [capabilityOf(async (request) => runTransform(sharp, request))]
109
142
  });
110
143
  var mimeToFormat = (mimeType) => {
@@ -1 +1 @@
1
- {"version":3,"file":"sharp.mjs","names":[],"sources":["../../../../src/batteries/media/engines/sharp.ts"],"sourcesContent":["/**\n * A Node-native image {@link @nhtio/adk/batteries/media/contracts!MediaEngine}\n * backed by sharp (libvips bindings — fast, full-format).\n *\n * @module @nhtio/adk/batteries/media/engines/sharp\n *\n * @remarks\n * The performance/fidelity engine for Node deployments: native speed plus webp/avif output\n * and the full `fit` mode set. sharp is permanently Node-only (native bindings); for a\n * cross-environment engine compose the jimp implementation instead — the capability\n * declaration is the seam, and BYO instances adapt via {@link fromSharp}.\n *\n * `sharp` is an optional peer dependency, lazily imported on first actual use.\n */\n\nimport { isError } from '@nhtio/adk/guards'\nimport { default as SharpDefault } from 'sharp'\nimport { E_INVALID_MEDIA_PIPELINE_CONFIG } from '../exceptions'\nimport type { MediaEngine, MutateCapability, MutateRequest, EngineBytesResult } from '../contracts'\n\ntype SharpFn = typeof SharpDefault\n\n/** Options for {@link sharpEngine}. */\nexport interface SharpEngineOptions {\n /** Override the module resolution (electron/custom builds). Default: `import('sharp')`. */\n sharp?: () => SharpFn | { default: SharpFn } | Promise<SharpFn | { default: SharpFn }>\n}\n\nconst SUPPORTED_OUTPUT = ['png', 'jpg', 'jpeg', 'webp', 'tiff', 'avif', 'gif'] as const\n\nconst MIME_BY_FORMAT: Record<string, string> = {\n png: 'image/png',\n jpg: 'image/jpeg',\n jpeg: 'image/jpeg',\n webp: 'image/webp',\n tiff: 'image/tiff',\n avif: 'image/avif',\n gif: 'image/gif',\n}\n\nconst resolveSharp = async (supplied: SharpEngineOptions['sharp']): Promise<SharpFn> => {\n try {\n const mod = await (supplied ? supplied() : import('sharp'))\n const fn = typeof mod === 'function' ? mod : (mod as { default: SharpFn }).default\n if (typeof fn !== 'function') throw new Error('sharp did not resolve to a function')\n return fn\n } catch (err) {\n const detail = isError(err) ? err.message : String(err)\n throw new E_INVALID_MEDIA_PIPELINE_CONFIG([\n `the sharp engine could not load its peer dependency \"sharp\": ${detail} — install it (pnpm add sharp); note sharp is Node-only`,\n ])\n }\n}\n\n/** Run a fused mutate request through a sharp instance function. */\nconst runTransform = async (sharp: SharpFn, request: MutateRequest): Promise<EngineBytesResult> => {\n let img = sharp(request.bytes)\n if (request.rotate) img = img.rotate(request.rotate)\n if (request.flip?.vertical) img = img.flip()\n if (request.flip?.horizontal) img = img.flop()\n if (\n request.resize &&\n (request.resize.width !== undefined || request.resize.height !== undefined)\n ) {\n img = img.resize({\n width: request.resize.width,\n height: request.resize.height,\n fit: request.resize.fit ?? 'cover',\n })\n }\n const target = request.format?.to ?? mimeToFormat(request.mimeType)\n const mimeType = MIME_BY_FORMAT[target]\n if (!mimeType) {\n throw new Error(`sharp cannot encode \"${target}\"; supported: ${SUPPORTED_OUTPUT.join(', ')}`)\n }\n const formatKey = (target === 'jpg' ? 'jpeg' : target) as\n | 'png'\n | 'jpeg'\n | 'webp'\n | 'tiff'\n | 'avif'\n | 'gif'\n img = img.toFormat(\n formatKey,\n request.format?.quality !== undefined ? { quality: request.format.quality } : {}\n )\n if (request.stripMetadata !== true) {\n // sharp strips metadata by default; keep it when NOT asked to strip.\n img = img.keepMetadata()\n }\n const buffer = await img.toBuffer()\n return { bytes: new Uint8Array(buffer), mimeType }\n}\n\n/** Build the single mutate capability over a sharp source. */\nconst capabilityOf = (\n run: (request: MutateRequest) => Promise<EngineBytesResult>\n): MutateCapability => ({\n over: ['image/*'],\n ops: ['resize', 'rotate', 'flip', 'strip_metadata'],\n encodes: SUPPORTED_OUTPUT,\n mutate: run,\n})\n\n/**\n * Construct the sharp-backed image engine.\n *\n * @param options - Optional module resolver override.\n * @returns The engine.\n */\nexport const sharpEngine = (options: SharpEngineOptions = {}): MediaEngine => {\n let sharpPromise: Promise<SharpFn> | undefined\n const getSharp = (): Promise<SharpFn> => {\n sharpPromise ??= resolveSharp(options.sharp)\n return sharpPromise\n }\n return {\n id: 'sharp',\n mutates: [capabilityOf(async (request) => runTransform(await getSharp(), request))],\n }\n}\n\n/**\n * Adapt an already-configured sharp module (your import, your build flags) to the engine\n * contract — the BYO transformer.\n *\n * @param sharp - The sharp function you imported.\n * @returns The engine.\n */\nexport const fromSharp = (sharp: SharpFn): MediaEngine => ({\n id: 'sharp',\n mutates: [capabilityOf(async (request) => runTransform(sharp, request))],\n})\n\nconst mimeToFormat = (mimeType: string): string => {\n const sub = mimeType.toLowerCase().split(';')[0].trim().split('/')[1] ?? 'png'\n return sub === 'jpeg' ? 'jpg' : sub\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AA4BA,IAAM,mBAAmB;CAAC;CAAO;CAAO;CAAQ;CAAQ;CAAQ;CAAQ;AAAK;AAE7E,IAAM,iBAAyC;CAC7C,KAAK;CACL,KAAK;CACL,MAAM;CACN,MAAM;CACN,MAAM;CACN,MAAM;CACN,KAAK;AACP;AAEA,IAAM,eAAe,OAAO,aAA4D;CACtF,IAAI;EACF,MAAM,MAAM,OAAO,WAAW,SAAS,IAAI,OAAO;EAClD,MAAM,KAAK,OAAO,QAAQ,aAAa,MAAO,IAA6B;EAC3E,IAAI,OAAO,OAAO,YAAY,MAAM,IAAI,MAAM,qCAAqC;EACnF,OAAO;CACT,SAAS,KAAK;EAEZ,MAAM,IAAI,gCAAgC,CACxC,gEAFa,QAAQ,GAAG,IAAI,IAAI,UAAU,OAAO,GAAG,EAEmB,wDACzE,CAAC;CACH;AACF;;AAGA,IAAM,eAAe,OAAO,OAAgB,YAAuD;CACjG,IAAI,MAAM,MAAM,QAAQ,KAAK;CAC7B,IAAI,QAAQ,QAAQ,MAAM,IAAI,OAAO,QAAQ,MAAM;CACnD,IAAI,QAAQ,MAAM,UAAU,MAAM,IAAI,KAAK;CAC3C,IAAI,QAAQ,MAAM,YAAY,MAAM,IAAI,KAAK;CAC7C,IACE,QAAQ,WACP,QAAQ,OAAO,UAAU,KAAA,KAAa,QAAQ,OAAO,WAAW,KAAA,IAEjE,MAAM,IAAI,OAAO;EACf,OAAO,QAAQ,OAAO;EACtB,QAAQ,QAAQ,OAAO;EACvB,KAAK,QAAQ,OAAO,OAAO;CAC7B,CAAC;CAEH,MAAM,SAAS,QAAQ,QAAQ,MAAM,aAAa,QAAQ,QAAQ;CAClE,MAAM,WAAW,eAAe;CAChC,IAAI,CAAC,UACH,MAAM,IAAI,MAAM,wBAAwB,OAAO,gBAAgB,iBAAiB,KAAK,IAAI,GAAG;CAE9F,MAAM,YAAa,WAAW,QAAQ,SAAS;CAO/C,MAAM,IAAI,SACR,WACA,QAAQ,QAAQ,YAAY,KAAA,IAAY,EAAE,SAAS,QAAQ,OAAO,QAAQ,IAAI,CAAC,CACjF;CACA,IAAI,QAAQ,kBAAkB,MAE5B,MAAM,IAAI,aAAa;CAEzB,MAAM,SAAS,MAAM,IAAI,SAAS;CAClC,OAAO;EAAE,OAAO,IAAI,WAAW,MAAM;EAAG;CAAS;AACnD;;AAGA,IAAM,gBACJ,SACsB;CACtB,MAAM,CAAC,SAAS;CAChB,KAAK;EAAC;EAAU;EAAU;EAAQ;CAAgB;CAClD,SAAS;CACT,QAAQ;AACV;;;;;;;AAQA,IAAa,eAAe,UAA8B,CAAC,MAAmB;CAC5E,IAAI;CACJ,MAAM,iBAAmC;EACvC,iBAAiB,aAAa,QAAQ,KAAK;EAC3C,OAAO;CACT;CACA,OAAO;EACL,IAAI;EACJ,SAAS,CAAC,aAAa,OAAO,YAAY,aAAa,MAAM,SAAS,GAAG,OAAO,CAAC,CAAC;CACpF;AACF;;;;;;;;AASA,IAAa,aAAa,WAAiC;CACzD,IAAI;CACJ,SAAS,CAAC,aAAa,OAAO,YAAY,aAAa,OAAO,OAAO,CAAC,CAAC;AACzE;AAEA,IAAM,gBAAgB,aAA6B;CACjD,MAAM,MAAM,SAAS,YAAY,EAAE,MAAM,GAAG,EAAE,GAAG,KAAK,EAAE,MAAM,GAAG,EAAE,MAAM;CACzE,OAAO,QAAQ,SAAS,QAAQ;AAClC"}
1
+ {"version":3,"file":"sharp.mjs","names":[],"sources":["../../../../src/batteries/media/engines/sharp.ts"],"sourcesContent":["/**\n * A Node-native image {@link @nhtio/adk/batteries/media/contracts!MediaEngine}\n * backed by sharp (libvips bindings — fast, full-format).\n *\n * @module @nhtio/adk/batteries/media/engines/sharp\n *\n * @remarks\n * The performance/fidelity engine for Node deployments: native speed plus webp/avif output\n * and the full `fit` mode set, plus a generation edge — `EMPTY_MIME` → a blank 1024×1024\n * white canvas in any supported encoding (resize in the same statement). sharp is permanently\n * Node-only (native bindings); for a cross-environment engine compose the jimp implementation\n * instead — the capability declaration is the seam, and BYO instances adapt via\n * {@link fromSharp}.\n *\n * `sharp` is an optional peer dependency, lazily imported on first actual use.\n */\n\nimport { EMPTY_MIME } from '../contracts'\nimport { isError } from '@nhtio/adk/guards'\nimport { default as SharpDefault } from 'sharp'\nimport { E_INVALID_MEDIA_PIPELINE_CONFIG } from '../exceptions'\nimport type {\n MediaEngine,\n MutateCapability,\n MutateRequest,\n EngineBytesResult,\n ConvertCapability,\n ConvertRequest,\n ConvertResult,\n} from '../contracts'\n\ntype SharpFn = typeof SharpDefault\n\n/** Options for {@link sharpEngine}. */\nexport interface SharpEngineOptions {\n /** Override the module resolution (electron/custom builds). Default: `import('sharp')`. */\n sharp?: () => SharpFn | { default: SharpFn } | Promise<SharpFn | { default: SharpFn }>\n}\n\nconst SUPPORTED_OUTPUT = ['png', 'jpg', 'jpeg', 'webp', 'tiff', 'avif', 'gif'] as const\n\nconst MIME_BY_FORMAT: Record<string, string> = {\n png: 'image/png',\n jpg: 'image/jpeg',\n jpeg: 'image/jpeg',\n webp: 'image/webp',\n tiff: 'image/tiff',\n avif: 'image/avif',\n gif: 'image/gif',\n}\n\nconst resolveSharp = async (supplied: SharpEngineOptions['sharp']): Promise<SharpFn> => {\n try {\n const mod = await (supplied ? supplied() : import('sharp'))\n const fn = typeof mod === 'function' ? mod : (mod as { default: SharpFn }).default\n if (typeof fn !== 'function') throw new Error('sharp did not resolve to a function')\n return fn\n } catch (err) {\n const detail = isError(err) ? err.message : String(err)\n throw new E_INVALID_MEDIA_PIPELINE_CONFIG([\n `the sharp engine could not load its peer dependency \"sharp\": ${detail} — install it (pnpm add sharp); note sharp is Node-only`,\n ])\n }\n}\n\n/** Run a fused mutate request through a sharp instance function. */\nconst runTransform = async (sharp: SharpFn, request: MutateRequest): Promise<EngineBytesResult> => {\n let img = sharp(request.bytes)\n if (request.rotate) img = img.rotate(request.rotate)\n if (request.flip?.vertical) img = img.flip()\n if (request.flip?.horizontal) img = img.flop()\n if (\n request.resize &&\n (request.resize.width !== undefined || request.resize.height !== undefined)\n ) {\n img = img.resize({\n width: request.resize.width,\n height: request.resize.height,\n fit: request.resize.fit ?? 'cover',\n })\n }\n const target = request.format?.to ?? mimeToFormat(request.mimeType)\n const mimeType = MIME_BY_FORMAT[target]\n if (!mimeType) {\n throw new Error(`sharp cannot encode \"${target}\"; supported: ${SUPPORTED_OUTPUT.join(', ')}`)\n }\n const formatKey = (target === 'jpg' ? 'jpeg' : target) as\n | 'png'\n | 'jpeg'\n | 'webp'\n | 'tiff'\n | 'avif'\n | 'gif'\n img = img.toFormat(\n formatKey,\n request.format?.quality !== undefined ? { quality: request.format.quality } : {}\n )\n if (request.stripMetadata !== true) {\n // sharp strips metadata by default; keep it when NOT asked to strip.\n img = img.keepMetadata()\n }\n const buffer = await img.toBuffer()\n return { bytes: new Uint8Array(buffer), mimeType }\n}\n\n/** Build the single mutate capability over a sharp source. */\nconst capabilityOf = (\n run: (request: MutateRequest) => Promise<EngineBytesResult>\n): MutateCapability => ({\n over: ['image/*'],\n ops: ['resize', 'rotate', 'flip', 'strip_metadata'],\n encodes: SUPPORTED_OUTPUT,\n mutate: run,\n})\n\n/**\n * Build the generation capability over a sharp source: `EMPTY_MIME` → a blank 1024×1024\n * white canvas (3 channels, so jpeg never trips on alpha) in any supported encoding.\n */\nconst blankCapability = (getSharp: () => Promise<SharpFn>): ConvertCapability => ({\n from: [EMPTY_MIME],\n to: SUPPORTED_OUTPUT,\n convert: async (request: ConvertRequest): Promise<ConvertResult> => {\n const mimeType = MIME_BY_FORMAT[request.to]\n if (!mimeType) {\n throw new Error(\n `sharp cannot generate \"${request.to}\"; supported: ${SUPPORTED_OUTPUT.join(', ')}`\n )\n }\n const sharp = await getSharp()\n const formatKey = (request.to === 'jpg' ? 'jpeg' : request.to) as\n | 'png'\n | 'jpeg'\n | 'webp'\n | 'tiff'\n | 'avif'\n | 'gif'\n const buffer = await sharp({\n create: { width: 1024, height: 1024, channels: 3, background: { r: 255, g: 255, b: 255 } },\n })\n .toFormat(formatKey)\n .toBuffer()\n return { outputs: [{ bytes: new Uint8Array(buffer), mimeType }] }\n },\n})\n\n/**\n * Construct the sharp-backed image engine.\n *\n * @param options - Optional module resolver override.\n * @returns The engine.\n */\nexport const sharpEngine = (options: SharpEngineOptions = {}): MediaEngine => {\n let sharpPromise: Promise<SharpFn> | undefined\n const getSharp = (): Promise<SharpFn> => {\n sharpPromise ??= resolveSharp(options.sharp)\n return sharpPromise\n }\n return {\n id: 'sharp',\n converts: [blankCapability(getSharp)],\n mutates: [capabilityOf(async (request) => runTransform(await getSharp(), request))],\n }\n}\n\n/**\n * Adapt an already-configured sharp module (your import, your build flags) to the engine\n * contract — the BYO transformer.\n *\n * @param sharp - The sharp function you imported.\n * @returns The engine.\n */\nexport const fromSharp = (sharp: SharpFn): MediaEngine => ({\n id: 'sharp',\n converts: [blankCapability(async () => sharp)],\n mutates: [capabilityOf(async (request) => runTransform(sharp, request))],\n})\n\nconst mimeToFormat = (mimeType: string): string => {\n const sub = mimeType.toLowerCase().split(';')[0].trim().split('/')[1] ?? 'png'\n return sub === 'jpeg' ? 'jpg' : sub\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAuCA,IAAM,mBAAmB;CAAC;CAAO;CAAO;CAAQ;CAAQ;CAAQ;CAAQ;AAAK;AAE7E,IAAM,iBAAyC;CAC7C,KAAK;CACL,KAAK;CACL,MAAM;CACN,MAAM;CACN,MAAM;CACN,MAAM;CACN,KAAK;AACP;AAEA,IAAM,eAAe,OAAO,aAA4D;CACtF,IAAI;EACF,MAAM,MAAM,OAAO,WAAW,SAAS,IAAI,OAAO;EAClD,MAAM,KAAK,OAAO,QAAQ,aAAa,MAAO,IAA6B;EAC3E,IAAI,OAAO,OAAO,YAAY,MAAM,IAAI,MAAM,qCAAqC;EACnF,OAAO;CACT,SAAS,KAAK;EAEZ,MAAM,IAAI,gCAAgC,CACxC,gEAFa,QAAQ,GAAG,IAAI,IAAI,UAAU,OAAO,GAAG,EAEmB,wDACzE,CAAC;CACH;AACF;;AAGA,IAAM,eAAe,OAAO,OAAgB,YAAuD;CACjG,IAAI,MAAM,MAAM,QAAQ,KAAK;CAC7B,IAAI,QAAQ,QAAQ,MAAM,IAAI,OAAO,QAAQ,MAAM;CACnD,IAAI,QAAQ,MAAM,UAAU,MAAM,IAAI,KAAK;CAC3C,IAAI,QAAQ,MAAM,YAAY,MAAM,IAAI,KAAK;CAC7C,IACE,QAAQ,WACP,QAAQ,OAAO,UAAU,KAAA,KAAa,QAAQ,OAAO,WAAW,KAAA,IAEjE,MAAM,IAAI,OAAO;EACf,OAAO,QAAQ,OAAO;EACtB,QAAQ,QAAQ,OAAO;EACvB,KAAK,QAAQ,OAAO,OAAO;CAC7B,CAAC;CAEH,MAAM,SAAS,QAAQ,QAAQ,MAAM,aAAa,QAAQ,QAAQ;CAClE,MAAM,WAAW,eAAe;CAChC,IAAI,CAAC,UACH,MAAM,IAAI,MAAM,wBAAwB,OAAO,gBAAgB,iBAAiB,KAAK,IAAI,GAAG;CAE9F,MAAM,YAAa,WAAW,QAAQ,SAAS;CAO/C,MAAM,IAAI,SACR,WACA,QAAQ,QAAQ,YAAY,KAAA,IAAY,EAAE,SAAS,QAAQ,OAAO,QAAQ,IAAI,CAAC,CACjF;CACA,IAAI,QAAQ,kBAAkB,MAE5B,MAAM,IAAI,aAAa;CAEzB,MAAM,SAAS,MAAM,IAAI,SAAS;CAClC,OAAO;EAAE,OAAO,IAAI,WAAW,MAAM;EAAG;CAAS;AACnD;;AAGA,IAAM,gBACJ,SACsB;CACtB,MAAM,CAAC,SAAS;CAChB,KAAK;EAAC;EAAU;EAAU;EAAQ;CAAgB;CAClD,SAAS;CACT,QAAQ;AACV;;;;;AAMA,IAAM,mBAAmB,cAAyD;CAChF,MAAM,CAAC,UAAU;CACjB,IAAI;CACJ,SAAS,OAAO,YAAoD;EAClE,MAAM,WAAW,eAAe,QAAQ;EACxC,IAAI,CAAC,UACH,MAAM,IAAI,MACR,0BAA0B,QAAQ,GAAG,gBAAgB,iBAAiB,KAAK,IAAI,GACjF;EAEF,MAAM,QAAQ,MAAM,SAAS;EAC7B,MAAM,YAAa,QAAQ,OAAO,QAAQ,SAAS,QAAQ;EAO3D,MAAM,SAAS,MAAM,MAAM,EACzB,QAAQ;GAAE,OAAO;GAAM,QAAQ;GAAM,UAAU;GAAG,YAAY;IAAE,GAAG;IAAK,GAAG;IAAK,GAAG;GAAI;EAAE,EAC3F,CAAC,EACE,SAAS,SAAS,EAClB,SAAS;EACZ,OAAO,EAAE,SAAS,CAAC;GAAE,OAAO,IAAI,WAAW,MAAM;GAAG;EAAS,CAAC,EAAE;CAClE;AACF;;;;;;;AAQA,IAAa,eAAe,UAA8B,CAAC,MAAmB;CAC5E,IAAI;CACJ,MAAM,iBAAmC;EACvC,iBAAiB,aAAa,QAAQ,KAAK;EAC3C,OAAO;CACT;CACA,OAAO;EACL,IAAI;EACJ,UAAU,CAAC,gBAAgB,QAAQ,CAAC;EACpC,SAAS,CAAC,aAAa,OAAO,YAAY,aAAa,MAAM,SAAS,GAAG,OAAO,CAAC,CAAC;CACpF;AACF;;;;;;;;AASA,IAAa,aAAa,WAAiC;CACzD,IAAI;CACJ,UAAU,CAAC,gBAAgB,YAAY,KAAK,CAAC;CAC7C,SAAS,CAAC,aAAa,OAAO,YAAY,aAAa,OAAO,OAAO,CAAC,CAAC;AACzE;AAEA,IAAM,gBAAgB,aAA6B;CACjD,MAAM,MAAM,SAAS,YAAY,EAAE,MAAM,GAAG,EAAE,GAAG,KAAK,EAAE,MAAM,GAAG,EAAE,MAAM;CACzE,OAAO,QAAQ,SAAS,QAAQ;AAClC"}