@uniformdev/cli 20.69.0 → 20.69.1-alpha.10

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 +179 -55
  2. package/package.json +9 -9
package/dist/index.mjs CHANGED
@@ -628,6 +628,9 @@ export default uniformConfig({
628
628
  `;
629
629
 
630
630
  // src/sync/fileSyncEngineDataSource.ts
631
+ function isErrorWithCode(error, code) {
632
+ return typeof error === "object" && error !== null && "code" in error && error.code === code;
633
+ }
631
634
  async function createFileSyncEngineDataSource({
632
635
  directory,
633
636
  format = "yaml",
@@ -688,7 +691,7 @@ ${e?.message}`));
688
691
  }
689
692
  await unlink(providerId);
690
693
  },
691
- writeObject: async (object4) => {
694
+ writeObject: async (object4, existingObject) => {
692
695
  const filename = selectFilename3 ? join(directory, `${selectFilename3(object4.object)}.${format}`) : getFullFilename(object4.id);
693
696
  let contents = object4.object;
694
697
  if (selectSchemaUrl2) {
@@ -701,6 +704,18 @@ ${e?.message}`));
701
704
  console.log(`Writing file ${filename}`);
702
705
  }
703
706
  emitWithFormat(contents, format, filename);
707
+ if (existingObject?.providerId && existingObject.providerId !== filename) {
708
+ if (verbose) {
709
+ console.log(`Deleting file ${existingObject.providerId}`);
710
+ }
711
+ try {
712
+ await unlink(existingObject.providerId);
713
+ } catch (error) {
714
+ if (!isErrorWithCode(error, "ENOENT")) {
715
+ throw error;
716
+ }
717
+ }
718
+ }
704
719
  }
705
720
  };
706
721
  }
@@ -724,6 +739,7 @@ function writeUniformPackage(filename, packageContents) {
724
739
  // src/sync/syncEngine.ts
725
740
  import { diffJson, diffLines } from "diff";
726
741
  import mitt from "mitt";
742
+ import PQueue from "p-queue";
727
743
 
728
744
  // src/sync/serializedDequal.ts
729
745
  var has = Object.prototype.hasOwnProperty;
@@ -790,7 +806,8 @@ async function syncEngine({
790
806
  onBeforeProcessObject,
791
807
  onBeforeCompareObjects,
792
808
  onBeforeWriteObject,
793
- onError
809
+ onError,
810
+ actionConcurrency
794
811
  //verbose = false,
795
812
  }) {
796
813
  const status = new ReactiveStatusUpdate((status2) => syncEngineEvents.emit("statusUpdate", status2));
@@ -839,43 +856,46 @@ async function syncEngine({
839
856
  const ids = Array.isArray(sourceObject.id) ? sourceObject.id : [sourceObject.id];
840
857
  const targetObject = targetItems.get(ids[0]);
841
858
  status.compared++;
842
- const invalidTargetObjects = ids.map((i) => targetItems.get(i)).filter((o) => o?.object !== targetObject?.object);
859
+ const invalidTargetObjects = ids.map((i) => targetItems.get(i)).filter(
860
+ (invalidTargetObject) => typeof invalidTargetObject !== "undefined" && invalidTargetObject.object !== targetObject?.object
861
+ );
862
+ const targetIds = Array.isArray(targetObject?.id) ? targetObject.id : [targetObject?.id];
863
+ const processedIds = new Set([...ids, ...targetIds].filter((id) => typeof id === "string"));
864
+ const processUpdate = async (sourceObject2, targetObject2) => {
865
+ try {
866
+ if (!whatIf) {
867
+ const finalSourceObject = onBeforeWriteObject ? await onBeforeWriteObject(sourceObject2, targetObject2) : sourceObject2;
868
+ await target.writeObject(finalSourceObject, targetObject2);
869
+ status.changesApplied++;
870
+ }
871
+ } catch (e) {
872
+ if (onError) {
873
+ onError(e, sourceObject2);
874
+ } else {
875
+ throw new SyncEngineError(e, sourceObject2);
876
+ }
877
+ } finally {
878
+ log2({
879
+ action: "update",
880
+ id: ids[0],
881
+ providerId: sourceObject2.providerId,
882
+ displayName: sourceObject2.displayName ?? sourceObject2.providerId,
883
+ whatIf,
884
+ diff: () => diffJson(targetObject2.object, sourceObject2.object)
885
+ });
886
+ }
887
+ };
843
888
  if (targetObject && invalidTargetObjects.length === 0) {
844
889
  sourceObject = onBeforeCompareObjects ? await onBeforeCompareObjects(sourceObject, targetObject) : sourceObject;
845
890
  const compareResult = compareContents(sourceObject, targetObject);
846
891
  if (!compareResult) {
847
892
  if (mode === "createOrUpdate" || mode === "mirror") {
848
893
  status.changeCount++;
849
- const process2 = async (sourceObject2, targetObject2) => {
850
- try {
851
- if (!whatIf) {
852
- const finalSourceObject = onBeforeWriteObject ? await onBeforeWriteObject(sourceObject2, targetObject2) : sourceObject2;
853
- await target.writeObject(finalSourceObject, targetObject2);
854
- status.changesApplied++;
855
- }
856
- } catch (e) {
857
- if (onError) {
858
- onError(e, sourceObject2);
859
- } else {
860
- throw new SyncEngineError(e, sourceObject2);
861
- }
862
- } finally {
863
- log2({
864
- action: "update",
865
- id: ids[0],
866
- providerId: sourceObject2.providerId,
867
- displayName: sourceObject2.displayName ?? sourceObject2.providerId,
868
- whatIf,
869
- diff: () => diffJson(targetObject2.object, sourceObject2.object)
870
- });
871
- }
872
- };
873
- actions.push(() => process2(sourceObject, targetObject));
894
+ actions.push(() => processUpdate(sourceObject, targetObject));
874
895
  }
875
896
  }
876
- ids.forEach((i) => targetItems.delete(i));
897
+ processedIds.forEach((i) => targetItems.delete(i));
877
898
  } else {
878
- status.changeCount++;
879
899
  const processUpsert = async (sourceObject2, id) => {
880
900
  try {
881
901
  if (!whatIf) {
@@ -901,6 +921,23 @@ async function syncEngine({
901
921
  }
902
922
  };
903
923
  if (invalidTargetObjects.length > 0) {
924
+ if (mode === "createOrUpdate" && !targetObject && invalidTargetObjects.length === 1) {
925
+ const matchedTargetObject = invalidTargetObjects[0];
926
+ sourceObject = onBeforeCompareObjects ? await onBeforeCompareObjects(sourceObject, matchedTargetObject) : sourceObject;
927
+ const compareResult = compareContents(sourceObject, matchedTargetObject);
928
+ if (!compareResult) {
929
+ status.changeCount++;
930
+ actions.push(() => processUpdate(sourceObject, matchedTargetObject));
931
+ }
932
+ (Array.isArray(matchedTargetObject.id) ? matchedTargetObject.id : [matchedTargetObject.id]).forEach(
933
+ (i) => targetItems.delete(i)
934
+ );
935
+ continue;
936
+ }
937
+ if (mode !== "mirror") {
938
+ continue;
939
+ }
940
+ status.changeCount++;
904
941
  [...invalidTargetObjects, targetObject].forEach((o) => {
905
942
  (Array.isArray(o?.id) ? o?.id : [o?.id])?.forEach((i) => i && targetItems.delete(i));
906
943
  });
@@ -908,31 +945,47 @@ async function syncEngine({
908
945
  if (targetObject) {
909
946
  deletes.push(() => processDelete(targetObject));
910
947
  }
911
- actions.push(
912
- () => Promise.all(deletes.map((deleteFn) => deleteFn())).then(() => processUpsert(sourceObject, ids[0]))
913
- );
948
+ actions.push(async () => {
949
+ for (const deleteFn of deletes) {
950
+ await deleteFn();
951
+ }
952
+ await processUpsert(sourceObject, ids[0]);
953
+ });
914
954
  } else {
955
+ status.changeCount++;
915
956
  actions.push(() => processUpsert(sourceObject, ids[0]));
916
957
  }
917
958
  }
918
959
  }
919
- status.changeCount += targetItems.size;
920
- status.compared += targetItems.size;
960
+ const orphanTargetObjects = new Set(targetItems.values());
921
961
  if (mode === "mirror") {
922
- if (!sourceHasItems && !allowEmptySource && targetItems.size > 0) {
962
+ status.changeCount += orphanTargetObjects.size;
963
+ status.compared += orphanTargetObjects.size;
964
+ if (!sourceHasItems && !allowEmptySource && orphanTargetObjects.size > 0) {
923
965
  throw new Error(
924
966
  `Sync source (${source.name}) is empty and mode is mirror. This would cause deletion of everything in the target (${target.name}), and most likely indicates an error in source definition.`
925
967
  );
926
968
  }
927
969
  const deletes = [];
928
- targetItems.forEach((object4) => {
970
+ orphanTargetObjects.forEach((object4) => {
929
971
  deletes.push(() => processDelete(object4));
930
972
  });
931
- await Promise.all(deletes.map((d) => d()));
973
+ await runSyncActions(deletes, actionConcurrency);
932
974
  }
933
- await Promise.all(actions.map((a) => a()));
975
+ await runSyncActions(actions, actionConcurrency);
934
976
  await Promise.all([source.onSyncComplete?.(false), target.onSyncComplete?.(true)]);
935
977
  }
978
+ var runSyncActions = async (actions, actionConcurrency) => {
979
+ if (actions.length === 0) {
980
+ return;
981
+ }
982
+ if (typeof actionConcurrency === "undefined") {
983
+ await Promise.all(actions.map((action) => action()));
984
+ return;
985
+ }
986
+ const queue = new PQueue({ concurrency: actionConcurrency });
987
+ await queue.addAll(actions);
988
+ };
936
989
  var SyncEngineError = class _SyncEngineError extends Error {
937
990
  constructor(innerError, sourceObject) {
938
991
  super(
@@ -2200,20 +2253,64 @@ import {
2200
2253
  } from "@uniformdev/canvas";
2201
2254
  import { isRichTextNodeType, isRichTextValue, walkRichTextTree } from "@uniformdev/richtext";
2202
2255
  import fsj4 from "fs-jetpack";
2203
- import PQueue2 from "p-queue";
2256
+ import PQueue3 from "p-queue";
2204
2257
  import { join as join10 } from "path";
2205
2258
 
2206
2259
  // src/files/downloadFile.ts
2260
+ import { createWriteStream } from "fs";
2207
2261
  import fsj2 from "fs-jetpack";
2208
- import { join as join8 } from "path";
2262
+ import { dirname as dirname2, join as join8 } from "path";
2263
+ import { Readable } from "stream";
2264
+ import { pipeline } from "stream/promises";
2265
+ var downloadedFilePathCacheByDirectory = /* @__PURE__ */ new Map();
2266
+ var tempDownloadFileCounter = 0;
2267
+ var getTempDownloadFilePath = (filePath) => {
2268
+ tempDownloadFileCounter += 1;
2269
+ return `${filePath}.${process.pid}.${Date.now()}.${tempDownloadFileCounter}.download`;
2270
+ };
2271
+ var getDownloadedFilePathCache = (filesDirectory) => {
2272
+ const cached = downloadedFilePathCacheByDirectory.get(filesDirectory);
2273
+ if (cached) {
2274
+ return cached;
2275
+ }
2276
+ const cache = fsj2.cwd(filesDirectory).findAsync({ files: true, directories: false }).then((paths) => new Set(paths)).catch(() => /* @__PURE__ */ new Set());
2277
+ downloadedFilePathCacheByDirectory.set(filesDirectory, cache);
2278
+ return cache;
2279
+ };
2280
+ var filePathMatchesSourceId = (filePath, sourceId) => filePath === sourceId || filePath.startsWith(`${sourceId}.`);
2281
+ var hasFilePathMatchingSourceId = (filePaths, sourceId) => {
2282
+ for (const filePath of filePaths) {
2283
+ if (filePathMatchesSourceId(filePath, sourceId)) {
2284
+ return true;
2285
+ }
2286
+ }
2287
+ return false;
2288
+ };
2289
+ var writeResponseBodyToFile = async (response, filePath) => {
2290
+ if (!response.body) {
2291
+ throw new Error("Response does not contain a body");
2292
+ }
2293
+ const tempFilePath = getTempDownloadFilePath(filePath);
2294
+ await fsj2.dirAsync(dirname2(filePath));
2295
+ try {
2296
+ const responseBody = response.body;
2297
+ await pipeline(Readable.fromWeb(responseBody), createWriteStream(tempFilePath));
2298
+ await fsj2.moveAsync(tempFilePath, filePath, { overwrite: true });
2299
+ } catch (error) {
2300
+ await fsj2.removeAsync(tempFilePath).catch(() => void 0);
2301
+ throw error;
2302
+ }
2303
+ };
2209
2304
  var downloadFile = async ({
2210
2305
  fileClient,
2211
2306
  fileUrl,
2212
2307
  directory
2213
2308
  }) => {
2214
2309
  const writeDirectory = getFilesDirectory(directory);
2310
+ const filesDirectory = join8(writeDirectory, FILES_DIRECTORY_NAME);
2215
2311
  const fileName = urlToFileName(fileUrl.toString());
2216
- const fileAlreadyExists = await fsj2.existsAsync(join8(writeDirectory, FILES_DIRECTORY_NAME, fileName));
2312
+ const filePath = join8(filesDirectory, fileName);
2313
+ const fileAlreadyExists = await fsj2.existsAsync(filePath);
2217
2314
  if (fileAlreadyExists) {
2218
2315
  return { url: fileUrl };
2219
2316
  }
@@ -2223,11 +2320,10 @@ var downloadFile = async ({
2223
2320
  return null;
2224
2321
  }
2225
2322
  if (file.sourceId) {
2323
+ const sourceId = file.sourceId;
2226
2324
  try {
2227
- const hashAlreadyExists = await fsj2.findAsync(join8(writeDirectory, FILES_DIRECTORY_NAME), {
2228
- matching: [file.sourceId, `${file.sourceId}.*`]
2229
- });
2230
- if (hashAlreadyExists.length > 0) {
2325
+ const downloadedFilePaths = await getDownloadedFilePathCache(filesDirectory);
2326
+ if (hasFilePathMatchingSourceId(downloadedFilePaths, sourceId)) {
2231
2327
  return { id: file.id, url: fileUrl };
2232
2328
  }
2233
2329
  } catch {
@@ -2238,8 +2334,12 @@ var downloadFile = async ({
2238
2334
  if (!response.ok) {
2239
2335
  return null;
2240
2336
  }
2241
- const fileBuffer = await response.arrayBuffer();
2242
- await fsj2.writeAsync(join8(writeDirectory, FILES_DIRECTORY_NAME, fileName), Buffer.from(fileBuffer));
2337
+ await writeResponseBodyToFile(response, filePath);
2338
+ const downloadedFilePathCache = downloadedFilePathCacheByDirectory.get(filesDirectory);
2339
+ if (downloadedFilePathCache) {
2340
+ const downloadedFilePaths = await downloadedFilePathCache;
2341
+ downloadedFilePaths.add(fileName);
2342
+ }
2243
2343
  return { id: file.id, url: fileUrl };
2244
2344
  };
2245
2345
 
@@ -2251,10 +2351,10 @@ import { createReadStream } from "fs";
2251
2351
  import fsj3 from "fs-jetpack";
2252
2352
  import { imageSizeFromFile } from "image-size/fromFile";
2253
2353
  import normalizeNewline from "normalize-newline";
2254
- import PQueue from "p-queue";
2354
+ import PQueue2 from "p-queue";
2255
2355
  import { join as join9 } from "path";
2256
2356
  var uploadQueueByKey = /* @__PURE__ */ new Map();
2257
- var fileUploadQueue = new PQueue({ concurrency: 10 });
2357
+ var fileUploadQueue = new PQueue2({ concurrency: 10 });
2258
2358
  var uploadFile = async ({
2259
2359
  fileClient,
2260
2360
  fileUrl,
@@ -2434,9 +2534,9 @@ var walkFileUrlsForCompositionOrEntry = ({
2434
2534
  };
2435
2535
 
2436
2536
  // src/files/files.ts
2437
- var fileDownloadQueue = new PQueue2({ concurrency: 10 });
2438
- var fileUploadQueue2 = new PQueue2({ concurrency: 10 });
2439
- var fileUrlReplacementQueue = new PQueue2({ concurrency: 10 });
2537
+ var fileDownloadQueue = new PQueue3({ concurrency: 10 });
2538
+ var fileUploadQueue2 = new PQueue3({ concurrency: 10 });
2539
+ var fileUrlReplacementQueue = new PQueue3({ concurrency: 10 });
2440
2540
  var downloadFileForAsset = async ({
2441
2541
  asset,
2442
2542
  directory,
@@ -2763,6 +2863,7 @@ function writeCanvasPackage(filename, packageContents) {
2763
2863
  }
2764
2864
 
2765
2865
  // src/commands/canvas/commands/asset/pull.ts
2866
+ var ASSET_PULL_ACTION_CONCURRENCY = 10;
2766
2867
  var AssetPullModule = {
2767
2868
  command: "pull <directory>",
2768
2869
  describe: "Pulls all assets to local files in a directory",
@@ -2861,6 +2962,7 @@ var AssetPullModule = {
2861
2962
  target,
2862
2963
  mode,
2863
2964
  whatIf,
2965
+ actionConcurrency: ASSET_PULL_ACTION_CONCURRENCY,
2864
2966
  allowEmptySource: allowEmptySource ?? true,
2865
2967
  log: createSyncEngineConsoleLogger({ diffMode }),
2866
2968
  onBeforeCompareObjects: async (sourceObject) => {
@@ -2888,6 +2990,7 @@ var AssetPullModule = {
2888
2990
  };
2889
2991
 
2890
2992
  // src/commands/canvas/commands/asset/push.ts
2993
+ var ASSET_PUSH_ACTION_CONCURRENCY = 10;
2891
2994
  var AssetPushModule = {
2892
2995
  command: "push <directory>",
2893
2996
  describe: "Pushes all assets from files in a directory to Uniform",
@@ -2963,6 +3066,7 @@ var AssetPushModule = {
2963
3066
  target,
2964
3067
  mode,
2965
3068
  whatIf,
3069
+ actionConcurrency: ASSET_PUSH_ACTION_CONCURRENCY,
2966
3070
  allowEmptySource,
2967
3071
  log: createSyncEngineConsoleLogger({ diffMode }),
2968
3072
  onBeforeCompareObjects: async (sourceObject, targetObject) => {
@@ -12163,6 +12267,20 @@ var selectIdentifier15 = (source, projectId) => [
12163
12267
  ];
12164
12268
  var selectFilename = (source) => cleanFileName(`${source.pathSegment}_${source.id}`);
12165
12269
  var selectDisplayName15 = (source) => `${source.name} (pid: ${source.id})`;
12270
+ function alignProjectMapNodeWithTargetIdentifier(sourceObject, targetObject) {
12271
+ if (!targetObject) {
12272
+ return sourceObject;
12273
+ }
12274
+ return {
12275
+ ...sourceObject,
12276
+ id: targetObject.id,
12277
+ providerId: targetObject.providerId,
12278
+ object: {
12279
+ ...sourceObject.object,
12280
+ id: targetObject.object.id
12281
+ }
12282
+ };
12283
+ }
12166
12284
 
12167
12285
  // src/commands/project-map/ProjectMapNodeEngineDataSource.ts
12168
12286
  function createProjectMapNodeEngineDataSource({
@@ -12379,6 +12497,12 @@ var ProjectMapNodePushModule = {
12379
12497
  whatIf,
12380
12498
  allowEmptySource,
12381
12499
  log: createSyncEngineConsoleLogger({ diffMode }),
12500
+ onBeforeCompareObjects: async (sourceObject, targetObject) => {
12501
+ return alignProjectMapNodeWithTargetIdentifier(sourceObject, targetObject);
12502
+ },
12503
+ onBeforeWriteObject: async (sourceObject, targetObject) => {
12504
+ return alignProjectMapNodeWithTargetIdentifier(sourceObject, targetObject);
12505
+ },
12382
12506
  onError: (error, object4) => {
12383
12507
  if (error.message.includes(__INTERNAL_MISSING_PARENT_NODE_ERROR)) {
12384
12508
  nodesFailedDueToMissingParent.add(object4.object);
@@ -12782,7 +12906,7 @@ import yargs40 from "yargs";
12782
12906
 
12783
12907
  // src/webhooksClient.ts
12784
12908
  import { ApiClient as ApiClient4 } from "@uniformdev/context/api";
12785
- import PQueue3 from "p-queue";
12909
+ import PQueue4 from "p-queue";
12786
12910
  import { Svix } from "svix";
12787
12911
  import * as z3 from "zod";
12788
12912
  var WEBHOOKS_DASHBOARD_BASE_PATH = "/api/v1/svix-dashboard";
@@ -12830,7 +12954,7 @@ var WebhooksClient = class extends ApiClient4 {
12830
12954
  };
12831
12955
  }
12832
12956
  async get() {
12833
- const webhooksAPIQueue = new PQueue3({ concurrency: 10 });
12957
+ const webhooksAPIQueue = new PQueue4({ concurrency: 10 });
12834
12958
  const { appId, token } = await this.getToken();
12835
12959
  const svix = new Svix(token);
12836
12960
  const getEndpoints = async ({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@uniformdev/cli",
3
- "version": "20.69.0",
3
+ "version": "20.69.1-alpha.10+3d89a58006",
4
4
  "description": "Uniform command line interface tool",
5
5
  "license": "SEE LICENSE IN LICENSE.txt",
6
6
  "main": "./cli.js",
@@ -27,13 +27,13 @@
27
27
  "dependencies": {
28
28
  "@inquirer/prompts": "^7.10.1",
29
29
  "@thi.ng/mime": "^2.2.23",
30
- "@uniformdev/assets": "20.69.0",
31
- "@uniformdev/canvas": "20.69.0",
32
- "@uniformdev/context": "20.69.0",
33
- "@uniformdev/files": "20.69.0",
34
- "@uniformdev/project-map": "20.69.0",
35
- "@uniformdev/redirect": "20.69.0",
36
- "@uniformdev/richtext": "20.69.0",
30
+ "@uniformdev/assets": "20.69.1-alpha.10+3d89a58006",
31
+ "@uniformdev/canvas": "20.69.1-alpha.10+3d89a58006",
32
+ "@uniformdev/context": "20.69.1-alpha.10+3d89a58006",
33
+ "@uniformdev/files": "20.69.1-alpha.10+3d89a58006",
34
+ "@uniformdev/project-map": "20.69.1-alpha.10+3d89a58006",
35
+ "@uniformdev/redirect": "20.69.1-alpha.10+3d89a58006",
36
+ "@uniformdev/richtext": "20.69.1-alpha.10+3d89a58006",
37
37
  "call-bind": "^1.0.2",
38
38
  "colorette": "2.0.20",
39
39
  "cosmiconfig": "9.0.0",
@@ -80,5 +80,5 @@
80
80
  "publishConfig": {
81
81
  "access": "public"
82
82
  },
83
- "gitHead": "c4b9b5df363c6f87dba72c772ae49a4624b4e2e4"
83
+ "gitHead": "3d89a5800698d773fd45afbcbec0bc5a3493cf0a"
84
84
  }