@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.
Files changed (178) hide show
  1. package/.creds.yml.sample +29 -0
  2. package/AGENTS.md +24 -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/fastsimon/.gitkeep +0 -0
  22. package/api/fastsimon/docs.md +14 -0
  23. package/api/fastsimon/fastsimon.constants.js +18 -0
  24. package/api/fastsimon/fastsimon.utils.js +246 -0
  25. package/api/fastsimon/fastsimonSearch.js +84 -0
  26. package/api/figma/docs.md +3 -3
  27. package/api/figma/figma.constants.js +1 -1
  28. package/api/figma/figma.utils.js +13 -2
  29. package/api/figma/figmaActivityLogsGet.js +44 -0
  30. package/api/figma/figmaAiUsageDailyGet.js +44 -0
  31. package/api/figma/figmaComponentGet.js +48 -0
  32. package/api/figma/figmaComponentSetGet.js +48 -0
  33. package/api/figma/figmaDevResourcesCreate.js +47 -0
  34. package/api/figma/figmaDevResourcesUpdate.js +47 -0
  35. package/api/figma/figmaDeveloperLogsCreate.js +47 -0
  36. package/api/figma/figmaDiscoveryGet.js +44 -0
  37. package/api/figma/figmaFileCommentCreate.js +50 -0
  38. package/api/figma/figmaFileCommentDelete.js +51 -0
  39. package/api/figma/figmaFileCommentReactionCreate.js +53 -0
  40. package/api/figma/figmaFileCommentReactionDelete.js +51 -0
  41. package/api/figma/figmaFileCommentReactionsGet.js +51 -0
  42. package/api/figma/figmaFileCommentsGet.js +48 -0
  43. package/api/figma/figmaFileComponentSetsGet.js +48 -0
  44. package/api/figma/figmaFileComponentsGet.js +48 -0
  45. package/api/figma/figmaFileDevResourceDelete.js +51 -0
  46. package/api/figma/figmaFileDevResourcesGet.js +48 -0
  47. package/api/figma/figmaFileGet.js +48 -0
  48. package/api/figma/figmaFileImageFillsGet.js +48 -0
  49. package/api/figma/figmaFileImagesGet.js +48 -0
  50. package/api/figma/figmaFileMetaGet.js +48 -0
  51. package/api/figma/figmaFileNodesGet.js +48 -0
  52. package/api/figma/figmaFileStylesGet.js +48 -0
  53. package/api/figma/figmaFileVersionsGet.js +48 -0
  54. package/api/figma/figmaFolderFilesGet.js +48 -0
  55. package/api/figma/figmaFolderFoldersGet.js +48 -0
  56. package/api/figma/figmaFolderMetaGet.js +48 -0
  57. package/api/figma/figmaGet.js +15 -63
  58. package/api/figma/figmaMeGet.js +53 -0
  59. package/api/figma/figmaOembedGet.js +44 -0
  60. package/api/figma/figmaPaymentsGet.js +44 -0
  61. package/api/figma/figmaProjectFilesGet.js +48 -0
  62. package/api/figma/figmaProjectMetaGet.js +48 -0
  63. package/api/figma/figmaStyleGet.js +48 -0
  64. package/api/figma/figmaTeamComponentSetsGet.js +48 -0
  65. package/api/figma/figmaTeamComponentsGet.js +48 -0
  66. package/api/figma/figmaTeamFoldersGet.js +48 -0
  67. package/api/figma/figmaTeamProjectsGet.js +48 -0
  68. package/api/figma/figmaTeamStylesGet.js +48 -0
  69. package/api/figma/figmaTeamWebhooksGet.js +47 -0
  70. package/api/figma/figmaVariablesLocalGet.js +48 -0
  71. package/api/figma/figmaVariablesPublishedGet.js +48 -0
  72. package/api/figma/figmaVariablesUpdate.js +50 -0
  73. package/api/figma/figmaWebhookCreate.js +47 -0
  74. package/api/figma/figmaWebhookDelete.js +48 -0
  75. package/api/figma/figmaWebhookGet.js +46 -0
  76. package/api/figma/figmaWebhookRequestsGet.js +47 -0
  77. package/api/figma/figmaWebhookUpdate.js +50 -0
  78. package/api/figma/figmaWebhooksGet.js +47 -0
  79. package/api/google/docs.md +1 -0
  80. package/api/google/google.constants.js +1 -0
  81. package/api/google/google.utils.js +21 -0
  82. package/api/google/googleanalyticsMetadataGet.js +62 -0
  83. package/api/google/googleanalyticsRealtimeReportRun.js +103 -0
  84. package/api/google/googleanalyticsReportRun.js +114 -0
  85. package/api/gorgias/gorgiasTicketCreate.js +1 -1
  86. package/api/gorgias/gorgiasTicketMessageCreate.js +1 -1
  87. package/api/gorgias/gorgiasTicketUpdate.js +1 -1
  88. package/api/linear/linearAttachmentCreate.js +1 -1
  89. package/api/linear/linearCommentCreate.js +1 -1
  90. package/api/linear/linearCommentUpdate.js +1 -1
  91. package/api/linear/linearIssueLabelCreate.js +1 -1
  92. package/api/linear/linearIssueUpdate.js +1 -1
  93. package/api/linear/linearProjectCreate.js +1 -1
  94. package/api/linear/linearProjectUpdate.js +1 -1
  95. package/api/linear/linearWebhookCreate.js +1 -1
  96. package/api/salesforce/salesforce.constants.js +13 -0
  97. package/api/salesforce/salesforce.utils.js +61 -0
  98. package/api/salesforce/salesforceAuthGet.js +115 -0
  99. package/api/salesforce/salesforceComposite.js +79 -0
  100. package/api/salesforce/salesforceCompositeBatch.js +73 -0
  101. package/api/salesforce/salesforceLimitsGet.js +55 -0
  102. package/api/salesforce/salesforceQuery.js +69 -0
  103. package/api/salesforce/salesforceQueryAll.js +62 -0
  104. package/api/salesforce/salesforceQueryMore.js +75 -0
  105. package/api/salesforce/salesforceRecentItemsGet.js +63 -0
  106. package/api/salesforce/salesforceResourcesGet.js +55 -0
  107. package/api/salesforce/salesforceSearch.js +62 -0
  108. package/api/salesforce/salesforceSobjectBasicInfoGet.js +81 -0
  109. package/api/salesforce/salesforceSobjectBlobGet.js +67 -0
  110. package/api/salesforce/salesforceSobjectCollectionCreate.js +78 -0
  111. package/api/salesforce/salesforceSobjectCollectionDelete.js +70 -0
  112. package/api/salesforce/salesforceSobjectCollectionGet.js +75 -0
  113. package/api/salesforce/salesforceSobjectCollectionUpdate.js +74 -0
  114. package/api/salesforce/salesforceSobjectCreate.js +66 -0
  115. package/api/salesforce/salesforceSobjectDelete.js +86 -0
  116. package/api/salesforce/salesforceSobjectDeleteByExternalId.js +91 -0
  117. package/api/salesforce/salesforceSobjectDeletedGet.js +71 -0
  118. package/api/salesforce/salesforceSobjectDescribe.js +81 -0
  119. package/api/salesforce/salesforceSobjectDescribeLayouts.js +64 -0
  120. package/api/salesforce/salesforceSobjectGet.js +93 -0
  121. package/api/salesforce/salesforceSobjectGetByExternalId.js +98 -0
  122. package/api/salesforce/salesforceSobjectTreeCreate.js +79 -0
  123. package/api/salesforce/salesforceSobjectUpdate.js +94 -0
  124. package/api/salesforce/salesforceSobjectUpdatedGet.js +71 -0
  125. package/api/salesforce/salesforceSobjectUpsert.js +74 -0
  126. package/api/salesforce/salesforceSobjectsDescribeGlobal.js +55 -0
  127. package/api/salesforce/salesforceVersionsGet.js +62 -0
  128. package/api/shopify/shopify.utils.js +53 -4
  129. package/api/shopify/shopifyMetaobjectCreate.js +79 -0
  130. package/api/shopify/shopifyMetaobjectDelete.js +90 -0
  131. package/api/shopify/shopifyMetaobjectGet.js +80 -0
  132. package/api/shopify/shopifyMetaobjectUpdate.js +108 -0
  133. package/api/shopify/shopifyStorefrontSearch.js +158 -0
  134. package/api/spotify/docs.md +8 -0
  135. package/api/spotify/spotify.constants.js +12 -0
  136. package/api/spotify/spotify.utils.js +106 -0
  137. package/api/spotify/spotifyAlbumGet.js +76 -0
  138. package/api/spotify/spotifyAlbumTracksGet.js +49 -0
  139. package/api/spotify/spotifyArtistAlbumsGet.js +55 -0
  140. package/api/spotify/spotifyArtistGet.js +71 -0
  141. package/api/spotify/spotifyArtistTopTracksGet.js +56 -0
  142. package/api/spotify/spotifyGet.js +171 -0
  143. package/api/spotify/spotifyMeGet.js +48 -0
  144. package/api/spotify/spotifyPlayerCurrentlyPlayingGet.js +62 -0
  145. package/api/spotify/spotifyPlayerDevicesGet.js +51 -0
  146. package/api/spotify/spotifyPlayerGet.js +63 -0
  147. package/api/spotify/spotifyPlayerNext.js +55 -0
  148. package/api/spotify/spotifyPlayerPause.js +55 -0
  149. package/api/spotify/spotifyPlayerPlay.js +70 -0
  150. package/api/spotify/spotifyPlayerPrevious.js +55 -0
  151. package/api/spotify/spotifyPlaylistCreate.js +63 -0
  152. package/api/spotify/spotifyPlaylistGet.js +91 -0
  153. package/api/spotify/spotifyPlaylistItemsAdd.js +61 -0
  154. package/api/spotify/spotifyPlaylistItemsGet.js +58 -0
  155. package/api/spotify/spotifyPlaylistItemsRemove.js +67 -0
  156. package/api/spotify/spotifyPlaylistUpdate.js +64 -0
  157. package/api/spotify/spotifyPlaylistsGet.js +47 -0
  158. package/api/spotify/spotifySavedTracksGet.js +46 -0
  159. package/api/spotify/spotifySavedTracksRemove.js +59 -0
  160. package/api/spotify/spotifySavedTracksSave.js +59 -0
  161. package/api/spotify/spotifySearch.js +174 -0
  162. package/api/spotify/spotifyTrackGet.js +76 -0
  163. package/api/tableau/tableau.constants.js +8 -0
  164. package/api/tableau/tableau.utils.js +93 -0
  165. package/api/tableau/tableauGet.js +174 -0
  166. package/api/tableau/tableauUserAdd.js +16 -94
  167. package/api/tableau/tableauUsersGet.js +46 -134
  168. package/api/tagalys/docs.md +2 -2
  169. package/api/tagalys/tagalys.constants.js +17 -0
  170. package/api/tagalys/tagalys.utils.js +125 -0
  171. package/api/tagalys/tagalysAnalyticsEventSend.js +125 -0
  172. package/api/tagalys/tagalysCollectionGet.js +100 -0
  173. package/api/tagalys/tagalysPopularSearchesGet.js +60 -0
  174. package/api/tagalys/tagalysRecommendationGet.js +109 -0
  175. package/api/tagalys/tagalysSearch.js +15 -89
  176. package/api/tagalys/tagalysSearchSuggestionsGet.js +76 -0
  177. package/package.json +2 -1
  178. 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
- return sortExampleFiles(await collectMineralExampleFiles(context.mineralApiDirectory));
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 templateLabel = path.relative(mineralRoot, selectedTemplate);
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
+ */