@adaptive-ds/assets-optimizer 0.1.0 → 0.2.1

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 (144) hide show
  1. package/README.md +36 -15
  2. package/bun.lock +12 -12
  3. package/changelogs/2026-04-18_v0.2.0.md +32 -0
  4. package/changelogs/2026-04-18_v0.2.1.md +5 -0
  5. package/dist/AssetsOptimizeOptions.d.ts +17 -0
  6. package/dist/AssetsOptimizeOptions.d.ts.map +1 -0
  7. package/dist/AssetsOptimizeOptions.js +1 -0
  8. package/dist/AssetsOptimizeResult.d.ts +12 -0
  9. package/dist/AssetsOptimizeResult.d.ts.map +1 -0
  10. package/dist/AssetsOptimizeResult.js +1 -0
  11. package/dist/assetsOptimize.d.ts +4 -0
  12. package/dist/assetsOptimize.d.ts.map +1 -0
  13. package/dist/assetsOptimize.js +61 -0
  14. package/dist/image/ExpectedImage.d.ts +5 -0
  15. package/dist/image/ExpectedImage.d.ts.map +1 -0
  16. package/dist/image/ExpectedImage.js +1 -0
  17. package/dist/image/ImageFormat.d.ts +2 -0
  18. package/dist/image/ImageFormat.d.ts.map +1 -0
  19. package/dist/image/ImageFormat.js +1 -0
  20. package/dist/image/ProcessImagesOptions.d.ts +10 -0
  21. package/dist/image/ProcessImagesOptions.d.ts.map +1 -0
  22. package/dist/image/ProcessImagesOptions.js +1 -0
  23. package/dist/image/TransformSpec.d.ts +8 -0
  24. package/dist/image/TransformSpec.d.ts.map +1 -0
  25. package/dist/image/TransformSpec.js +1 -0
  26. package/dist/image/buildExpectedImages.d.ts +4 -0
  27. package/dist/image/buildExpectedImages.d.ts.map +1 -0
  28. package/dist/image/buildExpectedImages.js +89 -0
  29. package/dist/image/createOutputHash.d.ts +2 -0
  30. package/dist/image/createOutputHash.d.ts.map +1 -0
  31. package/dist/image/createOutputHash.js +4 -0
  32. package/dist/image/createOutputHashForFile.d.ts +2 -0
  33. package/dist/image/createOutputHashForFile.d.ts.map +1 -0
  34. package/dist/image/createOutputHashForFile.js +14 -0
  35. package/dist/image/createRootImageTransform.d.ts +3 -0
  36. package/dist/image/createRootImageTransform.d.ts.map +1 -0
  37. package/dist/image/createRootImageTransform.js +33 -0
  38. package/dist/image/defaultQuality.d.ts +2 -0
  39. package/dist/image/defaultQuality.d.ts.map +1 -0
  40. package/dist/image/defaultQuality.js +1 -0
  41. package/dist/image/imageFormats.d.ts +3 -0
  42. package/dist/image/imageFormats.d.ts.map +1 -0
  43. package/dist/image/imageFormats.js +1 -0
  44. package/dist/image/isImageFormat.d.ts +3 -0
  45. package/dist/image/isImageFormat.d.ts.map +1 -0
  46. package/dist/image/isImageFormat.js +5 -0
  47. package/dist/image/parseTransformSpec.d.ts +3 -0
  48. package/dist/image/parseTransformSpec.d.ts.map +1 -0
  49. package/dist/image/parseTransformSpec.js +26 -0
  50. package/dist/image/processImage.d.ts +3 -0
  51. package/dist/image/processImage.d.ts.map +1 -0
  52. package/dist/image/processImage.js +28 -0
  53. package/dist/image/processImages.d.ts +3 -0
  54. package/dist/image/processImages.d.ts.map +1 -0
  55. package/dist/image/processImages.js +19 -0
  56. package/dist/image/supportedSourceExtensions.d.ts +2 -0
  57. package/dist/image/supportedSourceExtensions.d.ts.map +1 -0
  58. package/dist/image/supportedSourceExtensions.js +1 -0
  59. package/dist/index.d.ts +27 -0
  60. package/dist/index.d.ts.map +1 -0
  61. package/dist/index.js +26 -0
  62. package/dist/list/AssetListTypes.d.ts +13 -0
  63. package/dist/list/AssetListTypes.d.ts.map +1 -0
  64. package/dist/list/AssetListTypes.js +1 -0
  65. package/dist/list/formatGeneratedCodeFile.d.ts +3 -0
  66. package/dist/list/formatGeneratedCodeFile.d.ts.map +1 -0
  67. package/dist/list/formatGeneratedCodeFile.js +32 -0
  68. package/dist/list/generateImageList.d.ts +3 -0
  69. package/dist/list/generateImageList.d.ts.map +1 -0
  70. package/dist/list/generateImageList.js +85 -0
  71. package/dist/list/generateVideoList.d.ts +3 -0
  72. package/dist/list/generateVideoList.d.ts.map +1 -0
  73. package/dist/list/generateVideoList.js +87 -0
  74. package/dist/list/getAssetKey.d.ts +2 -0
  75. package/dist/list/getAssetKey.d.ts.map +1 -0
  76. package/dist/list/getAssetKey.js +10 -0
  77. package/dist/list/loadExistingAssetList.d.ts +2 -0
  78. package/dist/list/loadExistingAssetList.d.ts.map +1 -0
  79. package/dist/list/loadExistingAssetList.js +23 -0
  80. package/dist/list/sortAssetMap.d.ts +2 -0
  81. package/dist/list/sortAssetMap.d.ts.map +1 -0
  82. package/dist/list/sortAssetMap.js +8 -0
  83. package/dist/rclone/bisync.d.ts +9 -0
  84. package/dist/rclone/bisync.d.ts.map +1 -0
  85. package/dist/rclone/bisync.js +17 -0
  86. package/dist/rclone/runRclone.d.ts +2 -0
  87. package/dist/rclone/runRclone.d.ts.map +1 -0
  88. package/dist/rclone/runRclone.js +13 -0
  89. package/dist/shared/assertNever.d.ts +2 -0
  90. package/dist/shared/assertNever.d.ts.map +1 -0
  91. package/dist/shared/assertNever.js +3 -0
  92. package/dist/shared/dirExists.d.ts +2 -0
  93. package/dist/shared/dirExists.d.ts.map +1 -0
  94. package/dist/shared/dirExists.js +10 -0
  95. package/dist/shared/getOwnPackageName.d.ts +2 -0
  96. package/dist/shared/getOwnPackageName.d.ts.map +1 -0
  97. package/dist/shared/getOwnPackageName.js +21 -0
  98. package/dist/shared/isMissingDirError.d.ts +2 -0
  99. package/dist/shared/isMissingDirError.d.ts.map +1 -0
  100. package/dist/shared/isMissingDirError.js +3 -0
  101. package/dist/shared/listLocalFiles.d.ts +2 -0
  102. package/dist/shared/listLocalFiles.d.ts.map +1 -0
  103. package/dist/shared/listLocalFiles.js +13 -0
  104. package/dist/shared/logger.d.ts +13 -0
  105. package/dist/shared/logger.d.ts.map +1 -0
  106. package/dist/shared/logger.js +47 -0
  107. package/dist/shared/printSummary.d.ts +4 -0
  108. package/dist/shared/printSummary.d.ts.map +1 -0
  109. package/dist/shared/printSummary.js +25 -0
  110. package/dist/shared/walkFiles.d.ts +2 -0
  111. package/dist/shared/walkFiles.d.ts.map +1 -0
  112. package/dist/shared/walkFiles.js +17 -0
  113. package/dist/video/ProcessVideosOptions.d.ts +11 -0
  114. package/dist/video/ProcessVideosOptions.d.ts.map +1 -0
  115. package/dist/video/ProcessVideosOptions.js +1 -0
  116. package/dist/video/createVideoArgs.d.ts +3 -0
  117. package/dist/video/createVideoArgs.d.ts.map +1 -0
  118. package/dist/video/createVideoArgs.js +77 -0
  119. package/dist/video/createVideoPreviewArgs.d.ts +2 -0
  120. package/dist/video/createVideoPreviewArgs.d.ts.map +1 -0
  121. package/dist/video/createVideoPreviewArgs.js +18 -0
  122. package/dist/video/createVideoPreviewPath.d.ts +2 -0
  123. package/dist/video/createVideoPreviewPath.d.ts.map +1 -0
  124. package/dist/video/createVideoPreviewPath.js +3 -0
  125. package/dist/video/ensureVideoPreviews.d.ts +4 -0
  126. package/dist/video/ensureVideoPreviews.d.ts.map +1 -0
  127. package/dist/video/ensureVideoPreviews.js +30 -0
  128. package/dist/video/getAvailableVideoEncoders.d.ts +3 -0
  129. package/dist/video/getAvailableVideoEncoders.d.ts.map +1 -0
  130. package/dist/video/getAvailableVideoEncoders.js +36 -0
  131. package/dist/video/processLocalVideos.d.ts +4 -0
  132. package/dist/video/processLocalVideos.d.ts.map +1 -0
  133. package/dist/video/processLocalVideos.js +26 -0
  134. package/dist/video/processVideos.d.ts +3 -0
  135. package/dist/video/processVideos.d.ts.map +1 -0
  136. package/dist/video/processVideos.js +10 -0
  137. package/dist/video/runFfmpeg.d.ts +3 -0
  138. package/dist/video/runFfmpeg.d.ts.map +1 -0
  139. package/dist/video/runFfmpeg.js +26 -0
  140. package/dist/video/supportedVideoSourceExtensions.d.ts +2 -0
  141. package/dist/video/supportedVideoSourceExtensions.d.ts.map +1 -0
  142. package/dist/video/supportedVideoSourceExtensions.js +1 -0
  143. package/package.json +1 -1
  144. package/assets-optimizer.code-workspace +0 -8
