webflow-api 0.8.1 → 1.0.1
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/README.md +222 -17
- package/dist/ResponseWrapper.js +128 -197
- package/dist/Webflow.js +328 -466
- package/dist/WebflowClient.js +115 -0
- package/dist/index.js +8 -2
- package/index.d.ts +87 -50
- package/package.json +25 -27
- package/src/ResponseWrapper.js +25 -28
- package/src/Webflow.js +193 -234
- package/src/WebflowClient.js +98 -0
- package/src/index.js +3 -2
- package/yarn.lock +2056 -1933
- package/dist/WebflowError.js +0 -54
- package/dist/utils.js +0 -29
- package/src/WebflowError.js +0 -5
- package/src/utils.js +0 -13
package/src/Webflow.js
CHANGED
|
@@ -1,342 +1,301 @@
|
|
|
1
|
-
import
|
|
2
|
-
import qs from "qs";
|
|
3
|
-
|
|
4
|
-
import { isObjectEmpty } from "./utils";
|
|
1
|
+
import { WebflowClient, WebflowRequestError } from "./WebflowClient";
|
|
5
2
|
import ResponseWrapper from "./ResponseWrapper";
|
|
6
|
-
import WebflowError, { buildRequiredArgError } from "./WebflowError";
|
|
7
|
-
|
|
8
|
-
const DEFAULT_ENDPOINT = "https://api.webflow.com";
|
|
9
|
-
|
|
10
|
-
const buildMeta = (res) => {
|
|
11
|
-
if (!res || !res.headers) {
|
|
12
|
-
return {};
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
return {
|
|
16
|
-
rateLimit: {
|
|
17
|
-
limit: parseInt(res.headers.get("x-ratelimit-limit"), 10),
|
|
18
|
-
remaining: parseInt(res.headers.get("x-ratelimit-remaining"), 10),
|
|
19
|
-
},
|
|
20
|
-
};
|
|
21
|
-
};
|
|
22
|
-
|
|
23
|
-
const responseHandler = (res) =>
|
|
24
|
-
res
|
|
25
|
-
.json()
|
|
26
|
-
.catch((err) =>
|
|
27
|
-
// Catch unexpected server errors where json isn't sent and rewrite
|
|
28
|
-
// with proper class (WebflowError)
|
|
29
|
-
Promise.reject(new WebflowError(err))
|
|
30
|
-
)
|
|
31
|
-
.then((body) => {
|
|
32
|
-
if (res.status >= 400) {
|
|
33
|
-
const errOpts = {
|
|
34
|
-
code: body.code,
|
|
35
|
-
msg: body.msg,
|
|
36
|
-
_meta: buildMeta(res),
|
|
37
|
-
};
|
|
38
|
-
|
|
39
|
-
if (body.problems && body.problems.length > 0) {
|
|
40
|
-
errOpts.problems = body.problems;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
const errMsg = body && body.err ? body.err : "Unknown error occured";
|
|
44
|
-
const err = new WebflowError(errMsg);
|
|
45
|
-
|
|
46
|
-
return Promise.reject(Object.assign(err, errOpts));
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
body._meta = buildMeta(res); // eslint-disable-line no-param-reassign
|
|
50
|
-
|
|
51
|
-
return body;
|
|
52
|
-
});
|
|
53
|
-
|
|
54
|
-
export default class Webflow {
|
|
55
|
-
constructor({ endpoint = DEFAULT_ENDPOINT, token, version = "1.0.0" } = {}) {
|
|
56
|
-
if (!token) throw buildRequiredArgError("token");
|
|
57
3
|
|
|
4
|
+
export { WebflowRequestError };
|
|
5
|
+
export class WebflowArgumentError extends Error {
|
|
6
|
+
constructor(name) {
|
|
7
|
+
super(`Argument '${name}' is required but was not present`);
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
export class Webflow {
|
|
11
|
+
constructor(options = {}) {
|
|
12
|
+
this.client = new WebflowClient(options);
|
|
58
13
|
this.responseWrapper = new ResponseWrapper(this);
|
|
59
|
-
|
|
60
|
-
this.endpoint = endpoint;
|
|
61
|
-
this.token = token;
|
|
62
|
-
|
|
63
|
-
this.headers = {
|
|
64
|
-
Accept: "application/json",
|
|
65
|
-
Authorization: `Bearer ${token}`,
|
|
66
|
-
"accept-version": version,
|
|
67
|
-
"Content-Type": "application/json",
|
|
68
|
-
};
|
|
69
|
-
|
|
70
|
-
this.authenticatedFetch = (method, path, data, query) => {
|
|
71
|
-
const queryString =
|
|
72
|
-
query && !isObjectEmpty(query) ? `?${qs.stringify(query)}` : "";
|
|
73
|
-
|
|
74
|
-
const uri = `${this.endpoint}${path}${queryString}`;
|
|
75
|
-
const opts = {
|
|
76
|
-
method,
|
|
77
|
-
headers: this.headers,
|
|
78
|
-
mode: "cors",
|
|
79
|
-
};
|
|
80
|
-
|
|
81
|
-
if (data) {
|
|
82
|
-
opts.body = JSON.stringify(data);
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
return fetch(uri, opts).then(responseHandler);
|
|
86
|
-
};
|
|
87
14
|
}
|
|
88
15
|
|
|
89
|
-
|
|
16
|
+
set token(value) {
|
|
17
|
+
this.client.token = value;
|
|
18
|
+
}
|
|
19
|
+
get token() {
|
|
20
|
+
return this.client.token;
|
|
21
|
+
}
|
|
90
22
|
|
|
91
23
|
get(path, query = {}) {
|
|
92
|
-
return this.
|
|
24
|
+
return this.client.get(path, query);
|
|
93
25
|
}
|
|
94
26
|
|
|
95
27
|
post(path, data, query = {}) {
|
|
96
|
-
return this.
|
|
28
|
+
return this.client.post(path, data, query);
|
|
97
29
|
}
|
|
98
30
|
|
|
99
31
|
put(path, data, query = {}) {
|
|
100
|
-
return this.
|
|
32
|
+
return this.client.put(path, data, query);
|
|
101
33
|
}
|
|
102
34
|
|
|
103
35
|
patch(path, data, query = {}) {
|
|
104
|
-
return this.
|
|
36
|
+
return this.client.patch(path, data, query);
|
|
105
37
|
}
|
|
106
38
|
|
|
107
39
|
delete(path, data, query = {}) {
|
|
108
|
-
return this.
|
|
40
|
+
return this.client.delete(path, data, query);
|
|
109
41
|
}
|
|
110
42
|
|
|
111
43
|
// Meta
|
|
44
|
+
info() {
|
|
45
|
+
return this.get("/info");
|
|
46
|
+
}
|
|
112
47
|
|
|
113
|
-
|
|
114
|
-
return this.get("/
|
|
48
|
+
installer() {
|
|
49
|
+
return this.get("/user");
|
|
115
50
|
}
|
|
116
51
|
|
|
117
52
|
// Sites
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
return
|
|
121
|
-
sites.map((site) => this.responseWrapper.site(site))
|
|
122
|
-
);
|
|
53
|
+
async sites(query = {}) {
|
|
54
|
+
const sites = await this.get("/sites", query);
|
|
55
|
+
return sites.map((site) => this.responseWrapper.site(site));
|
|
123
56
|
}
|
|
124
57
|
|
|
125
|
-
site({ siteId }, query = {}) {
|
|
126
|
-
if (!siteId)
|
|
58
|
+
async site({ siteId }, query = {}) {
|
|
59
|
+
if (!siteId) throw new WebflowArgumentError("siteId");
|
|
127
60
|
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
);
|
|
61
|
+
const site = await this.get(`/sites/${siteId}`, query);
|
|
62
|
+
return this.responseWrapper.site(site);
|
|
131
63
|
}
|
|
132
64
|
|
|
133
65
|
publishSite({ siteId, domains }) {
|
|
134
|
-
if (!siteId)
|
|
135
|
-
if (!domains)
|
|
66
|
+
if (!siteId) throw new WebflowArgumentError("siteId");
|
|
67
|
+
if (!domains) throw new WebflowArgumentError("domains");
|
|
136
68
|
|
|
137
69
|
return this.post(`/sites/${siteId}/publish`, { domains });
|
|
138
70
|
}
|
|
139
71
|
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
domains({ siteId }) {
|
|
143
|
-
if (!siteId) return Promise.reject(buildRequiredArgError("siteId"));
|
|
72
|
+
async domains({ siteId }) {
|
|
73
|
+
if (!siteId) throw new WebflowArgumentError("siteId");
|
|
144
74
|
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
);
|
|
75
|
+
const domains = await this.client.get(`/sites/${siteId}/domains`);
|
|
76
|
+
return domains.map((domain) => this.responseWrapper.domain(domain, siteId));
|
|
148
77
|
}
|
|
149
78
|
|
|
150
79
|
// Collections
|
|
80
|
+
async collections({ siteId }, query = {}) {
|
|
81
|
+
if (!siteId) throw new WebflowArgumentError("siteId");
|
|
151
82
|
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
return this.get(`/sites/${siteId}/collections`, query).then((collections) =>
|
|
156
|
-
collections.map((collection) =>
|
|
157
|
-
this.responseWrapper.collection(collection)
|
|
158
|
-
)
|
|
83
|
+
const collections = await this.get(`/sites/${siteId}/collections`, query);
|
|
84
|
+
return collections.map((collection) =>
|
|
85
|
+
this.responseWrapper.collection(collection)
|
|
159
86
|
);
|
|
160
87
|
}
|
|
161
88
|
|
|
162
|
-
collection({ collectionId }, query = {}) {
|
|
163
|
-
if (!collectionId)
|
|
164
|
-
return Promise.reject(buildRequiredArgError("collectionId"));
|
|
89
|
+
async collection({ collectionId }, query = {}) {
|
|
90
|
+
if (!collectionId) throw new WebflowArgumentError("collectionId");
|
|
165
91
|
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
);
|
|
92
|
+
const uri = `/collections/${collectionId}`;
|
|
93
|
+
const collection = await this.client.get(uri, query);
|
|
94
|
+
return this.responseWrapper.collection(collection);
|
|
169
95
|
}
|
|
170
96
|
|
|
171
97
|
// Items
|
|
98
|
+
async items({ collectionId }, query = {}) {
|
|
99
|
+
if (!collectionId) throw new WebflowArgumentError("collectionId");
|
|
172
100
|
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
return Promise.reject(buildRequiredArgError("collectionId"));
|
|
101
|
+
const uri = `/collections/${collectionId}/items`;
|
|
102
|
+
const res = await this.client.get(uri, query);
|
|
176
103
|
|
|
177
|
-
return
|
|
178
|
-
|
|
179
|
-
...res,
|
|
104
|
+
return {
|
|
105
|
+
...res,
|
|
180
106
|
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
);
|
|
107
|
+
items: res.items.map((item) =>
|
|
108
|
+
this.responseWrapper.item(item, collectionId)
|
|
109
|
+
),
|
|
110
|
+
};
|
|
186
111
|
}
|
|
187
112
|
|
|
188
|
-
item({ collectionId, itemId }, query = {}) {
|
|
189
|
-
if (!collectionId)
|
|
190
|
-
|
|
191
|
-
if (!itemId) return Promise.reject(buildRequiredArgError("itemId"));
|
|
113
|
+
async item({ collectionId, itemId }, query = {}) {
|
|
114
|
+
if (!collectionId) throw new WebflowArgumentError("collectionId");
|
|
115
|
+
if (!itemId) throw new WebflowArgumentError("itemId");
|
|
192
116
|
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
);
|
|
117
|
+
const uri = `/collections/${collectionId}/items/${itemId}`;
|
|
118
|
+
const { items } = await this.client.get(uri, query);
|
|
119
|
+
return this.responseWrapper.item(items[0], collectionId);
|
|
196
120
|
}
|
|
197
121
|
|
|
198
|
-
createItem({ collectionId, ...data }, query = {}) {
|
|
199
|
-
if (!collectionId)
|
|
200
|
-
return Promise.reject(buildRequiredArgError("collectionId"));
|
|
122
|
+
async createItem({ collectionId, ...data }, query = {}) {
|
|
123
|
+
if (!collectionId) throw new WebflowArgumentError("collectionId");
|
|
201
124
|
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
);
|
|
125
|
+
const uri = `/collections/${collectionId}/items`;
|
|
126
|
+
const item = await this.post(uri, data, query);
|
|
127
|
+
return this.responseWrapper.item(item, collectionId);
|
|
205
128
|
}
|
|
206
129
|
|
|
207
130
|
updateItem({ collectionId, itemId, ...data }, query = {}) {
|
|
208
|
-
if (!collectionId)
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
return this.put(
|
|
213
|
-
`/collections/${collectionId}/items/${itemId}`,
|
|
214
|
-
data,
|
|
215
|
-
query
|
|
216
|
-
);
|
|
131
|
+
if (!collectionId) throw new WebflowArgumentError("collectionId");
|
|
132
|
+
if (!itemId) throw new WebflowArgumentError("itemId");
|
|
133
|
+
|
|
134
|
+
const uri = `/collections/${collectionId}/items/${itemId}`;
|
|
135
|
+
return this.put(uri, data, query);
|
|
217
136
|
}
|
|
218
137
|
|
|
219
138
|
removeItem({ collectionId, itemId }, query = {}) {
|
|
220
|
-
if (!collectionId)
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
return this.delete(
|
|
225
|
-
`/collections/${collectionId}/items/${itemId}`,
|
|
226
|
-
null,
|
|
227
|
-
query
|
|
228
|
-
);
|
|
139
|
+
if (!collectionId) throw new WebflowArgumentError("collectionId");
|
|
140
|
+
if (!itemId) throw new WebflowArgumentError("itemId");
|
|
141
|
+
|
|
142
|
+
const uri = `/collections/${collectionId}/items/${itemId}`;
|
|
143
|
+
return this.delete(uri, null, query);
|
|
229
144
|
}
|
|
230
145
|
|
|
231
146
|
patchItem({ collectionId, itemId, ...data }, query = {}) {
|
|
232
|
-
if (!collectionId)
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
return this.patch(
|
|
237
|
-
`/collections/${collectionId}/items/${itemId}`,
|
|
238
|
-
data,
|
|
239
|
-
query
|
|
240
|
-
);
|
|
147
|
+
if (!collectionId) throw new WebflowArgumentError("collectionId");
|
|
148
|
+
if (!itemId) throw new WebflowArgumentError("itemId");
|
|
149
|
+
|
|
150
|
+
const uri = `/collections/${collectionId}/items/${itemId}`;
|
|
151
|
+
return this.patch(uri, data, query);
|
|
241
152
|
}
|
|
242
153
|
|
|
243
154
|
deleteItems({ collectionId, itemIds, ...data }, query = {}) {
|
|
244
|
-
if (!collectionId)
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
return this.delete(
|
|
249
|
-
`/collections/${collectionId}/items`,
|
|
250
|
-
{ ...data, itemIds },
|
|
251
|
-
query
|
|
252
|
-
);
|
|
155
|
+
if (!collectionId) throw new WebflowArgumentError("collectionId");
|
|
156
|
+
if (!itemIds) throw new WebflowArgumentError("itemIds");
|
|
157
|
+
|
|
158
|
+
const uri = `/collections/${collectionId}/items`;
|
|
159
|
+
return this.delete(uri, { ...data, itemIds }, query);
|
|
253
160
|
}
|
|
254
161
|
|
|
255
162
|
publishItems({ collectionId, itemIds, ...data }, query = {}) {
|
|
256
|
-
if (!collectionId)
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
return this.put(
|
|
261
|
-
`/collections/${collectionId}/items/publish`,
|
|
262
|
-
{ ...data, itemIds },
|
|
263
|
-
query
|
|
264
|
-
);
|
|
163
|
+
if (!collectionId) throw new WebflowArgumentError("collectionId");
|
|
164
|
+
if (!itemIds) throw new WebflowArgumentError("itemIds");
|
|
165
|
+
|
|
166
|
+
const uri = `/collections/${collectionId}/items/publish`;
|
|
167
|
+
return this.put(uri, { ...data, itemIds }, query);
|
|
265
168
|
}
|
|
266
169
|
|
|
267
170
|
// Users
|
|
171
|
+
async users({ siteId }, query = {}) {
|
|
172
|
+
if (!siteId) throw new WebflowArgumentError("siteId");
|
|
268
173
|
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
);
|
|
174
|
+
const res = await this.get(`/sites/${siteId}/users`, query);
|
|
175
|
+
return {
|
|
176
|
+
...res,
|
|
177
|
+
users: res.users.map((user) => this.responseWrapper.user(user, siteId)),
|
|
178
|
+
};
|
|
275
179
|
}
|
|
276
180
|
|
|
277
|
-
user({ siteId, userId }, query = {}) {
|
|
278
|
-
if (!siteId)
|
|
279
|
-
if (!userId)
|
|
181
|
+
async user({ siteId, userId }, query = {}) {
|
|
182
|
+
if (!siteId) throw new WebflowArgumentError("siteId");
|
|
183
|
+
if (!userId) throw new WebflowArgumentError("userId");
|
|
280
184
|
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
);
|
|
185
|
+
const uri = `/sites/${siteId}/users/${userId}`;
|
|
186
|
+
const user = await this.get(uri, query);
|
|
187
|
+
return this.responseWrapper.user(user, siteId);
|
|
284
188
|
}
|
|
285
189
|
|
|
286
|
-
updateUser({ siteId, userId, ...data }, query = {}) {
|
|
287
|
-
if (!siteId)
|
|
288
|
-
if (!userId)
|
|
190
|
+
async updateUser({ siteId, userId, ...data }, query = {}) {
|
|
191
|
+
if (!siteId) throw new WebflowArgumentError("siteId");
|
|
192
|
+
if (!userId) throw new WebflowArgumentError("userId");
|
|
289
193
|
|
|
290
|
-
|
|
194
|
+
const uri = `/sites/${siteId}/users/${userId}`;
|
|
195
|
+
const user = await this.patch(uri, data, query);
|
|
196
|
+
return this.responseWrapper.user(user, siteId);
|
|
291
197
|
}
|
|
292
198
|
|
|
293
|
-
inviteUser({ siteId, email }, query = {}) {
|
|
294
|
-
if (!siteId)
|
|
295
|
-
if (!email)
|
|
199
|
+
async inviteUser({ siteId, email }, query = {}) {
|
|
200
|
+
if (!siteId) throw new WebflowArgumentError("siteId");
|
|
201
|
+
if (!email) throw new WebflowArgumentError("email");
|
|
296
202
|
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
);
|
|
203
|
+
const uri = `/sites/${siteId}/users/invite`;
|
|
204
|
+
const user = await this.post(uri, { email }, query);
|
|
205
|
+
return this.responseWrapper.user(user, siteId);
|
|
300
206
|
}
|
|
301
207
|
|
|
302
208
|
removeUser({ siteId, userId }, query = {}) {
|
|
303
|
-
if (!siteId)
|
|
304
|
-
if (!userId)
|
|
209
|
+
if (!siteId) throw new WebflowArgumentError("siteId");
|
|
210
|
+
if (!userId) throw new WebflowArgumentError("userId");
|
|
305
211
|
|
|
306
212
|
return this.delete(`/sites/${siteId}/users/${userId}`, null, query);
|
|
307
213
|
}
|
|
308
214
|
|
|
309
215
|
// Webhooks
|
|
216
|
+
async webhooks({ siteId }, query = {}) {
|
|
217
|
+
if (!siteId) throw new WebflowArgumentError("siteId");
|
|
310
218
|
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
webhooks.map((webhook) => this.responseWrapper.webhook(webhook, siteId))
|
|
219
|
+
const uri = `/sites/${siteId}/webhooks`;
|
|
220
|
+
const webhooks = await this.client.get(uri, query);
|
|
221
|
+
return webhooks.map((webhook) =>
|
|
222
|
+
this.responseWrapper.webhook(webhook, siteId)
|
|
316
223
|
);
|
|
317
224
|
}
|
|
318
225
|
|
|
319
|
-
webhook({ siteId, webhookId }, query = {}) {
|
|
320
|
-
if (!siteId)
|
|
321
|
-
if (!webhookId)
|
|
226
|
+
async webhook({ siteId, webhookId }, query = {}) {
|
|
227
|
+
if (!siteId) throw new WebflowArgumentError("siteId");
|
|
228
|
+
if (!webhookId) throw new WebflowArgumentError("webhookId");
|
|
322
229
|
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
);
|
|
230
|
+
const uri = `/sites/${siteId}/webhooks/${webhookId}`;
|
|
231
|
+
const webhook = await this.client.get(uri, query);
|
|
232
|
+
return this.responseWrapper.webhook(webhook, siteId);
|
|
326
233
|
}
|
|
327
234
|
|
|
328
|
-
createWebhook({ siteId, ...data }, query = {}) {
|
|
329
|
-
if (!siteId)
|
|
235
|
+
async createWebhook({ siteId, triggerType, ...data }, query = {}) {
|
|
236
|
+
if (!siteId) throw new WebflowArgumentError("siteId");
|
|
237
|
+
if (!triggerType) throw new WebflowArgumentError("triggerType");
|
|
330
238
|
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
);
|
|
239
|
+
const uri = `/sites/${siteId}/webhooks`;
|
|
240
|
+
const webhook = { ...data, triggerType };
|
|
241
|
+
const createdWebhook = await this.client.post(uri, webhook, query);
|
|
242
|
+
return this.responseWrapper.webhook(createdWebhook, siteId);
|
|
334
243
|
}
|
|
335
244
|
|
|
336
245
|
removeWebhook({ siteId, webhookId }, query = {}) {
|
|
337
|
-
if (!siteId)
|
|
338
|
-
if (!webhookId)
|
|
246
|
+
if (!siteId) throw new WebflowArgumentError("siteId");
|
|
247
|
+
if (!webhookId) throw new WebflowArgumentError("webhookId");
|
|
339
248
|
|
|
340
249
|
return this.delete(`/sites/${siteId}/webhooks/${webhookId}`, null, query);
|
|
341
250
|
}
|
|
251
|
+
|
|
252
|
+
// OAuth
|
|
253
|
+
authorizeUrl({
|
|
254
|
+
client_id,
|
|
255
|
+
redirect_uri,
|
|
256
|
+
state,
|
|
257
|
+
scope,
|
|
258
|
+
response_type = "code",
|
|
259
|
+
}) {
|
|
260
|
+
if (!client_id) throw new WebflowArgumentError("clientId");
|
|
261
|
+
|
|
262
|
+
const query = new URLSearchParams({ response_type, client_id });
|
|
263
|
+
|
|
264
|
+
if (redirect_uri) query.set("redirect_uri", redirect_uri);
|
|
265
|
+
if (state) query.set("state", state);
|
|
266
|
+
if (scope) query.set("scope", scope);
|
|
267
|
+
|
|
268
|
+
return `https://${this.host}/oauth/authorize?${query}`;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
accessToken({
|
|
272
|
+
client_id,
|
|
273
|
+
client_secret,
|
|
274
|
+
code,
|
|
275
|
+
redirect_uri,
|
|
276
|
+
grant_type = "authorization_code",
|
|
277
|
+
}) {
|
|
278
|
+
if (!client_id) throw new WebflowArgumentError("client_id");
|
|
279
|
+
if (!client_secret) throw new WebflowArgumentError("client_secret");
|
|
280
|
+
if (!code) throw new WebflowArgumentError("code");
|
|
281
|
+
|
|
282
|
+
return this.post("/oauth/access_token", {
|
|
283
|
+
client_id,
|
|
284
|
+
client_secret,
|
|
285
|
+
code,
|
|
286
|
+
redirect_uri,
|
|
287
|
+
grant_type,
|
|
288
|
+
});
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
revokeToken({ client_id, client_secret, access_token }) {
|
|
292
|
+
if (!client_id) throw new WebflowArgumentError("client_id");
|
|
293
|
+
if (!client_secret) throw new WebflowArgumentError("client_secret");
|
|
294
|
+
if (!access_token) throw new WebflowArgumentError("access_token");
|
|
295
|
+
|
|
296
|
+
const uri = "/oauth/revoke_authorization";
|
|
297
|
+
return this.post(uri, { client_id, client_secret, access_token });
|
|
298
|
+
}
|
|
342
299
|
}
|
|
300
|
+
|
|
301
|
+
export default Webflow;
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import fetch from "isomorphic-fetch";
|
|
2
|
+
|
|
3
|
+
const DEFAULT_HOST = "webflow.com";
|
|
4
|
+
const USER_AGENT = "Webflow Javascript SDK / 1.0";
|
|
5
|
+
|
|
6
|
+
export class WebflowRequestError extends Error {
|
|
7
|
+
constructor(error) {
|
|
8
|
+
super(error.err ? error.err : "Unknown error occured");
|
|
9
|
+
Object.assign(this, error);
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export class WebflowClient {
|
|
14
|
+
constructor({ host, token, version, headers, mode } = {}) {
|
|
15
|
+
this.host = host || DEFAULT_HOST;
|
|
16
|
+
this.headers = headers || {};
|
|
17
|
+
this.version = version;
|
|
18
|
+
this.token = token;
|
|
19
|
+
this.mode = mode;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
getUri(path, query = {}) {
|
|
23
|
+
const hasQuery = Object.keys(query).length > 0;
|
|
24
|
+
const queryString = hasQuery ? `?${new URLSearchParams(query)}` : "";
|
|
25
|
+
return `https://api.${this.host}${path}${queryString}`;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
getHeaders() {
|
|
29
|
+
const { version, token } = this;
|
|
30
|
+
|
|
31
|
+
const headers = {
|
|
32
|
+
"Content-Type": "application/json",
|
|
33
|
+
Accept: "application/json",
|
|
34
|
+
"User-Agent": USER_AGENT,
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
// set authorization header if token is set
|
|
38
|
+
if (token) headers.Authorization = `Bearer ${token}`;
|
|
39
|
+
|
|
40
|
+
// set the API version
|
|
41
|
+
if (version) headers["accept-version"] = version;
|
|
42
|
+
|
|
43
|
+
// merge headers with user headers;
|
|
44
|
+
return { ...headers, ...this.headers };
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
async parseBody(res) {
|
|
48
|
+
const body = await res.json();
|
|
49
|
+
|
|
50
|
+
// append ratelimit meta data to response
|
|
51
|
+
if (res.headers) {
|
|
52
|
+
const limit = parseInt(res.headers.get("x-ratelimit-limit"), 10);
|
|
53
|
+
const remaining = parseInt(res.headers.get("x-ratelimit-remaining"), 10);
|
|
54
|
+
body._meta = { rateLimit: { limit, remaining } };
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// webflow error
|
|
58
|
+
if (body.err) throw new WebflowRequestError(body);
|
|
59
|
+
|
|
60
|
+
return body;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
fetch(method, path, data, query) {
|
|
64
|
+
// build uri
|
|
65
|
+
const uri = this.getUri(path, query);
|
|
66
|
+
|
|
67
|
+
// build request options
|
|
68
|
+
const headers = this.getHeaders();
|
|
69
|
+
const opts = { method, headers, mode: this.mode };
|
|
70
|
+
if (data) opts.body = JSON.stringify(data);
|
|
71
|
+
|
|
72
|
+
// call fetch and wrap response
|
|
73
|
+
return fetch(uri, opts).then(this.parseBody.bind(this));
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// Generic HTTP request handlers
|
|
77
|
+
get(path, query = {}) {
|
|
78
|
+
return this.fetch("GET", path, null, query);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
post(path, data, query = {}) {
|
|
82
|
+
return this.fetch("POST", path, data, query);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
put(path, data, query = {}) {
|
|
86
|
+
return this.fetch("PUT", path, data, query);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
patch(path, data, query = {}) {
|
|
90
|
+
return this.fetch("PATCH", path, data, query);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
delete(path, data, query = {}) {
|
|
94
|
+
return this.fetch("DELETE", path, data, query);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
export default WebflowClient;
|
package/src/index.js
CHANGED
|
@@ -1,2 +1,3 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
import { Webflow } from "./Webflow";
|
|
2
|
+
|
|
3
|
+
export default Webflow;
|