@foxtware/mineral 0.1.26 → 0.1.28
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 +22 -4
- package/AGENTS.md +17 -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/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/shopifyMetaobjectCreate.js +72 -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 +82 -0
- package/api/tagalys/tagalysSearchSuggestionsGet.js +76 -0
- package/package.json +2 -1
package/.creds.yml.sample
CHANGED
|
@@ -94,6 +94,8 @@ telnyx:
|
|
|
94
94
|
|
|
95
95
|
figma:
|
|
96
96
|
API_KEY: figd___________________________
|
|
97
|
+
# Or use ACCESS_TOKEN for an OAuth 2 bearer token
|
|
98
|
+
ACCESS_TOKEN: __________________________
|
|
97
99
|
|
|
98
100
|
pipe17:
|
|
99
101
|
API_KEY: _______________________________
|
|
@@ -115,13 +117,29 @@ google:
|
|
|
115
117
|
|
|
116
118
|
tagalys:
|
|
117
119
|
store:
|
|
118
|
-
BASE_URL: ____________________________
|
|
119
|
-
CLIENT_CODE: _________________________
|
|
120
|
-
API_KEY: _____________________________
|
|
121
|
-
|
|
120
|
+
BASE_URL: ____________________________
|
|
121
|
+
CLIENT_CODE: _________________________ # unused but surfaced in dashboard
|
|
122
|
+
API_KEY: _____________________________ # unused but surfaced in dashboard
|
|
123
|
+
STOREFRONT_API_KEY: __________________
|
|
124
|
+
STORE_HANDLE: ________________________
|
|
122
125
|
|
|
123
126
|
tableau:
|
|
124
127
|
PAT_NAME: ______________________________
|
|
125
128
|
PAT_SECRET: ____________________________
|
|
126
129
|
SERVER_URL: ____________________________
|
|
127
130
|
SITE_CONTENT_URL: ______________________
|
|
131
|
+
|
|
132
|
+
salesforce:
|
|
133
|
+
# Option A — pre-issued token
|
|
134
|
+
ACCESS_TOKEN: __________________________
|
|
135
|
+
INSTANCE_URL: https://________.my.salesforce.com
|
|
136
|
+
|
|
137
|
+
# Option B — client credentials (if ACCESS_TOKEN missing)
|
|
138
|
+
CLIENT_ID: _____________________________
|
|
139
|
+
CLIENT_SECRET: _________________________
|
|
140
|
+
LOGIN_URL: https://login.salesforce.com # or My Domain / test.salesforce.com
|
|
141
|
+
|
|
142
|
+
fastsimon:
|
|
143
|
+
store: # instance name of your choice
|
|
144
|
+
UUID: _______________________________ # Dashboard → Settings
|
|
145
|
+
STORE_ID: ___________________________ # Dashboard → Settings
|
package/AGENTS.md
CHANGED
|
@@ -25,3 +25,20 @@ 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
|
+
|
|
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
|
+
};
|
|
@@ -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 figmaComponentSetGet = 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/component_sets/${ key }`,
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
},
|
|
35
|
+
context: {
|
|
36
|
+
credsPayload,
|
|
37
|
+
},
|
|
38
|
+
});
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
const funcApiConfig = {
|
|
42
|
+
argsWarden,
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
module.exports = {
|
|
46
|
+
figmaComponentSetGet,
|
|
47
|
+
funcApiConfig,
|
|
48
|
+
};
|