@foxtware/mineral 0.1.27 → 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.
- package/.creds.yml.sample +29 -0
- package/AGENTS.md +24 -0
- package/_build_scripts/createNewFunction.js +26 -3
- 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/fastsimon/.gitkeep +0 -0
- package/api/fastsimon/docs.md +14 -0
- package/api/fastsimon/fastsimon.constants.js +18 -0
- package/api/fastsimon/fastsimon.utils.js +246 -0
- package/api/fastsimon/fastsimonSearch.js +84 -0
- package/api/figma/docs.md +3 -3
- package/api/figma/figma.constants.js +1 -1
- package/api/figma/figma.utils.js +13 -2
- package/api/figma/figmaActivityLogsGet.js +44 -0
- package/api/figma/figmaAiUsageDailyGet.js +44 -0
- package/api/figma/figmaComponentGet.js +48 -0
- package/api/figma/figmaComponentSetGet.js +48 -0
- package/api/figma/figmaDevResourcesCreate.js +47 -0
- package/api/figma/figmaDevResourcesUpdate.js +47 -0
- package/api/figma/figmaDeveloperLogsCreate.js +47 -0
- package/api/figma/figmaDiscoveryGet.js +44 -0
- package/api/figma/figmaFileCommentCreate.js +50 -0
- package/api/figma/figmaFileCommentDelete.js +51 -0
- package/api/figma/figmaFileCommentReactionCreate.js +53 -0
- package/api/figma/figmaFileCommentReactionDelete.js +51 -0
- package/api/figma/figmaFileCommentReactionsGet.js +51 -0
- package/api/figma/figmaFileCommentsGet.js +48 -0
- package/api/figma/figmaFileComponentSetsGet.js +48 -0
- package/api/figma/figmaFileComponentsGet.js +48 -0
- package/api/figma/figmaFileDevResourceDelete.js +51 -0
- package/api/figma/figmaFileDevResourcesGet.js +48 -0
- package/api/figma/figmaFileGet.js +48 -0
- package/api/figma/figmaFileImageFillsGet.js +48 -0
- package/api/figma/figmaFileImagesGet.js +48 -0
- package/api/figma/figmaFileMetaGet.js +48 -0
- package/api/figma/figmaFileNodesGet.js +48 -0
- package/api/figma/figmaFileStylesGet.js +48 -0
- package/api/figma/figmaFileVersionsGet.js +48 -0
- package/api/figma/figmaFolderFilesGet.js +48 -0
- package/api/figma/figmaFolderFoldersGet.js +48 -0
- package/api/figma/figmaFolderMetaGet.js +48 -0
- package/api/figma/figmaGet.js +15 -63
- package/api/figma/figmaMeGet.js +53 -0
- package/api/figma/figmaOembedGet.js +44 -0
- package/api/figma/figmaPaymentsGet.js +44 -0
- package/api/figma/figmaProjectFilesGet.js +48 -0
- package/api/figma/figmaProjectMetaGet.js +48 -0
- package/api/figma/figmaStyleGet.js +48 -0
- package/api/figma/figmaTeamComponentSetsGet.js +48 -0
- package/api/figma/figmaTeamComponentsGet.js +48 -0
- package/api/figma/figmaTeamFoldersGet.js +48 -0
- package/api/figma/figmaTeamProjectsGet.js +48 -0
- package/api/figma/figmaTeamStylesGet.js +48 -0
- package/api/figma/figmaTeamWebhooksGet.js +47 -0
- package/api/figma/figmaVariablesLocalGet.js +48 -0
- package/api/figma/figmaVariablesPublishedGet.js +48 -0
- package/api/figma/figmaVariablesUpdate.js +50 -0
- package/api/figma/figmaWebhookCreate.js +47 -0
- package/api/figma/figmaWebhookDelete.js +48 -0
- package/api/figma/figmaWebhookGet.js +46 -0
- package/api/figma/figmaWebhookRequestsGet.js +47 -0
- package/api/figma/figmaWebhookUpdate.js +50 -0
- package/api/figma/figmaWebhooksGet.js +47 -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/gorgias/gorgiasTicketCreate.js +1 -1
- package/api/gorgias/gorgiasTicketMessageCreate.js +1 -1
- package/api/gorgias/gorgiasTicketUpdate.js +1 -1
- package/api/linear/linearAttachmentCreate.js +1 -1
- package/api/linear/linearCommentCreate.js +1 -1
- package/api/linear/linearCommentUpdate.js +1 -1
- package/api/linear/linearIssueLabelCreate.js +1 -1
- package/api/linear/linearIssueUpdate.js +1 -1
- package/api/linear/linearProjectCreate.js +1 -1
- package/api/linear/linearProjectUpdate.js +1 -1
- package/api/linear/linearWebhookCreate.js +1 -1
- package/api/salesforce/salesforce.constants.js +13 -0
- package/api/salesforce/salesforce.utils.js +61 -0
- package/api/salesforce/salesforceAuthGet.js +115 -0
- package/api/salesforce/salesforceComposite.js +79 -0
- package/api/salesforce/salesforceCompositeBatch.js +73 -0
- package/api/salesforce/salesforceLimitsGet.js +55 -0
- package/api/salesforce/salesforceQuery.js +69 -0
- package/api/salesforce/salesforceQueryAll.js +62 -0
- package/api/salesforce/salesforceQueryMore.js +75 -0
- package/api/salesforce/salesforceRecentItemsGet.js +63 -0
- package/api/salesforce/salesforceResourcesGet.js +55 -0
- package/api/salesforce/salesforceSearch.js +62 -0
- package/api/salesforce/salesforceSobjectBasicInfoGet.js +81 -0
- package/api/salesforce/salesforceSobjectBlobGet.js +67 -0
- package/api/salesforce/salesforceSobjectCollectionCreate.js +78 -0
- package/api/salesforce/salesforceSobjectCollectionDelete.js +70 -0
- package/api/salesforce/salesforceSobjectCollectionGet.js +75 -0
- package/api/salesforce/salesforceSobjectCollectionUpdate.js +74 -0
- package/api/salesforce/salesforceSobjectCreate.js +66 -0
- package/api/salesforce/salesforceSobjectDelete.js +86 -0
- package/api/salesforce/salesforceSobjectDeleteByExternalId.js +91 -0
- package/api/salesforce/salesforceSobjectDeletedGet.js +71 -0
- package/api/salesforce/salesforceSobjectDescribe.js +81 -0
- package/api/salesforce/salesforceSobjectDescribeLayouts.js +64 -0
- package/api/salesforce/salesforceSobjectGet.js +93 -0
- package/api/salesforce/salesforceSobjectGetByExternalId.js +98 -0
- package/api/salesforce/salesforceSobjectTreeCreate.js +79 -0
- package/api/salesforce/salesforceSobjectUpdate.js +94 -0
- package/api/salesforce/salesforceSobjectUpdatedGet.js +71 -0
- package/api/salesforce/salesforceSobjectUpsert.js +74 -0
- package/api/salesforce/salesforceSobjectsDescribeGlobal.js +55 -0
- package/api/salesforce/salesforceVersionsGet.js +62 -0
- package/api/shopify/shopify.utils.js +53 -4
- package/api/shopify/shopifyMetaobjectCreate.js +79 -0
- 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/tableau/tableau.constants.js +8 -0
- package/api/tableau/tableau.utils.js +93 -0
- package/api/tableau/tableauGet.js +174 -0
- package/api/tableau/tableauUserAdd.js +16 -94
- package/api/tableau/tableauUsersGet.js +46 -134
- package/api/tagalys/docs.md +2 -2
- package/api/tagalys/tagalys.constants.js +17 -0
- package/api/tagalys/tagalys.utils.js +125 -0
- package/api/tagalys/tagalysAnalyticsEventSend.js +125 -0
- package/api/tagalys/tagalysCollectionGet.js +100 -0
- package/api/tagalys/tagalysPopularSearchesGet.js +60 -0
- package/api/tagalys/tagalysRecommendationGet.js +109 -0
- package/api/tagalys/tagalysSearch.js +15 -89
- package/api/tagalys/tagalysSearchSuggestionsGet.js +76 -0
- package/package.json +2 -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: _____________________________
|
|
@@ -94,6 +95,8 @@ telnyx:
|
|
|
94
95
|
|
|
95
96
|
figma:
|
|
96
97
|
API_KEY: figd___________________________
|
|
98
|
+
# Or use ACCESS_TOKEN for an OAuth 2 bearer token
|
|
99
|
+
ACCESS_TOKEN: __________________________
|
|
97
100
|
|
|
98
101
|
pipe17:
|
|
99
102
|
API_KEY: _______________________________
|
|
@@ -126,3 +129,29 @@ tableau:
|
|
|
126
129
|
PAT_SECRET: ____________________________
|
|
127
130
|
SERVER_URL: ____________________________
|
|
128
131
|
SITE_CONTENT_URL: ______________________
|
|
132
|
+
|
|
133
|
+
salesforce:
|
|
134
|
+
# Option A — pre-issued token
|
|
135
|
+
ACCESS_TOKEN: __________________________
|
|
136
|
+
INSTANCE_URL: https://________.my.salesforce.com
|
|
137
|
+
|
|
138
|
+
# Option B — client credentials (if ACCESS_TOKEN missing)
|
|
139
|
+
CLIENT_ID: _____________________________
|
|
140
|
+
CLIENT_SECRET: _________________________
|
|
141
|
+
LOGIN_URL: https://login.salesforce.com # or My Domain / test.salesforce.com
|
|
142
|
+
|
|
143
|
+
fastsimon:
|
|
144
|
+
store: # instance name of your choice
|
|
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: _________________________
|
package/AGENTS.md
CHANGED
|
@@ -25,3 +25,27 @@ Notes for AI assistants working in this directory. **Read this file at the start
|
|
|
25
25
|
## API clients
|
|
26
26
|
- Base URLs for platform clients should live in `{platform}.constants.js`, not creds, if they are static for all users of the API.
|
|
27
27
|
- Don't explicitly set `Content-Type: application/json` on the client — `customFetch` already adds it when there is a request body.
|
|
28
|
+
|
|
29
|
+
## Usual structure of a platform API client
|
|
30
|
+
This is the usual structure, but it can be altered per platform, if required. If there is no good reason to deviate, this is how a platform should look.
|
|
31
|
+
- Functions live in `/api/[platform]`
|
|
32
|
+
- If `docs.md` exists, it is a minimal link to native API documentation and a brief description of its structure. It is not concerned with our implementation and does not need to be updated.
|
|
33
|
+
- Creds are supported by path from `.creds.yml`. `.creds.yml.sample` documents the structure of the required creds.
|
|
34
|
+
- A customised FetchClient called `[platform]Client` exists in `[platform].utils.js`, which handles API requests. It implements a base URL, and resolves `credsPayload` into `context.creds` for future steps.
|
|
35
|
+
- All functions require a `credsPayload` argument to tell them which credentials to use. They relate per instance.
|
|
36
|
+
- `[platform].constants.js` contains any max pagination limits, default API version, base url (if not changing per instance).
|
|
37
|
+
- `[platform]Get.js` is a generic function which gets resources in a paginated way. It implements Getter, and all `[platform]ResourceGet.js` functions export both `platformResourceGet` and `platformResourceGetter`, using the "bind" export style.
|
|
38
|
+
- Each endpoint of the platform's API is supported as a separate function within the platform directory. Functions are named `[platform]NounVerb.js`, e.g. `shopifyPageDelete`.
|
|
39
|
+
- Endpoints should return the unwrapped data inside the standard response format, e.g. `data: { ...resource }`. Not e.g. `data: { product/data/result: { ...resource } }`.
|
|
40
|
+
- Each function creates and exports an `ArgsWarden`. Inside, mandatory arguments are validated. At minimum, all mandatory arguments should be a singleton, which falls back to a generic "value provided" validator. Anything that is not mandatory should be an option, included in the optional "options" argument which is commonly destructured in the function definition.
|
|
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
|
+
- `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
|
+
|
|
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.
|
|
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({
|
|
@@ -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
|
+
*/
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
// https://www.dropbox.com/developers/documentation/http/documentation#files-download
|
|
2
|
+
// Returns file metadata plus contents as base64 (JSON-safe).
|
|
3
|
+
|
|
4
|
+
const { ArgsWarden, actionSingleOrMultiple, logDeep } = require('../utils');
|
|
5
|
+
const { credsValidator } = require('../validators');
|
|
6
|
+
const { customFetch, appendUrlToBase, credsFromPayload } = require('../utils');
|
|
7
|
+
const { DROPBOX_CONTENT_BASE_URL } = require('../dropbox/dropbox.constants');
|
|
8
|
+
|
|
9
|
+
const argsWarden = new ArgsWarden([
|
|
10
|
+
['credsPayload', credsValidator],
|
|
11
|
+
['path'],
|
|
12
|
+
]);
|
|
13
|
+
|
|
14
|
+
const dropboxFileDownloadSingle = async (
|
|
15
|
+
credsPayload,
|
|
16
|
+
path,
|
|
17
|
+
{
|
|
18
|
+
rev,
|
|
19
|
+
// When true, return raw ArrayBuffer in data.contentsBuffer instead of base64
|
|
20
|
+
// (not useful over funcApi JSON; kept for in-process callers).
|
|
21
|
+
asBuffer = false,
|
|
22
|
+
} = {},
|
|
23
|
+
) => {
|
|
24
|
+
const creds = await credsFromPayload(credsPayload);
|
|
25
|
+
const { ACCESS_TOKEN } = creds ?? {};
|
|
26
|
+
|
|
27
|
+
if (!ACCESS_TOKEN) {
|
|
28
|
+
return {
|
|
29
|
+
ok: false,
|
|
30
|
+
error: {
|
|
31
|
+
code: 'MISSING_DROPBOX_CREDS',
|
|
32
|
+
message: 'dropbox creds require ACCESS_TOKEN',
|
|
33
|
+
},
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const arg = {
|
|
38
|
+
path,
|
|
39
|
+
...(rev !== undefined && { rev }),
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
const url = appendUrlToBase(DROPBOX_CONTENT_BASE_URL, '/files/download');
|
|
43
|
+
|
|
44
|
+
// customFetch so we can read Dropbox-API-Result header + binary body.
|
|
45
|
+
const response = await customFetch(url, {
|
|
46
|
+
method: 'post',
|
|
47
|
+
headers: {
|
|
48
|
+
Authorization: `Bearer ${ ACCESS_TOKEN }`,
|
|
49
|
+
'Dropbox-API-Arg': JSON.stringify(arg),
|
|
50
|
+
},
|
|
51
|
+
// Empty body; Dropbox still expects POST.
|
|
52
|
+
body: '',
|
|
53
|
+
responseParser: async (res) => {
|
|
54
|
+
const resultHeader = res.headers.get('dropbox-api-result');
|
|
55
|
+
let metadata = null;
|
|
56
|
+
if (resultHeader) {
|
|
57
|
+
try {
|
|
58
|
+
metadata = JSON.parse(resultHeader);
|
|
59
|
+
} catch {
|
|
60
|
+
metadata = { raw: resultHeader };
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
const buffer = Buffer.from(await res.arrayBuffer());
|
|
65
|
+
return {
|
|
66
|
+
metadata,
|
|
67
|
+
buffer,
|
|
68
|
+
};
|
|
69
|
+
},
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
if (!response.ok) {
|
|
73
|
+
logDeep({ error: response.error ?? response.data });
|
|
74
|
+
return {
|
|
75
|
+
ok: false,
|
|
76
|
+
error: response.error ?? response.data,
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const { metadata, buffer } = response.data;
|
|
81
|
+
|
|
82
|
+
return {
|
|
83
|
+
ok: true,
|
|
84
|
+
data: {
|
|
85
|
+
...(metadata || {}),
|
|
86
|
+
...(asBuffer
|
|
87
|
+
? { contentsBuffer: buffer }
|
|
88
|
+
: { contentsBase64: buffer.toString('base64') }),
|
|
89
|
+
size: buffer.length,
|
|
90
|
+
},
|
|
91
|
+
};
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
const dropboxFileDownload = async (
|
|
95
|
+
credsPayload,
|
|
96
|
+
path,
|
|
97
|
+
{
|
|
98
|
+
rev,
|
|
99
|
+
asBuffer,
|
|
100
|
+
queueRunOptions,
|
|
101
|
+
} = {},
|
|
102
|
+
) => {
|
|
103
|
+
const rejectResponse = await argsWarden.responseIfRejectingArgs({
|
|
104
|
+
credsPayload,
|
|
105
|
+
path,
|
|
106
|
+
});
|
|
107
|
+
if (rejectResponse) {
|
|
108
|
+
return rejectResponse;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
return actionSingleOrMultiple(
|
|
112
|
+
path,
|
|
113
|
+
dropboxFileDownloadSingle,
|
|
114
|
+
(pathItem) => ({
|
|
115
|
+
args: [credsPayload, pathItem, { rev, asBuffer }],
|
|
116
|
+
}),
|
|
117
|
+
{
|
|
118
|
+
...(queueRunOptions ? { queueRunOptions } : {}),
|
|
119
|
+
},
|
|
120
|
+
);
|
|
121
|
+
};
|
|
122
|
+
|
|
123
|
+
const funcApiConfig = {
|
|
124
|
+
argsWarden,
|
|
125
|
+
};
|
|
126
|
+
|
|
127
|
+
module.exports = {
|
|
128
|
+
dropboxFileDownload,
|
|
129
|
+
funcApiConfig,
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
/*
|
|
133
|
+
curl -X POST "http://localhost:8000/dropboxFileDownload" \
|
|
134
|
+
-H "Content-Type: application/json" \
|
|
135
|
+
-d '{
|
|
136
|
+
"credsPayload": { "credsPath": "dropbox" },
|
|
137
|
+
"path": "/Homework/math/Prime_Numbers.txt"
|
|
138
|
+
}'
|
|
139
|
+
*/
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
// https://www.dropbox.com/developers/documentation/http/documentation#files-get_metadata
|
|
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 dropboxFileMetadataGetSingle = async (
|
|
13
|
+
credsPayload,
|
|
14
|
+
path,
|
|
15
|
+
{
|
|
16
|
+
includeMediaInfo = false,
|
|
17
|
+
includeDeleted = false,
|
|
18
|
+
includeHasExplicitSharedMembers = false,
|
|
19
|
+
fetchClient = dropboxClient,
|
|
20
|
+
} = {},
|
|
21
|
+
) => {
|
|
22
|
+
const response = await fetchClient.fetch({
|
|
23
|
+
context: { credsPayload },
|
|
24
|
+
requestPayload: {
|
|
25
|
+
method: 'post',
|
|
26
|
+
url: '/files/get_metadata',
|
|
27
|
+
body: {
|
|
28
|
+
path,
|
|
29
|
+
include_media_info: includeMediaInfo,
|
|
30
|
+
include_deleted: includeDeleted,
|
|
31
|
+
include_has_explicit_shared_members: includeHasExplicitSharedMembers,
|
|
32
|
+
},
|
|
33
|
+
},
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
const { ok, data, error } = response;
|
|
37
|
+
if (!ok) {
|
|
38
|
+
logDeep({ error });
|
|
39
|
+
return { ok: false, error };
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
return {
|
|
43
|
+
ok: true,
|
|
44
|
+
data,
|
|
45
|
+
};
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
const dropboxFileMetadataGet = async (
|
|
49
|
+
credsPayload,
|
|
50
|
+
path,
|
|
51
|
+
{
|
|
52
|
+
includeMediaInfo,
|
|
53
|
+
includeDeleted,
|
|
54
|
+
includeHasExplicitSharedMembers,
|
|
55
|
+
queueRunOptions,
|
|
56
|
+
fetchClient,
|
|
57
|
+
} = {},
|
|
58
|
+
) => {
|
|
59
|
+
const rejectResponse = await argsWarden.responseIfRejectingArgs({
|
|
60
|
+
credsPayload,
|
|
61
|
+
path,
|
|
62
|
+
});
|
|
63
|
+
if (rejectResponse) {
|
|
64
|
+
return rejectResponse;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
return actionSingleOrMultiple(
|
|
68
|
+
path,
|
|
69
|
+
dropboxFileMetadataGetSingle,
|
|
70
|
+
(pathItem) => ({
|
|
71
|
+
args: [credsPayload, pathItem, {
|
|
72
|
+
includeMediaInfo,
|
|
73
|
+
includeDeleted,
|
|
74
|
+
includeHasExplicitSharedMembers,
|
|
75
|
+
fetchClient,
|
|
76
|
+
}],
|
|
77
|
+
}),
|
|
78
|
+
{
|
|
79
|
+
...(queueRunOptions ? { queueRunOptions } : {}),
|
|
80
|
+
},
|
|
81
|
+
);
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
const funcApiConfig = {
|
|
85
|
+
argsWarden,
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
module.exports = {
|
|
89
|
+
dropboxFileMetadataGet,
|
|
90
|
+
funcApiConfig,
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
/*
|
|
94
|
+
curl -X POST "http://localhost:8000/dropboxFileMetadataGet" \
|
|
95
|
+
-H "Content-Type: application/json" \
|
|
96
|
+
-d '{
|
|
97
|
+
"credsPayload": { "credsPath": "dropbox" },
|
|
98
|
+
"path": "/Homework/math/Prime_Numbers.txt"
|
|
99
|
+
}'
|
|
100
|
+
*/
|