@uniformdev/cli 19.81.2-alpha.22 → 19.82.1-alpha.5

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 +168 -37
  2. package/package.json +8 -8
package/dist/index.mjs CHANGED
@@ -669,30 +669,62 @@ var AssetListModule = {
669
669
 
670
670
  // src/commands/canvas/commands/asset/pull.ts
671
671
  import { UncachedAssetClient as UncachedAssetClient3 } from "@uniformdev/assets";
672
+ import { UncachedFileClient } from "@uniformdev/files";
672
673
 
673
674
  // src/files/index.ts
674
675
  import { preferredType } from "@thi.ng/mime";
675
676
  import { FILE_READY_STATE, getFileNameFromUrl } from "@uniformdev/files";
676
- import { createHash } from "crypto";
677
677
  import fsj from "fs-jetpack";
678
678
  import sizeOf from "image-size";
679
679
  import PQueue from "p-queue";
680
680
  import { dirname as dirname2, join as join2 } from "path";
681
681
  var FILES_DIRECTORY_NAME = "files";
682
+ var escapeRegExp = (string) => {
683
+ return string.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
684
+ };
682
685
  var urlToHash = (url) => {
683
- const hash = createHash("sha256");
684
- hash.update(url);
685
- return hash.digest("hex");
686
+ return Buffer.from(
687
+ // We take only the first 64 characters of the pathname as
688
+ // that's enough to guarantee uniqueness
689
+ new URL(url).pathname.substring(0, 64)
690
+ ).toString("base64");
691
+ };
692
+ var hashToPartialPathname = (hash) => {
693
+ try {
694
+ return Buffer.from(hash, "base64").toString("utf8");
695
+ } catch {
696
+ return null;
697
+ }
698
+ };
699
+ var findUrlMatchingPartialPathname = (source, pathname) => {
700
+ const escapedPathname = escapeRegExp(pathname);
701
+ const regex = new RegExp(`"(https://([^"]*?)?img.uniform.(rocks|global)${escapedPathname}([^"]*?))"`);
702
+ const match = source.match(regex);
703
+ if (match && match[1]) {
704
+ return match[1];
705
+ }
706
+ return null;
686
707
  };
687
- var urlToFileName = (url) => {
688
- const fileName = urlToHash(url);
708
+ var urlToFileName = (url, hash) => {
709
+ const fileName = hash ?? urlToHash(url);
689
710
  const fileNameChunks = url.split(".");
690
711
  const fileExtension = fileNameChunks.length > 1 ? fileNameChunks.at(-1) : "";
691
712
  return `${fileName}${fileExtension ? `.${fileExtension}` : ""}`;
692
713
  };
714
+ var getFilesDirectory = (directory) => {
715
+ const isPackage = isPathAPackageFile(directory);
716
+ return isPackage ? dirname2(directory) : (
717
+ // If we are syncing to a directory, we want to write all files into a
718
+ // top-lvl folder. That way any entities that contain files will sync to the
719
+ // same directory, so there is no duplication
720
+ join2(directory, "..")
721
+ );
722
+ };
723
+ var getUniformFileUrlMatches = (string) => {
724
+ return string.matchAll(/"(https:\/\/(.*?)?img\.uniform\.(rocks|global)\/(.*?))"/g);
725
+ };
693
726
  var deleteDownloadedFileByUrl = async (url, options) => {
694
- const isPackage = isPathAPackageFile(options.directory);
695
- const writeDirectory = isPackage ? dirname2(options.directory) : options.directory;
727
+ const writeDirectory = getFilesDirectory(options.directory);
696
728
  const fileName = urlToFileName(url);
697
729
  const fileToDelete = join2(writeDirectory, FILES_DIRECTORY_NAME, fileName);
698
730
  try {
@@ -703,18 +735,14 @@ var deleteDownloadedFileByUrl = async (url, options) => {
703
735
  };
704
736
  var extractAndDownloadUniformFilesForObject = async (object, options) => {
705
737
  const objectAsString = JSON.stringify(object);
706
- const uniformFileUrlMatches = objectAsString.matchAll(
707
- /"(https:\/\/(.*)?img\.uniform\.(rocks|global)\/(.*?))"/g
708
- );
709
- const isPackage = isPathAPackageFile(options.directory);
710
- const writeDirectory = isPackage ? dirname2(options.directory) : options.directory;
738
+ const uniformFileUrlMatches = getUniformFileUrlMatches(objectAsString);
739
+ const writeDirectory = getFilesDirectory(options.directory);
711
740
  if (uniformFileUrlMatches) {
712
741
  const fileDownloadQueue = new PQueue({ concurrency: 10 });
713
742
  for (const match of uniformFileUrlMatches) {
714
743
  const url = new URL(match[1]);
715
744
  fileDownloadQueue.add(async () => {
716
745
  try {
717
- const fetchUrl = `${url.origin}${url.pathname}?format=original`;
718
746
  const fileName = urlToFileName(url.toString());
719
747
  const fileAlreadyExists = await fsj.existsAsync(
720
748
  join2(writeDirectory, FILES_DIRECTORY_NAME, fileName)
@@ -722,6 +750,20 @@ var extractAndDownloadUniformFilesForObject = async (object, options) => {
722
750
  if (fileAlreadyExists) {
723
751
  return;
724
752
  }
753
+ const file = await options.fileClient.get({ url: url.toString() }).catch(() => null);
754
+ if (!file) {
755
+ console.warn(`Skipping file ${url} as it does not exist in the project anymore`);
756
+ return;
757
+ }
758
+ if (file.sourceId) {
759
+ const hashAlreadyExists = await fsj.findAsync(join2(writeDirectory, FILES_DIRECTORY_NAME), {
760
+ matching: [file.sourceId, `${file.sourceId}.*`]
761
+ });
762
+ if (hashAlreadyExists.length > 0) {
763
+ return;
764
+ }
765
+ }
766
+ const fetchUrl = `${url.origin}${url.pathname}?format=original`;
725
767
  const response = await fetch(fetchUrl);
726
768
  if (!response.ok) {
727
769
  return;
@@ -739,11 +781,8 @@ var extractAndDownloadUniformFilesForObject = async (object, options) => {
739
781
  };
740
782
  var extractAndUploadUniformFilesForObject = async (object, options) => {
741
783
  let objectAsString = JSON.stringify(object);
742
- const uniformFileUrlMatches = objectAsString.matchAll(
743
- /"(https:\/\/(.*)?img\.uniform\.(rocks|global)\/(.*?))"/g
744
- );
745
- const isPackage = isPathAPackageFile(options.directory);
746
- const writeDirectory = isPackage ? dirname2(options.directory) : options.directory;
784
+ const uniformFileUrlMatches = getUniformFileUrlMatches(objectAsString);
785
+ const writeDirectory = getFilesDirectory(options.directory);
747
786
  if (uniformFileUrlMatches) {
748
787
  const fileUploadQueue = new PQueue({ concurrency: 3 });
749
788
  for (const match of uniformFileUrlMatches) {
@@ -831,9 +870,7 @@ var extractAndUploadUniformFilesForObject = async (object, options) => {
831
870
  };
832
871
  var swapOutUniformFileUrlsForTargetProject = async (object, options) => {
833
872
  let objectAsString = JSON.stringify(object);
834
- const uniformFileUrlMatches = objectAsString.matchAll(
835
- /"(https:\/\/(.*)?img\.uniform\.(rocks|global)\/(.*?))"/g
836
- );
873
+ const uniformFileUrlMatches = getUniformFileUrlMatches(objectAsString);
837
874
  if (uniformFileUrlMatches) {
838
875
  const fileUrlReplacementQueue = new PQueue({ concurrency: 3 });
839
876
  for (const match of uniformFileUrlMatches) {
@@ -858,6 +895,45 @@ var swapOutUniformFileUrlsForTargetProject = async (object, options) => {
858
895
  }
859
896
  return JSON.parse(objectAsString);
860
897
  };
898
+ var replaceRemoteUrlsWithLocalReferences = async (sourceObject, targetObject, options) => {
899
+ let sourceObjectAsString = JSON.stringify(sourceObject);
900
+ const targetObjectAsString = JSON.stringify(targetObject);
901
+ const uniformFileUrlMatches = getUniformFileUrlMatches(sourceObjectAsString);
902
+ const writeDirectory = getFilesDirectory(options.directory);
903
+ if (uniformFileUrlMatches) {
904
+ const fileUrlReplacementQueue = new PQueue({ concurrency: 3 });
905
+ for (const match of uniformFileUrlMatches) {
906
+ const url = match[1];
907
+ fileUrlReplacementQueue.add(async () => {
908
+ try {
909
+ const localFileName = urlToFileName(url);
910
+ const fileExistsLocally = await fsj.existsAsync(
911
+ join2(writeDirectory, FILES_DIRECTORY_NAME, localFileName)
912
+ );
913
+ if (fileExistsLocally) {
914
+ return;
915
+ }
916
+ const file = await options.fileClient.get({ url }).catch(() => null);
917
+ if (!file || !file.sourceId) {
918
+ return;
919
+ }
920
+ const originalPartialPath = hashToPartialPathname(file.sourceId);
921
+ if (!originalPartialPath) {
922
+ return;
923
+ }
924
+ const originalUrl = findUrlMatchingPartialPathname(targetObjectAsString, originalPartialPath);
925
+ if (!originalUrl) {
926
+ return;
927
+ }
928
+ sourceObjectAsString = sourceObjectAsString.replaceAll(`"${url}"`, `"${originalUrl}"`);
929
+ } catch {
930
+ }
931
+ });
932
+ }
933
+ await fileUrlReplacementQueue.onIdle();
934
+ }
935
+ return JSON.parse(sourceObjectAsString);
936
+ };
861
937
  var updateAssetFileIdBasedOnUrl = async (asset, options) => {
862
938
  var _a, _b, _c;
863
939
  const fileUrl = (_b = (_a = asset.asset.fields) == null ? void 0 : _a.url) == null ? void 0 : _b.value;
@@ -1009,6 +1085,7 @@ var AssetPullModule = {
1009
1085
  fetch: fetch3,
1010
1086
  projectId
1011
1087
  });
1088
+ const fileClient = new UncachedFileClient({ apiKey, apiHost, fetch: fetch3, projectId });
1012
1089
  const source = createAssetEngineDataSource({ client });
1013
1090
  let target;
1014
1091
  const isPackage = isPathAPackageFile(directory);
@@ -1050,14 +1127,27 @@ var AssetPullModule = {
1050
1127
  whatIf,
1051
1128
  allowEmptySource: true,
1052
1129
  log: createSyncEngineConsoleLogger({ diffMode }),
1053
- onBeforeCompareObjects: async (sourceObject) => {
1130
+ onBeforeCompareObjects: async (sourceObject, targetObject) => {
1131
+ var _a, _b;
1054
1132
  delete sourceObject.object.asset._author;
1055
- return sourceObject;
1133
+ const sourceObjectWithPotentiallySwappedUrl = await replaceRemoteUrlsWithLocalReferences(
1134
+ sourceObject,
1135
+ targetObject,
1136
+ {
1137
+ directory,
1138
+ fileClient
1139
+ }
1140
+ );
1141
+ if (((_a = sourceObjectWithPotentiallySwappedUrl.object.asset.fields) == null ? void 0 : _a.url) && ((_b = targetObject.object.asset.fields) == null ? void 0 : _b.url) && sourceObjectWithPotentiallySwappedUrl.object.asset.fields.url.value === targetObject.object.asset.fields.url.value) {
1142
+ targetObject.object.asset.fields.file = sourceObjectWithPotentiallySwappedUrl.object.asset.fields.file;
1143
+ }
1144
+ return sourceObjectWithPotentiallySwappedUrl;
1056
1145
  },
1057
1146
  onBeforeWriteObject: async (sourceObject) => {
1058
1147
  delete sourceObject.object.asset._author;
1059
1148
  return extractAndDownloadUniformFilesForObject(sourceObject, {
1060
- directory
1149
+ directory,
1150
+ fileClient
1061
1151
  });
1062
1152
  }
1063
1153
  });
@@ -1066,7 +1156,7 @@ var AssetPullModule = {
1066
1156
 
1067
1157
  // src/commands/canvas/commands/asset/push.ts
1068
1158
  import { UncachedAssetClient as UncachedAssetClient4 } from "@uniformdev/assets";
1069
- import { UncachedFileClient } from "@uniformdev/files";
1159
+ import { UncachedFileClient as UncachedFileClient2 } from "@uniformdev/files";
1070
1160
  var AssetPushModule = {
1071
1161
  command: "push <directory>",
1072
1162
  describe: "Pushes all assets from files in a directory to Uniform",
@@ -1127,7 +1217,7 @@ var AssetPushModule = {
1127
1217
  });
1128
1218
  }
1129
1219
  const target = createAssetEngineDataSource({ client });
1130
- const fileClient = new UncachedFileClient({ apiKey, apiHost, fetch: fetch3, projectId });
1220
+ const fileClient = new UncachedFileClient2({ apiKey, apiHost, fetch: fetch3, projectId });
1131
1221
  await syncEngine({
1132
1222
  source,
1133
1223
  target,
@@ -1150,10 +1240,15 @@ var AssetPushModule = {
1150
1240
  return sourceObjectWithNewFileUrls;
1151
1241
  },
1152
1242
  onBeforeWriteObject: async (sourceObject) => {
1153
- const sourceObjectWithNewFileUrls = await extractAndUploadUniformFilesForObject(sourceObject, {
1154
- directory,
1155
- fileClient
1156
- });
1243
+ const sourceObjectWithNewFileUrls = await swapOutUniformFileUrlsForTargetProject(
1244
+ await extractAndUploadUniformFilesForObject(sourceObject, {
1245
+ directory,
1246
+ fileClient
1247
+ }),
1248
+ {
1249
+ fileClient
1250
+ }
1251
+ );
1157
1252
  sourceObjectWithNewFileUrls.object = await updateAssetFileIdBasedOnUrl(
1158
1253
  sourceObjectWithNewFileUrls.object,
1159
1254
  {
@@ -2089,6 +2184,7 @@ var CompositionPublishModule = {
2089
2184
 
2090
2185
  // src/commands/canvas/commands/composition/pull.ts
2091
2186
  import { UncachedCanvasClient as UncachedCanvasClient10 } from "@uniformdev/canvas";
2187
+ import { UncachedFileClient as UncachedFileClient3 } from "@uniformdev/files";
2092
2188
  var CompositionPullModule = {
2093
2189
  command: "pull <directory>",
2094
2190
  describe: "Pulls all compositions to local files in a directory",
@@ -2148,6 +2244,7 @@ var CompositionPullModule = {
2148
2244
  }) => {
2149
2245
  const fetch3 = nodeFetchProxy(proxy);
2150
2246
  const client = new UncachedCanvasClient10({ apiKey, apiHost, fetch: fetch3, projectId });
2247
+ const fileClient = new UncachedFileClient3({ apiKey, apiHost, fetch: fetch3, projectId });
2151
2248
  const source = createComponentInstanceEngineDataSource({ client, state, onlyCompositions, onlyPatterns });
2152
2249
  const isPackage = isPathAPackageFile(directory);
2153
2250
  let target;
@@ -2177,9 +2274,16 @@ var CompositionPullModule = {
2177
2274
  whatIf,
2178
2275
  allowEmptySource: true,
2179
2276
  log: createSyncEngineConsoleLogger({ diffMode }),
2277
+ onBeforeCompareObjects: async (sourceObject, targetObject) => {
2278
+ return replaceRemoteUrlsWithLocalReferences(sourceObject, targetObject, {
2279
+ directory,
2280
+ fileClient
2281
+ });
2282
+ },
2180
2283
  onBeforeWriteObject: async (sourceObject) => {
2181
2284
  return extractAndDownloadUniformFilesForObject(sourceObject, {
2182
- directory
2285
+ directory,
2286
+ fileClient
2183
2287
  });
2184
2288
  }
2185
2289
  });
@@ -2188,7 +2292,7 @@ var CompositionPullModule = {
2188
2292
 
2189
2293
  // src/commands/canvas/commands/composition/push.ts
2190
2294
  import { UncachedCanvasClient as UncachedCanvasClient11 } from "@uniformdev/canvas";
2191
- import { UncachedFileClient as UncachedFileClient2 } from "@uniformdev/files";
2295
+ import { UncachedFileClient as UncachedFileClient4 } from "@uniformdev/files";
2192
2296
  var CompositionPushModule = {
2193
2297
  command: "push <directory>",
2194
2298
  describe: "Pushes all compositions from files in a directory to Uniform Canvas",
@@ -2258,7 +2362,7 @@ var CompositionPushModule = {
2258
2362
  });
2259
2363
  }
2260
2364
  const target = createComponentInstanceEngineDataSource({ client, state, onlyCompositions, onlyPatterns });
2261
- const fileClient = new UncachedFileClient2({ apiKey, apiHost, fetch: fetch3, projectId });
2365
+ const fileClient = new UncachedFileClient4({ apiKey, apiHost, fetch: fetch3, projectId });
2262
2366
  await syncEngine({
2263
2367
  source,
2264
2368
  target,
@@ -3061,6 +3165,7 @@ var EntryListModule = {
3061
3165
 
3062
3166
  // src/commands/canvas/commands/entry/pull.ts
3063
3167
  import { ContentClient as ContentClient10 } from "@uniformdev/canvas";
3168
+ import { UncachedFileClient as UncachedFileClient5 } from "@uniformdev/files";
3064
3169
 
3065
3170
  // src/commands/canvas/entryEngineDataSource.ts
3066
3171
  import { convertEntryToPutEntry } from "@uniformdev/canvas";
@@ -3160,6 +3265,7 @@ var EntryPullModule = {
3160
3265
  projectId,
3161
3266
  bypassCache: true
3162
3267
  });
3268
+ const fileClient = new UncachedFileClient5({ apiKey, apiHost, fetch: fetch3, projectId });
3163
3269
  const source = createEntryEngineDataSource({ client, state });
3164
3270
  let target;
3165
3271
  const isPackage = isPathAPackageFile(directory);
@@ -3188,13 +3294,26 @@ var EntryPullModule = {
3188
3294
  mode,
3189
3295
  whatIf,
3190
3296
  allowEmptySource: true,
3191
- log: createSyncEngineConsoleLogger({ diffMode })
3297
+ log: createSyncEngineConsoleLogger({ diffMode }),
3298
+ onBeforeCompareObjects: async (sourceObject, targetObject) => {
3299
+ return replaceRemoteUrlsWithLocalReferences(sourceObject, targetObject, {
3300
+ directory,
3301
+ fileClient
3302
+ });
3303
+ },
3304
+ onBeforeWriteObject: async (sourceObject) => {
3305
+ return extractAndDownloadUniformFilesForObject(sourceObject, {
3306
+ directory,
3307
+ fileClient
3308
+ });
3309
+ }
3192
3310
  });
3193
3311
  }
3194
3312
  };
3195
3313
 
3196
3314
  // src/commands/canvas/commands/entry/push.ts
3197
3315
  import { ContentClient as ContentClient11 } from "@uniformdev/canvas";
3316
+ import { UncachedFileClient as UncachedFileClient6 } from "@uniformdev/files";
3198
3317
  var EntryPushModule = {
3199
3318
  command: "push <directory>",
3200
3319
  describe: "Pushes all entries from files in a directory to Uniform",
@@ -3259,12 +3378,24 @@ var EntryPushModule = {
3259
3378
  });
3260
3379
  }
3261
3380
  const target = createEntryEngineDataSource({ client, state });
3381
+ const fileClient = new UncachedFileClient6({ apiKey, apiHost, fetch: fetch3, projectId });
3262
3382
  await syncEngine({
3263
3383
  source,
3264
3384
  target,
3265
3385
  mode,
3266
3386
  whatIf,
3267
- log: createSyncEngineConsoleLogger({ diffMode })
3387
+ log: createSyncEngineConsoleLogger({ diffMode }),
3388
+ onBeforeCompareObjects: async (sourceObject) => {
3389
+ return swapOutUniformFileUrlsForTargetProject(sourceObject, {
3390
+ fileClient
3391
+ });
3392
+ },
3393
+ onBeforeWriteObject: async (sourceObject) => {
3394
+ return extractAndUploadUniformFilesForObject(sourceObject, {
3395
+ directory,
3396
+ fileClient
3397
+ });
3398
+ }
3268
3399
  });
3269
3400
  }
3270
3401
  };
@@ -5455,7 +5586,7 @@ import { PostHog } from "posthog-node";
5455
5586
  // package.json
5456
5587
  var package_default = {
5457
5588
  name: "@uniformdev/cli",
5458
- version: "19.81.1",
5589
+ version: "19.82.0",
5459
5590
  description: "Uniform command line interface tool",
5460
5591
  license: "SEE LICENSE IN LICENSE.txt",
5461
5592
  main: "./cli.js",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@uniformdev/cli",
3
- "version": "19.81.2-alpha.22+2fbda83df",
3
+ "version": "19.82.1-alpha.5+7af3d5cdf",
4
4
  "description": "Uniform command line interface tool",
5
5
  "license": "SEE LICENSE IN LICENSE.txt",
6
6
  "main": "./cli.js",
@@ -17,12 +17,12 @@
17
17
  },
18
18
  "dependencies": {
19
19
  "@thi.ng/mime": "^2.2.23",
20
- "@uniformdev/assets": "19.81.2-alpha.22+2fbda83df",
21
- "@uniformdev/canvas": "19.81.2-alpha.22+2fbda83df",
22
- "@uniformdev/context": "19.81.2-alpha.22+2fbda83df",
23
- "@uniformdev/files": "19.81.2-alpha.22+2fbda83df",
24
- "@uniformdev/project-map": "19.81.2-alpha.22+2fbda83df",
25
- "@uniformdev/redirect": "19.81.2-alpha.22+2fbda83df",
20
+ "@uniformdev/assets": "19.82.1-alpha.5+7af3d5cdf",
21
+ "@uniformdev/canvas": "19.82.1-alpha.5+7af3d5cdf",
22
+ "@uniformdev/context": "19.82.1-alpha.5+7af3d5cdf",
23
+ "@uniformdev/files": "19.82.1-alpha.5+7af3d5cdf",
24
+ "@uniformdev/project-map": "19.82.1-alpha.5+7af3d5cdf",
25
+ "@uniformdev/redirect": "19.82.1-alpha.5+7af3d5cdf",
26
26
  "call-bind": "^1.0.2",
27
27
  "colorette": "2.0.20",
28
28
  "cosmiconfig": "8.3.6",
@@ -69,5 +69,5 @@
69
69
  "publishConfig": {
70
70
  "access": "public"
71
71
  },
72
- "gitHead": "2fbda83df1085a9a91c7fbe9ac53056cc64707d2"
72
+ "gitHead": "7af3d5cdfabfe24f8a0d55b430cb2c196d5934d8"
73
73
  }