@foxtware/mineral 0.1.28 → 0.1.29

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 (63) hide show
  1. package/.creds.yml.sample +14 -2
  2. package/AGENTS.md +7 -0
  3. package/_build_scripts/createNewFunction.js +26 -3
  4. package/api/dropbox/docs.md +7 -0
  5. package/api/dropbox/dropbox.constants.js +10 -0
  6. package/api/dropbox/dropbox.utils.js +67 -0
  7. package/api/dropbox/dropboxAccountGet.js +64 -0
  8. package/api/dropbox/dropboxFileCopy.js +67 -0
  9. package/api/dropbox/dropboxFileDelete.js +89 -0
  10. package/api/dropbox/dropboxFileDownload.js +139 -0
  11. package/api/dropbox/dropboxFileMetadataGet.js +100 -0
  12. package/api/dropbox/dropboxFileMove.js +67 -0
  13. package/api/dropbox/dropboxFileUpload.js +129 -0
  14. package/api/dropbox/dropboxFolderCreate.js +68 -0
  15. package/api/dropbox/dropboxFolderList.js +66 -0
  16. package/api/dropbox/dropboxGet.js +158 -0
  17. package/api/dropbox/dropboxSearch.js +161 -0
  18. package/api/dropbox/dropboxSharedLinkCreate.js +68 -0
  19. package/api/dropbox/dropboxSpaceUsageGet.js +55 -0
  20. package/api/dropbox/dropboxTemporaryLinkGet.js +75 -0
  21. package/api/google/docs.md +1 -0
  22. package/api/google/google.constants.js +1 -0
  23. package/api/google/google.utils.js +21 -0
  24. package/api/google/googleanalyticsMetadataGet.js +62 -0
  25. package/api/google/googleanalyticsRealtimeReportRun.js +103 -0
  26. package/api/google/googleanalyticsReportRun.js +114 -0
  27. package/api/shopify/shopify.utils.js +53 -4
  28. package/api/shopify/shopifyMetaobjectCreate.js +13 -6
  29. package/api/shopify/shopifyMetaobjectDelete.js +90 -0
  30. package/api/shopify/shopifyMetaobjectGet.js +80 -0
  31. package/api/shopify/shopifyMetaobjectUpdate.js +108 -0
  32. package/api/shopify/shopifyStorefrontSearch.js +158 -0
  33. package/api/spotify/docs.md +8 -0
  34. package/api/spotify/spotify.constants.js +12 -0
  35. package/api/spotify/spotify.utils.js +106 -0
  36. package/api/spotify/spotifyAlbumGet.js +76 -0
  37. package/api/spotify/spotifyAlbumTracksGet.js +49 -0
  38. package/api/spotify/spotifyArtistAlbumsGet.js +55 -0
  39. package/api/spotify/spotifyArtistGet.js +71 -0
  40. package/api/spotify/spotifyArtistTopTracksGet.js +56 -0
  41. package/api/spotify/spotifyGet.js +171 -0
  42. package/api/spotify/spotifyMeGet.js +48 -0
  43. package/api/spotify/spotifyPlayerCurrentlyPlayingGet.js +62 -0
  44. package/api/spotify/spotifyPlayerDevicesGet.js +51 -0
  45. package/api/spotify/spotifyPlayerGet.js +63 -0
  46. package/api/spotify/spotifyPlayerNext.js +55 -0
  47. package/api/spotify/spotifyPlayerPause.js +55 -0
  48. package/api/spotify/spotifyPlayerPlay.js +70 -0
  49. package/api/spotify/spotifyPlayerPrevious.js +55 -0
  50. package/api/spotify/spotifyPlaylistCreate.js +63 -0
  51. package/api/spotify/spotifyPlaylistGet.js +91 -0
  52. package/api/spotify/spotifyPlaylistItemsAdd.js +61 -0
  53. package/api/spotify/spotifyPlaylistItemsGet.js +58 -0
  54. package/api/spotify/spotifyPlaylistItemsRemove.js +67 -0
  55. package/api/spotify/spotifyPlaylistUpdate.js +64 -0
  56. package/api/spotify/spotifyPlaylistsGet.js +47 -0
  57. package/api/spotify/spotifySavedTracksGet.js +46 -0
  58. package/api/spotify/spotifySavedTracksRemove.js +59 -0
  59. package/api/spotify/spotifySavedTracksSave.js +59 -0
  60. package/api/spotify/spotifySearch.js +174 -0
  61. package/api/spotify/spotifyTrackGet.js +76 -0
  62. package/package.json +1 -1
  63. package/server.js +3 -1
