jazz-tools 0.18.26 → 0.18.27

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 (35) hide show
  1. package/.turbo/turbo-build.log +43 -43
  2. package/CHANGELOG.md +11 -0
  3. package/dist/index.js +96 -4
  4. package/dist/index.js.map +1 -1
  5. package/dist/media/{chunk-W3S526L3.js → chunk-K6GCHLQU.js} +1 -1
  6. package/dist/media/chunk-K6GCHLQU.js.map +1 -0
  7. package/dist/media/create-image/browser.d.ts +1 -1
  8. package/dist/media/create-image/react-native.d.ts +1 -1
  9. package/dist/media/create-image/react-native.d.ts.map +1 -1
  10. package/dist/media/create-image/server.d.ts +1 -1
  11. package/dist/media/create-image-factory.d.ts +5 -2
  12. package/dist/media/create-image-factory.d.ts.map +1 -1
  13. package/dist/media/index.browser.js +1 -1
  14. package/dist/media/index.d.ts +3 -4
  15. package/dist/media/index.d.ts.map +1 -1
  16. package/dist/media/index.js +1 -1
  17. package/dist/media/index.native.js +63 -28
  18. package/dist/media/index.native.js.map +1 -1
  19. package/dist/media/index.server.js +1 -1
  20. package/dist/react/index.js.map +1 -1
  21. package/dist/tools/coValues/request.d.ts +70 -0
  22. package/dist/tools/coValues/request.d.ts.map +1 -1
  23. package/dist/tools/exports.d.ts +1 -1
  24. package/dist/tools/exports.d.ts.map +1 -1
  25. package/dist/tools/tests/authenticate-request.test.d.ts +2 -0
  26. package/dist/tools/tests/authenticate-request.test.d.ts.map +1 -0
  27. package/package.json +8 -4
  28. package/src/media/create-image/react-native.ts +75 -30
  29. package/src/media/create-image-factory.test.ts +18 -0
  30. package/src/media/create-image-factory.ts +6 -1
  31. package/src/media/index.ts +7 -4
  32. package/src/tools/coValues/request.ts +188 -4
  33. package/src/tools/exports.ts +3 -0
  34. package/src/tools/tests/authenticate-request.test.ts +194 -0
  35. package/dist/media/chunk-W3S526L3.js.map +0 -1
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/media/utils.ts","../../src/media/create-image-factory.ts"],"sourcesContent":["import type { CoID } from \"cojson\";\nimport { Account, FileStream, ImageDefinition } from \"jazz-tools\";\n\nexport function highestResAvailable(\n image: ImageDefinition,\n wantedWidth: number,\n wantedHeight: number,\n): { width: number; height: number; image: FileStream } | null {\n const availableSizes: [number, number, string][] = image.$jazz.raw\n .keys()\n .filter((key) => /^\\d+x\\d+$/.test(key))\n .map((key) => {\n const [w, h] = key.split(\"x\").map(Number) as [number, number];\n return [w, h, key];\n });\n\n if (availableSizes.length === 0) {\n return image.original\n ? {\n width: image.originalSize[0],\n height: image.originalSize[1],\n image: image.original,\n }\n : null;\n }\n\n const sortedSizes = availableSizes\n .map((size) => {\n return {\n size,\n match: sizesMatchWanted(size[0], size[1], wantedWidth, wantedHeight),\n isLoaded: isLoaded(\n image.$jazz.raw.get(size[2]) as CoID<any> | undefined,\n ),\n };\n })\n .sort((a, b) => a.match - b.match);\n\n // We try to find the better already loaded image\n // note: `toReversed` is not available in react-native.\n const bestLoaded = [...sortedSizes]\n .reverse()\n .find((el) => el.isLoaded && image[el.size[2]]?.getChunks());\n\n // if I can't find a good match, let's use the highest resolution\n const bestTarget =\n sortedSizes.find((el) => el.match > 0.95) || sortedSizes.at(-1);\n\n // if the best target is already loaded, we are done\n if (image[bestTarget!.size[2]]?.getChunks()) {\n return image[bestTarget!.size[2]]\n ? {\n width: bestTarget!.size[0],\n height: bestTarget!.size[1],\n image: image[bestTarget!.size[2]]!,\n }\n : null;\n }\n\n // if the best already loaded is not the best target\n // let's trigger the load of the best target\n if (bestLoaded) {\n image[bestTarget!.size[2]]?.getChunks();\n return image[bestLoaded.size[2]]\n ? {\n width: bestLoaded.size[0],\n height: bestLoaded.size[1],\n image: image[bestLoaded.size[2]]!,\n }\n : null;\n }\n\n // if nothing is loaded, then start fetching all the images till the best\n for (let size of sortedSizes) {\n if (size.match <= bestTarget!.match) {\n image[size.size[2]]?.getChunks();\n }\n }\n\n return null;\n}\n\nfunction sizesMatchWanted(\n w: number,\n h: number,\n wantedW: number,\n wantedH: number,\n): number {\n const area1 = w * h;\n const area2 = wantedW * wantedH;\n\n const areaRatio = area1 / area2;\n\n // // Below 0.95 means the image is too small, we don't want to upscale it\n // if (areaRatio < 0.95) {\n // return 9999;\n // }\n\n return areaRatio;\n}\n\nfunction isLoaded(id: CoID<any> | null | undefined): boolean {\n if (!id) {\n return false;\n }\n\n return !!Account.getMe().$jazz.localNode.getLoaded(id);\n}\n\nexport async function loadImage(\n imageOrId: ImageDefinition | string,\n): Promise<{ width: number; height: number; image: FileStream } | null> {\n if (typeof imageOrId === \"string\") {\n const image = await ImageDefinition.load(imageOrId, {\n resolve: {\n original: true,\n },\n });\n\n if (image === null || image.original === null) {\n return null;\n }\n\n return {\n width: image.originalSize[0],\n height: image.originalSize[1],\n image: image.original,\n };\n }\n\n if (!imageOrId.original) {\n console.warn(\"Unable to find the original image\");\n return null;\n }\n\n const loadedOriginal = await FileStream.load(imageOrId.original.$jazz.id);\n\n if (!loadedOriginal) {\n console.warn(\"Unable to find the original image\");\n return null;\n }\n\n return {\n width: imageOrId.originalSize[0],\n height: imageOrId.originalSize[1],\n image: loadedOriginal,\n };\n}\n\nexport async function loadImageBySize(\n imageOrId: ImageDefinition | string,\n wantedWidth: number,\n wantedHeight: number,\n): Promise<{ width: number; height: number; image: FileStream } | null> {\n // @ts-expect-error The resolved type for CoMap does not include catchall properties\n const image: ImageDefinition | null =\n typeof imageOrId === \"string\"\n ? await ImageDefinition.load(imageOrId)\n : imageOrId;\n\n if (image === null) {\n return null;\n }\n\n if (image.progressive === false) {\n return loadImage(imageOrId);\n }\n\n const availableSizes: [number, number, string][] = image.$jazz.raw\n .keys()\n .filter((key) => /^\\d+x\\d+$/.test(key))\n .map((key) => {\n const [w, h] = key.split(\"x\").map(Number) as [number, number];\n return [w, h, key];\n });\n\n if (availableSizes.length === 0) {\n return null;\n }\n\n const sortedSizes = availableSizes\n .map((size) => ({\n size,\n match: sizesMatchWanted(size[0], size[1], wantedWidth, wantedHeight),\n }))\n .sort((a, b) => a.match - b.match);\n\n const bestTarget =\n sortedSizes.find((el) => el.match > 0.95) || sortedSizes.at(-1)!;\n\n // The image's `wxh` keys reference FileStream.\n // image[bestTarget.size[2]] returns undefined if FileStream hasn't loaded yet.\n // Since we only need the file's ID to fetch it later, we check the raw _refs\n // which contain only the linked covalue's ID.\n const file = image.$jazz.refs[bestTarget.size[2]];\n\n if (!file) {\n return null;\n }\n\n const loadedFile = await FileStream.load(file.id);\n\n if (!loadedFile) {\n return null;\n }\n\n return {\n width: bestTarget.size[0],\n height: bestTarget.size[1],\n image: loadedFile,\n };\n}\n","import {\n Account,\n FileStream,\n Group,\n ImageDefinition,\n type Loaded,\n} from \"jazz-tools\";\n\nexport type SourceType = Blob | File | string;\n\nexport type ResizeOutput = Blob | string;\n\nexport type CreateImageOptions = {\n /** The owner of the image. Can be either a Group or Account. If not specified, the current user will be the owner. */\n owner?: Group | Account;\n /**\n * Controls placeholder generation for the image.\n * - `\"blur\"`: Generates a blurred placeholder image (default)\n * - `false`: No placeholder is generated\n * @default \"blur\"\n */\n placeholder?: \"blur\" | false;\n /**\n * Maximum size constraint for the image. The image will be resized to fit within this size while maintaining aspect ratio.\n * If the image is smaller than maxSize in both dimensions, no resizing occurs.\n * @example 1024 // Resizes image to fit within 1024px in the largest dimension\n */\n maxSize?: number; // | [number, number];\n /**\n * The progressive loading pattern is a technique that allows images to load incrementally, starting with a small version and gradually replacing it with a larger version as it becomes available.\n * This is useful for improving the user experience by showing a placeholder while the image is loading.\n *\n * Passing progressive: true to createImage() will create internal smaller versions of the image for future uses.\n *\n * @default false\n */\n progressive?: boolean;\n};\n\nexport type CreateImageReturnType = Loaded<\n typeof ImageDefinition,\n { original: true }\n>;\n\nexport type CreateImageImpl<\n TSourceType = SourceType,\n TResizeOutput = ResizeOutput,\n> = {\n createFileStreamFromSource: (\n imageBlobOrFile: TSourceType | TResizeOutput,\n owner?: Group | Account,\n ) => Promise<FileStream>;\n getImageSize: (\n imageBlobOrFile: TSourceType,\n ) => Promise<{ width: number; height: number }>;\n getPlaceholderBase64: (imageBlobOrFile: TSourceType) => Promise<string>;\n resize: (\n imageBlobOrFile: TSourceType,\n width: number,\n height: number,\n ) => Promise<TResizeOutput>;\n};\n\nexport function createImageFactory<TSourceType, TResizeOutput>(\n impl: CreateImageImpl<TSourceType, TResizeOutput>,\n imageTypeGuard?: (imageBlobOrFile: TSourceType) => void,\n) {\n return (source: TSourceType, options?: CreateImageOptions) => {\n imageTypeGuard?.(source);\n return createImage(source, options ?? {}, impl);\n };\n}\n\nasync function createImage<TSourceType, TResizeOutput>(\n imageBlobOrFile: TSourceType,\n options: CreateImageOptions,\n impl: CreateImageImpl<TSourceType, TResizeOutput>,\n): Promise<CreateImageReturnType> {\n // Get the original size of the image\n const { width: originalWidth, height: originalHeight } =\n await impl.getImageSize(imageBlobOrFile);\n\n const def: {\n originalSize: [number, number];\n progressive: boolean;\n placeholderDataURL: string | undefined;\n original?: FileStream;\n files: Record<string, FileStream>;\n } = {\n originalSize: [originalWidth, originalHeight],\n progressive: false,\n placeholderDataURL: undefined,\n files: {},\n };\n\n // Placeholder\n if (options?.placeholder === \"blur\") {\n def.placeholderDataURL = await impl.getPlaceholderBase64(imageBlobOrFile);\n }\n\n /**\n * Original\n *\n * Save the original image.\n * If the maxSize is set, resize the image to the maxSize if needed\n */\n if (options?.maxSize === undefined) {\n def.original = await impl.createFileStreamFromSource(\n imageBlobOrFile,\n options?.owner,\n );\n def.files[`${originalWidth}x${originalHeight}`] = def.original;\n } else if (\n options?.maxSize >= originalWidth &&\n options?.maxSize >= originalHeight\n ) {\n // no resizes required, just return the original image\n def.original = await impl.createFileStreamFromSource(\n imageBlobOrFile,\n options?.owner,\n );\n def.files[`${originalWidth}x${originalHeight}`] = def.original;\n } else {\n const { width, height } = getNewDimensions(\n originalWidth,\n originalHeight,\n options.maxSize,\n );\n\n const blob = await impl.resize(imageBlobOrFile, width, height);\n def.originalSize = [width, height];\n def.original = await impl.createFileStreamFromSource(blob, options?.owner);\n def.files[`${width}x${height}`] = def.original;\n }\n\n const imageCoValue = ImageDefinition.create(\n {\n originalSize: def.originalSize,\n progressive: def.progressive,\n placeholderDataURL: def.placeholderDataURL,\n original: def.original,\n ...def.files,\n },\n options?.owner,\n );\n\n /**\n * Progressive loading\n *\n * Save a set of resized images using three sizes: 256, 1024, 2048\n *\n * On the client side, the image will be loaded progressively, starting from the smallest size and increasing the size until the original size is reached.\n */\n if (options?.progressive) {\n imageCoValue.$jazz.set(\"progressive\", true);\n\n const resizes = ([256, 1024, 2048] as const).filter(\n (s) =>\n s <\n Math.max(imageCoValue.originalSize[0], imageCoValue.originalSize[1]),\n );\n\n for (const size of resizes) {\n const { width, height } = getNewDimensions(\n originalWidth,\n originalHeight,\n size,\n );\n\n const blob = await impl.resize(imageBlobOrFile, width, height);\n imageCoValue.$jazz.set(\n `${width}x${height}`,\n await impl.createFileStreamFromSource(blob, options?.owner),\n );\n }\n }\n\n return imageCoValue;\n}\n\nconst getNewDimensions = (\n originalWidth: number,\n originalHeight: number,\n maxSize: number,\n) => {\n if (originalWidth > originalHeight) {\n return {\n width: maxSize,\n height: Math.round(maxSize * (originalHeight / originalWidth)),\n };\n }\n\n return {\n width: Math.round(maxSize * (originalWidth / originalHeight)),\n height: maxSize,\n };\n};\n"],"mappings":"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","names":["ImageDefinition"]}
@@ -31,7 +31,7 @@ import { FileStream } from "jazz-tools";
31
31
  * ```
32
32
  */
33
33
  export declare const createImage: (source: Blob | File, options?: import("../create-image-factory").CreateImageOptions) => Promise<{
34
- readonly [key: string]: FileStream;
34
+ readonly original: FileStream;
35
35
  } & {
36
36
  readonly original: FileStream | null;
37
37
  readonly originalSize: [number, number];
@@ -24,7 +24,7 @@ import { FileStream } from "jazz-tools";
24
24
  * ```