@@ -0,0 +1 @@
1
+ export const imageFormats = new Set(["jpg", "png", "webp", "avif"]);
@@ -0,0 +1,3 @@
1
+ import { type ImageFormat } from "./ImageFormat.js";
2
+ export declare function isImageFormat(value: string): value is ImageFormat;
3
+ //# sourceMappingURL=isImageFormat.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"isImageFormat.d.ts","sourceRoot":"","sources":["../../src/image/isImageFormat.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,WAAW,EAAE,MAAM,kBAAkB,CAAA;AAGnD,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,KAAK,IAAI,WAAW,CAEjE"}
@@ -0,0 +1,5 @@
1
+ import {} from "./ImageFormat.js";
2
+ import { imageFormats } from "./imageFormats.js";
3
+ export function isImageFormat(value) {
4
+ return imageFormats.has(value);
5
+ }
@@ -0,0 +1,3 @@
1
+ import type { TransformSpec } from "./TransformSpec.js";
2
+ export declare function parseTransformSpec(dirName: string): TransformSpec | null;
3
+ //# sourceMappingURL=parseTransformSpec.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parseTransformSpec.d.ts","sourceRoot":"","sources":["../../src/image/parseTransformSpec.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAA;AAEvD,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG,aAAa,GAAG,IAAI,CA4BxE"}
@@ -0,0 +1,26 @@
1
+ import { isImageFormat } from "./isImageFormat.js";
2
+ export function parseTransformSpec(dirName) {
3
+ const match = /^(?<width>\d+)x(?<height>\d+)_(?<format>jpg|png|webp|avif)$/.exec(dirName);
4
+ if (!match?.groups) {
5
+ return null;
6
+ }
7
+ const { width: widthValue, height: heightValue, format: formatValue } = match.groups;
8
+ if (!widthValue || !heightValue || !formatValue) {
9
+ return null;
10
+ }
11
+ const width = Number.parseInt(widthValue, 10);
12
+ const height = Number.parseInt(heightValue, 10);
13
+ if (!isImageFormat(formatValue)) {
14
+ return null;
15
+ }
16
+ const format = formatValue;
17
+ if (!Number.isFinite(width) || !Number.isFinite(height) || width <= 0 || height <= 0) {
18
+ return null;
19
+ }
20
+ return {
21
+ width,
22
+ height,
23
+ format,
24
+ normalized: `${width}x${height}_${format}`,
25
+ };
26
+ }
@@ -0,0 +1,3 @@
1
+ import type { TransformSpec } from "./TransformSpec.js";
2
+ export declare function processImage(sourceBuffer: Buffer, outputPath: string, transform: TransformSpec, quality?: number): Promise<void>;
3
+ //# sourceMappingURL=processImage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"processImage.d.ts","sourceRoot":"","sources":["../../src/image/processImage.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAA;AAEvD,wBAAsB,YAAY,CAChC,YAAY,EAAE,MAAM,EACpB,UAAU,EAAE,MAAM,EAClB,SAAS,EAAE,aAAa,EACxB,OAAO,SAAiB,GACvB,OAAO,CAAC,IAAI,CAAC,CA0Bf"}
@@ -0,0 +1,28 @@
1
+ import sharp from "sharp";
2
+ import { assertNever } from "../shared/assertNever.js";
3
+ import { defaultQuality } from "./defaultQuality.js";
4
+ export async function processImage(sourceBuffer, outputPath, transform, quality = defaultQuality) {
5
+ let pipeline = sharp(sourceBuffer, { animated: false }).rotate().resize({
6
+ width: transform.width,
7
+ height: transform.height,
8
+ fit: "inside",
9
+ withoutEnlargement: true,
10
+ });
11
+ switch (transform.format) {
12
+ case "jpg":
13
+ pipeline = pipeline.jpeg({ quality });
14
+ break;
15
+ case "png":
16
+ pipeline = pipeline.png({ quality });
17
+ break;
18
+ case "webp":
19
+ pipeline = pipeline.webp({ quality });
20
+ break;
21
+ case "avif":
22
+ pipeline = pipeline.avif({ quality });
23
+ break;
24
+ default:
25
+ assertNever(transform.format);
26
+ }
27
+ await pipeline.toFile(outputPath);
28
+ }
@@ -0,0 +1,3 @@
1
+ import type { ProcessImagesOptions } from "./ProcessImagesOptions.js";
2
+ export declare function processImages(options: ProcessImagesOptions): Promise<void>;
3
+ //# sourceMappingURL=processImages.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"processImages.d.ts","sourceRoot":"","sources":["../../src/image/processImages.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,2BAA2B,CAAA;AAErE,wBAAsB,aAAa,CAAC,OAAO,EAAE,oBAAoB,GAAG,OAAO,CAAC,IAAI,CAAC,CAiBhF"}
@@ -0,0 +1,19 @@
1
+ import fs from "node:fs/promises";
2
+ import path from "node:path";
3
+ import { listLocalFiles } from "../shared/listLocalFiles.js";
4
+ import { buildExpectedImages } from "./buildExpectedImages.js";
5
+ export async function processImages(options) {
6
+ const { allowRootImageFiles, imageOptimizedDir, imageOriginalsDir, result } = options;
7
+ await fs.mkdir(imageOriginalsDir, { recursive: true });
8
+ await fs.mkdir(imageOptimizedDir, { recursive: true });
9
+ const expectedImages = await buildExpectedImages(imageOriginalsDir, imageOptimizedDir, result, allowRootImageFiles);
10
+ const expectedFileNames = new Set(expectedImages.map((image) => image.fileName));
11
+ const localOptimizedFiles = await listLocalFiles(imageOptimizedDir);
12
+ for (const localFile of localOptimizedFiles) {
13
+ const relativeFile = path.relative(imageOptimizedDir, localFile);
14
+ if (!expectedFileNames.has(relativeFile) && !relativeFile.startsWith(".")) {
15
+ await fs.rm(localFile, { force: true });
16
+ result.deletedLocal.push(relativeFile);
17
+ }
18
+ }
19
+ }
@@ -0,0 +1,2 @@
1
+ export declare const supportedSourceExtensions: Set<string>;
2
+ //# sourceMappingURL=supportedSourceExtensions.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"supportedSourceExtensions.d.ts","sourceRoot":"","sources":["../../src/image/supportedSourceExtensions.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,yBAAyB,aAAgF,CAAA"}
@@ -0,0 +1 @@
1
+ export const supportedSourceExtensions = new Set([".jpg", ".jpeg", ".png", ".webp", ".avif", ".tif", ".tiff", ".gif"]);
@@ -0,0 +1,27 @@
1
+ export * from "./AssetsOptimizeOptions.js";
2
+ export * from "./AssetsOptimizeResult.js";
3
+ export * from "./image/buildExpectedImages.js";
4
+ export * from "./image/createOutputHash.js";
5
+ export * from "./image/defaultQuality.js";
6
+ export * from "./image/ExpectedImage.js";
7
+ export * from "./image/ImageFormat.js";
8
+ export * from "./image/parseTransformSpec.js";
9
+ export * from "./image/processImage.js";
10
+ export * from "./image/processImages.js";
11
+ export * from "./image/ProcessImagesOptions.js";
12
+ export * from "./image/supportedSourceExtensions.js";
13
+ export * from "./image/TransformSpec.js";
14
+ export * from "./list/AssetListTypes.js";
15
+ export * from "./list/generateImageList.js";
16
+ export * from "./list/generateVideoList.js";
17
+ export * from "./assetsOptimize.js";
18
+ export * from "./rclone/bisync.js";
19
+ export * from "./rclone/runRclone.js";
20
+ export * from "./shared/listLocalFiles.js";
21
+ export * from "./shared/printSummary.js";
22
+ export * from "./shared/walkFiles.js";
23
+ export * from "./video/createVideoPreviewPath.js";
24
+ export * from "./video/ensureVideoPreviews.js";
25
+ export * from "./video/processVideos.js";
26
+ export * from "./video/ProcessVideosOptions.js";
27
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,4BAA4B,CAAA;AAC1C,cAAc,2BAA2B,CAAA;AACzC,cAAc,gCAAgC,CAAA;AAC9C,cAAc,6BAA6B,CAAA;AAC3C,cAAc,2BAA2B,CAAA;AACzC,cAAc,0BAA0B,CAAA;AACxC,cAAc,wBAAwB,CAAA;AACtC,cAAc,+BAA+B,CAAA;AAC7C,cAAc,yBAAyB,CAAA;AACvC,cAAc,0BAA0B,CAAA;AACxC,cAAc,iCAAiC,CAAA;AAC/C,cAAc,sCAAsC,CAAA;AACpD,cAAc,0BAA0B,CAAA;AACxC,cAAc,0BAA0B,CAAA;AACxC,cAAc,6BAA6B,CAAA;AAC3C,cAAc,6BAA6B,CAAA;AAC3C,cAAc,qBAAqB,CAAA;AACnC,cAAc,oBAAoB,CAAA;AAClC,cAAc,uBAAuB,CAAA;AACrC,cAAc,4BAA4B,CAAA;AAC1C,cAAc,0BAA0B,CAAA;AACxC,cAAc,uBAAuB,CAAA;AACrC,cAAc,mCAAmC,CAAA;AACjD,cAAc,gCAAgC,CAAA;AAC9C,cAAc,0BAA0B,CAAA;AACxC,cAAc,iCAAiC,CAAA"}
package/dist/index.js ADDED
@@ -0,0 +1,26 @@
1
+ export * from "./AssetsOptimizeOptions.js";
2
+ export * from "./AssetsOptimizeResult.js";
3
+ export * from "./image/buildExpectedImages.js";
4
+ export * from "./image/createOutputHash.js";
5
+ export * from "./image/defaultQuality.js";
6
+ export * from "./image/ExpectedImage.js";
7
+ export * from "./image/ImageFormat.js";
8
+ export * from "./image/parseTransformSpec.js";
9
+ export * from "./image/processImage.js";
10
+ export * from "./image/processImages.js";
11
+ export * from "./image/ProcessImagesOptions.js";
12
+ export * from "./image/supportedSourceExtensions.js";
13
+ export * from "./image/TransformSpec.js";
14
+ export * from "./list/AssetListTypes.js";
15
+ export * from "./list/generateImageList.js";
16
+ export * from "./list/generateVideoList.js";
17
+ export * from "./assetsOptimize.js";
18
+ export * from "./rclone/bisync.js";
19
+ export * from "./rclone/runRclone.js";
20
+ export * from "./shared/listLocalFiles.js";
21
+ export * from "./shared/printSummary.js";
22
+ export * from "./shared/walkFiles.js";
23
+ export * from "./video/createVideoPreviewPath.js";
24
+ export * from "./video/ensureVideoPreviews.js";
25
+ export * from "./video/processVideos.js";
26
+ export * from "./video/ProcessVideosOptions.js";
@@ -0,0 +1,13 @@
1
+ export interface ImageType {
2
+ path: string;
3
+ width: number;
4
+ height: number;
5
+ alt: string;
6
+ mimeType?: string;
7
+ }
8
+ export interface VideoType {
9
+ path: string;
10
+ mimeType?: string;
11
+ image: ImageType;
12
+ }
13
+ //# sourceMappingURL=AssetListTypes.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AssetListTypes.d.ts","sourceRoot":"","sources":["../../src/list/AssetListTypes.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAA;IACZ,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,EAAE,MAAM,CAAA;IACd,GAAG,EAAE,MAAM,CAAA;IACX,QAAQ,CAAC,EAAE,MAAM,CAAA;CAClB;AAED,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAA;IACZ,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,KAAK,EAAE,SAAS,CAAA;CACjB"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,3 @@
1
+ import type { Logger } from "../shared/logger.js";
2
+ export declare function formatGeneratedCodeFile(outputPath: string, logger?: Logger): Promise<void>;
3
+ //# sourceMappingURL=formatGeneratedCodeFile.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"formatGeneratedCodeFile.d.ts","sourceRoot":"","sources":["../../src/list/formatGeneratedCodeFile.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAA;AAEjD,wBAAsB,uBAAuB,CAAC,UAAU,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAiChG"}
@@ -0,0 +1,32 @@
1
+ export async function formatGeneratedCodeFile(outputPath, logger) {
2
+ const command = ["bunx", "biome", "check", "--write", outputPath];
3
+ logger?.cli(command.join(" "));
4
+ const process = Bun.spawn(command, {
5
+ stdout: "pipe",
6
+ stderr: "pipe",
7
+ });
8
+ const exitCode = await process.exited;
9
+ if (exitCode !== 0) {
10
+ const stderr = await new Response(process.stderr).text();
11
+ const message = `Failed to format generated file ${outputPath}: ${stderr}`;
12
+ if (logger) {
13
+ logger.warn(message);
14
+ }
15
+ else {
16
+ console.warn(message);
17
+ }
18
+ return;
19
+ }
20
+ if (logger?.isEnabled(3)) {
21
+ const [stdout, stderr] = await Promise.all([
22
+ new Response(process.stdout).text(),
23
+ new Response(process.stderr).text(),
24
+ ]);
25
+ if (stdout.trim()) {
26
+ logger.verbose(stdout.trim());
27
+ }
28
+ if (stderr.trim()) {
29
+ logger.verbose(stderr.trim());
30
+ }
31
+ }
32
+ }
@@ -0,0 +1,3 @@
1
+ import type { Logger } from "../shared/logger.js";
2
+ export declare function generateImageList(imageDirectory: string, outputPath: string, imageTypeImportPath?: string, logger?: Logger): Promise<void>;
3
+ //# sourceMappingURL=generateImageList.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"generateImageList.d.ts","sourceRoot":"","sources":["../../src/list/generateImageList.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAA;AAUjD,wBAAsB,iBAAiB,CACrC,cAAc,EAAE,MAAM,EACtB,UAAU,EAAE,MAAM,EAClB,mBAAmB,CAAC,EAAE,MAAM,EAC5B,MAAM,CAAC,EAAE,MAAM,GACd,OAAO,CAAC,IAAI,CAAC,CAWf"}
@@ -0,0 +1,85 @@
1
+ import fs from "node:fs/promises";
2
+ import path from "node:path";
3
+ import { imageSize } from "image-size";
4
+ import { getOwnPackageName } from "../shared/getOwnPackageName.js";
5
+ import { walkFiles } from "../shared/walkFiles.js";
6
+ import { formatGeneratedCodeFile } from "./formatGeneratedCodeFile.js";
7
+ import { getAssetKey } from "./getAssetKey.js";
8
+ import { loadExistingAssetList } from "./loadExistingAssetList.js";
9
+ import { sortAssetMap } from "./sortAssetMap.js";
10
+ const IMAGE_EXTENSIONS = new Set([".jpg", ".jpeg", ".png", ".gif", ".webp", ".avif", ".tiff", ".svg"]);
11
+ export async function generateImageList(imageDirectory, outputPath, imageTypeImportPath, logger) {
12
+ const resolvedImageTypeImportPath = imageTypeImportPath ?? (await getOwnPackageName(import.meta.url));
13
+ const existingImages = await loadExistingAssetList(outputPath, "imageList");
14
+ const imageMap = await processImageFiles(imageDirectory, existingImages, logger);
15
+ const sorted = sortAssetMap(imageMap);
16
+ await fs.mkdir(path.dirname(outputPath), { recursive: true });
17
+ await Bun.write(outputPath, createGeneratedImageListContent(sorted, resolvedImageTypeImportPath));
18
+ await formatGeneratedCodeFile(outputPath, logger);
19
+ logger?.files(`generated image list: ${outputPath}`);
20
+ logger?.summary(`Generated ${Object.keys(sorted).length} images to ${outputPath}`);
21
+ }
22
+ async function processImageFiles(directory, existingImages, logger) {
23
+ const imageMap = {};
24
+ for (const filePath of await walkFiles(directory)) {
25
+ const extension = path.extname(filePath).toLowerCase();
26
+ if (!IMAGE_EXTENSIONS.has(extension)) {
27
+ continue;
28
+ }
29
+ try {
30
+ const buffer = await fs.readFile(filePath);
31
+ const dimensions = imageSize(buffer);
32
+ if (!dimensions.width || !dimensions.height) {
33
+ continue;
34
+ }
35
+ const relativePath = path.relative(directory, filePath);
36
+ const key = normalizeGeneratedImageKey(getAssetKey(filePath));
37
+ const fileName = path.basename(filePath, extension);
38
+ imageMap[key] = {
39
+ path: relativePath,
40
+ width: dimensions.width,
41
+ height: dimensions.height,
42
+ alt: existingImages[key]?.alt || formatGeneratedImageAlt(fileName),
43
+ mimeType: getImageMimeType(extension),
44
+ };
45
+ }
46
+ catch (error) {
47
+ logger?.error(`Error processing ${filePath}: ${error instanceof Error ? error.message : String(error)}`);
48
+ }
49
+ }
50
+ return imageMap;
51
+ }
52
+ function normalizeGeneratedImageKey(key) {
53
+ return key.replace(/_[0-9a-f]{8}$/i, "");
54
+ }
55
+ function formatGeneratedImageAlt(fileName) {
56
+ return normalizeGeneratedImageKey(fileName).replace(/[-_]/g, " ");
57
+ }
58
+ function createGeneratedImageListContent(imageMap, imageTypeImportPath) {
59
+ return `import type { ImageType } from "${imageTypeImportPath}"
60
+
61
+ // Auto-generated, manual changes will be lost, generated by optimizeAssets from @adaptive-ds/assets-optimizer
62
+ export const imageList = ${JSON.stringify(imageMap, null, 2)} as const satisfies Record<string, ImageType>
63
+ `;
64
+ }
65
+ function getImageMimeType(extension) {
66
+ switch (extension) {
67
+ case ".jpg":
68
+ case ".jpeg":
69
+ return "image/jpeg";
70
+ case ".png":
71
+ return "image/png";
72
+ case ".gif":
73
+ return "image/gif";
74
+ case ".webp":
75
+ return "image/webp";
76
+ case ".avif":
77
+ return "image/avif";
78
+ case ".tiff":
79
+ return "image/tiff";
80
+ case ".svg":
81
+ return "image/svg+xml";
82
+ default:
83
+ return "application/octet-stream";
84
+ }
85
+ }
@@ -0,0 +1,3 @@
1
+ import type { Logger } from "../shared/logger.js";
2
+ export declare function generateVideoList(videosDirectory: string, outputPath: string, videoTypeImportPath?: string, logger?: Logger): Promise<void>;
3
+ //# sourceMappingURL=generateVideoList.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"generateVideoList.d.ts","sourceRoot":"","sources":["../../src/list/generateVideoList.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAA;AAUjD,wBAAsB,iBAAiB,CACrC,eAAe,EAAE,MAAM,EACvB,UAAU,EAAE,MAAM,EAClB,mBAAmB,CAAC,EAAE,MAAM,EAC5B,MAAM,CAAC,EAAE,MAAM,GACd,OAAO,CAAC,IAAI,CAAC,CAUf"}
@@ -0,0 +1,87 @@
1
+ import fs from "node:fs/promises";
2
+ import path from "node:path";
3
+ import { imageSize } from "image-size";
4
+ import { getOwnPackageName } from "../shared/getOwnPackageName.js";
5
+ import { isMissingDirError } from "../shared/isMissingDirError.js";
6
+ import { walkFiles } from "../shared/walkFiles.js";
7
+ import { createVideoPreviewPath } from "../video/createVideoPreviewPath.js";
8
+ import { supportedVideoSourceExtensions } from "../video/supportedVideoSourceExtensions.js";
9
+ import { formatGeneratedCodeFile } from "./formatGeneratedCodeFile.js";
10
+ import { getAssetKey } from "./getAssetKey.js";
11
+ import { loadExistingAssetList } from "./loadExistingAssetList.js";
12
+ import { sortAssetMap } from "./sortAssetMap.js";
13
+ export async function generateVideoList(videosDirectory, outputPath, videoTypeImportPath, logger) {
14
+ const resolvedVideoTypeImportPath = videoTypeImportPath ?? (await getOwnPackageName(import.meta.url));
15
+ const existingVideos = await loadExistingAssetList(outputPath, "videoList");
16
+ const videoMap = sortAssetMap(await processVideoFiles(videosDirectory, existingVideos));
17
+ await fs.mkdir(path.dirname(outputPath), { recursive: true });
18
+ await Bun.write(outputPath, createGeneratedVideoListContent(videoMap, resolvedVideoTypeImportPath));
19
+ await formatGeneratedCodeFile(outputPath, logger);
20
+ logger?.files(`generated video list: ${outputPath}`);
21
+ logger?.summary(`Generated ${Object.keys(videoMap).length} videos to ${outputPath}`);
22
+ }
23
+ async function processVideoFiles(directory, existingVideos) {
24
+ const videoMap = {};
25
+ let filePaths;
26
+ try {
27
+ filePaths = await walkFiles(directory);
28
+ }
29
+ catch (error) {
30
+ if (isMissingDirError(error)) {
31
+ return videoMap;
32
+ }
33
+ throw error;
34
+ }
35
+ for (const filePath of filePaths) {
36
+ const extension = path.extname(filePath).toLowerCase();
37
+ if (!supportedVideoSourceExtensions.has(extension)) {
38
+ continue;
39
+ }
40
+ const relativePath = path.relative(directory, filePath);
41
+ const key = getAssetKey(filePath);
42
+ const previewPath = createVideoPreviewPath(filePath);
43
+ const previewBuffer = await fs.readFile(previewPath);
44
+ const previewDimensions = imageSize(previewBuffer);
45
+ if (!previewDimensions.width || !previewDimensions.height) {
46
+ continue;
47
+ }
48
+ const fileName = path.basename(filePath, extension);
49
+ const existingPreview = existingVideos[key]?.image;
50
+ videoMap[key] = {
51
+ path: relativePath,
52
+ mimeType: getVideoMimeType(extension),
53
+ image: {
54
+ path: path.relative(directory, previewPath),
55
+ width: previewDimensions.width,
56
+ height: previewDimensions.height,
57
+ alt: existingPreview?.alt || fileName.replace(/[-_]/g, " "),
58
+ mimeType: "image/jpeg",
59
+ },
60
+ };
61
+ }
62
+ return videoMap;
63
+ }
64
+ function createGeneratedVideoListContent(videoMap, videoTypeImportPath) {
65
+ return `import type { VideoType } from "${videoTypeImportPath}"
66
+
67
+ // Auto-generated, manual changes will be lost, generated by optimizeAssets from @adaptive-ds/assets-optimizer
68
+ export const videoList = ${JSON.stringify(videoMap, null, 2)} as const satisfies Record<string, VideoType>
69
+ `;
70
+ }
71
+ function getVideoMimeType(extension) {
72
+ switch (extension) {
73
+ case ".mp4":
74
+ case ".m4v":
75
+ return "video/mp4";
76
+ case ".mov":
77
+ return "video/quicktime";
78
+ case ".webm":
79
+ return "video/webm";
80
+ case ".avi":
81
+ return "video/x-msvideo";
82
+ case ".mkv":
83
+ return "video/x-matroska";
84
+ default:
85
+ return "application/octet-stream";
86
+ }
87
+ }
@@ -0,0 +1,2 @@
1
+ export declare function getAssetKey(filePath: string): string;
2
+ //# sourceMappingURL=getAssetKey.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"getAssetKey.d.ts","sourceRoot":"","sources":["../../src/list/getAssetKey.ts"],"names":[],"mappings":"AAEA,wBAAgB,WAAW,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAUpD"}
@@ -0,0 +1,10 @@
1
+ import path from "node:path";
2
+ export function getAssetKey(filePath) {
3
+ const extension = path.extname(filePath);
4
+ const fileName = path.basename(filePath, extension);
5
+ let key = fileName.replace(/-/g, "_");
6
+ if (/^\d/.test(key)) {
7
+ key = `i${key}`;
8
+ }
9
+ return key;
10
+ }
@@ -0,0 +1,2 @@
1
+ export declare function loadExistingAssetList<T>(filePath: string, exportName: string): Promise<Record<string, T>>;
2
+ //# sourceMappingURL=loadExistingAssetList.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"loadExistingAssetList.d.ts","sourceRoot":"","sources":["../../src/list/loadExistingAssetList.ts"],"names":[],"mappings":"AAGA,wBAAsB,qBAAqB,CAAC,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,CAgB/G"}
@@ -0,0 +1,23 @@
1
+ import fs from "node:fs/promises";
2
+ import { pathToFileURL } from "node:url";
3
+ export async function loadExistingAssetList(filePath, exportName) {
4
+ try {
5
+ await fs.access(filePath);
6
+ }
7
+ catch {
8
+ return {};
9
+ }
10
+ try {
11
+ const moduleUrl = `${pathToFileURL(filePath).href}?t=${Date.now()}`;
12
+ const existingModule = (await import(moduleUrl));
13
+ const existingList = existingModule[exportName];
14
+ return isRecord(existingList) ? existingList : {};
15
+ }
16
+ catch (error) {
17
+ console.warn(`Failed to load existing ${exportName} from ${filePath}:`, error);
18
+ return {};
19
+ }
20
+ }
21
+ function isRecord(value) {
22
+ return typeof value === "object" && value !== null;
23
+ }
@@ -0,0 +1,2 @@
1
+ export declare function sortAssetMap<T>(assetMap: Record<string, T>): Record<string, T>;
2
+ //# sourceMappingURL=sortAssetMap.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sortAssetMap.d.ts","sourceRoot":"","sources":["../../src/list/sortAssetMap.ts"],"names":[],"mappings":"AAAA,wBAAgB,YAAY,CAAC,CAAC,EAAE,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,CAU9E"}
@@ -0,0 +1,8 @@
1
+ export function sortAssetMap(assetMap) {
2
+ return Object.keys(assetMap)
3
+ .sort()
4
+ .reduce((sorted, key) => {
5
+ sorted[key] = assetMap[key];
6
+ return sorted;
7
+ }, {});
8
+ }
@@ -0,0 +1,9 @@
1
+ export interface BisyncOptions {
2
+ cwd?: string;
3
+ resync?: boolean;
4
+ }
5
+ /**
6
+ * https://rclone.org/bisync/#limitations
7
+ */
8
+ export declare function bisync(localPath: string, remotePath: string, options?: BisyncOptions): Promise<void>;
9
+ //# sourceMappingURL=bisync.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bisync.d.ts","sourceRoot":"","sources":["../../src/rclone/bisync.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,aAAa;IAC5B,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,MAAM,CAAC,EAAE,OAAO,CAAA;CACjB;AAED;;GAEG;AACH,wBAAsB,MAAM,CAAC,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,OAAO,GAAE,aAAkB,GAAG,OAAO,CAAC,IAAI,CAAC,CAa9G"}
@@ -0,0 +1,17 @@
1
+ import fs from "node:fs/promises";
2
+ import { dirExists } from "../shared/dirExists.js";
3
+ import { runRclone } from "./runRclone.js";
4
+ /**
5
+ * https://rclone.org/bisync/#limitations
6
+ */
7
+ export async function bisync(localPath, remotePath, options = {}) {
8
+ const cwd = options.cwd ?? process.cwd();
9
+ const localDirExists = await dirExists(localPath);
10
+ await fs.mkdir(localPath, { recursive: true });
11
+ await runRclone(["mkdir", remotePath], cwd);
12
+ const args = ["bisync", localPath, remotePath, "--create-empty-src-dirs", "--resilient", "--recover"];
13
+ if (options.resync === true || !localDirExists) {
14
+ args.push("--resync");
15
+ }
16
+ await runRclone(args, cwd);
17
+ }
@@ -0,0 +1,2 @@
1
+ export declare function runRclone(args: string[], cwd?: string): Promise<void>;
2
+ //# sourceMappingURL=runRclone.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runRclone.d.ts","sourceRoot":"","sources":["../../src/rclone/runRclone.ts"],"names":[],"mappings":"AAAA,wBAAsB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,GAAG,SAAgB,GAAG,OAAO,CAAC,IAAI,CAAC,CAclF"}
@@ -0,0 +1,13 @@
1
+ export async function runRclone(args, cwd = process.cwd()) {
2
+ const command = ["rclone", ...args];
3
+ console.log(command.join(" "));
4
+ const proc = Bun.spawn(command, {
5
+ cwd,
6
+ stdout: "inherit",
7
+ stderr: "inherit",
8
+ });
9
+ const exitCode = await proc.exited;
10
+ if (exitCode !== 0) {
11
+ throw new Error(`rclone ${args.join(" ")} failed with exit code ${exitCode}`);
12
+ }
13
+ }
@@ -0,0 +1,2 @@
1
+ export declare function assertNever(value: never): never;
2
+ //# sourceMappingURL=assertNever.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"assertNever.d.ts","sourceRoot":"","sources":["../../src/shared/assertNever.ts"],"names":[],"mappings":"AAAA,wBAAgB,WAAW,CAAC,KAAK,EAAE,KAAK,GAAG,KAAK,CAE/C"}
@@ -0,0 +1,3 @@
1
+ export function assertNever(value) {
2
+ throw new Error(`Unhandled value: ${String(value)}`);
3
+ }
@@ -0,0 +1,2 @@
1
+ export declare function dirExists(dir: string): Promise<boolean>;
2
+ //# sourceMappingURL=dirExists.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dirExists.d.ts","sourceRoot":"","sources":["../../src/shared/dirExists.ts"],"names":[],"mappings":"AAEA,wBAAsB,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAO7D"}
@@ -0,0 +1,10 @@
1
+ import fs from "node:fs/promises";
2
+ export async function dirExists(dir) {
3
+ try {
4
+ const stat = await fs.stat(dir);
5
+ return stat.isDirectory();
6
+ }
7
+ catch {
8
+ return false;
9
+ }
10
+ }
@@ -0,0 +1,2 @@
1
+ export declare function getOwnPackageName(moduleUrl: string): Promise<string>;
2
+ //# sourceMappingURL=getOwnPackageName.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"getOwnPackageName.d.ts","sourceRoot":"","sources":["../../src/shared/getOwnPackageName.ts"],"names":[],"mappings":"AAIA,wBAAsB,iBAAiB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAoB1E"}