@artinstack/migrator 0.1.19 → 0.1.21

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.
@@ -626,24 +626,32 @@ var smugMugClientOptionsSchema = z.object({
626
626
  });
627
627
  var ALBUM_IMAGES_CONFIG = {
628
628
  expand: {
629
- AlbumImage: {
630
- expand: {
631
- Image: {
632
- filter: ["FileName", "Caption", "KeywordsArray"],
633
- filteruri: ["ImageMetadata", "ImageSizeDetails"],
634
- expand: {
635
- ImageMetadata: {
636
- filter: ["ISO", "Aperture", "ApertureValue", "ShutterSpeed", "ExposureTime", "FocalLength"]
637
- },
638
- ImageSizeDetails: {
639
- filter: ["OriginalImageUrl"]
640
- }
641
- }
642
- }
643
- }
629
+ ImageSizeDetails: {},
630
+ ImageMetadata: {
631
+ filter: ["ISO", "Aperture", "ApertureValue", "ShutterSpeed", "ExposureTime", "FocalLength"]
632
+ },
633
+ LargestImage: {
634
+ filter: ["Url"]
644
635
  }
645
636
  }
646
637
  };
638
+ var SMUGMUG_SIZE_PREFERENCE = [
639
+ "ImageSizeOriginal",
640
+ "ImageSize5K",
641
+ "ImageSize4K",
642
+ "ImageSizeX5Large",
643
+ "ImageSizeX4Large",
644
+ "ImageSizeX3Large",
645
+ "ImageSizeX2Large",
646
+ "ImageSizeXLarge",
647
+ "ImageSizeLarge",
648
+ "ImageSizeMedium",
649
+ "ImageSizeSmall"
650
+ ];
651
+ function asSmugMugList(value) {
652
+ if (value == null) return [];
653
+ return Array.isArray(value) ? value : [value];
654
+ }
647
655
  function oauthPercentEncode(value) {
648
656
  return encodeURIComponent(value).replace(
649
657
  /[!'()*]/g,
@@ -876,11 +884,67 @@ function albumKeyFromUri(uri) {
876
884
  }
877
885
  return match[1];
878
886
  }
887
+ function unwrapInlineExpansion(link, locator) {
888
+ if (!link || typeof link !== "object") return void 0;
889
+ const record = link;
890
+ const nested = record[locator];
891
+ if (nested && typeof nested === "object" && !Array.isArray(nested)) {
892
+ return nested;
893
+ }
894
+ return void 0;
895
+ }
896
+ function sizeUrlFromDetails(details) {
897
+ if (!details) return void 0;
898
+ if (typeof details.OriginalImageUrl === "string" && details.OriginalImageUrl.trim()) {
899
+ return details.OriginalImageUrl.trim();
900
+ }
901
+ if (typeof details.ImageSizeOriginal?.Url === "string" && details.ImageSizeOriginal.Url.trim()) {
902
+ return details.ImageSizeOriginal.Url.trim();
903
+ }
904
+ const preferredKeys = [
905
+ details.LargestImageSize,
906
+ ...details.UsableSizes ?? [],
907
+ ...SMUGMUG_SIZE_PREFERENCE
908
+ ].filter((key) => typeof key === "string" && key.length > 0);
909
+ const seen = /* @__PURE__ */ new Set();
910
+ for (const key of preferredKeys) {
911
+ if (seen.has(key)) continue;
912
+ seen.add(key);
913
+ const size = details[key];
914
+ if (size && typeof size === "object" && !Array.isArray(size)) {
915
+ const url = size.Url;
916
+ if (typeof url === "string" && url.trim()) return url.trim();
917
+ }
918
+ }
919
+ return void 0;
920
+ }
921
+ function resolveAlbumImageDownloadUrl(albumImage) {
922
+ const sizeDetails = unwrapInlineExpansion(
923
+ albumImage.Uris?.ImageSizeDetails,
924
+ "ImageSizeDetails"
925
+ ) ?? albumImage.ImageSizeDetails ?? albumImage.Image?.ImageSizeDetails;
926
+ const fromSizes = sizeUrlFromDetails(sizeDetails);
927
+ if (fromSizes) return fromSizes;
928
+ const largestInline = unwrapInlineExpansion(
929
+ albumImage.Uris?.LargestImage,
930
+ "LargestImage"
931
+ );
932
+ const largestUrl = largestInline?.Url ?? albumImage.LargestImage?.Url;
933
+ if (typeof largestUrl === "string" && largestUrl.trim()) return largestUrl.trim();
934
+ if (typeof albumImage.ArchivedUri === "string" && albumImage.ArchivedUri.trim()) {
935
+ return albumImage.ArchivedUri.trim();
936
+ }
937
+ return void 0;
938
+ }
879
939
  function mapAlbumImage(albumImage, portfolioSourceId, sort) {
880
940
  const image = albumImage.Image;
881
- const metadata = image?.ImageMetadata ?? albumImage.ImageMetadata;
882
- const originalUrl = image?.ImageSizeDetails?.OriginalImageUrl ?? albumImage.LargestImage?.Url ?? albumImage.WebUri;
941
+ const metadata = unwrapInlineExpansion(
942
+ albumImage.Uris?.ImageMetadata,
943
+ "ImageMetadata"
944
+ ) ?? albumImage.ImageMetadata ?? image?.ImageMetadata;
945
+ const originalUrl = resolveAlbumImageDownloadUrl(albumImage);
883
946
  const fileName = image?.FileName ?? albumImage.FileName;
947
+ const keywords = (image?.KeywordsArray?.length ? image.KeywordsArray : void 0) ?? (image?.KeywordArray?.length ? image.KeywordArray : void 0) ?? (albumImage.KeywordsArray?.length ? albumImage.KeywordsArray : void 0) ?? (albumImage.KeywordArray?.length ? albumImage.KeywordArray : void 0);
884
948
  return {
885
949
  sourceId: albumImage.ImageKey,
886
950
  portfolioSourceId,
@@ -888,7 +952,7 @@ function mapAlbumImage(albumImage, portfolioSourceId, sort) {
888
952
  fileName,
889
953
  originalUrl,
890
954
  caption: albumImage.Caption ?? image?.Caption,
891
- keywords: image?.KeywordsArray?.length ? image.KeywordsArray : void 0,
955
+ keywords,
892
956
  exif: metadata ? {
893
957
  iso: metadata.ISO,
894
958
  aperture: metadata.Aperture ?? metadata.ApertureValue,
@@ -916,7 +980,7 @@ var SmugMugApiClient = class {
916
980
  this.requestIntervalMs = parsed.requestIntervalMs;
917
981
  this.fetchImpl = parsed.fetchImpl ?? fetch;
918
982
  }
919
- /** Validate credentials against `GET /user/!authuser`. */
983
+ /** Validate credentials against `GET /api/v2!authuser`. */
920
984
  async validateCredentials() {
921
985
  const user = await this.getAuthUser();
922
986
  return {
@@ -942,7 +1006,7 @@ var SmugMugApiClient = class {
942
1006
  }
943
1007
  async getAuthUser() {
944
1008
  const envelope = await this.requestJson(
945
- `${SMUGMUG_API_BASE}/user/!authuser`
1009
+ `${SMUGMUG_API_BASE}!authuser`
946
1010
  );
947
1011
  if (envelope.Response.User?.Uris?.Node != null) {
948
1012
  return envelope.Response.User;
@@ -973,17 +1037,34 @@ var SmugMugApiClient = class {
973
1037
  description: child.Description,
974
1038
  url: child.WebUri
975
1039
  });
976
- if (child.Uris?.Album != null) {
977
- const albumUri = resolveSmugMugUriLink(child.Uris.Album, "Node.Uris.Album");
1040
+ const albumUri = await this.resolveAlbumUri(child);
1041
+ if (albumUri) {
978
1042
  await this.collectAlbumImages(albumUri, child.NodeID, images);
979
1043
  }
980
1044
  }
981
1045
  }
982
1046
  }
1047
+ /**
1048
+ * Album nodes usually expose `Uris.Album`; if missing, re-fetch the node with `_filteruri=Album`.
1049
+ */
1050
+ async resolveAlbumUri(child) {
1051
+ if (child.Uris?.Album != null) {
1052
+ return resolveSmugMugUriLink(child.Uris.Album, "Node.Uris.Album");
1053
+ }
1054
+ try {
1055
+ const envelope = await this.requestJson(`${child.Uri}?_filteruri=Album`);
1056
+ const node = envelope.Response.Node ?? envelope.Response;
1057
+ if (node.Uris?.Album != null) {
1058
+ return resolveSmugMugUriLink(node.Uris.Album, "Node.Uris.Album");
1059
+ }
1060
+ } catch {
1061
+ }
1062
+ return null;
1063
+ }
983
1064
  async collectAlbumImages(albumUri, portfolioSourceId, images) {
984
1065
  const albumKey = albumKeyFromUri(albumUri);
985
1066
  const configQuery = `_config=${encodeURIComponent(JSON.stringify(ALBUM_IMAGES_CONFIG))}`;
986
- const initialPath = `${SMUGMUG_API_BASE}/album/${albumKey}!images?${configQuery}`;
1067
+ const initialPath = `${SMUGMUG_API_BASE}/album/${albumKey}!images?${configQuery}&_expandmethod=inline`;
987
1068
  let sort = 0;
988
1069
  for await (const albumImage of this.paginateAlbumImages(initialPath)) {
989
1070
  images.push(mapAlbumImage(albumImage, portfolioSourceId, sort));
@@ -992,14 +1073,14 @@ var SmugMugApiClient = class {
992
1073
  }
993
1074
  async *paginateNodes(path) {
994
1075
  for await (const page of this.paginate(path)) {
995
- for (const node of page.Node ?? []) {
1076
+ for (const node of asSmugMugList(page.Node)) {
996
1077
  yield node;
997
1078
  }
998
1079
  }
999
1080
  }
1000
1081
  async *paginateAlbumImages(path) {
1001
1082
  for await (const page of this.paginate(path)) {
1002
- for (const albumImage of page.AlbumImage ?? []) {
1083
+ for (const albumImage of asSmugMugList(page.AlbumImage)) {
1003
1084
  yield albumImage;
1004
1085
  }
1005
1086
  }
@@ -1012,17 +1093,37 @@ var SmugMugApiClient = class {
1012
1093
  nextPath = envelope.Response.Pages?.NextPage;
1013
1094
  }
1014
1095
  }
1096
+ /**
1097
+ * OAuth-signed GET for private original/media URLs (and API endpoints).
1098
+ * Hosts should prefer this over anonymous `fetch` when downloading vault images.
1099
+ */
1100
+ async fetchAuthenticated(url, options) {
1101
+ return this.requestWithRetry(toAbsoluteUrl(url), {
1102
+ accept: options?.accept ?? "*/*"
1103
+ });
1104
+ }
1105
+ /** Convenience: signed GET → bytes (for MigrationSink `resolveAssetStream`). */
1106
+ async fetchAuthenticatedBytes(url) {
1107
+ const response = await this.fetchAuthenticated(url);
1108
+ const buffer = new Uint8Array(await response.arrayBuffer());
1109
+ return {
1110
+ body: buffer,
1111
+ contentType: response.headers.get("content-type") ?? void 0,
1112
+ contentLength: buffer.byteLength
1113
+ };
1114
+ }
1015
1115
  async requestJson(pathOrUrl) {
1016
1116
  const url = toAbsoluteUrl(pathOrUrl);
1017
- const response = await this.requestWithRetry(url);
1117
+ const response = await this.requestWithRetry(url, { accept: "application/json" });
1018
1118
  const body = await response.json();
1019
1119
  if (body.Code !== 200) {
1020
1120
  throw new Error(`SmugMug API error ${body.Code}: ${body.Message}`);
1021
1121
  }
1022
1122
  return body;
1023
1123
  }
1024
- async requestWithRetry(url) {
1124
+ async requestWithRetry(url, options) {
1025
1125
  let attempt = 0;
1126
+ const accept = options?.accept ?? "application/json";
1026
1127
  while (true) {
1027
1128
  await this.throttle();
1028
1129
  const authorization = buildSmugMugAuthorizationHeader({
@@ -1033,7 +1134,7 @@ var SmugMugApiClient = class {
1033
1134
  const response = await this.fetchImpl(url, {
1034
1135
  method: "GET",
1035
1136
  headers: {
1036
- Accept: "application/json",
1137
+ Accept: accept,
1037
1138
  Authorization: authorization
1038
1139
  }
1039
1140
  });
@@ -2718,6 +2819,7 @@ export {
2718
2819
  SMUGMUG_OAUTH_ENDPOINTS,
2719
2820
  smugMugConsumerCredentialsSchema,
2720
2821
  smugMugCredentialsSchema,
2822
+ asSmugMugList,
2721
2823
  signSmugMugOAuthRequest,
2722
2824
  buildSmugMugAuthorizationHeader,
2723
2825
  parseSmugMugOAuthFormBody,
@@ -2735,4 +2837,4 @@ export {
2735
2837
  wixAdapter,
2736
2838
  getAdapter
2737
2839
  };
2738
- //# sourceMappingURL=chunk-5RKHB6GI.js.map
2840
+ //# sourceMappingURL=chunk-J3WX7IAS.js.map