25
25
  */
26
26
  export declare const createImage: (source: string, options?: import("../create-image-factory").CreateImageOptions) => Promise<{
27
- readonly [key: string]: FileStream;
27
+ readonly original: FileStream;
28
28
  } & {
29
29
  readonly original: FileStream | null;
30
30
  readonly originalSize: [number, number];
@@ -1 +1 @@
1
- {"version":3,"file":"react-native.d.ts","sourceRoot":"","sources":["../../../src/media/create-image/react-native.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACjD,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAMxC;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,eAAO,MAAM,WAAW;;;;;;;;;+BAcvB,CAAC;AAwEF,wBAAsB,0BAA0B,CAC9C,QAAQ,EAAE,MAAM,EAChB,KAAK,CAAC,EAAE,OAAO,GAAG,KAAK,GACtB,OAAO,CAAC,UAAU,CAAC,CAOrB"}
1
+ {"version":3,"file":"react-native.d.ts","sourceRoot":"","sources":["../../../src/media/create-image/react-native.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACjD,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAIxC;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,eAAO,MAAM,WAAW;;;;;;;;;+BAcvB,CAAC;AAqHF,wBAAsB,0BAA0B,CAC9C,QAAQ,EAAE,MAAM,EAChB,KAAK,CAAC,EAAE,OAAO,GAAG,KAAK,GACtB,OAAO,CAAC,UAAU,CAAC,CAOrB"}
@@ -22,7 +22,7 @@ export type SharpImageType = File | Blob | Buffer | ArrayBuffer | Uint8Array | U
22
22
  * ```
23
23
  */
24
24
  export declare const createImage: (source: SharpImageType, options?: import("../create-image-factory").CreateImageOptions) => Promise<{
25
- readonly [key: string]: FileStream;
25
+ readonly original: FileStream;
26
26
  } & {
27
27
  readonly original: FileStream | null;
28
28
  readonly originalSize: [number, number];
@@ -1,4 +1,4 @@
1
- import { Account, FileStream, Group } from "jazz-tools";
1
+ import { Account, FileStream, Group, ImageDefinition, type Loaded } from "jazz-tools";
2
2
  export type SourceType = Blob | File | string;
3
3
  export type ResizeOutput = Blob | string;
4
4
  export type CreateImageOptions = {
@@ -27,6 +27,9 @@ export type CreateImageOptions = {
27
27
  */
28
28
  progressive?: boolean;
29
29
  };
30
+ export type CreateImageReturnType = Loaded<typeof ImageDefinition, {
31
+ original: true;
32
+ }>;
30
33
  export type CreateImageImpl<TSourceType = SourceType, TResizeOutput = ResizeOutput> = {
31
34
  createFileStreamFromSource: (imageBlobOrFile: TSourceType | TResizeOutput, owner?: Group | Account) => Promise<FileStream>;
32
35
  getImageSize: (imageBlobOrFile: TSourceType) => Promise<{
@@ -37,7 +40,7 @@ export type CreateImageImpl<TSourceType = SourceType, TResizeOutput = ResizeOutp
37
40
  resize: (imageBlobOrFile: TSourceType, width: number, height: number) => Promise<TResizeOutput>;
38
41
  };
39
42
  export declare function createImageFactory<TSourceType, TResizeOutput>(impl: CreateImageImpl<TSourceType, TResizeOutput>, imageTypeGuard?: (imageBlobOrFile: TSourceType) => void): (source: TSourceType, options?: CreateImageOptions) => Promise<{
40
- readonly [key: string]: FileStream;
43
+ readonly original: FileStream;
41
44
  } & {
42
45
  readonly original: FileStream | null;
43
46
  readonly originalSize: [number, number];
@@ -1 +1 @@
1
- {"version":3,"file":"create-image-factory.d.ts","sourceRoot":"","sources":["../../src/media/create-image-factory.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,OAAO,EACP,UAAU,EACV,KAAK,EAGN,MAAM,YAAY,CAAC;AAEpB,MAAM,MAAM,UAAU,GAAG,IAAI,GAAG,IAAI,GAAG,MAAM,CAAC;AAE9C,MAAM,MAAM,YAAY,GAAG,IAAI,GAAG,MAAM,CAAC;AAEzC,MAAM,MAAM,kBAAkB,GAAG;IAC/B,sHAAsH;IACtH,KAAK,CAAC,EAAE,KAAK,GAAG,OAAO,CAAC;IACxB;;;;;OAKG;IACH,WAAW,CAAC,EAAE,MAAM,GAAG,KAAK,CAAC;IAC7B;;;;OAIG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;;;;;;OAOG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB,CAAC;AAEF,MAAM,MAAM,eAAe,CACzB,WAAW,GAAG,UAAU,EACxB,aAAa,GAAG,YAAY,IAC1B;IACF,0BAA0B,EAAE,CAC1B,eAAe,EAAE,WAAW,GAAG,aAAa,EAC5C,KAAK,CAAC,EAAE,KAAK,GAAG,OAAO,KACpB,OAAO,CAAC,UAAU,CAAC,CAAC;IACzB,YAAY,EAAE,CACZ,eAAe,EAAE,WAAW,KACzB,OAAO,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAChD,oBAAoB,EAAE,CAAC,eAAe,EAAE,WAAW,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IACxE,MAAM,EAAE,CACN,eAAe,EAAE,WAAW,EAC5B,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,KACX,OAAO,CAAC,aAAa,CAAC,CAAC;CAC7B,CAAC;AAEF,wBAAgB,kBAAkB,CAAC,WAAW,EAAE,aAAa,EAC3D,IAAI,EAAE,eAAe,CAAC,WAAW,EAAE,aAAa,CAAC,EACjD,cAAc,CAAC,EAAE,CAAC,eAAe,EAAE,WAAW,KAAK,IAAI,YAEvC,WAAW,YAAY,kBAAkB;;;;;;;;;gCAI1D"}
1
+ {"version":3,"file":"create-image-factory.d.ts","sourceRoot":"","sources":["../../src/media/create-image-factory.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,OAAO,EACP,UAAU,EACV,KAAK,EACL,eAAe,EACf,KAAK,MAAM,EACZ,MAAM,YAAY,CAAC;AAEpB,MAAM,MAAM,UAAU,GAAG,IAAI,GAAG,IAAI,GAAG,MAAM,CAAC;AAE9C,MAAM,MAAM,YAAY,GAAG,IAAI,GAAG,MAAM,CAAC;AAEzC,MAAM,MAAM,kBAAkB,GAAG;IAC/B,sHAAsH;IACtH,KAAK,CAAC,EAAE,KAAK,GAAG,OAAO,CAAC;IACxB;;;;;OAKG;IACH,WAAW,CAAC,EAAE,MAAM,GAAG,KAAK,CAAC;IAC7B;;;;OAIG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;;;;;;OAOG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB,CAAC;AAEF,MAAM,MAAM,qBAAqB,GAAG,MAAM,CACxC,OAAO,eAAe,EACtB;IAAE,QAAQ,EAAE,IAAI,CAAA;CAAE,CACnB,CAAC;AAEF,MAAM,MAAM,eAAe,CACzB,WAAW,GAAG,UAAU,EACxB,aAAa,GAAG,YAAY,IAC1B;IACF,0BAA0B,EAAE,CAC1B,eAAe,EAAE,WAAW,GAAG,aAAa,EAC5C,KAAK,CAAC,EAAE,KAAK,GAAG,OAAO,KACpB,OAAO,CAAC,UAAU,CAAC,CAAC;IACzB,YAAY,EAAE,CACZ,eAAe,EAAE,WAAW,KACzB,OAAO,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAChD,oBAAoB,EAAE,CAAC,eAAe,EAAE,WAAW,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IACxE,MAAM,EAAE,CACN,eAAe,EAAE,WAAW,EAC5B,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,KACX,OAAO,CAAC,aAAa,CAAC,CAAC;CAC7B,CAAC;AAEF,wBAAgB,kBAAkB,CAAC,WAAW,EAAE,aAAa,EAC3D,IAAI,EAAE,eAAe,CAAC,WAAW,EAAE,aAAa,CAAC,EACjD,cAAc,CAAC,EAAE,CAAC,eAAe,EAAE,WAAW,KAAK,IAAI,YAEvC,WAAW,YAAY,kBAAkB;;;;;;;;;gCAI1D"}
@@ -3,7 +3,7 @@ import {
3
3
  highestResAvailable,
4
4
  loadImage,
5
5
  loadImageBySize
6
- } from "./chunk-W3S526L3.js";
6
+ } from "./chunk-K6GCHLQU.js";
7
7
 
8
8
  // src/media/create-image/browser.ts
9
9
  import { FileStream } from "jazz-tools";
@@ -1,5 +1,4 @@
1
- import type { ImageDefinition } from "jazz-tools";
2
- import { CreateImageOptions } from "./create-image-factory";
1
+ import type { CreateImageOptions, CreateImageReturnType } from "./create-image-factory";
3
2
  export * from "./exports";
4
3
  /**
5
4
  * Creates an ImageDefinition from an image file or blob with built-in UX features.
@@ -33,7 +32,7 @@ export * from "./exports";
33
32
  * ```
34
33
  * ```
35
34
  */
36
- export declare function createImage(imageBlobOrFile: Blob | File, options?: CreateImageOptions): Promise<ImageDefinition>;
35
+ export declare function createImage(imageBlobOrFile: Blob | File, options?: CreateImageOptions): Promise<CreateImageReturnType>;
37
36
  /**
38
37
  * Creates an ImageDefinition from an image file path with built-in UX features.
39
38
  *
@@ -57,5 +56,5 @@ export declare function createImage(imageBlobOrFile: Blob | File, options?: Crea
57
56
  * }
58
57
  * ```
59
58
  */
60
- export declare function createImage(filePath: string, options?: CreateImageOptions): Promise<ImageDefinition>;
59
+ export declare function createImage(filePath: string, options?: CreateImageOptions): Promise<CreateImageReturnType>;
61
60
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/media/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAClD,OAAO,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AAE5D,cAAc,WAAW,CAAC;AAE1B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,MAAM,CAAC,OAAO,UAAU,WAAW,CACjC,eAAe,EAAE,IAAI,GAAG,IAAI,EAC5B,OAAO,CAAC,EAAE,kBAAkB,GAC3B,OAAO,CAAC,eAAe,CAAC,CAAC;AAE5B;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,MAAM,CAAC,OAAO,UAAU,WAAW,CACjC,QAAQ,EAAE,MAAM,EAChB,OAAO,CAAC,EAAE,kBAAkB,GAC3B,OAAO,CAAC,eAAe,CAAC,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/media/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,kBAAkB,EAClB,qBAAqB,EACtB,MAAM,wBAAwB,CAAC;AAEhC,cAAc,WAAW,CAAC;AAE1B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,MAAM,CAAC,OAAO,UAAU,WAAW,CACjC,eAAe,EAAE,IAAI,GAAG,IAAI,EAC5B,OAAO,CAAC,EAAE,kBAAkB,GAC3B,OAAO,CAAC,qBAAqB,CAAC,CAAC;AAElC;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,MAAM,CAAC,OAAO,UAAU,WAAW,CACjC,QAAQ,EAAE,MAAM,EAChB,OAAO,CAAC,EAAE,kBAAkB,GAC3B,OAAO,CAAC,qBAAqB,CAAC,CAAC"}
@@ -3,7 +3,7 @@ import {
3
3
  highestResAvailable,
4
4
  loadImage,
5
5
  loadImageBySize
6
- } from "./chunk-W3S526L3.js";
6
+ } from "./chunk-K6GCHLQU.js";
7
7
  export {
8
8
  createImageFactory,
9
9
  highestResAvailable,
@@ -3,12 +3,11 @@ import {
3
3
  highestResAvailable,
4
4
  loadImage,
5
5
  loadImageBySize
6
- } from "./chunk-W3S526L3.js";
6
+ } from "./chunk-K6GCHLQU.js";
7
7
 
8
8
  // src/media/create-image/react-native.ts
9
9
  import { FileStream } from "jazz-tools";
10
10
  import { Image } from "react-native";
11
- var ImageResizer;
12
11
  var createImage = createImageFactory(
13
12
  {
14
13
  getImageSize,
@@ -25,43 +24,79 @@ var createImage = createImageFactory(
25
24
  }
26
25
  );
27
26
  async function getResizer() {
28
- if (!ImageResizer) {
29
- try {
30
- ImageResizer = (await import("@bam.tech/react-native-image-resizer")).default;
31
- } catch (e) {
32
- throw new Error(
33
- "ImageResizer is not installed, please run `npm install @bam.tech/react-native-image-resizer`"
34
- );
27
+ try {
28
+ const rnImageResizer = await import("@bam.tech/react-native-image-resizer");
29
+ if (rnImageResizer.default !== void 0) {
30
+ return rnImageResizer.default;
35
31
  }
32
+ } catch (e) {
36
33
  }
37
- return ImageResizer;
34
+ try {
35
+ const expoImageManipulator = await import("expo-image-manipulator");
36
+ if (expoImageManipulator.ImageManipulator !== void 0) {
37
+ return expoImageManipulator;
38
+ }
39
+ } catch (e) {
40
+ }
41
+ throw new Error(
42
+ "No resizer lib found. Please install `@bam.tech/react-native-image-resizer` or `expo-image-manipulator`"
43
+ );
38
44
  }
39
45
  async function getImageSize(filePath) {
40
46
  const { width, height } = await Image.getSize(filePath);
41
47
  return { width, height };
42
48
  }
43
49
  async function getPlaceholderBase64(filePath) {
44
- const ImageResizer2 = await getResizer();
45
- const { uri } = await ImageResizer2.createResizedImage(
46
- filePath,
47
- 8,
48
- 8,
49
- "PNG",
50
- 100
51
- );
52
- return imageUrlToBase64(uri);
50
+ const ImageResizer = await getResizer();
51
+ if ("createResizedImage" in ImageResizer) {
52
+ const { uri } = await ImageResizer.createResizedImage(
53
+ filePath,
54
+ 8,
55
+ 8,
56
+ "PNG",
57
+ 100
58
+ );
59
+ return imageUrlToBase64(uri);
60
+ } else {
61
+ const ctx = ImageResizer.ImageManipulator.manipulate(filePath);
62
+ ctx.resize({ width: 8, height: 8 });
63
+ const im = await ctx.renderAsync();
64
+ const result = await im.saveAsync({
65
+ base64: true,
66
+ format: ImageResizer.SaveFormat.PNG
67
+ });
68
+ const base64 = result.base64;
69
+ if (!base64) {
70
+ throw new Error(
71
+ "Failed to get generate placeholder using expo-image-manipulator"
72
+ );
73
+ }
74
+ return base64;
75
+ }
53
76
  }
54
77
  async function resize(filePath, width, height) {
55
- const ImageResizer2 = await getResizer();
78
+ const ImageResizer = await getResizer();
56
79
  const mimeType = await getMimeType(filePath);
57
- const { uri } = await ImageResizer2.createResizedImage(
58
- filePath,
59
- width,
60
- height,
61
- contentTypeToFormat(mimeType),
62
- 80
63
- );
64
- return uri;
80
+ if ("createResizedImage" in ImageResizer) {
81
+ const { uri } = await ImageResizer.createResizedImage(
82
+ filePath,
83
+ width,
84
+ height,
85
+ contentTypeToFormat(mimeType),
86
+ 80
87
+ );
88
+ return uri;
89
+ } else {
90
+ const ctx = ImageResizer.ImageManipulator.manipulate(filePath);
91
+ ctx.resize({ width, height });
92
+ const mime = contentTypeToFormat(mimeType);
93
+ const im = await ctx.renderAsync();
94
+ const result = await im.saveAsync({
95
+ format: ImageResizer.SaveFormat[mime],
96
+ compress: 0.8
97
+ });
98
+ return result.uri;
99
+ }
65
100
  }
66
101
  function getMimeType(filePath) {
67
102
  return fetch(filePath).then((res) => res.blob()).then((blob) => blob.type);
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/media/create-image/react-native.ts"],"sourcesContent":["import type ImageResizerType from \"@bam.tech/react-native-image-resizer\";\nimport type { Account, Group } from \"jazz-tools\";\nimport { FileStream } from \"jazz-tools\";\nimport { Image } from \"react-native\";\nimport { createImageFactory } from \"../create-image-factory\";\n\nlet ImageResizer: typeof ImageResizerType | undefined;\n\n/**\n * Creates an ImageDefinition from an image file path with built-in UX features.\n *\n * This function creates a specialized CoValue for managing images in Jazz applications.\n * It supports blurry placeholders, built-in resizing, and progressive loading patterns.\n *\n * @returns Promise that resolves to an ImageDefinition\n *\n * @example\n * ```ts\n * import { createImage } from \"jazz-tools/media\";\n *\n * async function uploadImageFromCamera(imagePath: string) {\n * const image = await createImage(imagePath, {\n * maxSize: 800,\n * placeholder: \"blur\",\n * progressive: false,\n * });\n *\n * return image;\n * }\n * ```\n */\nexport const createImage = createImageFactory(\n {\n getImageSize,\n getPlaceholderBase64,\n createFileStreamFromSource,\n resize,\n },\n (filePath) => {\n if (typeof filePath !== \"string\") {\n throw new Error(\n \"createImage(Blob | File) is not supported on this platform\",\n );\n }\n },\n);\n\nasync function getResizer(): Promise<typeof ImageResizerType> {\n if (!ImageResizer) {\n try {\n ImageResizer = (await import(\"@bam.tech/react-native-image-resizer\"))\n .default;\n } catch (e) {\n throw new Error(\n \"ImageResizer is not installed, please run `npm install @bam.tech/react-native-image-resizer`\",\n );\n }\n }\n\n return ImageResizer;\n}\n\nasync function getImageSize(\n filePath: string,\n): Promise<{ width: number; height: number }> {\n const { width, height } = await Image.getSize(filePath);\n\n return { width, height };\n}\n\nasync function getPlaceholderBase64(filePath: string): Promise<string> {\n const ImageResizer = await getResizer();\n\n const { uri } = await ImageResizer.createResizedImage(\n filePath,\n 8,\n 8,\n \"PNG\",\n 100,\n );\n\n return imageUrlToBase64(uri);\n}\n\nasync function resize(\n filePath: string,\n width: number,\n height: number,\n): Promise<string> {\n const ImageResizer = await getResizer();\n\n const mimeType = await getMimeType(filePath);\n\n const { uri } = await ImageResizer.createResizedImage(\n filePath,\n width,\n height,\n contentTypeToFormat(mimeType),\n 80,\n );\n\n return uri;\n}\n\nfunction getMimeType(filePath: string): Promise<string> {\n return fetch(filePath)\n .then((res) => res.blob())\n .then((blob) => blob.type);\n}\n\nfunction contentTypeToFormat(contentType: string) {\n if (contentType.includes(\"image/png\")) return \"PNG\";\n if (contentType.includes(\"image/jpeg\")) return \"JPEG\";\n if (contentType.includes(\"image/webp\")) return \"WEBP\";\n return \"PNG\";\n}\n\nexport async function createFileStreamFromSource(\n filePath: string,\n owner?: Account | Group,\n): Promise<FileStream> {\n const blob = await fetch(filePath).then((res) => res.blob());\n const arrayBuffer = await toArrayBuffer(blob);\n\n return FileStream.createFromArrayBuffer(arrayBuffer, blob.type, undefined, {\n owner,\n });\n}\n\n// TODO: look for more efficient way to do this as React Native hasn't blob.arrayBuffer()\nfunction toArrayBuffer(blob: Blob): Promise<ArrayBuffer> {\n return new Promise((resolve, reject) => {\n const reader = new FileReader();\n reader.onloadend = () => {\n resolve(reader.result as ArrayBuffer);\n };\n reader.onerror = (error) => {\n reject(error);\n };\n reader.readAsArrayBuffer(blob);\n });\n}\n\nasync function imageUrlToBase64(url: string): Promise<string> {\n const response = await fetch(url);\n const blob = await response.blob();\n return new Promise((onSuccess, onError) => {\n try {\n const reader = new FileReader();\n reader.onload = function () {\n onSuccess(reader.result as string);\n };\n reader.readAsDataURL(blob);\n } catch (e) {\n onError(e);\n }\n });\n}\n"],"mappings":";;;;;;;;AAEA,SAAS,kBAAkB;AAC3B,SAAS,aAAa;AAGtB,IAAI;AAyBG,IAAM,cAAc;AAAA,EACzB;AAAA,IACE;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,CAAC,aAAa;AACZ,QAAI,OAAO,aAAa,UAAU;AAChC,YAAM,IAAI;AAAA,QACR;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF;AAEA,eAAe,aAA+C;AAC5D,MAAI,CAAC,cAAc;AACjB,QAAI;AACF,sBAAgB,MAAM,OAAO,sCAAsC,GAChE;AAAA,IACL,SAAS,GAAG;AACV,YAAM,IAAI;AAAA,QACR;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;AAEA,eAAe,aACb,UAC4C;AAC5C,QAAM,EAAE,OAAO,OAAO,IAAI,MAAM,MAAM,QAAQ,QAAQ;AAEtD,SAAO,EAAE,OAAO,OAAO;AACzB;AAEA,eAAe,qBAAqB,UAAmC;AACrE,QAAMA,gBAAe,MAAM,WAAW;AAEtC,QAAM,EAAE,IAAI,IAAI,MAAMA,cAAa;AAAA,IACjC;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAEA,SAAO,iBAAiB,GAAG;AAC7B;AAEA,eAAe,OACb,UACA,OACA,QACiB;AACjB,QAAMA,gBAAe,MAAM,WAAW;AAEtC,QAAM,WAAW,MAAM,YAAY,QAAQ;AAE3C,QAAM,EAAE,IAAI,IAAI,MAAMA,cAAa;AAAA,IACjC;AAAA,IACA;AAAA,IACA;AAAA,IACA,oBAAoB,QAAQ;AAAA,IAC5B;AAAA,EACF;AAEA,SAAO;AACT;AAEA,SAAS,YAAY,UAAmC;AACtD,SAAO,MAAM,QAAQ,EAClB,KAAK,CAAC,QAAQ,IAAI,KAAK,CAAC,EACxB,KAAK,CAAC,SAAS,KAAK,IAAI;AAC7B;AAEA,SAAS,oBAAoB,aAAqB;AAChD,MAAI,YAAY,SAAS,WAAW,EAAG,QAAO;AAC9C,MAAI,YAAY,SAAS,YAAY,EAAG,QAAO;AAC/C,MAAI,YAAY,SAAS,YAAY,EAAG,QAAO;AAC/C,SAAO;AACT;AAEA,eAAsB,2BACpB,UACA,OACqB;AACrB,QAAM,OAAO,MAAM,MAAM,QAAQ,EAAE,KAAK,CAAC,QAAQ,IAAI,KAAK,CAAC;AAC3D,QAAM,cAAc,MAAM,cAAc,IAAI;AAE5C,SAAO,WAAW,sBAAsB,aAAa,KAAK,MAAM,QAAW;AAAA,IACzE;AAAA,EACF,CAAC;AACH;AAGA,SAAS,cAAc,MAAkC;AACvD,SAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AACtC,UAAM,SAAS,IAAI,WAAW;AAC9B,WAAO,YAAY,MAAM;AACvB,cAAQ,OAAO,MAAqB;AAAA,IACtC;AACA,WAAO,UAAU,CAAC,UAAU;AAC1B,aAAO,KAAK;AAAA,IACd;AACA,WAAO,kBAAkB,IAAI;AAAA,EAC/B,CAAC;AACH;AAEA,eAAe,iBAAiB,KAA8B;AAC5D,QAAM,WAAW,MAAM,MAAM,GAAG;AAChC,QAAM,OAAO,MAAM,SAAS,KAAK;AACjC,SAAO,IAAI,QAAQ,CAAC,WAAW,YAAY;AACzC,QAAI;AACF,YAAM,SAAS,IAAI,WAAW;AAC9B,aAAO,SAAS,WAAY;AAC1B,kBAAU,OAAO,MAAgB;AAAA,MACnC;AACA,aAAO,cAAc,IAAI;AAAA,IAC3B,SAAS,GAAG;AACV,cAAQ,CAAC;AAAA,IACX;AAAA,EACF,CAAC;AACH;","names":["ImageResizer"]}
1
+ {"version":3,"sources":["../../src/media/create-image/react-native.ts"],"sourcesContent":["import { NativeModules } from \"react-native\";\nimport type ImageResizerType from \"@bam.tech/react-native-image-resizer\";\nimport type ImageManipulatorType from \"expo-image-manipulator\";\nimport type { Account, Group } from \"jazz-tools\";\nimport { FileStream } from \"jazz-tools\";\nimport { Image } from \"react-native\";\nimport { createImageFactory } from \"../create-image-factory\";\n\n/**\n * Creates an ImageDefinition from an image file path with built-in UX features.\n *\n * This function creates a specialized CoValue for managing images in Jazz applications.\n * It supports blurry placeholders, built-in resizing, and progressive loading patterns.\n *\n * @returns Promise that resolves to an ImageDefinition\n *\n * @example\n * ```ts\n * import { createImage } from \"jazz-tools/media\";\n *\n * async function uploadImageFromCamera(imagePath: string) {\n * const image = await createImage(imagePath, {\n * maxSize: 800,\n * placeholder: \"blur\",\n * progressive: false,\n * });\n *\n * return image;\n * }\n * ```\n */\nexport const createImage = createImageFactory(\n {\n getImageSize,\n getPlaceholderBase64,\n createFileStreamFromSource,\n resize,\n },\n (filePath) => {\n if (typeof filePath !== \"string\") {\n throw new Error(\n \"createImage(Blob | File) is not supported on this platform\",\n );\n }\n },\n);\n\nasync function getResizer(): Promise<\n typeof ImageResizerType | typeof ImageManipulatorType\n> {\n try {\n const rnImageResizer = await import(\"@bam.tech/react-native-image-resizer\");\n\n if (rnImageResizer.default !== undefined) {\n return rnImageResizer.default;\n }\n } catch (e) {}\n\n try {\n const expoImageManipulator = await import(\"expo-image-manipulator\");\n if (expoImageManipulator.ImageManipulator !== undefined) {\n return expoImageManipulator;\n }\n } catch (e) {}\n\n throw new Error(\n \"No resizer lib found. Please install `@bam.tech/react-native-image-resizer` or `expo-image-manipulator`\",\n );\n}\n\nasync function getImageSize(\n filePath: string,\n): Promise<{ width: number; height: number }> {\n const { width, height } = await Image.getSize(filePath);\n\n return { width, height };\n}\n\nasync function getPlaceholderBase64(filePath: string): Promise<string> {\n const ImageResizer = await getResizer();\n\n if (\"createResizedImage\" in ImageResizer) {\n const { uri } = await ImageResizer.createResizedImage(\n filePath,\n 8,\n 8,\n \"PNG\",\n 100,\n );\n\n return imageUrlToBase64(uri);\n } else {\n const ctx = ImageResizer.ImageManipulator.manipulate(filePath);\n\n ctx.resize({ width: 8, height: 8 });\n\n const im = await ctx.renderAsync();\n const result = await im.saveAsync({\n base64: true,\n format: ImageResizer.SaveFormat.PNG,\n });\n\n const base64 = result.base64;\n\n if (!base64) {\n throw new Error(\n \"Failed to get generate placeholder using expo-image-manipulator\",\n );\n }\n\n return base64;\n }\n}\n\nasync function resize(\n filePath: string,\n width: number,\n height: number,\n): Promise<string> {\n const ImageResizer = await getResizer();\n\n const mimeType = await getMimeType(filePath);\n\n if (\"createResizedImage\" in ImageResizer) {\n const { uri } = await ImageResizer.createResizedImage(\n filePath,\n width,\n height,\n contentTypeToFormat(mimeType),\n 80,\n );\n\n return uri;\n } else {\n const ctx = ImageResizer.ImageManipulator.manipulate(filePath);\n ctx.resize({ width: width, height: height });\n\n const mime = contentTypeToFormat(mimeType);\n\n const im = await ctx.renderAsync();\n const result = await im.saveAsync({\n format: ImageResizer.SaveFormat[mime],\n compress: 0.8,\n });\n\n return result.uri;\n }\n}\n\nfunction getMimeType(filePath: string): Promise<string> {\n return fetch(filePath)\n .then((res) => res.blob())\n .then((blob) => blob.type);\n}\n\nfunction contentTypeToFormat(contentType: string) {\n if (contentType.includes(\"image/png\")) return \"PNG\";\n if (contentType.includes(\"image/jpeg\")) return \"JPEG\";\n if (contentType.includes(\"image/webp\")) return \"WEBP\";\n return \"PNG\";\n}\n\nexport async function createFileStreamFromSource(\n filePath: string,\n owner?: Account | Group,\n): Promise<FileStream> {\n const blob = await fetch(filePath).then((res) => res.blob());\n const arrayBuffer = await toArrayBuffer(blob);\n\n return FileStream.createFromArrayBuffer(arrayBuffer, blob.type, undefined, {\n owner,\n });\n}\n\n// TODO: look for more efficient way to do this as React Native hasn't blob.arrayBuffer()\nfunction toArrayBuffer(blob: Blob): Promise<ArrayBuffer> {\n return new Promise((resolve, reject) => {\n const reader = new FileReader();\n reader.onloadend = () => {\n resolve(reader.result as ArrayBuffer);\n };\n reader.onerror = (error) => {\n reject(error);\n };\n reader.readAsArrayBuffer(blob);\n });\n}\n\nasync function imageUrlToBase64(url: string): Promise<string> {\n const response = await fetch(url);\n const blob = await response.blob();\n return new Promise((onSuccess, onError) => {\n try {\n const reader = new FileReader();\n reader.onload = function () {\n onSuccess(reader.result as string);\n };\n reader.readAsDataURL(blob);\n } catch (e) {\n onError(e);\n }\n });\n}\n"],"mappings":"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","names":[]}
@@ -3,7 +3,7 @@ import {
3
3
  highestResAvailable,
4
4
  loadImage,
5
5
  loadImageBySize
6
- } from "./chunk-W3S526L3.js";
6
+ } from "./chunk-K6GCHLQU.js";
7
7
 
8
8
  // src/media/create-image/server.ts
9
9
  import { FileStream } from "jazz-tools";