@foxtware/mineral 0.1.28 → 0.1.30
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.
- package/.creds.yml.sample +35 -2
- package/AGENTS.md +7 -0
- package/_build_scripts/createNewFunction.js +26 -3
- package/api/dpd/docs.md +6 -0
- package/api/dpd/dpd.constants.js +9 -0
- package/api/dpd/dpd.utils.js +145 -0
- package/api/dpd/dpdTrackingGet.js +64 -0
- package/api/dropbox/docs.md +7 -0
- package/api/dropbox/dropbox.constants.js +10 -0
- package/api/dropbox/dropbox.utils.js +67 -0
- package/api/dropbox/dropboxAccountGet.js +64 -0
- package/api/dropbox/dropboxFileCopy.js +67 -0
- package/api/dropbox/dropboxFileDelete.js +89 -0
- package/api/dropbox/dropboxFileDownload.js +139 -0
- package/api/dropbox/dropboxFileMetadataGet.js +100 -0
- package/api/dropbox/dropboxFileMove.js +67 -0
- package/api/dropbox/dropboxFileUpload.js +129 -0
- package/api/dropbox/dropboxFolderCreate.js +68 -0
- package/api/dropbox/dropboxFolderList.js +66 -0
- package/api/dropbox/dropboxGet.js +158 -0
- package/api/dropbox/dropboxSearch.js +161 -0
- package/api/dropbox/dropboxSharedLinkCreate.js +68 -0
- package/api/dropbox/dropboxSpaceUsageGet.js +55 -0
- package/api/dropbox/dropboxTemporaryLinkGet.js +75 -0
- package/api/fedex/docs.md +6 -0
- package/api/fedex/fedex.constants.js +11 -0
- package/api/fedex/fedex.utils.js +151 -0
- package/api/fedex/fedexTrackingGet.js +76 -0
- package/api/google/docs.md +1 -0
- package/api/google/google.constants.js +1 -0
- package/api/google/google.utils.js +21 -0
- package/api/google/googleanalyticsMetadataGet.js +62 -0
- package/api/google/googleanalyticsRealtimeReportRun.js +103 -0
- package/api/google/googleanalyticsReportRun.js +114 -0
- package/api/paypal/docs.md +14 -0
- package/api/paypal/paypal.constants.js +13 -0
- package/api/paypal/paypal.utils.js +166 -0
- package/api/paypal/paypalAccessTokenGet.js +81 -0
- package/api/paypal/paypalAuthorizationCapture.js +75 -0
- package/api/paypal/paypalAuthorizationGet.js +57 -0
- package/api/paypal/paypalBalancesGet.js +65 -0
- package/api/paypal/paypalCaptureGet.js +57 -0
- package/api/paypal/paypalCaptureRefund.js +78 -0
- package/api/paypal/paypalOrderAuthorize.js +69 -0
- package/api/paypal/paypalOrderCapture.js +69 -0
- package/api/paypal/paypalOrderCreate.js +81 -0
- package/api/paypal/paypalOrderGet.js +57 -0
- package/api/paypal/paypalRefundGet.js +57 -0
- package/api/paypal/paypalTransactionsGet.js +101 -0
- package/api/paypal/paypalUserInfoGet.js +62 -0
- package/api/royalmail/docs.md +6 -0
- package/api/royalmail/royalmail.constants.js +7 -0
- package/api/royalmail/royalmail.utils.js +55 -0
- package/api/royalmail/royalmailTrackingGet.js +70 -0
- package/api/shopify/shopify.utils.js +65 -4
- package/api/shopify/shopifyMetaobjectCreate.js +13 -6
- package/api/shopify/shopifyMetaobjectDelete.js +90 -0
- package/api/shopify/shopifyMetaobjectGet.js +80 -0
- package/api/shopify/shopifyMetaobjectUpdate.js +108 -0
- package/api/shopify/shopifyStorefrontSearch.js +158 -0
- package/api/spotify/docs.md +8 -0
- package/api/spotify/spotify.constants.js +12 -0
- package/api/spotify/spotify.utils.js +106 -0
- package/api/spotify/spotifyAlbumGet.js +76 -0
- package/api/spotify/spotifyAlbumTracksGet.js +49 -0
- package/api/spotify/spotifyArtistAlbumsGet.js +55 -0
- package/api/spotify/spotifyArtistGet.js +71 -0
- package/api/spotify/spotifyArtistTopTracksGet.js +56 -0
- package/api/spotify/spotifyGet.js +171 -0
- package/api/spotify/spotifyMeGet.js +48 -0
- package/api/spotify/spotifyPlayerCurrentlyPlayingGet.js +62 -0
- package/api/spotify/spotifyPlayerDevicesGet.js +51 -0
- package/api/spotify/spotifyPlayerGet.js +63 -0
- package/api/spotify/spotifyPlayerNext.js +55 -0
- package/api/spotify/spotifyPlayerPause.js +55 -0
- package/api/spotify/spotifyPlayerPlay.js +70 -0
- package/api/spotify/spotifyPlayerPrevious.js +55 -0
- package/api/spotify/spotifyPlaylistCreate.js +63 -0
- package/api/spotify/spotifyPlaylistGet.js +91 -0
- package/api/spotify/spotifyPlaylistItemsAdd.js +61 -0
- package/api/spotify/spotifyPlaylistItemsGet.js +58 -0
- package/api/spotify/spotifyPlaylistItemsRemove.js +67 -0
- package/api/spotify/spotifyPlaylistUpdate.js +64 -0
- package/api/spotify/spotifyPlaylistsGet.js +47 -0
- package/api/spotify/spotifySavedTracksGet.js +46 -0
- package/api/spotify/spotifySavedTracksRemove.js +59 -0
- package/api/spotify/spotifySavedTracksSave.js +59 -0
- package/api/spotify/spotifySearch.js +174 -0
- package/api/spotify/spotifyTrackGet.js +76 -0
- package/api/starshipit/starshipitProductUpdate.js +102 -0
- package/api/starshipit/starshipitProductsGet.js +2 -2
- package/api/stylearcade/stylearcadeGet.js +5 -2
- package/api/utils.js +39 -0
- package/package.json +1 -1
- package/server.js +3 -1
package/.creds.yml.sample
CHANGED
|
@@ -2,6 +2,7 @@ shopify:
|
|
|
2
2
|
au:
|
|
3
3
|
STORE_HANDLE: ________________________
|
|
4
4
|
API_KEY: shpat________________________
|
|
5
|
+
STOREFRONT_API_KEY: __________________
|
|
5
6
|
|
|
6
7
|
peoplevox:
|
|
7
8
|
CLIENT_ID: _____________________________
|
|
@@ -141,5 +142,37 @@ salesforce:
|
|
|
141
142
|
|
|
142
143
|
fastsimon:
|
|
143
144
|
store: # instance name of your choice
|
|
144
|
-
UUID:
|
|
145
|
-
STORE_ID:
|
|
145
|
+
UUID: ________________________________ # Dashboard → Settings
|
|
146
|
+
STORE_ID: ____________________________ # Dashboard → Settings
|
|
147
|
+
|
|
148
|
+
dropbox:
|
|
149
|
+
ACCESS_TOKEN: __________________________
|
|
150
|
+
|
|
151
|
+
spotify:
|
|
152
|
+
# Option A — pre-issued user or client-credentials access token
|
|
153
|
+
ACCESS_TOKEN: __________________________
|
|
154
|
+
|
|
155
|
+
# Option B — app client credentials (catalog-only; auto-minted token)
|
|
156
|
+
CLIENT_ID: _____________________________
|
|
157
|
+
CLIENT_SECRET: _________________________
|
|
158
|
+
|
|
159
|
+
paypal:
|
|
160
|
+
CLIENT_ID: _____________________________
|
|
161
|
+
CLIENT_SECRET: _________________________
|
|
162
|
+
# SANDBOX: true # only if using sandbox credentials
|
|
163
|
+
|
|
164
|
+
royalmail:
|
|
165
|
+
CLIENT_ID: _____________________________
|
|
166
|
+
CLIENT_SECRET: _________________________
|
|
167
|
+
|
|
168
|
+
dpd:
|
|
169
|
+
ACCOUNT_NUMBER: _________________________
|
|
170
|
+
USERNAME: ______________________________
|
|
171
|
+
PASSWORD: ______________________________
|
|
172
|
+
# BASE_URL: https://api.dpdlocal.co.uk # only for DPD Local accounts
|
|
173
|
+
|
|
174
|
+
fedex:
|
|
175
|
+
CLIENT_ID: _____________________________
|
|
176
|
+
CLIENT_SECRET: _________________________
|
|
177
|
+
# SANDBOX: true # only if using sandbox credentials
|
|
178
|
+
|
package/AGENTS.md
CHANGED
|
@@ -41,4 +41,11 @@ This is the usual structure, but it can be altered per platform, if required. If
|
|
|
41
41
|
- For functions which act on a single resource, e.g. `shopifyPageGet`, `actionSingleOrMultiple` is implemented as an enhancement to allow acting on multiple items in a one-by-one fashion.
|
|
42
42
|
- `fetchClient` is implemented as an option, allowing implementations outside mineral core to use their own pipeline in making requests. This may include caching auth or utilising other platforms in the pipeline.
|
|
43
43
|
|
|
44
|
+
## Doing things
|
|
45
|
+
- If you are being asked to do something that involves using a platform, use this repo's functionality as your first option.
|
|
46
|
+
- Try using curl commands based on the example curl commands documented in comments on the function files.
|
|
47
|
+
- If the server is not running, start one with `npm run dev` or `npm run serve`.
|
|
48
|
+
- Where an API functionality is not currently implemented, but fits this repo's mission, create functions for yourself to use, then use those.
|
|
44
49
|
|
|
50
|
+
## .yml formatting
|
|
51
|
+
When you edit a YAML file, restore whitespaces afterwards.
|
|
@@ -22,6 +22,7 @@ const getContext = () => {
|
|
|
22
22
|
inMineral,
|
|
23
23
|
apiDirectory: inMineral ? mineralApiDirectory : path.join(process.cwd(), 'api'),
|
|
24
24
|
mineralApiDirectory,
|
|
25
|
+
workspaceName: path.basename(process.cwd()),
|
|
25
26
|
};
|
|
26
27
|
};
|
|
27
28
|
|
|
@@ -390,7 +391,24 @@ const getExampleFilesForContext = async ({ context, dir }) => {
|
|
|
390
391
|
return sortExampleFiles(await findExampleFiles(path.join(context.apiDirectory, dir)));
|
|
391
392
|
}
|
|
392
393
|
|
|
393
|
-
|
|
394
|
+
const localExampleFiles = (await findExampleFiles(path.join(context.apiDirectory, dir))).map(file => ({
|
|
395
|
+
...file,
|
|
396
|
+
relativePath: file.filename,
|
|
397
|
+
displayName: file.filename,
|
|
398
|
+
sourceName: context.workspaceName,
|
|
399
|
+
}));
|
|
400
|
+
const mineralExampleFiles = (await collectMineralExampleFiles(context.mineralApiDirectory))
|
|
401
|
+
.map(file => ({
|
|
402
|
+
...file,
|
|
403
|
+
sourceName: path.basename(mineralRoot),
|
|
404
|
+
}));
|
|
405
|
+
const exampleFilesByPath = new Map();
|
|
406
|
+
|
|
407
|
+
for (const file of [ ...mineralExampleFiles, ...localExampleFiles ]) {
|
|
408
|
+
exampleFilesByPath.set(file.relativePath, file);
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
return sortExampleFiles([ ...exampleFilesByPath.values() ]);
|
|
394
412
|
};
|
|
395
413
|
|
|
396
414
|
const formatTemplateLabel = (file, { inMineral }) => {
|
|
@@ -398,7 +416,7 @@ const formatTemplateLabel = (file, { inMineral }) => {
|
|
|
398
416
|
return file.displayName;
|
|
399
417
|
}
|
|
400
418
|
|
|
401
|
-
return file.relativePath
|
|
419
|
+
return `${ file.sourceName } > ${ file.relativePath }`;
|
|
402
420
|
};
|
|
403
421
|
|
|
404
422
|
const selectTemplateInteractive = async ({ exampleFiles, dir, inMineral }) => {
|
|
@@ -532,7 +550,12 @@ const createNewFunction = async () => {
|
|
|
532
550
|
inMineral: context.inMineral,
|
|
533
551
|
});
|
|
534
552
|
|
|
535
|
-
const
|
|
553
|
+
const selectedTemplateFile = exampleFiles.find(file => file.fullPath === selectedTemplate);
|
|
554
|
+
const templateLabel = context.inMineral
|
|
555
|
+
? path.relative(mineralRoot, selectedTemplate)
|
|
556
|
+
: selectedTemplateFile
|
|
557
|
+
? formatTemplateLabel(selectedTemplateFile, { inMineral: false })
|
|
558
|
+
: path.relative(mineralRoot, selectedTemplate);
|
|
536
559
|
console.log(`Using template: ${ templateLabel }`);
|
|
537
560
|
|
|
538
561
|
await writeNewFunction({
|
package/api/dpd/docs.md
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
# DPD
|
|
2
|
+
|
|
3
|
+
- [DPD UK technology and API information](https://dpd.co.uk/content/about_dpd/technology.jsp)
|
|
4
|
+
- [DPD API documentation](https://www.dpd.com/wp-content/uploads/sites/235/2023/04/DPD-API-documentation-v1-2-1.pdf)
|
|
5
|
+
|
|
6
|
+
DPD API access is account-managed. DPD UK credentials authenticate against `https://api.dpd.co.uk/user/?action=login`, returning a `geoSession` token. The tracking client uses that session with the DPD network tracking endpoint. DPD Local accounts can use the same client with their account-specific `BASE_URL`.
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
const { resolveCreds } = require('../pipelineSteps');
|
|
2
|
+
const {
|
|
3
|
+
FetchClient,
|
|
4
|
+
appendUrlToBase,
|
|
5
|
+
customFetch,
|
|
6
|
+
fetchClientCommonSteps,
|
|
7
|
+
} = require('../utils');
|
|
8
|
+
const {
|
|
9
|
+
DPD_API_BASE_URL,
|
|
10
|
+
DPD_AUTH_PATH,
|
|
11
|
+
} = require('./dpd.constants');
|
|
12
|
+
|
|
13
|
+
const geoSessionCache = new Map();
|
|
14
|
+
|
|
15
|
+
const baseUrlForCreds = (creds) => {
|
|
16
|
+
return (creds?.BASE_URL || DPD_API_BASE_URL).replace(/\/$/, '');
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
const geoClientForCreds = (creds) => {
|
|
20
|
+
return creds?.GEO_CLIENT || `account/${ creds?.ACCOUNT_NUMBER || '' }`;
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
const cacheKeyForCreds = (creds) => {
|
|
24
|
+
return [
|
|
25
|
+
baseUrlForCreds(creds),
|
|
26
|
+
creds?.USERNAME || '',
|
|
27
|
+
creds?.ACCOUNT_NUMBER || '',
|
|
28
|
+
].join(':');
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
const getGeoSession = async (creds) => {
|
|
32
|
+
const {
|
|
33
|
+
USERNAME,
|
|
34
|
+
PASSWORD,
|
|
35
|
+
} = creds || {};
|
|
36
|
+
|
|
37
|
+
if (!USERNAME || !PASSWORD || !geoClientForCreds(creds).split('/').pop()) {
|
|
38
|
+
throw new Error(
|
|
39
|
+
'DPD creds require USERNAME, PASSWORD, and ACCOUNT_NUMBER or GEO_CLIENT',
|
|
40
|
+
);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const cacheKey = cacheKeyForCreds(creds);
|
|
44
|
+
const cachedSession = geoSessionCache.get(cacheKey);
|
|
45
|
+
if (cachedSession && cachedSession.expiresAt > Date.now()) {
|
|
46
|
+
return cachedSession.geoSession;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const basicAuth = Buffer
|
|
50
|
+
.from(`${ USERNAME }:${ PASSWORD }`)
|
|
51
|
+
.toString('base64');
|
|
52
|
+
const response = await customFetch(
|
|
53
|
+
appendUrlToBase(baseUrlForCreds(creds), DPD_AUTH_PATH),
|
|
54
|
+
{
|
|
55
|
+
method: 'post',
|
|
56
|
+
headers: {
|
|
57
|
+
Accept: 'application/json',
|
|
58
|
+
Authorization: `Basic ${ basicAuth }`,
|
|
59
|
+
GEOClient: geoClientForCreds(creds),
|
|
60
|
+
},
|
|
61
|
+
},
|
|
62
|
+
);
|
|
63
|
+
|
|
64
|
+
if (!response.ok) {
|
|
65
|
+
throw new Error(
|
|
66
|
+
`DPD authentication failed: ${ JSON.stringify(response.error || response.data) }`,
|
|
67
|
+
);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const geoSession = response.data?.geoSession || response.data?.data?.geoSession;
|
|
71
|
+
if (!geoSession) {
|
|
72
|
+
throw new Error('DPD authentication response missing geoSession');
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
geoSessionCache.set(cacheKey, {
|
|
76
|
+
geoSession,
|
|
77
|
+
expiresAt: Date.now() + (60 * 60 * 1000),
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
return geoSession;
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
const useBaseUrlFromCreds = async (state) => {
|
|
84
|
+
const { requestPayload, context } = state;
|
|
85
|
+
const { creds } = context;
|
|
86
|
+
|
|
87
|
+
return {
|
|
88
|
+
requestPayload: {
|
|
89
|
+
...requestPayload,
|
|
90
|
+
url: appendUrlToBase(
|
|
91
|
+
baseUrlForCreds(creds),
|
|
92
|
+
requestPayload.url || '',
|
|
93
|
+
),
|
|
94
|
+
},
|
|
95
|
+
};
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
const useAuthHeaders = async (state) => {
|
|
99
|
+
const { requestPayload, context } = state;
|
|
100
|
+
const { creds } = context;
|
|
101
|
+
|
|
102
|
+
let geoSession;
|
|
103
|
+
try {
|
|
104
|
+
geoSession = await getGeoSession(creds);
|
|
105
|
+
} catch (error) {
|
|
106
|
+
return {
|
|
107
|
+
breakChain: true,
|
|
108
|
+
response: {
|
|
109
|
+
ok: false,
|
|
110
|
+
error: {
|
|
111
|
+
code: 'DPD_AUTH_ERROR',
|
|
112
|
+
message: error.message,
|
|
113
|
+
},
|
|
114
|
+
},
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
return {
|
|
119
|
+
requestPayload: {
|
|
120
|
+
...requestPayload,
|
|
121
|
+
headers: {
|
|
122
|
+
Accept: 'application/json',
|
|
123
|
+
GEOClient: geoClientForCreds(creds),
|
|
124
|
+
GEOSession: geoSession,
|
|
125
|
+
...requestPayload.headers,
|
|
126
|
+
},
|
|
127
|
+
},
|
|
128
|
+
};
|
|
129
|
+
};
|
|
130
|
+
|
|
131
|
+
const dpdClient = new FetchClient({
|
|
132
|
+
pipeline: [
|
|
133
|
+
resolveCreds,
|
|
134
|
+
useBaseUrlFromCreds,
|
|
135
|
+
useAuthHeaders,
|
|
136
|
+
'fetch',
|
|
137
|
+
fetchClientCommonSteps.exitEarlyOnNotOk,
|
|
138
|
+
],
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
module.exports = {
|
|
142
|
+
dpdClient,
|
|
143
|
+
geoSessionCache,
|
|
144
|
+
getGeoSession,
|
|
145
|
+
};
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
// https://www.dpd.com/wp-content/uploads/sites/235/2023/04/DPD-API-documentation-v1-2-1.pdf
|
|
2
|
+
|
|
3
|
+
const { ArgsWarden } = require('../utils');
|
|
4
|
+
const { credsValidator } = require('../validators');
|
|
5
|
+
const { DPD_TRACKING_PATH } = require('./dpd.constants');
|
|
6
|
+
const { dpdClient } = require('./dpd.utils');
|
|
7
|
+
|
|
8
|
+
const trackingIdentifierValidator = (trackingIdentifier) => {
|
|
9
|
+
return Boolean(trackingIdentifier?.trackingNumber);
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
const argsWarden = new ArgsWarden([
|
|
13
|
+
['credsPayload', credsValidator],
|
|
14
|
+
['trackingIdentifier', trackingIdentifierValidator],
|
|
15
|
+
]);
|
|
16
|
+
|
|
17
|
+
const dpdTrackingGet = async (
|
|
18
|
+
credsPayload,
|
|
19
|
+
trackingIdentifier,
|
|
20
|
+
{
|
|
21
|
+
fetchClient = dpdClient,
|
|
22
|
+
} = {},
|
|
23
|
+
) => {
|
|
24
|
+
const rejectResponse = await argsWarden.responseIfRejectingArgs({
|
|
25
|
+
credsPayload,
|
|
26
|
+
trackingIdentifier,
|
|
27
|
+
});
|
|
28
|
+
if (rejectResponse) {
|
|
29
|
+
return rejectResponse;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const {
|
|
33
|
+
trackingNumber,
|
|
34
|
+
} = trackingIdentifier;
|
|
35
|
+
|
|
36
|
+
return fetchClient.fetch({
|
|
37
|
+
requestPayload: {
|
|
38
|
+
url: `${ DPD_TRACKING_PATH }/${ encodeURIComponent(trackingNumber) }`,
|
|
39
|
+
},
|
|
40
|
+
context: {
|
|
41
|
+
credsPayload,
|
|
42
|
+
},
|
|
43
|
+
});
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
const funcApiConfig = {
|
|
47
|
+
argsWarden,
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
module.exports = {
|
|
51
|
+
dpdTrackingGet,
|
|
52
|
+
funcApiConfig,
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
/*
|
|
56
|
+
curl -X POST "http://localhost:8000/dpdTrackingGet" \
|
|
57
|
+
-H "Content-Type: application/json" \
|
|
58
|
+
-d '{
|
|
59
|
+
"credsPayload": { "credsPath": "dpd" },
|
|
60
|
+
"trackingIdentifier": {
|
|
61
|
+
"trackingNumber": "15509742315259"
|
|
62
|
+
}
|
|
63
|
+
}'
|
|
64
|
+
*/
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
# Dropbox
|
|
2
|
+
|
|
3
|
+
- [HTTP documentation](https://www.dropbox.com/developers/documentation/http/documentation)
|
|
4
|
+
- [OAuth guide](https://www.dropbox.com/developers/reference/oauth-guide)
|
|
5
|
+
- [API explorer](https://www.dropbox.com/developers/explorer)
|
|
6
|
+
|
|
7
|
+
RPC JSON over HTTPS at `https://api.dropboxapi.com/2/...` (most methods are POST with a JSON body). Content upload/download uses `https://content.dropboxapi.com/2/...` with arguments in the `Dropbox-API-Arg` header and binary body or response. Auth is OAuth 2 bearer access token (`Authorization: Bearer`). Paths are rooted at `""` (app or full Dropbox root depending on app permission); folder listing uses cursor pagination via `list_folder` / `list_folder/continue`.
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
const DROPBOX_API_BASE_URL = 'https://api.dropboxapi.com/2';
|
|
2
|
+
const DROPBOX_CONTENT_BASE_URL = 'https://content.dropboxapi.com/2';
|
|
3
|
+
// list_folder limit max is 2000
|
|
4
|
+
const MAX_PER_PAGE = 2000;
|
|
5
|
+
|
|
6
|
+
module.exports = {
|
|
7
|
+
DROPBOX_API_BASE_URL,
|
|
8
|
+
DROPBOX_CONTENT_BASE_URL,
|
|
9
|
+
MAX_PER_PAGE,
|
|
10
|
+
};
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
const {
|
|
2
|
+
DROPBOX_API_BASE_URL,
|
|
3
|
+
DROPBOX_CONTENT_BASE_URL,
|
|
4
|
+
} = require('../dropbox/dropbox.constants');
|
|
5
|
+
const { resolveCreds, useBaseUrl } = require('../pipelineSteps');
|
|
6
|
+
const {
|
|
7
|
+
FetchClient,
|
|
8
|
+
fetchClientCommonSteps,
|
|
9
|
+
} = require('../utils');
|
|
10
|
+
|
|
11
|
+
const useAuthHeaders = async (state) => {
|
|
12
|
+
const { requestPayload, context } = state;
|
|
13
|
+
const { creds } = context;
|
|
14
|
+
const { ACCESS_TOKEN } = creds;
|
|
15
|
+
|
|
16
|
+
return {
|
|
17
|
+
requestPayload: {
|
|
18
|
+
...requestPayload,
|
|
19
|
+
headers: {
|
|
20
|
+
Authorization: `Bearer ${ ACCESS_TOKEN }`,
|
|
21
|
+
...requestPayload.headers,
|
|
22
|
+
},
|
|
23
|
+
},
|
|
24
|
+
};
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
// Dropbox RPC endpoints are almost always POST with a JSON body.
|
|
28
|
+
const defaultPostMethod = async (state) => {
|
|
29
|
+
const { requestPayload } = state;
|
|
30
|
+
if (requestPayload.method) {
|
|
31
|
+
return {};
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
return {
|
|
35
|
+
requestPayload: {
|
|
36
|
+
...requestPayload,
|
|
37
|
+
method: 'post',
|
|
38
|
+
},
|
|
39
|
+
};
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
const dropboxClient = new FetchClient({
|
|
43
|
+
pipeline: [
|
|
44
|
+
resolveCreds,
|
|
45
|
+
useBaseUrl(DROPBOX_API_BASE_URL),
|
|
46
|
+
useAuthHeaders,
|
|
47
|
+
defaultPostMethod,
|
|
48
|
+
'fetch',
|
|
49
|
+
fetchClientCommonSteps.exitEarlyOnNotOk,
|
|
50
|
+
],
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
const dropboxContentClient = new FetchClient({
|
|
54
|
+
pipeline: [
|
|
55
|
+
resolveCreds,
|
|
56
|
+
useBaseUrl(DROPBOX_CONTENT_BASE_URL),
|
|
57
|
+
useAuthHeaders,
|
|
58
|
+
defaultPostMethod,
|
|
59
|
+
'fetch',
|
|
60
|
+
fetchClientCommonSteps.exitEarlyOnNotOk,
|
|
61
|
+
],
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
module.exports = {
|
|
65
|
+
dropboxClient,
|
|
66
|
+
dropboxContentClient,
|
|
67
|
+
};
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
// https://www.dropbox.com/developers/documentation/http/documentation#users-get_current_account
|
|
2
|
+
|
|
3
|
+
const { ArgsWarden, logDeep } = require('../utils');
|
|
4
|
+
const { credsValidator } = require('../validators');
|
|
5
|
+
const { dropboxClient } = require('../dropbox/dropbox.utils');
|
|
6
|
+
|
|
7
|
+
const argsWarden = new ArgsWarden([
|
|
8
|
+
['credsPayload', credsValidator],
|
|
9
|
+
]);
|
|
10
|
+
|
|
11
|
+
const dropboxAccountGet = async (
|
|
12
|
+
credsPayload,
|
|
13
|
+
{
|
|
14
|
+
fetchClient = dropboxClient,
|
|
15
|
+
} = {},
|
|
16
|
+
) => {
|
|
17
|
+
const rejectResponse = await argsWarden.responseIfRejectingArgs({
|
|
18
|
+
credsPayload,
|
|
19
|
+
});
|
|
20
|
+
if (rejectResponse) {
|
|
21
|
+
return rejectResponse;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const response = await fetchClient.fetch({
|
|
25
|
+
context: { credsPayload },
|
|
26
|
+
requestPayload: {
|
|
27
|
+
method: 'post',
|
|
28
|
+
url: '/users/get_current_account',
|
|
29
|
+
// Dropbox expects the literal JSON null for no-arg endpoints.
|
|
30
|
+
headers: {
|
|
31
|
+
'Content-Type': 'application/json',
|
|
32
|
+
},
|
|
33
|
+
body: 'null',
|
|
34
|
+
},
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
const { ok, data, error } = response;
|
|
38
|
+
if (!ok) {
|
|
39
|
+
logDeep({ error });
|
|
40
|
+
return { ok: false, error };
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
return {
|
|
44
|
+
ok: true,
|
|
45
|
+
data,
|
|
46
|
+
};
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
const funcApiConfig = {
|
|
50
|
+
argsWarden,
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
module.exports = {
|
|
54
|
+
dropboxAccountGet,
|
|
55
|
+
funcApiConfig,
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
/*
|
|
59
|
+
curl -X POST "http://localhost:8000/dropboxAccountGet" \
|
|
60
|
+
-H "Content-Type: application/json" \
|
|
61
|
+
-d '{
|
|
62
|
+
"credsPayload": { "credsPath": "dropbox" }
|
|
63
|
+
}'
|
|
64
|
+
*/
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
// https://www.dropbox.com/developers/documentation/http/documentation#files-copy_v2
|
|
2
|
+
|
|
3
|
+
const { ArgsWarden, logDeep } = require('../utils');
|
|
4
|
+
const { credsValidator } = require('../validators');
|
|
5
|
+
const { dropboxClient } = require('../dropbox/dropbox.utils');
|
|
6
|
+
|
|
7
|
+
const argsWarden = new ArgsWarden([
|
|
8
|
+
['credsPayload', credsValidator],
|
|
9
|
+
['fromPath'],
|
|
10
|
+
['toPath'],
|
|
11
|
+
]);
|
|
12
|
+
|
|
13
|
+
const dropboxFileCopy = async (
|
|
14
|
+
credsPayload,
|
|
15
|
+
fromPath,
|
|
16
|
+
toPath,
|
|
17
|
+
{
|
|
18
|
+
allowSharedFolder = false,
|
|
19
|
+
autorename = false,
|
|
20
|
+
allowOwnershipTransfer = false,
|
|
21
|
+
fetchClient = dropboxClient,
|
|
22
|
+
} = {},
|
|
23
|
+
) => {
|
|
24
|
+
const rejectResponse = await argsWarden.responseIfRejectingArgs({
|
|
25
|
+
credsPayload,
|
|
26
|
+
fromPath,
|
|
27
|
+
toPath,
|
|
28
|
+
});
|
|
29
|
+
if (rejectResponse) {
|
|
30
|
+
return rejectResponse;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const response = await fetchClient.fetch({
|
|
34
|
+
context: { credsPayload },
|
|
35
|
+
requestPayload: {
|
|
36
|
+
method: 'post',
|
|
37
|
+
url: '/files/copy_v2',
|
|
38
|
+
body: {
|
|
39
|
+
from_path: fromPath,
|
|
40
|
+
to_path: toPath,
|
|
41
|
+
allow_shared_folder: allowSharedFolder,
|
|
42
|
+
autorename,
|
|
43
|
+
allow_ownership_transfer: allowOwnershipTransfer,
|
|
44
|
+
},
|
|
45
|
+
},
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
const { ok, data, error } = response;
|
|
49
|
+
if (!ok) {
|
|
50
|
+
logDeep({ error });
|
|
51
|
+
return { ok: false, error };
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
return {
|
|
55
|
+
ok: true,
|
|
56
|
+
data: data.metadata ?? data,
|
|
57
|
+
};
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
const funcApiConfig = {
|
|
61
|
+
argsWarden,
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
module.exports = {
|
|
65
|
+
dropboxFileCopy,
|
|
66
|
+
funcApiConfig,
|
|
67
|
+
};
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
// https://www.dropbox.com/developers/documentation/http/documentation#files-delete_v2
|
|
2
|
+
|
|
3
|
+
const { ArgsWarden, actionSingleOrMultiple, logDeep } = require('../utils');
|
|
4
|
+
const { credsValidator } = require('../validators');
|
|
5
|
+
const { dropboxClient } = require('../dropbox/dropbox.utils');
|
|
6
|
+
|
|
7
|
+
const argsWarden = new ArgsWarden([
|
|
8
|
+
['credsPayload', credsValidator],
|
|
9
|
+
['path'],
|
|
10
|
+
]);
|
|
11
|
+
|
|
12
|
+
const dropboxFileDeleteSingle = async (
|
|
13
|
+
credsPayload,
|
|
14
|
+
path,
|
|
15
|
+
{
|
|
16
|
+
parentRev,
|
|
17
|
+
fetchClient = dropboxClient,
|
|
18
|
+
} = {},
|
|
19
|
+
) => {
|
|
20
|
+
const response = await fetchClient.fetch({
|
|
21
|
+
context: { credsPayload },
|
|
22
|
+
requestPayload: {
|
|
23
|
+
method: 'post',
|
|
24
|
+
url: '/files/delete_v2',
|
|
25
|
+
body: {
|
|
26
|
+
path,
|
|
27
|
+
...(parentRev !== undefined && { parent_rev: parentRev }),
|
|
28
|
+
},
|
|
29
|
+
},
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
const { ok, data, error } = response;
|
|
33
|
+
if (!ok) {
|
|
34
|
+
logDeep({ error });
|
|
35
|
+
return { ok: false, error };
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
return {
|
|
39
|
+
ok: true,
|
|
40
|
+
data: data.metadata ?? data,
|
|
41
|
+
};
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
const dropboxFileDelete = async (
|
|
45
|
+
credsPayload,
|
|
46
|
+
path,
|
|
47
|
+
{
|
|
48
|
+
parentRev,
|
|
49
|
+
queueRunOptions,
|
|
50
|
+
fetchClient,
|
|
51
|
+
} = {},
|
|
52
|
+
) => {
|
|
53
|
+
const rejectResponse = await argsWarden.responseIfRejectingArgs({
|
|
54
|
+
credsPayload,
|
|
55
|
+
path,
|
|
56
|
+
});
|
|
57
|
+
if (rejectResponse) {
|
|
58
|
+
return rejectResponse;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
return actionSingleOrMultiple(
|
|
62
|
+
path,
|
|
63
|
+
dropboxFileDeleteSingle,
|
|
64
|
+
(pathItem) => ({
|
|
65
|
+
args: [credsPayload, pathItem, { parentRev, fetchClient }],
|
|
66
|
+
}),
|
|
67
|
+
{
|
|
68
|
+
...(queueRunOptions ? { queueRunOptions } : {}),
|
|
69
|
+
},
|
|
70
|
+
);
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
const funcApiConfig = {
|
|
74
|
+
argsWarden,
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
module.exports = {
|
|
78
|
+
dropboxFileDelete,
|
|
79
|
+
funcApiConfig,
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
/*
|
|
83
|
+
curl -X POST "http://localhost:8000/dropboxFileDelete" \
|
|
84
|
+
-H "Content-Type: application/json" \
|
|
85
|
+
-d '{
|
|
86
|
+
"credsPayload": { "credsPath": "dropbox" },
|
|
87
|
+
"path": "/Homework/math/Prime_Numbers.txt"
|
|
88
|
+
}'
|
|
89
|
+
*/
|