@@ -0,0 +1,80 @@
1
+ // https://shopify.dev/docs/api/admin-graphql/latest/queries/metaobject
2
+
3
+ const { credsValidator } = require('../validators');
4
+ const { actionSingleOrMultiple, ArgsWarden } = require('../utils');
5
+ const { shopifyGetSingle } = require('../shopify/shopifyGetSingle');
6
+
7
+ const defaultAttrs = 'id handle type updatedAt capabilities { publishable { status } } fields { key value type }';
8
+
9
+ const argsWarden = new ArgsWarden([
10
+ ['credsPayload', credsValidator],
11
+ ['metaobjectId'],
12
+ ]);
13
+
14
+ const shopifyMetaobjectGetSingle = async (
15
+ credsPayload,
16
+ metaobjectId,
17
+ {
18
+ apiVersion,
19
+ attrs = defaultAttrs,
20
+ } = {},
21
+ ) => {
22
+
23
+ return shopifyGetSingle(
24
+ credsPayload,
25
+ 'metaobject',
26
+ metaobjectId,
27
+ {
28
+ apiVersion,
29
+ attrs,
30
+ },
31
+ );
32
+ };
33
+
34
+ const shopifyMetaobjectGet = async (
35
+ credsPayload,
36
+ metaobjectId,
37
+ {
38
+ queueRunOptions,
39
+ apiVersion,
40
+ attrs = defaultAttrs,
41
+ } = {},
42
+ ) => {
43
+
44
+ const rejectResponse = await argsWarden.responseIfRejectingArgs({
45
+ credsPayload,
46
+ metaobjectId,
47
+ });
48
+ if (rejectResponse) {
49
+ return rejectResponse;
50
+ }
51
+
52
+ return actionSingleOrMultiple(
53
+ metaobjectId,
54
+ shopifyMetaobjectGetSingle,
55
+ (metaobjectIdItem) => ({
56
+ args: [credsPayload, metaobjectIdItem, { apiVersion, attrs }],
57
+ }),
58
+ {
59
+ ...(queueRunOptions ? { queueRunOptions } : {}),
60
+ },
61
+ );
62
+ };
63
+
64
+ const funcApiConfig = {
65
+ argsWarden,
66
+ };
67
+
68
+ module.exports = {
69
+ shopifyMetaobjectGet,
70
+ funcApiConfig,
71
+ };
72
+
73
+ /*
74
+ curl -X POST "http://localhost:8000/shopifyMetaobjectGet" \
75
+ -H "Content-Type: application/json" \
76
+ -d '{
77
+ "credsPayload": { "credsPath": "shopify.au" },
78
+ "metaobjectId": "207864102984"
79
+ }'
80
+ */
@@ -0,0 +1,108 @@
1
+ // https://shopify.dev/docs/api/admin-graphql/latest/mutations/metaobjectUpdate
2
+
3
+ const { credsValidator } = require('../validators');
4
+ const { actionSingleOrMultiple, everyIfArray, ArgsWarden, valueProvided } = require('../utils');
5
+ const { shopifyMutationDo } = require('../shopify/shopifyMutationDo');
6
+
7
+ const updatePayloadValidator = (updatePayload) => valueProvided(updatePayload)
8
+ && typeof updatePayload === 'object';
9
+
10
+ const argsWarden = new ArgsWarden([
11
+ ['credsPayload', credsValidator],
12
+ ['metaobjectId', (i) => everyIfArray(valueProvided, i)],
13
+ ['updatePayload', (i) => everyIfArray(updatePayloadValidator, i)],
14
+ ]);
15
+
16
+ const defaultReturnMetaobjectAttrs = 'id handle type updatedAt capabilities { publishable { status } }';
17
+
18
+ const shopifyMetaobjectUpdateSingle = async (
19
+ credsPayload,
20
+ metaobjectId,
21
+ updatePayload,
22
+ {
23
+ apiVersion,
24
+ returnMetaobjectAttrs = defaultReturnMetaobjectAttrs,
25
+ } = {},
26
+ ) => {
27
+
28
+ return shopifyMutationDo(
29
+ credsPayload,
30
+ 'metaobjectUpdate',
31
+ {
32
+ mutationVariables: {
33
+ id: {
34
+ type: 'ID!',
35
+ value: `gid://shopify/Metaobject/${ metaobjectId }`,
36
+ },
37
+ metaobject: {
38
+ type: 'MetaobjectUpdateInput!',
39
+ value: updatePayload,
40
+ },
41
+ },
42
+ returnSchema: `metaobject { ${ returnMetaobjectAttrs } }`,
43
+ apiVersion,
44
+ },
45
+ );
46
+ };
47
+
48
+ const shopifyMetaobjectUpdate = async (
49
+ credsPayload,
50
+ metaobjectId,
51
+ updatePayload,
52
+ {
53
+ queueRunOptions,
54
+ apiVersion,
55
+ returnMetaobjectAttrs = defaultReturnMetaobjectAttrs,
56
+ } = {},
57
+ ) => {
58
+
59
+ const rejectResponse = await argsWarden.responseIfRejectingArgs({
60
+ credsPayload,
61
+ metaobjectId,
62
+ updatePayload,
63
+ });
64
+ if (rejectResponse) {
65
+ return rejectResponse;
66
+ }
67
+
68
+ return actionSingleOrMultiple(
69
+ [metaobjectId, updatePayload],
70
+ shopifyMetaobjectUpdateSingle,
71
+ (metaobjectIdItem, updatePayloadItem) => ({
72
+ args: [
73
+ credsPayload,
74
+ metaobjectIdItem,
75
+ updatePayloadItem,
76
+ { apiVersion, returnMetaobjectAttrs },
77
+ ],
78
+ }),
79
+ {
80
+ ...(queueRunOptions ? { queueRunOptions } : {}),
81
+ },
82
+ );
83
+ };
84
+
85
+ const funcApiConfig = {
86
+ argsWarden,
87
+ };
88
+
89
+ module.exports = {
90
+ shopifyMetaobjectUpdate,
91
+ funcApiConfig,
92
+ };
93
+
94
+ /*
95
+ curl -X POST "http://localhost:8000/shopifyMetaobjectUpdate" \
96
+ -H "Content-Type: application/json" \
97
+ -d '{
98
+ "credsPayload": { "credsPath": "shopify.au" },
99
+ "metaobjectId": "207864102984",
100
+ "updatePayload": {
101
+ "capabilities": {
102
+ "publishable": {
103
+ "status": "ACTIVE"
104
+ }
105
+ }
106
+ }
107
+ }'
108
+ */
@@ -0,0 +1,158 @@
1
+ // https://shopify.dev/docs/api/storefront/latest/queries/search
2
+
3
+ const { credsValidator } = require('../validators');
4
+ const { ArgsWarden } = require('../utils');
5
+ const { shopifyStorefrontClient } = require('./shopify.utils');
6
+ const { MAX_PER_PAGE } = require('./shopify.constants');
7
+
8
+ const defaultAttrs = `
9
+ ... on Product {
10
+ id
11
+ handle
12
+ title
13
+ }
14
+ ... on Page {
15
+ id
16
+ handle
17
+ title
18
+ }
19
+ ... on Article {
20
+ id
21
+ handle
22
+ title
23
+ }
24
+ `.trim();
25
+
26
+ const argsWarden = new ArgsWarden([
27
+ ['credsPayload', credsValidator],
28
+ ['query'],
29
+ ]);
30
+
31
+ const shopifyStorefrontSearch = async (
32
+ credsPayload,
33
+ query,
34
+ {
35
+ apiVersion,
36
+ attrs = defaultAttrs,
37
+ first = MAX_PER_PAGE,
38
+ cursor,
39
+ reverse,
40
+ sortKey,
41
+ types,
42
+ prefix,
43
+ productFilters,
44
+ unavailableProducts,
45
+ fetchClient = shopifyStorefrontClient,
46
+ } = {},
47
+ ) => {
48
+
49
+ const rejectResponse = await argsWarden.responseIfRejectingArgs({
50
+ credsPayload,
51
+ query,
52
+ });
53
+ if (rejectResponse) {
54
+ return rejectResponse;
55
+ }
56
+
57
+ const queryTypeDeclaration = [
58
+ '$query: String!',
59
+ '$first: Int!',
60
+ '$cursor: String',
61
+ ...reverse !== undefined ? ['$reverse: Boolean'] : [],
62
+ ...sortKey ? ['$sortKey: SearchSortKeys'] : [],
63
+ ...types ? ['$types: [SearchType!]'] : [],
64
+ ...prefix ? ['$prefix: SearchPrefixQueryType'] : [],
65
+ ...productFilters ? ['$productFilters: [ProductFilter!]'] : [],
66
+ ...unavailableProducts ? ['$unavailableProducts: SearchUnavailableProductsType'] : [],
67
+ ].join('\n');
68
+
69
+ const queryVariableDeclaration = [
70
+ 'query: $query',
71
+ 'first: $first',
72
+ 'after: $cursor',
73
+ ...reverse !== undefined ? ['reverse: $reverse'] : [],
74
+ ...sortKey ? ['sortKey: $sortKey'] : [],
75
+ ...types ? ['types: $types'] : [],
76
+ ...prefix ? ['prefix: $prefix'] : [],
77
+ ...productFilters ? ['productFilters: $productFilters'] : [],
78
+ ...unavailableProducts ? ['unavailableProducts: $unavailableProducts'] : [],
79
+ ].join('\n');
80
+
81
+ const variables = {
82
+ query,
83
+ first,
84
+ cursor,
85
+ ...reverse !== undefined && { reverse },
86
+ ...sortKey && { sortKey },
87
+ ...types && { types },
88
+ ...prefix && { prefix },
89
+ ...productFilters && { productFilters },
90
+ ...unavailableProducts && { unavailableProducts },
91
+ };
92
+
93
+ return fetchClient.fetch({
94
+ requestPayload: {
95
+ method: 'post',
96
+ body: {
97
+ query: `
98
+ query StorefrontSearch (
99
+ ${ queryTypeDeclaration }
100
+ ) {
101
+ search(
102
+ ${ queryVariableDeclaration }
103
+ ) {
104
+ totalCount
105
+ productFilters {
106
+ id
107
+ label
108
+ type
109
+ values {
110
+ id
111
+ label
112
+ count
113
+ }
114
+ }
115
+ edges {
116
+ node {
117
+ ${ attrs }
118
+ }
119
+ }
120
+ pageInfo {
121
+ hasNextPage
122
+ endCursor
123
+ }
124
+ }
125
+ }
126
+ `,
127
+ variables,
128
+ },
129
+ },
130
+ context: {
131
+ credsPayload,
132
+ apiVersion,
133
+ resultPath: 'data.search',
134
+ },
135
+ });
136
+ };
137
+
138
+ const funcApiConfig = {
139
+ argsWarden,
140
+ };
141
+
142
+ module.exports = {
143
+ shopifyStorefrontSearch,
144
+ funcApiConfig,
145
+ };
146
+
147
+ /*
148
+ curl -X POST "http://localhost:8000/shopifyStorefrontSearch" \
149
+ -H "Content-Type: application/json" \
150
+ -d '{
151
+ "credsPayload": { "credsPath": "shopify.au" },
152
+ "query": "dress",
153
+ "options": {
154
+ "first": 5,
155
+ "types": ["PRODUCT"]
156
+ }
157
+ }'
158
+ */
@@ -0,0 +1,8 @@
1
+ # Spotify
2
+
3
+ - [Web API](https://developer.spotify.com/documentation/web-api)
4
+ - [API reference](https://developer.spotify.com/documentation/web-api/reference)
5
+ - [Authorization](https://developer.spotify.com/documentation/web-api/concepts/authorization)
6
+ - [API calls](https://developer.spotify.com/documentation/web-api/concepts/api-calls)
7
+
8
+ REST JSON at `https://api.spotify.com/v1/...` with OAuth 2 bearer access tokens (`Authorization: Bearer`). Catalog and user endpoints use standard GET/POST/PUT/DELETE; many list responses are offset/limit paginated (`items`, `next`, `total`). User-scoped routes (playlists, library, player) need appropriate OAuth scopes; client-credentials tokens only cover public catalog data.
@@ -0,0 +1,12 @@
1
+ const SPOTIFY_API_BASE_URL = 'https://api.spotify.com/v1';
2
+ const SPOTIFY_ACCOUNTS_BASE_URL = 'https://accounts.spotify.com';
3
+ // Most list endpoints cap at 50; search max is lower (10 as of 2026 policy changes).
4
+ const MAX_PER_PAGE = 50;
5
+ const MAX_SEARCH_PER_PAGE = 10;
6
+
7
+ module.exports = {
8
+ SPOTIFY_API_BASE_URL,
9
+ SPOTIFY_ACCOUNTS_BASE_URL,
10
+ MAX_PER_PAGE,
11
+ MAX_SEARCH_PER_PAGE,
12
+ };
@@ -0,0 +1,106 @@
1
+ const {
2
+ SPOTIFY_API_BASE_URL,
3
+ SPOTIFY_ACCOUNTS_BASE_URL,
4
+ } = require('../spotify/spotify.constants');
5
+ const { resolveCreds, useBaseUrl } = require('../pipelineSteps');
6
+ const {
7
+ FetchClient,
8
+ fetchClientCommonSteps,
9
+ customFetch,
10
+ credsFromPayload,
11
+ } = require('../utils');
12
+
13
+ // Cache client-credentials tokens per CLIENT_ID so we are not minting on every call.
14
+ const clientCredentialsTokenCache = new Map();
15
+
16
+ const getClientCredentialsToken = async ({ CLIENT_ID, CLIENT_SECRET }) => {
17
+ const cacheKey = CLIENT_ID;
18
+ const cached = clientCredentialsTokenCache.get(cacheKey);
19
+ if (cached && cached.expiresAt > Date.now()) {
20
+ return cached.accessToken;
21
+ }
22
+
23
+ const basic = Buffer
24
+ .from(`${ CLIENT_ID }:${ CLIENT_SECRET }`)
25
+ .toString('base64');
26
+
27
+ const response = await customFetch(
28
+ `${ SPOTIFY_ACCOUNTS_BASE_URL }/api/token`,
29
+ {
30
+ method: 'post',
31
+ headers: {
32
+ Authorization: `Basic ${ basic }`,
33
+ 'Content-Type': 'application/x-www-form-urlencoded',
34
+ },
35
+ body: 'grant_type=client_credentials',
36
+ },
37
+ );
38
+
39
+ if (!response.ok) {
40
+ throw new Error(
41
+ `Spotify client_credentials failed: ${ JSON.stringify(response.error ?? response.data) }`,
42
+ );
43
+ }
44
+
45
+ const { access_token: accessToken, expires_in: expiresIn = 3600 } = response.data ?? {};
46
+ if (!accessToken) {
47
+ throw new Error('Spotify client_credentials response missing access_token');
48
+ }
49
+
50
+ clientCredentialsTokenCache.set(cacheKey, {
51
+ accessToken,
52
+ // Refresh a minute early.
53
+ expiresAt: Date.now() + (expiresIn - 60) * 1000,
54
+ });
55
+
56
+ return accessToken;
57
+ };
58
+
59
+ const resolveAccessToken = async (creds) => {
60
+ if (creds?.ACCESS_TOKEN) {
61
+ return creds.ACCESS_TOKEN;
62
+ }
63
+
64
+ const { CLIENT_ID, CLIENT_SECRET } = creds ?? {};
65
+ if (CLIENT_ID && CLIENT_SECRET) {
66
+ return getClientCredentialsToken({ CLIENT_ID, CLIENT_SECRET });
67
+ }
68
+
69
+ throw new Error(
70
+ 'spotify creds require ACCESS_TOKEN or CLIENT_ID + CLIENT_SECRET',
71
+ );
72
+ };
73
+
74
+ const useAuthHeaders = async (state) => {
75
+ const { requestPayload, context } = state;
76
+ const { creds } = context;
77
+
78
+ const accessToken = await resolveAccessToken(creds);
79
+
80
+ return {
81
+ requestPayload: {
82
+ ...requestPayload,
83
+ headers: {
84
+ Accept: 'application/json',
85
+ Authorization: `Bearer ${ accessToken }`,
86
+ ...requestPayload.headers,
87
+ },
88
+ },
89
+ };
90
+ };
91
+
92
+ const spotifyClient = new FetchClient({
93
+ pipeline: [
94
+ resolveCreds,
95
+ useBaseUrl(SPOTIFY_API_BASE_URL),
96
+ useAuthHeaders,
97
+ 'fetch',
98
+ fetchClientCommonSteps.exitEarlyOnNotOk,
99
+ ],
100
+ });
101
+
102
+ module.exports = {
103
+ spotifyClient,
104
+ resolveAccessToken,
105
+ getClientCredentialsToken,
106
+ };
@@ -0,0 +1,76 @@
1
+ // https://developer.spotify.com/documentation/web-api/reference/get-an-album
2
+
3
+ const { ArgsWarden, actionSingleOrMultiple, logDeep } = require('../utils');
4
+ const { credsValidator } = require('../validators');
5
+ const { spotifyClient } = require('../spotify/spotify.utils');
6
+
7
+ const argsWarden = new ArgsWarden([
8
+ ['credsPayload', credsValidator],
9
+ ['albumId'],
10
+ ]);
11
+
12
+ const spotifyAlbumGetSingle = async (
13
+ credsPayload,
14
+ albumId,
15
+ {
16
+ market,
17
+ fetchClient = spotifyClient,
18
+ } = {},
19
+ ) => {
20
+ const response = await fetchClient.fetch({
21
+ context: { credsPayload },
22
+ requestPayload: {
23
+ method: 'get',
24
+ url: `/albums/${ albumId }`,
25
+ params: {
26
+ ...(market !== undefined && { market }),
27
+ },
28
+ },
29
+ });
30
+
31
+ const { ok, data, error } = response;
32
+ if (!ok) {
33
+ logDeep({ error });
34
+ return { ok: false, error };
35
+ }
36
+
37
+ return { ok: true, data };
38
+ };
39
+
40
+ const spotifyAlbumGet = async (
41
+ credsPayload,
42
+ albumId,
43
+ {
44
+ market,
45
+ queueRunOptions,
46
+ fetchClient,
47
+ } = {},
48
+ ) => {
49
+ const rejectResponse = await argsWarden.responseIfRejectingArgs({
50
+ credsPayload,
51
+ albumId,
52
+ });
53
+ if (rejectResponse) {
54
+ return rejectResponse;
55
+ }
56
+
57
+ return actionSingleOrMultiple(
58
+ albumId,
59
+ spotifyAlbumGetSingle,
60
+ (albumIdItem) => ({
61
+ args: [credsPayload, albumIdItem, { market, fetchClient }],
62
+ }),
63
+ {
64
+ ...(queueRunOptions ? { queueRunOptions } : {}),
65
+ },
66
+ );
67
+ };
68
+
69
+ const funcApiConfig = {
70
+ argsWarden,
71
+ };
72
+
73
+ module.exports = {
74
+ spotifyAlbumGet,
75
+ funcApiConfig,
76
+ };
@@ -0,0 +1,49 @@
1
+ // https://developer.spotify.com/documentation/web-api/reference/get-an-albums-tracks
2
+
3
+ const { ArgsWarden } = require('../utils');
4
+ const { credsValidator } = require('../validators');
5
+ const { spotifyGet } = require('../spotify/spotifyGet');
6
+ const { MAX_PER_PAGE } = require('../spotify/spotify.constants');
7
+
8
+ const argsWarden = new ArgsWarden([
9
+ ['credsPayload', credsValidator],
10
+ ['albumId'],
11
+ ]);
12
+
13
+ const spotifyAlbumTracksGet = async (
14
+ credsPayload,
15
+ albumId,
16
+ {
17
+ market,
18
+ perPage = MAX_PER_PAGE,
19
+ fetchClient,
20
+ ...getterOptions
21
+ } = {},
22
+ ) => {
23
+ const rejectResponse = await argsWarden.responseIfRejectingArgs({
24
+ credsPayload,
25
+ albumId,
26
+ });
27
+ if (rejectResponse) {
28
+ return rejectResponse;
29
+ }
30
+
31
+ return spotifyGet(credsPayload, `/albums/${ albumId }/tracks`, {
32
+ params: {
33
+ ...(market !== undefined && { market }),
34
+ },
35
+ perPage,
36
+ resultsKey: 'items',
37
+ fetchClient,
38
+ ...getterOptions,
39
+ });
40
+ };
41
+
42
+ const funcApiConfig = {
43
+ argsWarden,
44
+ };
45
+
46
+ module.exports = {
47
+ spotifyAlbumTracksGet,
48
+ funcApiConfig,
49
+ };
@@ -0,0 +1,55 @@
1
+ // https://developer.spotify.com/documentation/web-api/reference/get-an-artists-albums
2
+
3
+ const { ArgsWarden } = require('../utils');
4
+ const { credsValidator } = require('../validators');
5
+ const { spotifyGet } = require('../spotify/spotifyGet');
6
+ const { MAX_PER_PAGE } = require('../spotify/spotify.constants');
7
+
8
+ const argsWarden = new ArgsWarden([
9
+ ['credsPayload', credsValidator],
10
+ ['artistId'],
11
+ ]);
12
+
13
+ const spotifyArtistAlbumsGet = async (
14
+ credsPayload,
15
+ artistId,
16
+ {
17
+ includeGroups,
18
+ market,
19
+ perPage = MAX_PER_PAGE,
20
+ fetchClient,
21
+ ...getterOptions
22
+ } = {},
23
+ ) => {
24
+ const rejectResponse = await argsWarden.responseIfRejectingArgs({
25
+ credsPayload,
26
+ artistId,
27
+ });
28
+ if (rejectResponse) {
29
+ return rejectResponse;
30
+ }
31
+
32
+ return spotifyGet(credsPayload, `/artists/${ artistId }/albums`, {
33
+ params: {
34
+ ...(includeGroups !== undefined && {
35
+ include_groups: Array.isArray(includeGroups)
36
+ ? includeGroups.join(',')
37
+ : includeGroups,
38
+ }),
39
+ ...(market !== undefined && { market }),
40
+ },
41
+ perPage,
42
+ resultsKey: 'items',
43
+ fetchClient,
44
+ ...getterOptions,
45
+ });
46
+ };
47
+
48
+ const funcApiConfig = {
49
+ argsWarden,
50
+ };
51
+
52
+ module.exports = {
53
+ spotifyArtistAlbumsGet,
54
+ funcApiConfig,
55
+ };