webflow-api 0.5.4
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/LICENSE +21 -0
- package/README.md +44 -0
- package/dist/ResponseWrapper.js +140 -0
- package/dist/Webflow.js +432 -0
- package/dist/WebflowError.js +35 -0
- package/dist/index.js +4 -0
- package/dist/utils.js +24 -0
- package/package.json +54 -0
- package/src/ResponseWrapper.js +72 -0
- package/src/Webflow.js +255 -0
- package/src/WebflowError.js +6 -0
- package/src/index.js +2 -0
- package/src/utils.js +13 -0
- package/yarn.lock +3669 -0
package/dist/utils.js
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
var isObjectEmpty = exports.isObjectEmpty = function isObjectEmpty(obj) {
|
|
7
|
+
return Object.keys(obj).length === 0;
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
var pick = exports.pick = function pick(obj) {
|
|
11
|
+
for (var _len = arguments.length, props = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
|
|
12
|
+
props[_key - 1] = arguments[_key];
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
var picked = {};
|
|
16
|
+
|
|
17
|
+
props.forEach(function (prop) {
|
|
18
|
+
if (obj[prop] !== undefined) {
|
|
19
|
+
picked[prop] = obj[prop];
|
|
20
|
+
}
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
return picked;
|
|
24
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "webflow-api",
|
|
3
|
+
"version": "0.5.4",
|
|
4
|
+
"description": "SDK for the Webflow CMS API",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"jsnext:main": "src/index.js",
|
|
7
|
+
"repository": {
|
|
8
|
+
"url": "https://github.com/webflow/js-webflow-api.git",
|
|
9
|
+
"type": "git"
|
|
10
|
+
},
|
|
11
|
+
"license": "MIT",
|
|
12
|
+
"types": "index.d.ts",
|
|
13
|
+
"files": [
|
|
14
|
+
"dist",
|
|
15
|
+
"src",
|
|
16
|
+
"LICENSE",
|
|
17
|
+
"yarn.lock"
|
|
18
|
+
],
|
|
19
|
+
"scripts": {
|
|
20
|
+
"build": "BABEL_ENV=production babel --out-dir dist src/",
|
|
21
|
+
"lint": "eslint src",
|
|
22
|
+
"prepublish": "npm run build",
|
|
23
|
+
"report": "nyc report --reporter=html",
|
|
24
|
+
"test": "nyc ava",
|
|
25
|
+
"watch": "npm run build -- --watch",
|
|
26
|
+
"watch:test": "npm run test -- --watch"
|
|
27
|
+
},
|
|
28
|
+
"devDependencies": {
|
|
29
|
+
"ava": "^0.16.0",
|
|
30
|
+
"babel-cli": "^6.18.0",
|
|
31
|
+
"babel-core": "^6.18.2",
|
|
32
|
+
"babel-eslint": "^7.1.0",
|
|
33
|
+
"babel-plugin-add-module-exports": "^0.2.1",
|
|
34
|
+
"babel-preset-es2015": "^6.18.0",
|
|
35
|
+
"babel-preset-stage-1": "^6.16.0",
|
|
36
|
+
"babel-register": "^6.18.0",
|
|
37
|
+
"eslint": "^3.10.1",
|
|
38
|
+
"eslint-config-airbnb-base": "^10.0.1",
|
|
39
|
+
"eslint-plugin-import": "^2.2.0",
|
|
40
|
+
"nock": "^13.0.7",
|
|
41
|
+
"nyc": "^9.0.1"
|
|
42
|
+
},
|
|
43
|
+
"dependencies": {
|
|
44
|
+
"es6-error": "^4.0.0",
|
|
45
|
+
"isomorphic-fetch": "^3.0.0",
|
|
46
|
+
"qs": "^6.3.0"
|
|
47
|
+
},
|
|
48
|
+
"ava": {
|
|
49
|
+
"require": [
|
|
50
|
+
"babel-register"
|
|
51
|
+
],
|
|
52
|
+
"babel": "inherit"
|
|
53
|
+
}
|
|
54
|
+
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
export default class ResponseWrapper {
|
|
2
|
+
constructor(api) {
|
|
3
|
+
this.api = api;
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
site(site) {
|
|
7
|
+
return {
|
|
8
|
+
...site,
|
|
9
|
+
|
|
10
|
+
collections: this.api.collections.bind(this.api, { siteId: site._id }),
|
|
11
|
+
webhooks: this.api.webhooks.bind(this.api, { siteId: site._id }),
|
|
12
|
+
domains: this.api.domains.bind(this.api, { siteId: site._id }),
|
|
13
|
+
webhook(first, ...rest) {
|
|
14
|
+
return this.api.webhook({ ...first, siteId: site._id }, ...rest);
|
|
15
|
+
},
|
|
16
|
+
createWebhook(first, ...rest) {
|
|
17
|
+
return this.api.createWebhook({ ...first, siteId: site._id }, ...rest);
|
|
18
|
+
},
|
|
19
|
+
removeWebhook(first, ...rest) {
|
|
20
|
+
return this.api.removeWebhook({ ...first, siteId: site._id }, ...rest);
|
|
21
|
+
},
|
|
22
|
+
publishSite(domains) {
|
|
23
|
+
return this.api.publishSite({ siteId: site._id, domains });
|
|
24
|
+
},
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
domain(domain) {
|
|
29
|
+
return {
|
|
30
|
+
...domain,
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
collection(collection) {
|
|
35
|
+
return {
|
|
36
|
+
...collection,
|
|
37
|
+
|
|
38
|
+
items: this.api.items.bind(this.api, { collectionId: collection._id }),
|
|
39
|
+
item(first, ...rest) {
|
|
40
|
+
return this.api.item({ ...first, collectionId: collection._id }, ...rest);
|
|
41
|
+
},
|
|
42
|
+
createItem(first, ...rest) {
|
|
43
|
+
return this.api.createItem({ ...first, collectionId: collection._id }, ...rest);
|
|
44
|
+
},
|
|
45
|
+
updateItem(first, ...rest) {
|
|
46
|
+
return this.api.updateItem({ ...first, collectionId: collection._id }, ...rest);
|
|
47
|
+
},
|
|
48
|
+
removeItem(first, ...rest) {
|
|
49
|
+
return this.api.removeItem({ ...first, collectionId: collection._id }, ...rest);
|
|
50
|
+
},
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
item(item, collectionId) {
|
|
55
|
+
return {
|
|
56
|
+
...item,
|
|
57
|
+
|
|
58
|
+
update(first, ...rest) {
|
|
59
|
+
return this.api.updateItem({ ...first, collectionId, itemId: item._id }, ...rest);
|
|
60
|
+
},
|
|
61
|
+
remove: this.api.updateItem.bind(this.api, { collectionId, itemId: item._id }),
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
webhook(webhook, siteId) {
|
|
66
|
+
return {
|
|
67
|
+
...webhook,
|
|
68
|
+
|
|
69
|
+
remove: this.api.removeWebhook.bind(this.api, { siteId, webhookId: webhook._id }),
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
}
|
package/src/Webflow.js
ADDED
|
@@ -0,0 +1,255 @@
|
|
|
1
|
+
import fetch from 'isomorphic-fetch';
|
|
2
|
+
import qs from 'qs';
|
|
3
|
+
|
|
4
|
+
import { isObjectEmpty } from './utils';
|
|
5
|
+
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) { return {}; }
|
|
12
|
+
|
|
13
|
+
return {
|
|
14
|
+
rateLimit: {
|
|
15
|
+
limit: parseInt(res.headers.get('x-ratelimit-limit'), 10),
|
|
16
|
+
remaining: parseInt(res.headers.get('x-ratelimit-remaining'), 10),
|
|
17
|
+
},
|
|
18
|
+
};
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
const responseHandler = res =>
|
|
22
|
+
res.json()
|
|
23
|
+
.catch(err =>
|
|
24
|
+
// Catch unexpected server errors where json isn't sent and rewrite
|
|
25
|
+
// with proper class (WebflowError)
|
|
26
|
+
Promise.reject(new WebflowError(err)))
|
|
27
|
+
.then((body) => {
|
|
28
|
+
if (res.status >= 400) {
|
|
29
|
+
const errOpts = {
|
|
30
|
+
code: body.code,
|
|
31
|
+
msg: body.msg,
|
|
32
|
+
_meta: buildMeta(res),
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
if (body.problems && body.problems.length > 0) {
|
|
36
|
+
errOpts.problems = body.problems;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const errMsg = (body && body.err) ? body.err : 'Unknown error occured';
|
|
40
|
+
const err = new WebflowError(errMsg);
|
|
41
|
+
|
|
42
|
+
return Promise.reject(Object.assign(err, errOpts));
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
body._meta = buildMeta(res); // eslint-disable-line no-param-reassign
|
|
46
|
+
|
|
47
|
+
return body;
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
export default class Webflow {
|
|
51
|
+
constructor({
|
|
52
|
+
endpoint = DEFAULT_ENDPOINT,
|
|
53
|
+
token,
|
|
54
|
+
version = '1.0.0',
|
|
55
|
+
} = {}) {
|
|
56
|
+
if (!token) throw buildRequiredArgError('token');
|
|
57
|
+
|
|
58
|
+
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 = query && !isObjectEmpty(query)
|
|
72
|
+
? `?${qs.stringify(query)}`
|
|
73
|
+
: '';
|
|
74
|
+
|
|
75
|
+
const uri = `${this.endpoint}${path}${queryString}`;
|
|
76
|
+
const opts = {
|
|
77
|
+
method,
|
|
78
|
+
headers: this.headers,
|
|
79
|
+
mode: 'cors',
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
if (data) {
|
|
83
|
+
opts.body = JSON.stringify(data);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
return fetch(uri, opts)
|
|
87
|
+
.then(responseHandler);
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// Generic HTTP request handlers
|
|
92
|
+
|
|
93
|
+
get(path, query = {}) {
|
|
94
|
+
return this.authenticatedFetch('GET', path, false, query);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
post(path, data, query = {}) {
|
|
98
|
+
return this.authenticatedFetch('POST', path, data, query);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
put(path, data, query = {}) {
|
|
102
|
+
return this.authenticatedFetch('PUT', path, data, query);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
patch(path, data, query = {}) {
|
|
106
|
+
return this.authenticatedFetch('PATCH', path, data, query);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
delete(path, query = {}) {
|
|
110
|
+
return this.authenticatedFetch('DELETE', path, query);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// Meta
|
|
114
|
+
|
|
115
|
+
info(query = {}) {
|
|
116
|
+
return this.get('/info', query);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// Sites
|
|
120
|
+
|
|
121
|
+
sites(query = {}) {
|
|
122
|
+
return this.get('/sites', query).then(sites => sites.map(site => this.responseWrapper.site(site)));
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
site({ siteId }, query = {}) {
|
|
126
|
+
if (!siteId) return Promise.reject(buildRequiredArgError('siteId'));
|
|
127
|
+
|
|
128
|
+
return this.get(`/sites/${siteId}`, query).then(site => this.responseWrapper.site(site));
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
publishSite({ siteId, domains }) {
|
|
132
|
+
if (!siteId) return Promise.reject(buildRequiredArgError('siteId'));
|
|
133
|
+
if (!domains) return Promise.reject(buildRequiredArgError('domains'));
|
|
134
|
+
|
|
135
|
+
return this.post(`/sites/${siteId}/publish`, { domains });
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// Domains
|
|
139
|
+
|
|
140
|
+
domains({ siteId }) {
|
|
141
|
+
if (!siteId) return Promise.reject(buildRequiredArgError('siteId'));
|
|
142
|
+
|
|
143
|
+
return this.get(`/sites/${siteId}/domains`).then(
|
|
144
|
+
domains => domains.map(domain => this.responseWrapper.domain(domain, siteId)),
|
|
145
|
+
);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// Collections
|
|
149
|
+
|
|
150
|
+
collections({ siteId }, query = {}) {
|
|
151
|
+
if (!siteId) return Promise.reject(buildRequiredArgError('siteId'));
|
|
152
|
+
|
|
153
|
+
return this.get(`/sites/${siteId}/collections`, query).then(
|
|
154
|
+
collections => collections.map(collection => this.responseWrapper.collection(collection)),
|
|
155
|
+
);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
collection({ collectionId }, query = {}) {
|
|
159
|
+
if (!collectionId) return Promise.reject(buildRequiredArgError('collectionId'));
|
|
160
|
+
|
|
161
|
+
return this.get(`/collections/${collectionId}`, query).then(
|
|
162
|
+
collection => this.responseWrapper.collection(collection),
|
|
163
|
+
);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// Items
|
|
167
|
+
|
|
168
|
+
items({ collectionId }, query = {}) {
|
|
169
|
+
if (!collectionId) return Promise.reject(buildRequiredArgError('collectionId'));
|
|
170
|
+
|
|
171
|
+
return this.get(`/collections/${collectionId}/items`, query).then(
|
|
172
|
+
res => ({
|
|
173
|
+
...res,
|
|
174
|
+
|
|
175
|
+
items: res.items.map(item => this.responseWrapper.item(item, collectionId)),
|
|
176
|
+
}),
|
|
177
|
+
);
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
item({ collectionId, itemId }, query = {}) {
|
|
181
|
+
if (!collectionId) return Promise.reject(buildRequiredArgError('collectionId'));
|
|
182
|
+
if (!itemId) return Promise.reject(buildRequiredArgError('siteId'));
|
|
183
|
+
|
|
184
|
+
return this.get(`/collections/${collectionId}/items/${itemId}`, query).then(
|
|
185
|
+
res => this.responseWrapper.item(res.items[0], collectionId),
|
|
186
|
+
);
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
createItem({ collectionId, ...data }, query = {}) {
|
|
190
|
+
if (!collectionId) return Promise.reject(buildRequiredArgError('collectionId'));
|
|
191
|
+
|
|
192
|
+
return this.post(`/collections/${collectionId}/items`, data, query).then(
|
|
193
|
+
item => this.responseWrapper.item(item, collectionId),
|
|
194
|
+
);
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
updateItem({ collectionId, itemId, ...data }, query = {}) {
|
|
198
|
+
if (!collectionId) return Promise.reject(buildRequiredArgError('collectionId'));
|
|
199
|
+
if (!itemId) return Promise.reject(buildRequiredArgError('itemId'));
|
|
200
|
+
|
|
201
|
+
return this.put(`/collections/${collectionId}/items/${itemId}`, data, query);
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
removeItem({ collectionId, itemId }, query = {}) {
|
|
205
|
+
if (!collectionId) return Promise.reject(buildRequiredArgError('collectionId'));
|
|
206
|
+
if (!itemId) return Promise.reject(buildRequiredArgError('itemId'));
|
|
207
|
+
|
|
208
|
+
return this.delete(`/collections/${collectionId}/items/${itemId}`, query);
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
patchItem({ collectionId, itemId, ...data }, query = {}) {
|
|
212
|
+
if (!collectionId) return Promise.reject(buildRequiredArgError('collectionId'));
|
|
213
|
+
if (!itemId) return Promise.reject(buildRequiredArgError('itemId'));
|
|
214
|
+
|
|
215
|
+
return this.patch(`/collections/${collectionId}/items/${itemId}`, data, query);
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
// Images
|
|
219
|
+
|
|
220
|
+
// TODO
|
|
221
|
+
|
|
222
|
+
// Webhooks
|
|
223
|
+
|
|
224
|
+
webhooks({ siteId }, query = {}) {
|
|
225
|
+
if (!siteId) return Promise.reject(buildRequiredArgError('siteId'));
|
|
226
|
+
|
|
227
|
+
return this.get(`/sites/${siteId}/webhooks`, query).then(
|
|
228
|
+
webhooks => webhooks.map(webhook => this.responseWrapper.webhook(webhook, siteId)),
|
|
229
|
+
);
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
webhook({ siteId, webhookId }, query = {}) {
|
|
233
|
+
if (!siteId) return Promise.reject(buildRequiredArgError('siteId'));
|
|
234
|
+
if (!webhookId) return Promise.reject(buildRequiredArgError('webhookId'));
|
|
235
|
+
|
|
236
|
+
return this.get(`/sites/${siteId}/webhooks/${webhookId}`, query).then(
|
|
237
|
+
webhook => this.responseWrapper.webhook(webhook, siteId),
|
|
238
|
+
);
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
createWebhook({ siteId, ...data }, query = {}) {
|
|
242
|
+
if (!siteId) return Promise.reject(buildRequiredArgError('siteId'));
|
|
243
|
+
|
|
244
|
+
return this.post(`/sites/${siteId}/webhooks`, data, query).then(
|
|
245
|
+
webhook => this.responseWrapper.webhook(webhook, siteId),
|
|
246
|
+
);
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
removeWebhook({ siteId, webhookId }, query = {}) {
|
|
250
|
+
if (!siteId) return Promise.reject(buildRequiredArgError('siteId'));
|
|
251
|
+
if (!webhookId) return Promise.reject(buildRequiredArgError('webhookId'));
|
|
252
|
+
|
|
253
|
+
return this.delete(`/sites/${siteId}/webhooks/${webhookId}`, query);
|
|
254
|
+
}
|
|
255
|
+
}
|
package/src/index.js
ADDED
package/src/utils.js
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export const isObjectEmpty = obj => Object.keys(obj).length === 0;
|
|
2
|
+
|
|
3
|
+
export const pick = (obj, ...props) => {
|
|
4
|
+
const picked = {};
|
|
5
|
+
|
|
6
|
+
props.forEach((prop) => {
|
|
7
|
+
if (obj[prop] !== undefined) {
|
|
8
|
+
picked[prop] = obj[prop];
|
|
9
|
+
}
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
return picked;
|
|
13
|
+
};
|