@artinstack/migrator 0.1.18 → 0.1.20
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.
|
@@ -644,6 +644,10 @@ var ALBUM_IMAGES_CONFIG = {
|
|
|
644
644
|
}
|
|
645
645
|
}
|
|
646
646
|
};
|
|
647
|
+
function asSmugMugList(value) {
|
|
648
|
+
if (value == null) return [];
|
|
649
|
+
return Array.isArray(value) ? value : [value];
|
|
650
|
+
}
|
|
647
651
|
function oauthPercentEncode(value) {
|
|
648
652
|
return encodeURIComponent(value).replace(
|
|
649
653
|
/[!'()*]/g,
|
|
@@ -861,6 +865,14 @@ function readSmugMugCredentialsFromEnv(env = process.env) {
|
|
|
861
865
|
function sleep(ms) {
|
|
862
866
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
863
867
|
}
|
|
868
|
+
function resolveSmugMugUriLink(link, label) {
|
|
869
|
+
if (typeof link === "string" && link.trim()) return link.trim();
|
|
870
|
+
if (link && typeof link === "object") {
|
|
871
|
+
const uri = link.Uri;
|
|
872
|
+
if (typeof uri === "string" && uri.trim()) return uri.trim();
|
|
873
|
+
}
|
|
874
|
+
throw new Error(`SmugMug response missing ${label} URI`);
|
|
875
|
+
}
|
|
864
876
|
function albumKeyFromUri(uri) {
|
|
865
877
|
const match = uri.match(/\/album\/([^/?!]+)/i);
|
|
866
878
|
if (!match?.[1]) {
|
|
@@ -871,7 +883,8 @@ function albumKeyFromUri(uri) {
|
|
|
871
883
|
function mapAlbumImage(albumImage, portfolioSourceId, sort) {
|
|
872
884
|
const image = albumImage.Image;
|
|
873
885
|
const metadata = image?.ImageMetadata ?? albumImage.ImageMetadata;
|
|
874
|
-
const
|
|
886
|
+
const sizeDetails = image?.ImageSizeDetails;
|
|
887
|
+
const originalUrl = sizeDetails?.OriginalImageUrl ?? sizeDetails?.ImageSizeOriginal?.Url ?? albumImage.LargestImage?.Url ?? albumImage.WebUri;
|
|
875
888
|
const fileName = image?.FileName ?? albumImage.FileName;
|
|
876
889
|
return {
|
|
877
890
|
sourceId: albumImage.ImageKey,
|
|
@@ -908,10 +921,13 @@ var SmugMugApiClient = class {
|
|
|
908
921
|
this.requestIntervalMs = parsed.requestIntervalMs;
|
|
909
922
|
this.fetchImpl = parsed.fetchImpl ?? fetch;
|
|
910
923
|
}
|
|
911
|
-
/** Validate credentials against `GET /
|
|
924
|
+
/** Validate credentials against `GET /api/v2!authuser`. */
|
|
912
925
|
async validateCredentials() {
|
|
913
926
|
const user = await this.getAuthUser();
|
|
914
|
-
return {
|
|
927
|
+
return {
|
|
928
|
+
nick: user.NickName,
|
|
929
|
+
rootNodeUri: resolveSmugMugUriLink(user.Uris.Node, "User.Uris.Node")
|
|
930
|
+
};
|
|
915
931
|
}
|
|
916
932
|
/** Crawl the authenticated user's node tree into flat export tables for `parse-node.ts`. */
|
|
917
933
|
async crawlExport() {
|
|
@@ -919,7 +935,8 @@ var SmugMugApiClient = class {
|
|
|
919
935
|
const folders = [];
|
|
920
936
|
const albums = [];
|
|
921
937
|
const images = [];
|
|
922
|
-
|
|
938
|
+
const rootNodeUri = resolveSmugMugUriLink(user.Uris.Node, "User.Uris.Node");
|
|
939
|
+
await this.walkNode(rootNodeUri, void 0, folders, albums, images);
|
|
923
940
|
return {
|
|
924
941
|
exportVersion: 1,
|
|
925
942
|
exportedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -929,7 +946,12 @@ var SmugMugApiClient = class {
|
|
|
929
946
|
};
|
|
930
947
|
}
|
|
931
948
|
async getAuthUser() {
|
|
932
|
-
const envelope = await this.requestJson(
|
|
949
|
+
const envelope = await this.requestJson(
|
|
950
|
+
`${SMUGMUG_API_BASE}!authuser`
|
|
951
|
+
);
|
|
952
|
+
if (envelope.Response.User?.Uris?.Node != null) {
|
|
953
|
+
return envelope.Response.User;
|
|
954
|
+
}
|
|
933
955
|
return envelope.Response;
|
|
934
956
|
}
|
|
935
957
|
async walkNode(nodeUri, parentFolderId, folders, albums, images) {
|
|
@@ -956,13 +978,30 @@ var SmugMugApiClient = class {
|
|
|
956
978
|
description: child.Description,
|
|
957
979
|
url: child.WebUri
|
|
958
980
|
});
|
|
959
|
-
const albumUri = child
|
|
981
|
+
const albumUri = await this.resolveAlbumUri(child);
|
|
960
982
|
if (albumUri) {
|
|
961
983
|
await this.collectAlbumImages(albumUri, child.NodeID, images);
|
|
962
984
|
}
|
|
963
985
|
}
|
|
964
986
|
}
|
|
965
987
|
}
|
|
988
|
+
/**
|
|
989
|
+
* Album nodes usually expose `Uris.Album`; if missing, re-fetch the node with `_filteruri=Album`.
|
|
990
|
+
*/
|
|
991
|
+
async resolveAlbumUri(child) {
|
|
992
|
+
if (child.Uris?.Album != null) {
|
|
993
|
+
return resolveSmugMugUriLink(child.Uris.Album, "Node.Uris.Album");
|
|
994
|
+
}
|
|
995
|
+
try {
|
|
996
|
+
const envelope = await this.requestJson(`${child.Uri}?_filteruri=Album`);
|
|
997
|
+
const node = envelope.Response.Node ?? envelope.Response;
|
|
998
|
+
if (node.Uris?.Album != null) {
|
|
999
|
+
return resolveSmugMugUriLink(node.Uris.Album, "Node.Uris.Album");
|
|
1000
|
+
}
|
|
1001
|
+
} catch {
|
|
1002
|
+
}
|
|
1003
|
+
return null;
|
|
1004
|
+
}
|
|
966
1005
|
async collectAlbumImages(albumUri, portfolioSourceId, images) {
|
|
967
1006
|
const albumKey = albumKeyFromUri(albumUri);
|
|
968
1007
|
const configQuery = `_config=${encodeURIComponent(JSON.stringify(ALBUM_IMAGES_CONFIG))}`;
|
|
@@ -975,14 +1014,14 @@ var SmugMugApiClient = class {
|
|
|
975
1014
|
}
|
|
976
1015
|
async *paginateNodes(path) {
|
|
977
1016
|
for await (const page of this.paginate(path)) {
|
|
978
|
-
for (const node of page.Node
|
|
1017
|
+
for (const node of asSmugMugList(page.Node)) {
|
|
979
1018
|
yield node;
|
|
980
1019
|
}
|
|
981
1020
|
}
|
|
982
1021
|
}
|
|
983
1022
|
async *paginateAlbumImages(path) {
|
|
984
1023
|
for await (const page of this.paginate(path)) {
|
|
985
|
-
for (const albumImage of page.AlbumImage
|
|
1024
|
+
for (const albumImage of asSmugMugList(page.AlbumImage)) {
|
|
986
1025
|
yield albumImage;
|
|
987
1026
|
}
|
|
988
1027
|
}
|
|
@@ -995,17 +1034,37 @@ var SmugMugApiClient = class {
|
|
|
995
1034
|
nextPath = envelope.Response.Pages?.NextPage;
|
|
996
1035
|
}
|
|
997
1036
|
}
|
|
1037
|
+
/**
|
|
1038
|
+
* OAuth-signed GET for private original/media URLs (and API endpoints).
|
|
1039
|
+
* Hosts should prefer this over anonymous `fetch` when downloading vault images.
|
|
1040
|
+
*/
|
|
1041
|
+
async fetchAuthenticated(url, options) {
|
|
1042
|
+
return this.requestWithRetry(toAbsoluteUrl(url), {
|
|
1043
|
+
accept: options?.accept ?? "*/*"
|
|
1044
|
+
});
|
|
1045
|
+
}
|
|
1046
|
+
/** Convenience: signed GET → bytes (for MigrationSink `resolveAssetStream`). */
|
|
1047
|
+
async fetchAuthenticatedBytes(url) {
|
|
1048
|
+
const response = await this.fetchAuthenticated(url);
|
|
1049
|
+
const buffer = new Uint8Array(await response.arrayBuffer());
|
|
1050
|
+
return {
|
|
1051
|
+
body: buffer,
|
|
1052
|
+
contentType: response.headers.get("content-type") ?? void 0,
|
|
1053
|
+
contentLength: buffer.byteLength
|
|
1054
|
+
};
|
|
1055
|
+
}
|
|
998
1056
|
async requestJson(pathOrUrl) {
|
|
999
1057
|
const url = toAbsoluteUrl(pathOrUrl);
|
|
1000
|
-
const response = await this.requestWithRetry(url);
|
|
1058
|
+
const response = await this.requestWithRetry(url, { accept: "application/json" });
|
|
1001
1059
|
const body = await response.json();
|
|
1002
1060
|
if (body.Code !== 200) {
|
|
1003
1061
|
throw new Error(`SmugMug API error ${body.Code}: ${body.Message}`);
|
|
1004
1062
|
}
|
|
1005
1063
|
return body;
|
|
1006
1064
|
}
|
|
1007
|
-
async requestWithRetry(url) {
|
|
1065
|
+
async requestWithRetry(url, options) {
|
|
1008
1066
|
let attempt = 0;
|
|
1067
|
+
const accept = options?.accept ?? "application/json";
|
|
1009
1068
|
while (true) {
|
|
1010
1069
|
await this.throttle();
|
|
1011
1070
|
const authorization = buildSmugMugAuthorizationHeader({
|
|
@@ -1016,7 +1075,7 @@ var SmugMugApiClient = class {
|
|
|
1016
1075
|
const response = await this.fetchImpl(url, {
|
|
1017
1076
|
method: "GET",
|
|
1018
1077
|
headers: {
|
|
1019
|
-
Accept:
|
|
1078
|
+
Accept: accept,
|
|
1020
1079
|
Authorization: authorization
|
|
1021
1080
|
}
|
|
1022
1081
|
});
|
|
@@ -2701,6 +2760,7 @@ export {
|
|
|
2701
2760
|
SMUGMUG_OAUTH_ENDPOINTS,
|
|
2702
2761
|
smugMugConsumerCredentialsSchema,
|
|
2703
2762
|
smugMugCredentialsSchema,
|
|
2763
|
+
asSmugMugList,
|
|
2704
2764
|
signSmugMugOAuthRequest,
|
|
2705
2765
|
buildSmugMugAuthorizationHeader,
|
|
2706
2766
|
parseSmugMugOAuthFormBody,
|
|
@@ -2709,6 +2769,7 @@ export {
|
|
|
2709
2769
|
getSmugMugAccessToken,
|
|
2710
2770
|
createSmugMugOAuthSession,
|
|
2711
2771
|
readSmugMugCredentialsFromEnv,
|
|
2772
|
+
resolveSmugMugUriLink,
|
|
2712
2773
|
SmugMugApiClient,
|
|
2713
2774
|
smugmugAdapter,
|
|
2714
2775
|
squarespaceAdapter,
|
|
@@ -2717,4 +2778,4 @@ export {
|
|
|
2717
2778
|
wixAdapter,
|
|
2718
2779
|
getAdapter
|
|
2719
2780
|
};
|
|
2720
|
-
//# sourceMappingURL=chunk-
|
|
2781
|
+
//# sourceMappingURL=chunk-CG5ON2RW.js.map
|