buildfree 1.0.0

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 ADDED
@@ -0,0 +1,127 @@
1
+ # BuildFree SDK
2
+
3
+ BuildFree is a simple Node.js SDK that lets you connect your application to the BuildFree CMS API and use your CMS data anywhere.
4
+
5
+ [buildfree.dev](https://buildfree.dev)
6
+
7
+ ---
8
+
9
+ ## Installation
10
+
11
+ ```bash
12
+ npm install buildfree
13
+ ```
14
+
15
+ ## Quick Start
16
+
17
+ ```javascript
18
+ const { BuildFree } = require("buildfree");
19
+
20
+ const buildfree = new BuildFree({
21
+ apiKey: "cms_live_your_api_key"
22
+ });
23
+ ```
24
+
25
+ ---
26
+
27
+ ## Records
28
+
29
+ ### Get all records
30
+
31
+ ```javascript
32
+ const products = await buildfree.getRecords({
33
+ projectSlug: "my-project",
34
+ collectionSlug: "products"
35
+ });
36
+ ```
37
+
38
+ ### Get one record
39
+
40
+ ```javascript
41
+ const product = await buildfree.getRecord({
42
+ projectSlug: "my-project",
43
+ collectionSlug: "products",
44
+ recordId: "record-id"
45
+ });
46
+ ```
47
+
48
+ ---
49
+
50
+ ## Forms
51
+
52
+ ### Get a form
53
+
54
+ ```javascript
55
+ const form = await buildfree.getForm({
56
+ projectSlug: "my-project",
57
+ formSlug: "contact-form"
58
+ });
59
+ ```
60
+
61
+ ### Submit a form
62
+
63
+ ```javascript
64
+ const result = await buildfree.submitForm({
65
+ projectSlug: "my-project",
66
+ formSlug: "contact-form",
67
+ data: {
68
+ name: "John",
69
+ email: "john@example.com",
70
+ message: "Hello!"
71
+ }
72
+ });
73
+ ```
74
+
75
+ ---
76
+
77
+ ## File Upload
78
+
79
+ Forms also support file uploads:
80
+
81
+ ```javascript
82
+ const result = await buildfree.submitForm({
83
+ projectSlug: "my-project",
84
+ formSlug: "application-form",
85
+
86
+ data: {
87
+ name: "John"
88
+ },
89
+
90
+ files: [
91
+ {
92
+ fieldname: "resume",
93
+ path: "./resume.pdf"
94
+ }
95
+ ]
96
+ });
97
+ ```
98
+
99
+ ---
100
+
101
+ ## API Key
102
+
103
+ Your API key must start with:
104
+
105
+ ```text
106
+ cms_live_
107
+ ```
108
+
109
+ > Keep your API key secure and use environment variables in production.
110
+
111
+ ---
112
+
113
+ ## Available Methods
114
+
115
+ ```text
116
+ buildfree.getRecords()
117
+ buildfree.getRecord()
118
+
119
+ buildfree.getForm()
120
+ buildfree.submitForm()
121
+ ```
122
+
123
+ ---
124
+
125
+ **BuildFree** — Build your API. Use it anywhere.
126
+
127
+ [buildfree.dev](https://buildfree.dev)
package/package.json ADDED
@@ -0,0 +1,18 @@
1
+ {
2
+ "name": "buildfree",
3
+ "version": "1.0.0",
4
+ "description": "Official JavaScript SDK for buildfree",
5
+ "main": "src/index.js",
6
+ "scripts": {
7
+ "test": "echo \"Error: no test specified\" && exit 1",
8
+ "start": "node src/index.js",
9
+ "dev": ""
10
+ },
11
+ "keywords": [],
12
+ "author": "BuildFree",
13
+ "license": "MIT",
14
+ "dependencies": {
15
+ "axios": "^1.20.0",
16
+ "nodemon": "^3.1.14"
17
+ }
18
+ }
package/src/forms.js ADDED
@@ -0,0 +1,327 @@
1
+ const axios = require("axios");
2
+ const FormData = require("form-data");
3
+ const fs = require("fs");
4
+
5
+ class Forms {
6
+
7
+ constructor({
8
+ apiKey,
9
+ baseURL
10
+ }) {
11
+
12
+ this.client = axios.create({
13
+
14
+ baseURL,
15
+
16
+ timeout: 10000,
17
+
18
+ headers: {
19
+ "x-api-key": apiKey,
20
+ "Accept": "application/json"
21
+ }
22
+
23
+ });
24
+
25
+ }
26
+
27
+
28
+ // ==========================================================
29
+ // GET FORM
30
+ // ==========================================================
31
+
32
+ async getOne({
33
+ projectSlug,
34
+ formSlug
35
+ } = {}) {
36
+
37
+ // ==========================================
38
+ // VALIDATION
39
+ // ==========================================
40
+
41
+ if (!projectSlug) {
42
+ throw new Error("projectSlug is required");
43
+ }
44
+
45
+ if (!formSlug) {
46
+ throw new Error("formSlug is required");
47
+ }
48
+
49
+
50
+ // ==========================================
51
+ // REQUEST
52
+ // ==========================================
53
+
54
+ try {
55
+
56
+ const response = await this.client.get(
57
+
58
+ `/public/${encodeURIComponent(projectSlug)}/forms/${encodeURIComponent(formSlug)}`
59
+
60
+ );
61
+
62
+ return response.data;
63
+
64
+ } catch (error) {
65
+
66
+ this.handleError(error);
67
+
68
+ }
69
+
70
+ }
71
+
72
+
73
+ // ==========================================================
74
+ // SUBMIT FORM
75
+ // ==========================================================
76
+
77
+ async submit({
78
+ projectSlug,
79
+ formSlug,
80
+ data = {},
81
+ files = []
82
+ } = {}) {
83
+
84
+ // ==========================================
85
+ // VALIDATION
86
+ // ==========================================
87
+
88
+ if (!projectSlug) {
89
+ throw new Error("projectSlug is required");
90
+ }
91
+
92
+ if (!formSlug) {
93
+ throw new Error("formSlug is required");
94
+ }
95
+
96
+
97
+ try {
98
+
99
+ // ========================================================
100
+ // NORMAL JSON REQUEST
101
+ // ========================================================
102
+
103
+ if (!files || files.length === 0) {
104
+
105
+ const response = await this.client.post(
106
+
107
+ `/public/${encodeURIComponent(projectSlug)}/forms/${encodeURIComponent(formSlug)}/submit`,
108
+
109
+ data,
110
+
111
+ {
112
+ headers: {
113
+ "Content-Type": "application/json"
114
+ }
115
+ }
116
+
117
+ );
118
+
119
+ return response.data;
120
+
121
+ }
122
+
123
+
124
+ // ========================================================
125
+ // MULTIPART FORM REQUEST
126
+ // ========================================================
127
+
128
+ const formData = new FormData();
129
+
130
+
131
+ // ========================================================
132
+ // ADD NORMAL DATA
133
+ // ========================================================
134
+
135
+ for (
136
+ const [key, value]
137
+ of Object.entries(data)
138
+ ) {
139
+
140
+ if (
141
+ value !== undefined &&
142
+ value !== null
143
+ ) {
144
+
145
+ formData.append(
146
+ key,
147
+ value
148
+ );
149
+
150
+ }
151
+
152
+ }
153
+
154
+
155
+ // ========================================================
156
+ // ADD FILES
157
+ // ========================================================
158
+
159
+ for (const file of files) {
160
+
161
+ if (!file) {
162
+ continue;
163
+ }
164
+
165
+
166
+ // ------------------------------------------------------
167
+ // BUFFER
168
+ // ------------------------------------------------------
169
+
170
+ if (Buffer.isBuffer(file.buffer)) {
171
+
172
+ formData.append(
173
+
174
+ file.fieldname,
175
+
176
+ file.buffer,
177
+
178
+ {
179
+ filename:
180
+ file.filename ||
181
+ file.originalname ||
182
+ "upload",
183
+
184
+ contentType:
185
+ file.contentType ||
186
+ file.mimetype
187
+ }
188
+
189
+ );
190
+
191
+ continue;
192
+
193
+ }
194
+
195
+
196
+ // ------------------------------------------------------
197
+ // FILE PATH
198
+ // ------------------------------------------------------
199
+
200
+ if (file.path) {
201
+
202
+ formData.append(
203
+
204
+ file.fieldname,
205
+
206
+ fs.createReadStream(
207
+ file.path
208
+ ),
209
+
210
+ {
211
+ filename:
212
+ file.filename ||
213
+ file.originalname
214
+ }
215
+
216
+ );
217
+
218
+ continue;
219
+
220
+ }
221
+
222
+
223
+ throw new Error(
224
+ `Invalid file for field: ${file.fieldname}`
225
+ );
226
+
227
+ }
228
+
229
+
230
+ // ========================================================
231
+ // SUBMIT
232
+ // ========================================================
233
+
234
+ const response = await this.client.post(
235
+
236
+ `/public/${encodeURIComponent(projectSlug)}/forms/${encodeURIComponent(formSlug)}/submit`,
237
+
238
+ formData,
239
+
240
+ {
241
+ headers: {
242
+ ...formData.getHeaders()
243
+ }
244
+ }
245
+
246
+ );
247
+
248
+
249
+ return response.data;
250
+
251
+ } catch (error) {
252
+
253
+ this.handleError(error);
254
+
255
+ }
256
+
257
+ }
258
+
259
+
260
+ // ==========================================================
261
+ // ERROR HANDLER
262
+ // ==========================================================
263
+
264
+ handleError(error) {
265
+
266
+ // ==========================================
267
+ // SERVER RESPONSE
268
+ // ==========================================
269
+
270
+ if (error.response) {
271
+
272
+ const message =
273
+ error.response.data?.message ||
274
+ "CMS API request failed";
275
+
276
+ const apiError =
277
+ new Error(message);
278
+
279
+ apiError.status =
280
+ error.response.status;
281
+
282
+ apiError.response =
283
+ error.response.data;
284
+
285
+ throw apiError;
286
+
287
+ }
288
+
289
+
290
+ // ==========================================
291
+ // NO RESPONSE
292
+ // ==========================================
293
+
294
+ if (error.request) {
295
+
296
+ if (
297
+ error.code === "ECONNABORTED" ||
298
+ error.code === "ETIMEDOUT"
299
+ ) {
300
+
301
+ throw new Error(
302
+ "CMS API request timed out"
303
+ );
304
+
305
+ }
306
+
307
+ throw new Error(
308
+ "Could not connect to CMS API"
309
+ );
310
+
311
+ }
312
+
313
+
314
+ // ==========================================
315
+ // UNKNOWN ERROR
316
+ // ==========================================
317
+
318
+ throw error;
319
+
320
+ }
321
+
322
+ }
323
+
324
+
325
+ module.exports = {
326
+ Forms
327
+ };
package/src/index.js ADDED
@@ -0,0 +1,84 @@
1
+ const { Records } = require("./records");
2
+ const { Forms } = require("./forms");
3
+
4
+ class BuildFree {
5
+
6
+ constructor({
7
+ apiKey,
8
+ baseURL = "https://cms-backend-9nkz.onrender.com/api/v1"
9
+ } = {}) {
10
+
11
+ // ==========================================
12
+ // API KEY VALIDATION
13
+ // ==========================================
14
+
15
+ if (!apiKey) {
16
+ throw new Error("API key is required");
17
+ }
18
+
19
+ if (
20
+ typeof apiKey !== "string" ||
21
+ !apiKey.startsWith("cms_live_")
22
+ ) {
23
+ throw new Error("Invalid API key");
24
+ }
25
+
26
+
27
+ // ==========================================
28
+ // INITIALIZE SERVICES
29
+ // ==========================================
30
+
31
+ this.records = new Records({
32
+ apiKey,
33
+ baseURL
34
+ });
35
+
36
+ this.forms = new Forms({
37
+ apiKey,
38
+ baseURL
39
+ });
40
+
41
+ }
42
+
43
+
44
+ // ==========================================
45
+ // RECORDS
46
+ // ==========================================
47
+
48
+ getRecords(options) {
49
+
50
+ return this.records.getAll(options);
51
+
52
+ }
53
+
54
+
55
+ getRecord(options) {
56
+
57
+ return this.records.getOne(options);
58
+
59
+ }
60
+
61
+
62
+ // ==========================================
63
+ // FORMS
64
+ // ==========================================
65
+
66
+ getForm(options) {
67
+
68
+ return this.forms.getOne(options);
69
+
70
+ }
71
+
72
+
73
+ submitForm(options) {
74
+
75
+ return this.forms.submit(options);
76
+
77
+ }
78
+
79
+ }
80
+
81
+
82
+ module.exports = {
83
+ BuildFree
84
+ };
package/src/records.js ADDED
@@ -0,0 +1,189 @@
1
+ const axios = require("axios");
2
+
3
+ class Records {
4
+
5
+ constructor({
6
+ apiKey,
7
+ baseURL
8
+ }) {
9
+
10
+ this.client = axios.create({
11
+
12
+ baseURL,
13
+
14
+ timeout: 10000,
15
+
16
+ headers: {
17
+ "x-api-key": apiKey,
18
+ "Content-Type": "application/json",
19
+ "Accept": "application/json"
20
+ }
21
+
22
+ });
23
+
24
+ }
25
+
26
+
27
+ // ==========================================================
28
+ // GET ALL RECORDS
29
+ // ==========================================================
30
+
31
+ async getAll({
32
+ projectSlug,
33
+ collectionSlug
34
+ } = {}) {
35
+
36
+ // ==========================================
37
+ // VALIDATION
38
+ // ==========================================
39
+
40
+ if (!projectSlug) {
41
+ throw new Error("projectSlug is required");
42
+ }
43
+
44
+ if (!collectionSlug) {
45
+ throw new Error("collectionSlug is required");
46
+ }
47
+
48
+
49
+ // ==========================================
50
+ // REQUEST
51
+ // ==========================================
52
+
53
+ try {
54
+
55
+ const response = await this.client.get(
56
+
57
+ `/public/${encodeURIComponent(projectSlug)}/${encodeURIComponent(collectionSlug)}`
58
+
59
+ );
60
+
61
+ return response.data;
62
+
63
+ } catch (error) {
64
+
65
+ this.handleError(error);
66
+
67
+ }
68
+
69
+ }
70
+
71
+
72
+ // ==========================================================
73
+ // GET ONE RECORD
74
+ // ==========================================================
75
+
76
+ async getOne({
77
+ projectSlug,
78
+ collectionSlug,
79
+ recordId
80
+ } = {}) {
81
+
82
+ // ==========================================
83
+ // VALIDATION
84
+ // ==========================================
85
+
86
+ if (!projectSlug) {
87
+ throw new Error("projectSlug is required");
88
+ }
89
+
90
+ if (!collectionSlug) {
91
+ throw new Error("collectionSlug is required");
92
+ }
93
+
94
+ if (!recordId) {
95
+ throw new Error("recordId is required");
96
+ }
97
+
98
+
99
+ // ==========================================
100
+ // REQUEST
101
+ // ==========================================
102
+
103
+ try {
104
+
105
+ const response = await this.client.get(
106
+
107
+ `/public/${encodeURIComponent(projectSlug)}/${encodeURIComponent(collectionSlug)}/${encodeURIComponent(recordId)}`
108
+
109
+ );
110
+
111
+ return response.data;
112
+
113
+ } catch (error) {
114
+
115
+ this.handleError(error);
116
+
117
+ }
118
+
119
+ }
120
+
121
+
122
+ // ==========================================================
123
+ // ERROR HANDLER
124
+ // ==========================================================
125
+
126
+ handleError(error) {
127
+
128
+ // ==========================================
129
+ // SERVER RESPONSE
130
+ // ==========================================
131
+
132
+ if (error.response) {
133
+
134
+ const message =
135
+ error.response.data?.message ||
136
+ "CMS API request failed";
137
+
138
+ const apiError =
139
+ new Error(message);
140
+
141
+ apiError.status =
142
+ error.response.status;
143
+
144
+ apiError.response =
145
+ error.response.data;
146
+
147
+ throw apiError;
148
+
149
+ }
150
+
151
+
152
+ // ==========================================
153
+ // NO RESPONSE
154
+ // ==========================================
155
+
156
+ if (error.request) {
157
+
158
+ if (
159
+ error.code === "ECONNABORTED" ||
160
+ error.code === "ETIMEDOUT"
161
+ ) {
162
+
163
+ throw new Error(
164
+ "CMS API request timed out"
165
+ );
166
+
167
+ }
168
+
169
+ throw new Error(
170
+ "Could not connect to CMS API"
171
+ );
172
+
173
+ }
174
+
175
+
176
+ // ==========================================
177
+ // UNKNOWN ERROR
178
+ // ==========================================
179
+
180
+ throw error;
181
+
182
+ }
183
+
184
+ }
185
+
186
+
187
+ module.exports = {
188
+ Records
189
+ };