@uniformdev/cli 19.214.1-alpha.32 → 19.214.1-alpha.33

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 (2) hide show
  1. package/dist/index.mjs +287 -493
  2. package/package.json +10 -11
package/dist/index.mjs CHANGED
@@ -615,22 +615,17 @@ var AssetListModule = {
615
615
  }
616
616
  };
617
617
 
618
- // src/files/deleteDownloadedFileByUrl.ts
618
+ // src/files/index.ts
619
+ import { preferredType } from "@thi.ng/mime";
620
+ import { FILE_READY_STATE, getFileNameFromUrl } from "@uniformdev/files";
621
+ import { fileTypeFromBuffer } from "file-type";
619
622
  import fsj from "fs-jetpack";
620
- import { join as join3 } from "path";
621
-
622
- // src/files/urlToFileName.ts
623
- import { join as join2 } from "path";
624
- import { dirname } from "path";
623
+ import sizeOf from "image-size";
624
+ import PQueue from "p-queue";
625
+ import { dirname, join as join2 } from "path";
625
626
  var FILES_DIRECTORY_NAME = "files";
626
- var getFilesDirectory = (directory) => {
627
- const isPackage = isPathAPackageFile(directory);
628
- return isPackage ? dirname(directory) : (
629
- // If we are syncing to a directory, we want to write all files into a
630
- // top-lvl folder. That way any entities that contain files will sync to the
631
- // same directory, so there is no duplication
632
- join2(directory, "..")
633
- );
627
+ var escapeRegExp = (string) => {
628
+ return string.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
634
629
  };
635
630
  var urlToHash = (url) => {
636
631
  return Buffer.from(
@@ -639,6 +634,24 @@ var urlToHash = (url) => {
639
634
  new URL(url).pathname.substring(0, 64)
640
635
  ).toString("base64");
641
636
  };
637
+ var hashToPartialPathname = (hash) => {
638
+ try {
639
+ return Buffer.from(hash, "base64").toString("utf8");
640
+ } catch {
641
+ return null;
642
+ }
643
+ };
644
+ var findUrlMatchingPartialPathname = (source, pathname) => {
645
+ const escapedPathname = escapeRegExp(pathname);
646
+ const regex = new RegExp(
647
+ `"(https://([^"]*?)?(img|files).uniform.(rocks|global)${escapedPathname}([^"]*?))"`
648
+ );
649
+ const match = source.match(regex);
650
+ if (match && match[1]) {
651
+ return match[1];
652
+ }
653
+ return null;
654
+ };
642
655
  var urlToFileExtension = (url) => {
643
656
  try {
644
657
  const urlObject = new URL(url);
@@ -653,383 +666,228 @@ var urlToFileName = (url, hash) => {
653
666
  const fileExtension = urlToFileExtension(url);
654
667
  return `${fileName}${fileExtension ? `.${fileExtension}` : ""}`;
655
668
  };
656
-
657
- // src/files/deleteDownloadedFileByUrl.ts
669
+ var getFilesDirectory = (directory) => {
670
+ const isPackage = isPathAPackageFile(directory);
671
+ return isPackage ? dirname(directory) : (
672
+ // If we are syncing to a directory, we want to write all files into a
673
+ // top-lvl folder. That way any entities that contain files will sync to the
674
+ // same directory, so there is no duplication
675
+ join2(directory, "..")
676
+ );
677
+ };
678
+ var getUniformFileUrlMatches = (string) => {
679
+ return string.matchAll(/"(https:\/\/([^"]*?)?(img|files)\.uniform\.(rocks|global)\/([^"]*?))"/g);
680
+ };
658
681
  var deleteDownloadedFileByUrl = async (url, options) => {
659
682
  const writeDirectory = getFilesDirectory(options.directory);
660
683
  const fileName = urlToFileName(url);
661
- const fileToDelete = join3(writeDirectory, FILES_DIRECTORY_NAME, fileName);
684
+ const fileToDelete = join2(writeDirectory, FILES_DIRECTORY_NAME, fileName);
662
685
  try {
663
686
  await fsj.removeAsync(fileToDelete);
664
687
  } catch {
665
688
  console.warn(`Failed to delete a local file ${fileToDelete}`);
666
689
  }
667
690
  };
668
-
669
- // src/files/files.ts
670
- import {
671
- ASSETS_SOURCE_UNIFORM,
672
- getPropertiesValue as getPropertiesValue2,
673
- isAssetParamValue,
674
- isAssetParamValueItem,
675
- walkNodeTree as walkNodeTree2,
676
- walkPropertyValues as walkPropertyValues2
677
- } from "@uniformdev/canvas";
678
- import { isRichTextNodeType, isRichTextValue, walkRichTextTree } from "@uniformdev/richtext";
679
- import fsj4 from "fs-jetpack";
680
- import PQueue3 from "p-queue";
681
- import { join as join6 } from "path";
682
-
683
- // src/files/downloadFile.ts
684
- import fsj2 from "fs-jetpack";
685
- import { join as join4 } from "path";
686
- var downloadFile = async ({
687
- fileClient,
688
- fileUrl,
689
- directory
690
- }) => {
691
- const writeDirectory = getFilesDirectory(directory);
692
- const fileName = urlToFileName(fileUrl.toString());
693
- const fileAlreadyExists = await fsj2.existsAsync(join4(writeDirectory, FILES_DIRECTORY_NAME, fileName));
694
- if (fileAlreadyExists) {
695
- return { url: fileUrl };
696
- }
697
- const file = await fileClient.get({ url: fileUrl }).catch(() => null);
698
- if (!file) {
699
- console.warn(`Skipping file ${fileUrl} as it does not exist in the project anymore`);
700
- return null;
701
- }
702
- if (file.sourceId) {
703
- try {
704
- const hashAlreadyExists = await fsj2.findAsync(join4(writeDirectory, FILES_DIRECTORY_NAME), {
705
- matching: [file.sourceId, `${file.sourceId}.*`]
706
- });
707
- if (hashAlreadyExists.length > 0) {
708
- return { id: file.id, url: fileUrl };
709
- }
710
- } catch {
711
- }
712
- }
713
- const fetchUrl = `${fileUrl}?format=original`;
714
- const response = await fetch(fetchUrl);
715
- if (!response.ok) {
716
- return null;
717
- }
718
- const fileBuffer = await response.arrayBuffer();
719
- await fsj2.writeAsync(join4(writeDirectory, FILES_DIRECTORY_NAME, fileName), Buffer.from(fileBuffer));
720
- return { id: file.id, url: fileUrl };
721
- };
722
-
723
- // src/files/uploadFile.ts
724
- import { preferredType } from "@thi.ng/mime";
725
- import { FILE_READY_STATE, getFileNameFromUrl } from "@uniformdev/files";
726
- import { fileTypeFromBuffer } from "file-type";
727
- import fsj3 from "fs-jetpack";
728
- import sizeOf from "image-size";
729
- import PQueue from "p-queue";
730
- import { join as join5 } from "path";
731
- var fileUploadQueue = new PQueue({ concurrency: 10 });
732
- var uploadFile = async ({
733
- fileClient,
734
- fileUrl,
735
- directory,
736
- fileId
737
- }) => {
738
- return await fileUploadQueue.add(async () => {
739
- try {
740
- const writeDirectory = getFilesDirectory(directory);
741
- const hash = urlToHash(fileUrl);
742
- const fileAlreadyExistsChecks = await Promise.all([
743
- fileClient.get({ url: fileUrl }).catch(() => null),
744
- fileClient.get({ sourceId: hash }).catch(() => null)
745
- ]);
746
- const file = fileAlreadyExistsChecks.find((check) => check !== null);
747
- if (file?.url) {
748
- return { id: file.id, url: file.url };
749
- }
750
- const localFileName = urlToFileName(fileUrl);
751
- const expectedFilePath = join5(writeDirectory, FILES_DIRECTORY_NAME, localFileName);
752
- const fileExistsLocally = await fsj3.existsAsync(expectedFilePath);
753
- if (!fileExistsLocally) {
754
- console.warn(
755
- `Skipping file ${fileUrl} as we couldn't find a local copy (looked at ${expectedFilePath})`
756
- );
757
- return null;
758
- }
759
- const fileBuffer = await fsj3.readAsync(expectedFilePath, "buffer");
760
- if (!fileBuffer) {
761
- console.warn(`Skipping file ${fileUrl} (${expectedFilePath}) as we couldn't read it`);
762
- return null;
763
- }
764
- const fileName = getFileNameFromUrl(fileUrl);
765
- let mimeType = expectedFilePath.endsWith(".svg") ? "image/svg+xml" : (await fileTypeFromBuffer(fileBuffer))?.mime;
766
- if (!mimeType) {
767
- mimeType = preferredType(fileUrl.split(".").at(-1) ?? "");
768
- }
769
- if (mimeType === "audio/x-flac") {
770
- mimeType = "audio/flac";
771
- }
772
- const { width, height } = (() => {
773
- if (!mimeType.startsWith("image/")) {
774
- return {
775
- width: void 0,
776
- height: void 0
777
- };
778
- }
691
+ var extractAndDownloadUniformFilesForObject = async (object, options) => {
692
+ const objectAsString = JSON.stringify(object);
693
+ const uniformFileUrlMatches = getUniformFileUrlMatches(objectAsString);
694
+ const writeDirectory = getFilesDirectory(options.directory);
695
+ if (uniformFileUrlMatches) {
696
+ const fileDownloadQueue = new PQueue({ concurrency: 10 });
697
+ for (const match of uniformFileUrlMatches) {
698
+ const url = new URL(match[1]);
699
+ fileDownloadQueue.add(async () => {
779
700
  try {
780
- return sizeOf(fileBuffer);
701
+ const fileName = urlToFileName(url.toString());
702
+ const fileAlreadyExists = await fsj.existsAsync(
703
+ join2(writeDirectory, FILES_DIRECTORY_NAME, fileName)
704
+ );
705
+ if (fileAlreadyExists) {
706
+ return;
707
+ }
708
+ const file = await options.fileClient.get({ url: url.toString() }).catch(() => null);
709
+ if (!file) {
710
+ console.warn(`Skipping file ${url} as it does not exist in the project anymore`);
711
+ return;
712
+ }
713
+ if (file.sourceId) {
714
+ try {
715
+ const hashAlreadyExists = await fsj.findAsync(join2(writeDirectory, FILES_DIRECTORY_NAME), {
716
+ matching: [file.sourceId, `${file.sourceId}.*`]
717
+ });
718
+ if (hashAlreadyExists.length > 0) {
719
+ return;
720
+ }
721
+ } catch {
722
+ }
723
+ }
724
+ const fetchUrl = `${url.origin}${url.pathname}?format=original`;
725
+ const response = await fetch(fetchUrl);
726
+ if (!response.ok) {
727
+ return;
728
+ }
729
+ const fileBuffer = await response.arrayBuffer();
730
+ await fsj.writeAsync(join2(writeDirectory, FILES_DIRECTORY_NAME, fileName), Buffer.from(fileBuffer));
781
731
  } catch {
782
- return {
783
- width: void 0,
784
- height: void 0
785
- };
732
+ console.warn(`Failed to download file ${url}`);
786
733
  }
787
- })();
788
- const { id, method, uploadUrl } = await fileClient.insert({
789
- id: fileId,
790
- name: fileName,
791
- mediaType: mimeType,
792
- size: fileBuffer.length,
793
- width,
794
- height,
795
- sourceId: hash
796
734
  });
797
- const uploadResponse = await fetch(uploadUrl, {
798
- method,
799
- body: fileBuffer,
800
- headers: {
801
- "Content-Type": mimeType,
802
- "Content-Length": fileBuffer.length.toString()
803
- }
804
- });
805
- if (!uploadResponse.ok) {
806
- console.warn(`Failed to upload file ${fileUrl} (${expectedFilePath})`);
807
- return null;
808
- }
809
- let error;
810
- const checkForFile = async () => {
811
- if (error) {
812
- throw error;
813
- }
814
- const file2 = await fileClient.get({ id });
815
- if (!file2 || file2.state !== FILE_READY_STATE || !file2.url) {
816
- await new Promise((resolve) => setTimeout(resolve, 1e3));
817
- return checkForFile();
818
- }
819
- return file2.url;
820
- };
821
- const abortTimeout = setTimeout(() => {
822
- error = new Error(`Failed to upload file ${fileUrl} (${expectedFilePath}) - upload timed out`);
823
- }, 6e4);
824
- const uploadedFileUrl = await checkForFile();
825
- clearTimeout(abortTimeout);
826
- return { id, url: uploadedFileUrl };
827
- } catch (e) {
828
- console.warn(`Failed to upload file ${fileUrl}`, e);
829
- return null;
830
- }
831
- }) ?? null;
832
- };
833
-
834
- // src/files/walkFilesForCompositionOrEntry.ts
835
- import {
836
- getPropertiesValue,
837
- walkNodeTree,
838
- walkPropertyValues
839
- } from "@uniformdev/canvas";
840
- import PQueue2 from "p-queue";
841
- var UNIFORM_FILE_MATCH = /"(https:\/\/([^"]*?)?(img|files)\.uniform\.(rocks|global)\/([^"]*?))"/g;
842
- var walkFilesForCompositionOrEntry = async ({
843
- entity,
844
- directory,
845
- fileClient,
846
- callback
847
- }) => {
848
- const urlReplacementMap = /* @__PURE__ */ new Map();
849
- const fileDownloadQueue = new PQueue2({ concurrency: 3 });
850
- const thumbnail = "entry" in entity ? entity.entry._thumbnail : void 0;
851
- if (typeof thumbnail === "string") {
852
- const isUniformFile = `"${thumbnail}"`.match(UNIFORM_FILE_MATCH) !== null;
853
- if (isUniformFile) {
854
- fileDownloadQueue.add(async () => {
855
- const result = await callback({ fileUrl: thumbnail, directory, fileClient });
856
- if (result) {
857
- urlReplacementMap.set(thumbnail, result.url);
858
- }
859
- });
860
- }
861
- }
862
- walkNodeTree("entry" in entity ? entity.entry : entity.composition, ({ node }) => {
863
- const properties = getPropertiesValue(node);
864
- if (!properties) {
865
- return;
866
735
  }
867
- Object.entries(properties).forEach(([_, property]) => {
868
- if (property.type !== "image") {
869
- return;
870
- }
871
- walkPropertyValues(property, ({ value }) => {
872
- if (typeof value !== "string") {
873
- return;
874
- }
875
- const isUniformFile = `"${value}"`.match(UNIFORM_FILE_MATCH) !== null;
876
- if (!isUniformFile) {
877
- return;
878
- }
879
- fileDownloadQueue.add(async () => {
880
- const result = await callback({ fileUrl: value, directory, fileClient });
881
- if (result) {
882
- urlReplacementMap.set(value, result.url);
883
- }
884
- });
885
- });
886
- });
887
- });
888
- await fileDownloadQueue.onIdle();
889
- return urlReplacementMap;
890
- };
891
-
892
- // src/files/files.ts
893
- var downloadFileForAsset = async ({
894
- asset,
895
- directory,
896
- fileClient
897
- }) => {
898
- if (asset.asset.fields?.file?.value === void 0 || asset.asset.fields.url?.value === void 0) {
899
- return null;
736
+ await fileDownloadQueue.onIdle();
900
737
  }
901
- const fileId = asset.asset.fields?.file?.value;
902
- const fileUrl = asset.asset.fields.url?.value;
903
- if (fileId === "" || fileUrl === "") {
904
- return null;
905
- }
906
- return downloadFile({ fileUrl, directory, fileClient });
738
+ return object;
907
739
  };
908
- var uploadFileForAsset = async ({
909
- asset,
910
- directory,
911
- fileClient
912
- }) => {
913
- if (asset.asset.fields?.file?.value === void 0 || asset.asset.fields.url?.value === void 0) {
914
- return null;
915
- }
916
- const fileUrl = asset.asset.fields.url.value;
917
- const fileId = asset.asset.fields.file.value;
918
- return uploadFile({ fileUrl, directory, fileClient, fileId });
919
- };
920
- var removeUrlsFromAssetParameters = (entity) => {
921
- walkNodeTree2("entry" in entity ? entity.entry : entity.composition, ({ node }) => {
922
- const properties = getPropertiesValue2(node);
923
- if (!properties) {
924
- return;
925
- }
926
- Object.entries(properties).forEach(([_, property]) => {
927
- if (property.type === "asset") {
928
- walkPropertyValues2(property, ({ value }) => {
929
- if (!isAssetParamValue(value)) {
740
+ var extractAndUploadUniformFilesForObject = async (object, options) => {
741
+ let objectAsString = JSON.stringify(object);
742
+ const uniformFileUrlMatches = getUniformFileUrlMatches(objectAsString);
743
+ const writeDirectory = getFilesDirectory(options.directory);
744
+ if (uniformFileUrlMatches) {
745
+ const fileUploadQueue = new PQueue({ concurrency: 3 });
746
+ for (const match of uniformFileUrlMatches) {
747
+ const url = match[1];
748
+ const hash = urlToHash(url);
749
+ fileUploadQueue.add(async () => {
750
+ try {
751
+ const fileAlreadyExistsChecks = await Promise.all([
752
+ options.fileClient.get({ url }).catch(() => null),
753
+ options.fileClient.get({ sourceId: hash }).catch(() => null)
754
+ ]);
755
+ const file = fileAlreadyExistsChecks.find((check) => check !== null);
756
+ if (file) {
757
+ objectAsString = objectAsString.replaceAll(`"${url}"`, `"${file.url}"`);
758
+ return;
759
+ }
760
+ const localFileName = urlToFileName(url);
761
+ const expectedFilePath = join2(writeDirectory, FILES_DIRECTORY_NAME, localFileName);
762
+ const fileExistsLocally = await fsj.existsAsync(expectedFilePath);
763
+ if (!fileExistsLocally) {
764
+ console.warn(
765
+ `Skipping file ${url} as we couldn't find a local copy (looked at ${expectedFilePath})`
766
+ );
930
767
  return;
931
768
  }
932
- value.forEach((asset) => {
933
- if (!isAssetParamValueItem(asset)) {
934
- return;
769
+ const fileBuffer = await fsj.readAsync(expectedFilePath, "buffer");
770
+ if (!fileBuffer) {
771
+ console.warn(`Skipping file ${url} (${expectedFilePath}) as we couldn't read it`);
772
+ return;
773
+ }
774
+ const fileName = getFileNameFromUrl(url);
775
+ let mimeType = expectedFilePath.endsWith(".svg") ? "image/svg+xml" : (await fileTypeFromBuffer(fileBuffer))?.mime;
776
+ if (!mimeType) {
777
+ mimeType = preferredType(url.split(".").at(-1) ?? "");
778
+ }
779
+ if (mimeType === "audio/x-flac") {
780
+ mimeType = "audio/flac";
781
+ }
782
+ const { width, height } = (() => {
783
+ if (!mimeType.startsWith("image/")) {
784
+ return {
785
+ width: void 0,
786
+ height: void 0
787
+ };
935
788
  }
936
- if (asset._source !== ASSETS_SOURCE_UNIFORM || !asset.fields?.url.value) {
937
- return;
789
+ try {
790
+ return sizeOf(fileBuffer);
791
+ } catch {
792
+ return {
793
+ width: void 0,
794
+ height: void 0
795
+ };
938
796
  }
939
- asset.fields.url.value = "";
797
+ })();
798
+ const { id, method, uploadUrl } = await options.fileClient.insert({
799
+ name: fileName,
800
+ mediaType: mimeType,
801
+ size: fileBuffer.length,
802
+ width,
803
+ height,
804
+ sourceId: hash
940
805
  });
941
- });
942
- } else if (property.type === "richText") {
943
- walkPropertyValues2(property, ({ value }) => {
944
- if (!isRichTextValue(value)) {
806
+ const uploadResponse = await fetch(uploadUrl, {
807
+ method,
808
+ body: fileBuffer,
809
+ headers: {
810
+ "Content-Type": mimeType,
811
+ "Content-Length": fileBuffer.length.toString()
812
+ }
813
+ });
814
+ if (!uploadResponse.ok) {
815
+ console.warn(`Failed to upload file ${url} (${expectedFilePath})`);
945
816
  return;
946
817
  }
947
- walkRichTextTree(value.root, (node2) => {
948
- if (isRichTextNodeType(node2, "asset")) {
949
- if (node2.__asset?._source !== ASSETS_SOURCE_UNIFORM || !node2.__asset.fields.url.value) {
950
- return;
951
- }
952
- node2.__asset.fields.url.value = "";
818
+ let error;
819
+ const checkForFile = async () => {
820
+ if (error) {
821
+ throw error;
953
822
  }
954
- });
955
- });
956
- }
957
- });
958
- });
959
- return entity;
960
- };
961
- var compareCompositionsOrEntriesWithoutAssetUrls = (source, target) => {
962
- return serializedDequal(
963
- removeUrlsFromAssetParameters(structuredClone(source.object)),
964
- removeUrlsFromAssetParameters(structuredClone(target.object))
965
- );
966
- };
967
- var removeUrlFromAsset = (asset) => {
968
- if (asset.asset.fields?.url?.value) {
969
- asset.asset.fields.url.value = "";
823
+ const file2 = await options.fileClient.get({ id });
824
+ if (!file2 || file2.state !== FILE_READY_STATE || !file2.url) {
825
+ await new Promise((resolve) => setTimeout(resolve, 1e3));
826
+ return checkForFile();
827
+ }
828
+ return file2.url;
829
+ };
830
+ const abortTimeout = setTimeout(() => {
831
+ error = new Error(`Failed to upload file ${url} (${expectedFilePath}) - upload timed out`);
832
+ }, 6e4);
833
+ const uploadedFileUrl = await checkForFile();
834
+ clearTimeout(abortTimeout);
835
+ objectAsString = objectAsString.replaceAll(`"${url}"`, `"${uploadedFileUrl}"`);
836
+ } catch (e) {
837
+ console.warn(`Failed to upload file ${url}`, e);
838
+ }
839
+ });
840
+ }
841
+ await fileUploadQueue.onIdle();
970
842
  }
971
- return asset;
972
- };
973
- var compareAssetsWithoutUrls = (source, target) => {
974
- return serializedDequal(
975
- removeUrlFromAsset(structuredClone(source.object)),
976
- removeUrlFromAsset(structuredClone(target.object))
977
- );
978
- };
979
- var downloadFilesForCompositionOrEntry = async ({
980
- entity,
981
- directory,
982
- fileClient
983
- }) => {
984
- await walkFilesForCompositionOrEntry({
985
- entity,
986
- directory,
987
- fileClient,
988
- callback: downloadFile
989
- });
843
+ return JSON.parse(objectAsString);
990
844
  };
991
- var uploadFilesForCompositionOrEntry = async ({
992
- entity,
993
- directory,
994
- fileClient
995
- }) => {
996
- const replacements = await walkFilesForCompositionOrEntry({
997
- entity: entity.object,
998
- directory,
999
- fileClient,
1000
- callback: uploadFile
1001
- });
1002
- let entityAsString = JSON.stringify(entity);
1003
- for (const [key, value] of replacements.entries()) {
1004
- entityAsString = entityAsString.replaceAll(`"${key}"`, `"${value}"`);
845
+ var swapOutUniformFileUrlsForTargetProject = async (object, options) => {
846
+ let objectAsString = JSON.stringify(object);
847
+ const uniformFileUrlMatches = getUniformFileUrlMatches(objectAsString);
848
+ if (uniformFileUrlMatches) {
849
+ const fileUrlReplacementQueue = new PQueue({ concurrency: 3 });
850
+ for (const match of uniformFileUrlMatches) {
851
+ const url = match[1];
852
+ const hash = urlToHash(url);
853
+ fileUrlReplacementQueue.add(async () => {
854
+ try {
855
+ const fileAlreadyExistsChecks = await Promise.all([
856
+ options.fileClient.get({ url }).catch(() => null),
857
+ options.fileClient.get({ sourceId: hash }).catch(() => null)
858
+ ]);
859
+ const file = fileAlreadyExistsChecks.find((check) => check !== null);
860
+ if (!file) {
861
+ return;
862
+ }
863
+ objectAsString = objectAsString.replaceAll(`"${url}"`, `"${file.url}"`);
864
+ } catch {
865
+ }
866
+ });
867
+ }
868
+ await fileUrlReplacementQueue.onIdle();
1005
869
  }
1006
- return JSON.parse(entityAsString);
870
+ return JSON.parse(objectAsString);
1007
871
  };
1008
- var replaceRemoteUrlsWithLocalReferences = async ({
1009
- sourceEntity,
1010
- targetEntity,
1011
- fileClient,
1012
- directory
1013
- }) => {
1014
- let sourceEntityAsString = JSON.stringify(sourceEntity);
1015
- const targetEntityAsString = JSON.stringify(targetEntity);
1016
- const writeDirectory = getFilesDirectory(directory);
1017
- const fileUrlReplacementQueue = new PQueue3({ concurrency: 3 });
1018
- await walkFilesForCompositionOrEntry({
1019
- entity: sourceEntity.object,
1020
- directory,
1021
- fileClient,
1022
- callback: async ({ fileUrl }) => {
872
+ var replaceRemoteUrlsWithLocalReferences = async (sourceObject, targetObject, options) => {
873
+ let sourceObjectAsString = JSON.stringify(sourceObject);
874
+ const targetObjectAsString = JSON.stringify(targetObject);
875
+ const uniformFileUrlMatches = getUniformFileUrlMatches(sourceObjectAsString);
876
+ const writeDirectory = getFilesDirectory(options.directory);
877
+ if (uniformFileUrlMatches) {
878
+ const fileUrlReplacementQueue = new PQueue({ concurrency: 3 });
879
+ for (const match of uniformFileUrlMatches) {
880
+ const url = match[1];
1023
881
  fileUrlReplacementQueue.add(async () => {
1024
882
  try {
1025
- const localFileName = urlToFileName(fileUrl);
1026
- const fileExistsLocally = await fsj4.existsAsync(
1027
- join6(writeDirectory, FILES_DIRECTORY_NAME, localFileName)
883
+ const localFileName = urlToFileName(url);
884
+ const fileExistsLocally = await fsj.existsAsync(
885
+ join2(writeDirectory, FILES_DIRECTORY_NAME, localFileName)
1028
886
  );
1029
887
  if (fileExistsLocally) {
1030
888
  return;
1031
889
  }
1032
- const file = await fileClient.get({ url: fileUrl }).catch(() => null);
890
+ const file = await options.fileClient.get({ url }).catch(() => null);
1033
891
  if (!file || !file.sourceId) {
1034
892
  return;
1035
893
  }
@@ -1037,74 +895,36 @@ var replaceRemoteUrlsWithLocalReferences = async ({
1037
895
  if (!originalPartialPath) {
1038
896
  return;
1039
897
  }
1040
- const originalUrl = findUrlMatchingPartialPathname(targetEntityAsString, originalPartialPath);
898
+ const originalUrl = findUrlMatchingPartialPathname(targetObjectAsString, originalPartialPath);
1041
899
  if (!originalUrl) {
1042
900
  return;
1043
901
  }
1044
- sourceEntityAsString = sourceEntityAsString.replaceAll(`"${fileUrl}"`, `"${originalUrl}"`);
902
+ sourceObjectAsString = sourceObjectAsString.replaceAll(`"${url}"`, `"${originalUrl}"`);
1045
903
  } catch {
1046
904
  }
1047
905
  });
1048
- return null;
1049
906
  }
1050
- });
1051
- await fileUrlReplacementQueue.onIdle();
1052
- return JSON.parse(sourceEntityAsString);
1053
- };
1054
- var replaceLocalUrlsWithRemoteReferences = async ({
1055
- entity,
1056
- directory,
1057
- fileClient
1058
- }) => {
1059
- let entityAsString = JSON.stringify(entity);
1060
- const fileUrlReplacementQueue = new PQueue3({ concurrency: 3 });
1061
- await walkFilesForCompositionOrEntry({
1062
- entity: entity.object,
1063
- directory,
1064
- fileClient,
1065
- callback: async ({ fileUrl }) => {
1066
- fileUrlReplacementQueue.add(async () => {
1067
- try {
1068
- const hash = urlToHash(fileUrl);
1069
- fileUrlReplacementQueue.add(async () => {
1070
- try {
1071
- const file = await fileClient.get({ sourceId: hash }).catch(() => null);
1072
- if (!file) {
1073
- return;
1074
- }
1075
- entityAsString = entityAsString.replaceAll(`"${fileUrl}"`, `"${file.url}"`);
1076
- } catch {
1077
- }
1078
- });
1079
- } catch {
1080
- }
1081
- });
1082
- return null;
1083
- }
1084
- });
1085
- await fileUrlReplacementQueue.onIdle();
1086
- return JSON.parse(entityAsString);
1087
- };
1088
- var escapeRegExp = (string) => {
1089
- return string.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
1090
- };
1091
- var hashToPartialPathname = (hash) => {
1092
- try {
1093
- return Buffer.from(hash, "base64").toString("utf8");
1094
- } catch {
1095
- return null;
907
+ await fileUrlReplacementQueue.onIdle();
1096
908
  }
909
+ return JSON.parse(sourceObjectAsString);
1097
910
  };
1098
- var findUrlMatchingPartialPathname = (source, pathname) => {
1099
- const escapedPathname = escapeRegExp(pathname);
1100
- const regex = new RegExp(
1101
- `"(https://([^"]*?)?(img|files).uniform.(rocks|global)${escapedPathname}([^"]*?))"`
1102
- );
1103
- const match = source.match(regex);
1104
- if (match && match[1]) {
1105
- return match[1];
911
+ var updateAssetFileIdBasedOnUrl = async (asset, options) => {
912
+ if (!asset.asset.fields) {
913
+ return asset;
1106
914
  }
1107
- return null;
915
+ const fileUrl = asset.asset.fields.url?.value;
916
+ if (!fileUrl) {
917
+ return asset;
918
+ }
919
+ const file = await options.fileClient.get({ url: fileUrl }).catch(() => null);
920
+ if (!file) {
921
+ return asset;
922
+ }
923
+ asset.asset.fields.file = {
924
+ type: "file",
925
+ value: file.id
926
+ };
927
+ return asset;
1108
928
  };
1109
929
 
1110
930
  // src/commands/canvas/assetEngineDataSource.ts
@@ -1295,25 +1115,27 @@ var AssetPullModule = {
1295
1115
  whatIf,
1296
1116
  allowEmptySource: allowEmptySource ?? true,
1297
1117
  log: createSyncEngineConsoleLogger({ diffMode }),
1298
- onBeforeCompareObjects: async (sourceObject) => {
1118
+ onBeforeCompareObjects: async (sourceObject, targetObject) => {
1299
1119
  delete sourceObject.object.asset._author;
1300
- return sourceObject;
1120
+ const sourceObjectWithPotentiallySwappedUrl = await replaceRemoteUrlsWithLocalReferences(
1121
+ sourceObject,
1122
+ targetObject,
1123
+ {
1124
+ directory,
1125
+ fileClient
1126
+ }
1127
+ );
1128
+ if (sourceObjectWithPotentiallySwappedUrl.object.asset.fields?.url && targetObject.object.asset.fields?.url && sourceObjectWithPotentiallySwappedUrl.object.asset.fields.url.value === targetObject.object.asset.fields.url.value) {
1129
+ targetObject.object.asset.fields.file = sourceObjectWithPotentiallySwappedUrl.object.asset.fields.file;
1130
+ }
1131
+ return sourceObjectWithPotentiallySwappedUrl;
1301
1132
  },
1302
- compareContents: compareAssetsWithoutUrls,
1303
1133
  onBeforeWriteObject: async (sourceObject) => {
1304
1134
  delete sourceObject.object.asset._author;
1305
- if (!sourceObject.object.asset.fields?.file) {
1306
- return sourceObject;
1307
- }
1308
- const downloadedFile = await downloadFileForAsset({
1309
- asset: sourceObject.object,
1135
+ return extractAndDownloadUniformFilesForObject(sourceObject, {
1310
1136
  directory,
1311
1137
  fileClient
1312
1138
  });
1313
- if (downloadedFile?.id) {
1314
- sourceObject.object.asset.fields.file.value = downloadedFile.id;
1315
- }
1316
- return sourceObject;
1317
1139
  }
1318
1140
  });
1319
1141
  }
@@ -1393,29 +1215,29 @@ var AssetPushModule = {
1393
1215
  if (targetObject) {
1394
1216
  delete targetObject.object.asset._author;
1395
1217
  }
1396
- return sourceObject;
1218
+ const sourceObjectWithNewFileUrls = await swapOutUniformFileUrlsForTargetProject(sourceObject, {
1219
+ fileClient
1220
+ });
1221
+ sourceObjectWithNewFileUrls.object = await updateAssetFileIdBasedOnUrl(
1222
+ sourceObjectWithNewFileUrls.object,
1223
+ {
1224
+ fileClient
1225
+ }
1226
+ );
1227
+ return sourceObjectWithNewFileUrls;
1397
1228
  },
1398
- compareContents: compareAssetsWithoutUrls,
1399
1229
  onBeforeWriteObject: async (sourceObject) => {
1400
- const uploadedFile = await uploadFileForAsset({
1401
- asset: sourceObject.object,
1230
+ const sourceObjectWithNewFileUrls = await extractAndUploadUniformFilesForObject(sourceObject, {
1402
1231
  directory,
1403
1232
  fileClient
1404
1233
  });
1405
- if (uploadedFile !== null) {
1406
- if (sourceObject.object.asset.fields === void 0) {
1407
- sourceObject.object.asset.fields = {};
1234
+ sourceObjectWithNewFileUrls.object = await updateAssetFileIdBasedOnUrl(
1235
+ sourceObjectWithNewFileUrls.object,
1236
+ {
1237
+ fileClient
1408
1238
  }
1409
- sourceObject.object.asset.fields.file = {
1410
- type: "file",
1411
- value: uploadedFile.id
1412
- };
1413
- sourceObject.object.asset.fields.url = {
1414
- type: "text",
1415
- value: uploadedFile.url
1416
- };
1417
- }
1418
- return sourceObject;
1239
+ );
1240
+ return sourceObjectWithNewFileUrls;
1419
1241
  }
1420
1242
  });
1421
1243
  }
@@ -2683,21 +2505,16 @@ var CompositionPullModule = {
2683
2505
  allowEmptySource: allowEmptySource ?? true,
2684
2506
  log: createSyncEngineConsoleLogger({ diffMode }),
2685
2507
  onBeforeCompareObjects: async (sourceObject, targetObject) => {
2686
- return replaceRemoteUrlsWithLocalReferences({
2687
- sourceEntity: sourceObject,
2688
- targetEntity: targetObject,
2508
+ return replaceRemoteUrlsWithLocalReferences(sourceObject, targetObject, {
2689
2509
  directory,
2690
2510
  fileClient
2691
2511
  });
2692
2512
  },
2693
- compareContents: compareCompositionsOrEntriesWithoutAssetUrls,
2694
2513
  onBeforeWriteObject: async (sourceObject) => {
2695
- await downloadFilesForCompositionOrEntry({
2696
- entity: sourceObject.object,
2514
+ return extractAndDownloadUniformFilesForObject(sourceObject, {
2697
2515
  directory,
2698
2516
  fileClient
2699
2517
  });
2700
- return sourceObject;
2701
2518
  }
2702
2519
  });
2703
2520
  }
@@ -2841,16 +2658,12 @@ var CompositionPushModule = {
2841
2658
  allowEmptySource,
2842
2659
  log: createSyncEngineConsoleLogger({ diffMode }),
2843
2660
  onBeforeCompareObjects: async (sourceObject) => {
2844
- return replaceLocalUrlsWithRemoteReferences({
2845
- entity: sourceObject,
2846
- directory,
2661
+ return swapOutUniformFileUrlsForTargetProject(sourceObject, {
2847
2662
  fileClient
2848
2663
  });
2849
2664
  },
2850
- compareContents: compareCompositionsOrEntriesWithoutAssetUrls,
2851
2665
  onBeforeWriteObject: async (sourceObject) => {
2852
- return uploadFilesForCompositionOrEntry({
2853
- entity: sourceObject,
2666
+ return extractAndUploadUniformFilesForObject(sourceObject, {
2854
2667
  directory,
2855
2668
  fileClient
2856
2669
  });
@@ -4444,21 +4257,16 @@ var EntryPullModule = {
4444
4257
  allowEmptySource: allowEmptySource ?? true,
4445
4258
  log: createSyncEngineConsoleLogger({ diffMode }),
4446
4259
  onBeforeCompareObjects: async (sourceObject, targetObject) => {
4447
- return replaceRemoteUrlsWithLocalReferences({
4448
- sourceEntity: sourceObject,
4449
- targetEntity: targetObject,
4260
+ return replaceRemoteUrlsWithLocalReferences(sourceObject, targetObject, {
4450
4261
  directory,
4451
4262
  fileClient
4452
4263
  });
4453
4264
  },
4454
- compareContents: compareCompositionsOrEntriesWithoutAssetUrls,
4455
4265
  onBeforeWriteObject: async (sourceObject) => {
4456
- await downloadFilesForCompositionOrEntry({
4457
- entity: sourceObject.object,
4266
+ return extractAndDownloadUniformFilesForObject(sourceObject, {
4458
4267
  directory,
4459
4268
  fileClient
4460
4269
  });
4461
- return sourceObject;
4462
4270
  }
4463
4271
  });
4464
4272
  }
@@ -4538,16 +4346,12 @@ var EntryPushModule = {
4538
4346
  allowEmptySource,
4539
4347
  log: createSyncEngineConsoleLogger({ diffMode }),
4540
4348
  onBeforeCompareObjects: async (sourceObject) => {
4541
- return replaceLocalUrlsWithRemoteReferences({
4542
- entity: sourceObject,
4543
- directory,
4349
+ return swapOutUniformFileUrlsForTargetProject(sourceObject, {
4544
4350
  fileClient
4545
4351
  });
4546
4352
  },
4547
- compareContents: compareCompositionsOrEntriesWithoutAssetUrls,
4548
4353
  onBeforeWriteObject: async (sourceObject) => {
4549
- return uploadFilesForCompositionOrEntry({
4550
- entity: sourceObject,
4354
+ return extractAndUploadUniformFilesForObject(sourceObject, {
4551
4355
  directory,
4552
4356
  fileClient
4553
4357
  });
@@ -4923,21 +4727,16 @@ var EntryPatternPullModule = {
4923
4727
  allowEmptySource: allowEmptySource ?? true,
4924
4728
  log: createSyncEngineConsoleLogger({ diffMode }),
4925
4729
  onBeforeCompareObjects: async (sourceObject, targetObject) => {
4926
- return replaceRemoteUrlsWithLocalReferences({
4927
- sourceEntity: sourceObject,
4928
- targetEntity: targetObject,
4730
+ return replaceRemoteUrlsWithLocalReferences(sourceObject, targetObject, {
4929
4731
  directory,
4930
4732
  fileClient
4931
4733
  });
4932
4734
  },
4933
- compareContents: compareCompositionsOrEntriesWithoutAssetUrls,
4934
4735
  onBeforeWriteObject: async (sourceObject) => {
4935
- await downloadFilesForCompositionOrEntry({
4936
- entity: sourceObject.object,
4736
+ return extractAndDownloadUniformFilesForObject(sourceObject, {
4937
4737
  directory,
4938
4738
  fileClient
4939
4739
  });
4940
- return sourceObject;
4941
4740
  }
4942
4741
  });
4943
4742
  }
@@ -5022,16 +4821,12 @@ var EntryPatternPushModule = {
5022
4821
  allowEmptySource,
5023
4822
  log: createSyncEngineConsoleLogger({ diffMode }),
5024
4823
  onBeforeCompareObjects: async (sourceObject) => {
5025
- return replaceLocalUrlsWithRemoteReferences({
5026
- entity: sourceObject,
5027
- directory,
4824
+ return swapOutUniformFileUrlsForTargetProject(sourceObject, {
5028
4825
  fileClient
5029
4826
  });
5030
4827
  },
5031
- compareContents: compareCompositionsOrEntriesWithoutAssetUrls,
5032
4828
  onBeforeWriteObject: async (sourceObject) => {
5033
- return uploadFilesForCompositionOrEntry({
5034
- entity: sourceObject,
4829
+ return extractAndUploadUniformFilesForObject(sourceObject, {
5035
4830
  directory,
5036
4831
  fileClient
5037
4832
  });
@@ -8418,7 +8213,6 @@ var package_default = {
8418
8213
  "@uniformdev/canvas": "workspace:*",
8419
8214
  "@uniformdev/context": "workspace:*",
8420
8215
  "@uniformdev/files": "workspace:*",
8421
- "@uniformdev/richtext": "workspace:*",
8422
8216
  "@uniformdev/project-map": "workspace:*",
8423
8217
  "@uniformdev/redirect": "workspace:*",
8424
8218
  "call-bind": "^1.0.2",
@@ -8428,11 +8222,11 @@ var package_default = {
8428
8222
  diff: "^5.0.0",
8429
8223
  dotenv: "^16.0.3",
8430
8224
  execa: "5.1.1",
8431
- "file-type": "^20.0.0",
8225
+ "file-type": "^19.6.0",
8432
8226
  "fs-jetpack": "5.1.0",
8433
8227
  graphql: "16.9.0",
8434
8228
  "graphql-request": "6.1.0",
8435
- "image-size": "^1.2.0",
8229
+ "image-size": "^1.0.2",
8436
8230
  inquirer: "9.2.17",
8437
8231
  "isomorphic-git": "1.25.2",
8438
8232
  "js-yaml": "^4.1.0",
@@ -8778,7 +8572,7 @@ ${err.message}`);
8778
8572
  // src/projects/cloneStarter.ts
8779
8573
  import crypto2 from "crypto";
8780
8574
  import fs3 from "fs";
8781
- import fsj5 from "fs-jetpack";
8575
+ import fsj2 from "fs-jetpack";
8782
8576
  import * as git from "isomorphic-git";
8783
8577
  import * as http from "isomorphic-git/http/node/index.js";
8784
8578
  import os from "os";
@@ -8809,7 +8603,7 @@ async function cloneStarter({
8809
8603
  throw new Error(`"${targetDir}" is not empty`);
8810
8604
  }
8811
8605
  const starterDir = path.join(cloneDir, ...pathSegments);
8812
- fsj5.copy(starterDir, targetDir, { overwrite: true });
8606
+ fsj2.copy(starterDir, targetDir, { overwrite: true });
8813
8607
  if (dotEnvFile) {
8814
8608
  fs3.writeFileSync(path.resolve(targetDir, ".env"), dotEnvFile, "utf-8");
8815
8609
  }
@@ -10789,14 +10583,14 @@ import { existsSync as existsSync4, promises as fs5 } from "fs";
10789
10583
  import { get as getHttp } from "http";
10790
10584
  import { get as getHttps } from "https";
10791
10585
  import { tmpdir } from "os";
10792
- import { join as join7 } from "path";
10586
+ import { join as join3 } from "path";
10793
10587
  import registryUrl from "registry-url";
10794
10588
  import { URL as URL2 } from "url";
10795
10589
  var compareVersions = (a, b) => a.localeCompare(b, "en-US", { numeric: true });
10796
10590
  var encode = (value) => encodeURIComponent(value).replace(/^%40/, "@");
10797
10591
  var getFile = async (details, distTag) => {
10798
10592
  const rootDir = tmpdir();
10799
- const subDir = join7(rootDir, "update-check");
10593
+ const subDir = join3(rootDir, "update-check");
10800
10594
  if (!existsSync4(subDir)) {
10801
10595
  await fs5.mkdir(subDir);
10802
10596
  }
@@ -10804,7 +10598,7 @@ var getFile = async (details, distTag) => {
10804
10598
  if (details.scope) {
10805
10599
  name = `${details.scope}-${name}`;
10806
10600
  }
10807
- return join7(subDir, name);
10601
+ return join3(subDir, name);
10808
10602
  };
10809
10603
  var evaluateCache = async (file, time, interval) => {
10810
10604
  if (existsSync4(file)) {
@@ -10959,7 +10753,7 @@ var checkForUpdateMiddleware = async ({ verbose }) => {
10959
10753
 
10960
10754
  // src/middleware/checkLocalDepsVersionsMiddleware.ts
10961
10755
  import { magenta, red as red5 } from "colorette";
10962
- import { join as join8 } from "path";
10756
+ import { join as join4 } from "path";
10963
10757
 
10964
10758
  // src/fs.ts
10965
10759
  import { promises as fs6 } from "fs";
@@ -10998,7 +10792,7 @@ var checkLocalDepsVersions = async (args) => {
10998
10792
  try {
10999
10793
  let isOutside = false;
11000
10794
  let warning = `${magenta("Warning:")} Installed Uniform packages should be the same version`;
11001
- const localPackages = await tryReadJSON(join8(process.cwd(), "package.json"));
10795
+ const localPackages = await tryReadJSON(join4(process.cwd(), "package.json"));
11002
10796
  if (!localPackages) return;
11003
10797
  let firstVersion;
11004
10798
  const allDependencies = {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@uniformdev/cli",
3
- "version": "19.214.1-alpha.32+fb2084b713",
3
+ "version": "19.214.1-alpha.33+be2bde7eba",
4
4
  "description": "Uniform command line interface tool",
5
5
  "license": "SEE LICENSE IN LICENSE.txt",
6
6
  "main": "./cli.js",
@@ -27,13 +27,12 @@
27
27
  },
28
28
  "dependencies": {
29
29
  "@thi.ng/mime": "^2.2.23",
30
- "@uniformdev/assets": "19.214.1-alpha.32+fb2084b713",
31
- "@uniformdev/canvas": "19.214.1-alpha.32+fb2084b713",
32
- "@uniformdev/context": "19.214.1-alpha.32+fb2084b713",
33
- "@uniformdev/files": "19.214.1-alpha.32+fb2084b713",
34
- "@uniformdev/project-map": "19.214.1-alpha.32+fb2084b713",
35
- "@uniformdev/redirect": "19.214.1-alpha.32+fb2084b713",
36
- "@uniformdev/richtext": "19.214.1-alpha.32+fb2084b713",
30
+ "@uniformdev/assets": "19.214.1-alpha.33+be2bde7eba",
31
+ "@uniformdev/canvas": "19.214.1-alpha.33+be2bde7eba",
32
+ "@uniformdev/context": "19.214.1-alpha.33+be2bde7eba",
33
+ "@uniformdev/files": "19.214.1-alpha.33+be2bde7eba",
34
+ "@uniformdev/project-map": "19.214.1-alpha.33+be2bde7eba",
35
+ "@uniformdev/redirect": "19.214.1-alpha.33+be2bde7eba",
37
36
  "call-bind": "^1.0.2",
38
37
  "colorette": "2.0.20",
39
38
  "cosmiconfig": "9.0.0",
@@ -41,11 +40,11 @@
41
40
  "diff": "^5.0.0",
42
41
  "dotenv": "^16.0.3",
43
42
  "execa": "5.1.1",
44
- "file-type": "^20.0.0",
43
+ "file-type": "^19.6.0",
45
44
  "fs-jetpack": "5.1.0",
46
45
  "graphql": "16.9.0",
47
46
  "graphql-request": "6.1.0",
48
- "image-size": "^1.2.0",
47
+ "image-size": "^1.0.2",
49
48
  "inquirer": "9.2.17",
50
49
  "isomorphic-git": "1.25.2",
51
50
  "js-yaml": "^4.1.0",
@@ -79,5 +78,5 @@
79
78
  "publishConfig": {
80
79
  "access": "public"
81
80
  },
82
- "gitHead": "fb2084b713e551eb79a28c6d8a372f3b3038d02e"
81
+ "gitHead": "be2bde7eba9949b3a2841fdac6d27e54565f7897"
83
82
  }