@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
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
// https://www.dropbox.com/developers/documentation/http/documentation#users-get_space_usage
|
|
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 dropboxSpaceUsageGet = 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_space_usage',
|
|
29
|
+
headers: {
|
|
30
|
+
'Content-Type': 'application/json',
|
|
31
|
+
},
|
|
32
|
+
body: 'null',
|
|
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 funcApiConfig = {
|
|
49
|
+
argsWarden,
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
module.exports = {
|
|
53
|
+
dropboxSpaceUsageGet,
|
|
54
|
+
funcApiConfig,
|
|
55
|
+
};
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
// https://www.dropbox.com/developers/documentation/http/documentation#files-get_temporary_link
|
|
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 dropboxTemporaryLinkGetSingle = async (
|
|
13
|
+
credsPayload,
|
|
14
|
+
path,
|
|
15
|
+
{
|
|
16
|
+
fetchClient = dropboxClient,
|
|
17
|
+
} = {},
|
|
18
|
+
) => {
|
|
19
|
+
const response = await fetchClient.fetch({
|
|
20
|
+
context: { credsPayload },
|
|
21
|
+
requestPayload: {
|
|
22
|
+
method: 'post',
|
|
23
|
+
url: '/files/get_temporary_link',
|
|
24
|
+
body: { path },
|
|
25
|
+
},
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
const { ok, data, error } = response;
|
|
29
|
+
if (!ok) {
|
|
30
|
+
logDeep({ error });
|
|
31
|
+
return { ok: false, error };
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
return {
|
|
35
|
+
ok: true,
|
|
36
|
+
data,
|
|
37
|
+
};
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
const dropboxTemporaryLinkGet = async (
|
|
41
|
+
credsPayload,
|
|
42
|
+
path,
|
|
43
|
+
{
|
|
44
|
+
queueRunOptions,
|
|
45
|
+
fetchClient,
|
|
46
|
+
} = {},
|
|
47
|
+
) => {
|
|
48
|
+
const rejectResponse = await argsWarden.responseIfRejectingArgs({
|
|
49
|
+
credsPayload,
|
|
50
|
+
path,
|
|
51
|
+
});
|
|
52
|
+
if (rejectResponse) {
|
|
53
|
+
return rejectResponse;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
return actionSingleOrMultiple(
|
|
57
|
+
path,
|
|
58
|
+
dropboxTemporaryLinkGetSingle,
|
|
59
|
+
(pathItem) => ({
|
|
60
|
+
args: [credsPayload, pathItem, { fetchClient }],
|
|
61
|
+
}),
|
|
62
|
+
{
|
|
63
|
+
...(queueRunOptions ? { queueRunOptions } : {}),
|
|
64
|
+
},
|
|
65
|
+
);
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
const funcApiConfig = {
|
|
69
|
+
argsWarden,
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
module.exports = {
|
|
73
|
+
dropboxTemporaryLinkGet,
|
|
74
|
+
funcApiConfig,
|
|
75
|
+
};
|
|
File without changes
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# Fast Simon
|
|
2
|
+
|
|
3
|
+
- [API Documentation](https://docs.fastsimon.com/api/api-doc.html)
|
|
4
|
+
- [Serving API – full text search](https://docs.fastsimon.com/api/api-doc.html#tag/Serving-API/operation/fulltextProducts)
|
|
5
|
+
- [SDK docs](https://docs.fastsimon.com/sdk)
|
|
6
|
+
|
|
7
|
+
Public Serving API over HTTPS at `https://api.fastsimon.com`. Search and collection reads are unauthenticated beyond the store identifiers: every request carries `UUID` and `store_id` as query parameters (values from the Fast Simon dashboard after install). Admin / merchandising endpoints additionally require an API key and the `X-Site-UUID` / `X-Store-ID` headers.
|
|
8
|
+
|
|
9
|
+
Core serving flow:
|
|
10
|
+
|
|
11
|
+
1. `GET /load` – returns site config including `cdn_cache_key` (required on subsequent product requests).
|
|
12
|
+
2. `GET /full_text_search` – full-text product search with optional facets, sorting, narrowing filters, and pagination (`page_num`).
|
|
13
|
+
|
|
14
|
+
Product results land under `data.items`; facets under `data.facets`. When `facets_required=1` and `data.facets_completed` is false, repeat the request with `facets_required=2` to finish facet computation. JSONP is supported via a `callback` query param; this client uses plain JSON.
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
const BASE_URL = 'https://api.fastsimon.com';
|
|
2
|
+
|
|
3
|
+
// Common sort_by values documented on full_text_search
|
|
4
|
+
const SORT_BY_OPTIONS = [
|
|
5
|
+
'relevency', // spelling as returned by the API docs
|
|
6
|
+
'price_min_to_max',
|
|
7
|
+
'price_max_to_min',
|
|
8
|
+
'creation_date',
|
|
9
|
+
'creation_date_oldest',
|
|
10
|
+
'reviews',
|
|
11
|
+
'a_to_z',
|
|
12
|
+
'z_to_a',
|
|
13
|
+
];
|
|
14
|
+
|
|
15
|
+
module.exports = {
|
|
16
|
+
BASE_URL,
|
|
17
|
+
SORT_BY_OPTIONS,
|
|
18
|
+
};
|
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
// https://docs.fastsimon.com/api/api-doc.html
|
|
2
|
+
|
|
3
|
+
const { BASE_URL } = require('../fastsimon/fastsimon.constants');
|
|
4
|
+
const { resolveCreds } = require('../pipelineSteps');
|
|
5
|
+
const {
|
|
6
|
+
FetchClient,
|
|
7
|
+
fetchClientCommonSteps,
|
|
8
|
+
appendUrlToBase,
|
|
9
|
+
} = require('../utils');
|
|
10
|
+
|
|
11
|
+
const sessionCacheKeyForCredsPayload = (credsPayload) => {
|
|
12
|
+
if (credsPayload?.credsPath) {
|
|
13
|
+
return credsPayload.credsPath;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
return JSON.stringify(credsPayload);
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
// cdn_cache_key is required on product endpoints and is obtained from /load.
|
|
20
|
+
// Cache per creds identity so repeated searches in the same process reuse it.
|
|
21
|
+
const cdnCacheKeyByCredsKey = new Map();
|
|
22
|
+
|
|
23
|
+
const normaliseLoadData = (data) => {
|
|
24
|
+
if (data == null) {
|
|
25
|
+
return {};
|
|
26
|
+
}
|
|
27
|
+
if (typeof data === 'string') {
|
|
28
|
+
try {
|
|
29
|
+
return JSON.parse(data);
|
|
30
|
+
} catch {
|
|
31
|
+
return {};
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
return data;
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
const pickCdnCacheKey = (data) => {
|
|
38
|
+
const body = normaliseLoadData(data);
|
|
39
|
+
return (
|
|
40
|
+
body.cdn_cache_key ??
|
|
41
|
+
body.cdnCacheKey ??
|
|
42
|
+
body.cache_key ??
|
|
43
|
+
body.cacheKey ??
|
|
44
|
+
null
|
|
45
|
+
);
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
const useUrlAndAuthQuery = async (state) => {
|
|
49
|
+
const { requestPayload, context } = state;
|
|
50
|
+
const { creds } = context;
|
|
51
|
+
const {
|
|
52
|
+
UUID,
|
|
53
|
+
STORE_ID,
|
|
54
|
+
} = creds ?? {};
|
|
55
|
+
|
|
56
|
+
if (!UUID || !STORE_ID) {
|
|
57
|
+
return {
|
|
58
|
+
response: {
|
|
59
|
+
ok: false,
|
|
60
|
+
error: {
|
|
61
|
+
code: 'MISSING_FASTSIMON_CREDS',
|
|
62
|
+
message: 'fastsimon creds require UUID and STORE_ID',
|
|
63
|
+
},
|
|
64
|
+
},
|
|
65
|
+
breakChain: true,
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const query = {
|
|
70
|
+
UUID,
|
|
71
|
+
store_id: STORE_ID,
|
|
72
|
+
...(requestPayload.query || {}),
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
// Prefer an explicitly provided cdn_cache_key (e.g. from options),
|
|
76
|
+
// otherwise inject a previously cached one if present.
|
|
77
|
+
const cacheKey = sessionCacheKeyForCredsPayload(context.credsPayload || {});
|
|
78
|
+
if (!query.cdn_cache_key && cdnCacheKeyByCredsKey.has(cacheKey)) {
|
|
79
|
+
query.cdn_cache_key = cdnCacheKeyByCredsKey.get(cacheKey);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const searchParams = new URLSearchParams();
|
|
83
|
+
Object.entries(query).forEach(([key, value]) => {
|
|
84
|
+
if (value === undefined || value === null) {
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
// narrow is documented as a JSON-encoded list of tuples; stringify objects/arrays
|
|
88
|
+
if (typeof value === 'object') {
|
|
89
|
+
searchParams.append(key, JSON.stringify(value));
|
|
90
|
+
} else {
|
|
91
|
+
searchParams.append(key, String(value));
|
|
92
|
+
}
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
const path = requestPayload.url || '';
|
|
96
|
+
const url = `${ appendUrlToBase(BASE_URL, path) }?${ searchParams.toString() }`;
|
|
97
|
+
|
|
98
|
+
return {
|
|
99
|
+
requestPayload: {
|
|
100
|
+
...requestPayload,
|
|
101
|
+
url,
|
|
102
|
+
headers: {
|
|
103
|
+
Accept: 'application/json',
|
|
104
|
+
...requestPayload.headers,
|
|
105
|
+
},
|
|
106
|
+
},
|
|
107
|
+
};
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
const rememberCdnCacheKey = async (state) => {
|
|
111
|
+
const { response, context } = state;
|
|
112
|
+
if (!response?.ok || !response?.data) {
|
|
113
|
+
return {};
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
const cdnCacheKey = pickCdnCacheKey(response.data);
|
|
117
|
+
if (cdnCacheKey == null) {
|
|
118
|
+
return {};
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
const cacheKey = sessionCacheKeyForCredsPayload(context.credsPayload || {});
|
|
122
|
+
cdnCacheKeyByCredsKey.set(cacheKey, cdnCacheKey);
|
|
123
|
+
|
|
124
|
+
return {};
|
|
125
|
+
};
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Fast Simon often returns the body as a JSON string. Parse it, then for
|
|
129
|
+
* product payloads dig `items` into `data` and move everything else to `meta`
|
|
130
|
+
* (total_results, term, facets, page info, uuid, etc.).
|
|
131
|
+
*/
|
|
132
|
+
const normaliseSearchResponse = async (state) => {
|
|
133
|
+
const { response } = state;
|
|
134
|
+
if (!response?.ok || response.data == null) {
|
|
135
|
+
return {};
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
let body = response.data;
|
|
139
|
+
if (typeof body === 'string') {
|
|
140
|
+
try {
|
|
141
|
+
body = JSON.parse(body);
|
|
142
|
+
} catch {
|
|
143
|
+
return {};
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
if (!body || typeof body !== 'object' || Array.isArray(body)) {
|
|
148
|
+
return {
|
|
149
|
+
response: {
|
|
150
|
+
data: body,
|
|
151
|
+
},
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
if (!Object.prototype.hasOwnProperty.call(body, 'items')) {
|
|
156
|
+
return {
|
|
157
|
+
response: {
|
|
158
|
+
data: body,
|
|
159
|
+
},
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
const { items, ...rest } = body;
|
|
164
|
+
|
|
165
|
+
return {
|
|
166
|
+
response: {
|
|
167
|
+
data: items,
|
|
168
|
+
meta: {
|
|
169
|
+
...(response.meta || {}),
|
|
170
|
+
...rest,
|
|
171
|
+
},
|
|
172
|
+
},
|
|
173
|
+
};
|
|
174
|
+
};
|
|
175
|
+
|
|
176
|
+
const fastsimonClient = new FetchClient({
|
|
177
|
+
pipeline: [
|
|
178
|
+
resolveCreds,
|
|
179
|
+
useUrlAndAuthQuery,
|
|
180
|
+
'fetch',
|
|
181
|
+
fetchClientCommonSteps.exitEarlyOnNotOk,
|
|
182
|
+
rememberCdnCacheKey,
|
|
183
|
+
normaliseSearchResponse,
|
|
184
|
+
],
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* Fetch (and cache) the current CDN cache key via GET /load.
|
|
189
|
+
* Safe to call repeatedly; subsequent calls hit the in-memory cache.
|
|
190
|
+
*
|
|
191
|
+
* Some stores' /load payloads omit `cdn_cache_key` even though the OpenAPI
|
|
192
|
+
* marks it required. In that case we fall back to the current Unix epoch
|
|
193
|
+
* (the documented type of the field), which is enough for the search CDN
|
|
194
|
+
* to accept the request.
|
|
195
|
+
*/
|
|
196
|
+
const ensureCdnCacheKey = async (credsPayload, { fetchClient = fastsimonClient } = {}) => {
|
|
197
|
+
const cacheKey = sessionCacheKeyForCredsPayload(credsPayload);
|
|
198
|
+
if (cdnCacheKeyByCredsKey.has(cacheKey)) {
|
|
199
|
+
return {
|
|
200
|
+
ok: true,
|
|
201
|
+
data: { cdn_cache_key: cdnCacheKeyByCredsKey.get(cacheKey) },
|
|
202
|
+
};
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
const response = await fetchClient.fetch({
|
|
206
|
+
requestPayload: {
|
|
207
|
+
method: 'get',
|
|
208
|
+
url: '/load',
|
|
209
|
+
query: {},
|
|
210
|
+
},
|
|
211
|
+
context: {
|
|
212
|
+
credsPayload,
|
|
213
|
+
},
|
|
214
|
+
});
|
|
215
|
+
|
|
216
|
+
if (!response?.ok) {
|
|
217
|
+
return response;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
let cdnCacheKey = pickCdnCacheKey(response.data);
|
|
221
|
+
|
|
222
|
+
if (cdnCacheKey == null) {
|
|
223
|
+
// Live /load responses for some stores return theme/config fields but no
|
|
224
|
+
// cdn_cache_key. The field is documented as a Unix epoch integer — using
|
|
225
|
+
// "now" is a safe cache-busting fallback that the Serving API accepts.
|
|
226
|
+
cdnCacheKey = Math.floor(Date.now() / 1000);
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
cdnCacheKeyByCredsKey.set(cacheKey, cdnCacheKey);
|
|
230
|
+
|
|
231
|
+
return {
|
|
232
|
+
ok: true,
|
|
233
|
+
data: {
|
|
234
|
+
cdn_cache_key: cdnCacheKey,
|
|
235
|
+
// surface whether we synthesised the key, in case callers care
|
|
236
|
+
synthesised: pickCdnCacheKey(response.data) == null,
|
|
237
|
+
},
|
|
238
|
+
};
|
|
239
|
+
};
|
|
240
|
+
|
|
241
|
+
module.exports = {
|
|
242
|
+
fastsimonClient,
|
|
243
|
+
ensureCdnCacheKey,
|
|
244
|
+
// exposed for tests / manual cache control
|
|
245
|
+
cdnCacheKeyByCredsKey,
|
|
246
|
+
};
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
// https://docs.fastsimon.com/api/api-doc.html#tag/Serving-API/operation/fulltextProducts
|
|
2
|
+
|
|
3
|
+
const { credsValidator } = require('../validators');
|
|
4
|
+
const { ArgsWarden } = require('../utils');
|
|
5
|
+
const { fastsimonClient, ensureCdnCacheKey } = require('../fastsimon/fastsimon.utils');
|
|
6
|
+
|
|
7
|
+
const argsWarden = new ArgsWarden([
|
|
8
|
+
['credsPayload', credsValidator],
|
|
9
|
+
['query'],
|
|
10
|
+
]);
|
|
11
|
+
|
|
12
|
+
const fastsimonSearch = async (
|
|
13
|
+
credsPayload,
|
|
14
|
+
query,
|
|
15
|
+
{
|
|
16
|
+
cdnCacheKey,
|
|
17
|
+
facetsRequired,
|
|
18
|
+
sortBy,
|
|
19
|
+
narrow,
|
|
20
|
+
pageNum,
|
|
21
|
+
fetchClient = fastsimonClient,
|
|
22
|
+
} = {},
|
|
23
|
+
) => {
|
|
24
|
+
|
|
25
|
+
const rejectResponse = await argsWarden.responseIfRejectingArgs({
|
|
26
|
+
credsPayload,
|
|
27
|
+
query,
|
|
28
|
+
});
|
|
29
|
+
if (rejectResponse) {
|
|
30
|
+
return rejectResponse;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
let resolvedCdnCacheKey = cdnCacheKey;
|
|
34
|
+
if (!resolvedCdnCacheKey) {
|
|
35
|
+
const loadRes = await ensureCdnCacheKey(credsPayload, { fetchClient });
|
|
36
|
+
if (!loadRes.ok) {
|
|
37
|
+
return loadRes;
|
|
38
|
+
}
|
|
39
|
+
resolvedCdnCacheKey = loadRes.data.cdn_cache_key;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const response = await fetchClient.fetch({
|
|
43
|
+
requestPayload: {
|
|
44
|
+
method: 'get',
|
|
45
|
+
url: '/full_text_search',
|
|
46
|
+
query: {
|
|
47
|
+
q: query,
|
|
48
|
+
cdn_cache_key: resolvedCdnCacheKey,
|
|
49
|
+
...(facetsRequired !== undefined ? { facets_required: facetsRequired } : {}),
|
|
50
|
+
...(sortBy ? { sort_by: sortBy } : {}),
|
|
51
|
+
...(narrow !== undefined ? { narrow } : {}),
|
|
52
|
+
...(pageNum !== undefined ? { page_num: pageNum } : {}),
|
|
53
|
+
},
|
|
54
|
+
},
|
|
55
|
+
context: {
|
|
56
|
+
credsPayload,
|
|
57
|
+
},
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
return response;
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
const funcApiConfig = {
|
|
64
|
+
argsWarden,
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
module.exports = {
|
|
68
|
+
fastsimonSearch,
|
|
69
|
+
funcApiConfig,
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
/*
|
|
73
|
+
curl -X POST "http://localhost:8000/fastsimonSearch" \
|
|
74
|
+
-H "Content-Type: application/json" \
|
|
75
|
+
-d '{
|
|
76
|
+
"credsPayload": { "credsPath": "fastsimon.au" },
|
|
77
|
+
"query": "dress",
|
|
78
|
+
"options": {
|
|
79
|
+
"facetsRequired": 1,
|
|
80
|
+
"pageNum": 1,
|
|
81
|
+
"sortBy": "relevency"
|
|
82
|
+
}
|
|
83
|
+
}'
|
|
84
|
+
*/
|
package/api/figma/docs.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Figma
|
|
2
2
|
|
|
3
|
-
- [Developer documentation](https://
|
|
4
|
-
- [Authentication](https://
|
|
3
|
+
- [Developer documentation](https://developers.figma.com/docs/rest-api/)
|
|
4
|
+
- [Authentication](https://developers.figma.com/docs/rest-api/authentication/)
|
|
5
5
|
|
|
6
|
-
REST JSON at `https://api.figma.com
|
|
6
|
+
REST JSON at `https://api.figma.com` for files, comments, variables, components, styles, folders, dev resources, webhooks, and organization APIs. Personal and plan access tokens use the `X-Figma-Token` header; OAuth 2 access tokens use `Authorization: Bearer`.
|
package/api/figma/figma.utils.js
CHANGED
|
@@ -8,13 +8,24 @@ const {
|
|
|
8
8
|
const useAuthHeaders = async (state) => {
|
|
9
9
|
const { requestPayload, context } = state;
|
|
10
10
|
const { creds } = context;
|
|
11
|
-
const {
|
|
11
|
+
const {
|
|
12
|
+
API_KEY,
|
|
13
|
+
ACCESS_TOKEN,
|
|
14
|
+
} = creds ?? {};
|
|
15
|
+
|
|
16
|
+
const authHeaders = ACCESS_TOKEN
|
|
17
|
+
? {
|
|
18
|
+
Authorization: `Bearer ${ ACCESS_TOKEN }`,
|
|
19
|
+
}
|
|
20
|
+
: {
|
|
21
|
+
'X-Figma-Token': API_KEY,
|
|
22
|
+
};
|
|
12
23
|
|
|
13
24
|
return {
|
|
14
25
|
requestPayload: {
|
|
15
26
|
...requestPayload,
|
|
16
27
|
headers: {
|
|
17
|
-
|
|
28
|
+
...authHeaders,
|
|
18
29
|
...requestPayload.headers,
|
|
19
30
|
},
|
|
20
31
|
},
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
// https://developers.figma.com/docs/rest-api/activity-logs-endpoints/
|
|
2
|
+
|
|
3
|
+
const { ArgsWarden } = require('../utils');
|
|
4
|
+
const { credsValidator } = require('../validators');
|
|
5
|
+
const { figmaClient } = require('../figma/figma.utils');
|
|
6
|
+
|
|
7
|
+
const argsWarden = new ArgsWarden([
|
|
8
|
+
['credsPayload', credsValidator],
|
|
9
|
+
]);
|
|
10
|
+
|
|
11
|
+
const figmaActivityLogsGet = async (
|
|
12
|
+
credsPayload,
|
|
13
|
+
{
|
|
14
|
+
params,
|
|
15
|
+
fetchClient = figmaClient,
|
|
16
|
+
} = {},
|
|
17
|
+
) => {
|
|
18
|
+
const rejectResponse = await argsWarden.responseIfRejectingArgs({
|
|
19
|
+
credsPayload
|
|
20
|
+
});
|
|
21
|
+
if (rejectResponse) {
|
|
22
|
+
return rejectResponse;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
return fetchClient.fetch({
|
|
26
|
+
requestPayload: {
|
|
27
|
+
method: 'get',
|
|
28
|
+
url: `/v1/activity_logs`,
|
|
29
|
+
params,
|
|
30
|
+
},
|
|
31
|
+
context: {
|
|
32
|
+
credsPayload,
|
|
33
|
+
},
|
|
34
|
+
});
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
const funcApiConfig = {
|
|
38
|
+
argsWarden,
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
module.exports = {
|
|
42
|
+
figmaActivityLogsGet,
|
|
43
|
+
funcApiConfig,
|
|
44
|
+
};
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
// https://developers.figma.com/docs/rest-api/ai-usage-endpoints/
|
|
2
|
+
|
|
3
|
+
const { ArgsWarden } = require('../utils');
|
|
4
|
+
const { credsValidator } = require('../validators');
|
|
5
|
+
const { figmaClient } = require('../figma/figma.utils');
|
|
6
|
+
|
|
7
|
+
const argsWarden = new ArgsWarden([
|
|
8
|
+
['credsPayload', credsValidator],
|
|
9
|
+
]);
|
|
10
|
+
|
|
11
|
+
const figmaAiUsageDailyGet = async (
|
|
12
|
+
credsPayload,
|
|
13
|
+
{
|
|
14
|
+
params,
|
|
15
|
+
fetchClient = figmaClient,
|
|
16
|
+
} = {},
|
|
17
|
+
) => {
|
|
18
|
+
const rejectResponse = await argsWarden.responseIfRejectingArgs({
|
|
19
|
+
credsPayload
|
|
20
|
+
});
|
|
21
|
+
if (rejectResponse) {
|
|
22
|
+
return rejectResponse;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
return fetchClient.fetch({
|
|
26
|
+
requestPayload: {
|
|
27
|
+
method: 'get',
|
|
28
|
+
url: `/v1/ai_usage/daily`,
|
|
29
|
+
params,
|
|
30
|
+
},
|
|
31
|
+
context: {
|
|
32
|
+
credsPayload,
|
|
33
|
+
},
|
|
34
|
+
});
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
const funcApiConfig = {
|
|
38
|
+
argsWarden,
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
module.exports = {
|
|
42
|
+
figmaAiUsageDailyGet,
|
|
43
|
+
funcApiConfig,
|
|
44
|
+
};
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
// https://developers.figma.com/docs/rest-api/component-endpoints/
|
|
2
|
+
|
|
3
|
+
const { ArgsWarden } = require('../utils');
|
|
4
|
+
const { credsValidator } = require('../validators');
|
|
5
|
+
const { figmaClient } = require('../figma/figma.utils');
|
|
6
|
+
|
|
7
|
+
const argsWarden = new ArgsWarden([
|
|
8
|
+
['credsPayload', credsValidator],
|
|
9
|
+
['key'],
|
|
10
|
+
]);
|
|
11
|
+
|
|
12
|
+
const figmaComponentGet = async (
|
|
13
|
+
credsPayload,
|
|
14
|
+
key,
|
|
15
|
+
{
|
|
16
|
+
params,
|
|
17
|
+
fetchClient = figmaClient,
|
|
18
|
+
} = {},
|
|
19
|
+
) => {
|
|
20
|
+
const rejectResponse = await argsWarden.responseIfRejectingArgs({
|
|
21
|
+
credsPayload,
|
|
22
|
+
key,
|
|
23
|
+
});
|
|
24
|
+
if (rejectResponse) {
|
|
25
|
+
return rejectResponse;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
return fetchClient.fetch({
|
|
29
|
+
requestPayload: {
|
|
30
|
+
method: 'get',
|
|
31
|
+
url: `/v1/components/${ key }`,
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
},
|
|
35
|
+
context: {
|
|
36
|
+
credsPayload,
|
|
37
|
+
},
|
|
38
|
+
});
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
const funcApiConfig = {
|
|
42
|
+
argsWarden,
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
module.exports = {
|
|
46
|
+
figmaComponentGet,
|
|
47
|
+
funcApiConfig,
|
|
48
|
+
};
|