@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
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
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 =
|
|
882
|
-
|
|
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
|
|
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 /
|
|
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}
|
|
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
|
-
|
|
977
|
-
|
|
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:
|
|
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-
|
|
2840
|
+
//# sourceMappingURL=chunk-J3WX7IAS.js.map
|