@cloudcannon/sdk 0.0.3 → 0.0.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/README.md ADDED
@@ -0,0 +1,1514 @@
1
+ # @cloudcannon/sdk
2
+
3
+ A TypeScript SDK for interacting with the CloudCannon REST API.
4
+
5
+ ## Table of contents
6
+
7
+ - [Installation](#installation)
8
+ - [Creating and configuring the client](#creating-and-configuring-the-client)
9
+ - [Optional configuration](#optional-configuration)
10
+ - [Client functions](#client-functions)
11
+ - [Root client](#root-client)
12
+ - [Organizations (`client.org(uuid)`)](#organizations-clientorguuid)
13
+ - [Sites (`client.site(uuid)`)](#sites-clientsiteuuid)
14
+ - [Inboxes (`client.inbox(uuid)`)](#inboxes-clientinboxuuid)
15
+ - [Site Inboxes (`client.siteInbox(uuid)`)](#site-inboxes-clientsiteinboxuuid)
16
+ - [Editing Sessions (`client.editingSession(uuid)`)](#editing-sessions-clienteditingsessionuuid)
17
+ - [Editing Session Files (`client.editingSessionFile(uuid)`)](#editing-session-files-clienteditingsessionfileuuid)
18
+ - [Builds (`client.build(uuid)`)](#builds-clientbuilduuid)
19
+ - [Backups (`client.backup(uuid)`)](#backups-clientbackupuuid)
20
+ - [Syncs (`client.sync(uuid)`)](#syncs-clientsyncuuid)
21
+ - [Pagination, sorting, and filtering](#pagination-sorting-and-filtering)
22
+ - [Error handling](#error-handling)
23
+ - [Advanced: using the raw `client.fetch`](#advanced-using-the-raw-clientfetch)
24
+
25
+ ## Installation
26
+
27
+ ```bash
28
+ npm install @cloudcannon/sdk
29
+ ```
30
+
31
+ ## Creating and configuring the client
32
+
33
+ Import `CloudCannonClient` and instantiate it with your API key:
34
+
35
+ ```typescript
36
+ import CloudCannonClient from '@cloudcannon/sdk';
37
+
38
+ const client = new CloudCannonClient({
39
+ key: 'your-api-key-here',
40
+ });
41
+ ```
42
+
43
+ ### Optional configuration
44
+
45
+ | Option | Type | Description |
46
+ |--------|------|-------------|
47
+ | `key` | `string` | **Required.** Your CloudCannon API key. |
48
+ | `apiOrigin` | `string` | The API host. Defaults to `app.cloudcannon.com`. |
49
+ | `getCustomAuthHeaders` | `() => Record<string, string>` | Provide custom authentication headers instead of the default `X-API-KEY`. |
50
+
51
+ ```typescript
52
+ const client = new CloudCannonClient({
53
+ key: 'your-api-key-here',
54
+ apiOrigin: 'app.cloudcannon.com',
55
+ });
56
+ ```
57
+
58
+ ## Client functions
59
+
60
+ The SDK exposes a hierarchy of sub-clients that map to CloudCannon's REST API resources. Each sub-client is accessed by calling a method on the root client with a UUID, or by calling top-level list methods directly on the root client.
61
+
62
+ ### Root client
63
+
64
+ #### `client.orgs(options?)`
65
+
66
+ List all organizations you have access to. Supports pagination, sorting, and filtering.
67
+
68
+ ```typescript
69
+ const { items, total_items } = await client.orgs({
70
+ // Pagination, sorting, and filtering options
71
+ page: 1, // Page number to fetch (1-indexed)
72
+ items: 10, // Number of items per page
73
+ sort_attribute: 'name', // Attribute to sort the results by (e.g. 'id', 'uuid', 'name', 'partner_points', 'updated_at')
74
+ sort_direction: 'ASC', // Sort direction: 'ASC' or 'DESC'
75
+ filters: {
76
+ // Optional filters
77
+ search: 'acme', // Search term
78
+ plan: 'pro', // Filter by plan name
79
+ country: 'US', // Filter by country
80
+ billing_status: 'active', // Filter by billing status
81
+ expired: false, // Filter by expired status
82
+ locked: false, // Filter by locked status
83
+ trial: false, // Filter by trial status
84
+ hosting_limit_exceeded: false, // Filter by hosting limit
85
+ build_time_limit_exceeded: false, // Filter by build time limit
86
+ user_limit_exceeded: false, // Filter by user limit
87
+ domain_limit_exceeded: false, // Filter by domain limit
88
+ in_partner_program: false, // Filter by partner program membership
89
+ user_uuid: 'user-uuid', // Filter by user UUID
90
+ uuid: 'org-uuid', // Filter by organization UUID
91
+ id: 123, // Filter by organization ID
92
+ // Date range filters (ISO 8601 strings)
93
+ created_at_lt: '2024-01-01T00:00:00Z',
94
+ created_at_gt: '2023-01-01T00:00:00Z',
95
+ created_at_lte: '2024-01-01T00:00:00Z',
96
+ created_at_gte: '2023-01-01T00:00:00Z',
97
+ updated_at_lt: '2024-01-01T00:00:00Z',
98
+ updated_at_gt: '2023-01-01T00:00:00Z',
99
+ updated_at_lte: '2024-01-01T00:00:00Z',
100
+ updated_at_gte: '2023-01-01T00:00:00Z',
101
+ },
102
+ });
103
+ // { // PaginatedResponse<Org>
104
+ // items: [
105
+ // { // Org
106
+ // uuid: "STRING_VALUE",
107
+ // id: 123,
108
+ // name: "STRING_VALUE",
109
+ // plan: "STRING_VALUE",
110
+ // billing_status: "STRING_VALUE",
111
+ // country: "STRING_VALUE",
112
+ // created_at: "TIMESTAMP",
113
+ // updated_at: "TIMESTAMP",
114
+ // }
115
+ // ],
116
+ // current_page: 1,
117
+ // total_items: 10,
118
+ // total_pages: 1,
119
+ // }
120
+ ```
121
+
122
+ #### `client.getUploadData()`
123
+
124
+ Fetch temporary S3 upload credentials used when uploading files through editing sessions.
125
+
126
+ ```typescript
127
+ const uploadData = await client.getUploadData();
128
+ // { // UploadData
129
+ // url: "STRING_VALUE",
130
+ // prefix: "STRING_VALUE",
131
+ // fields: {
132
+ // "<key>": "STRING_VALUE",
133
+ // },
134
+ // }
135
+ ```
136
+
137
+ ---
138
+
139
+ ### Organizations (`client.org(uuid)`)
140
+
141
+ ```typescript
142
+ const org = client.org('org-uuid');
143
+ ```
144
+
145
+ #### `org.get()`
146
+
147
+ Get details for a single organization.
148
+
149
+ ```typescript
150
+ const orgDetails = await org.get();
151
+ // { // Org
152
+ // uuid: "STRING_VALUE",
153
+ // id: 123,
154
+ // name: "STRING_VALUE",
155
+ // plan: "STRING_VALUE",
156
+ // billing_status: "STRING_VALUE",
157
+ // country: "STRING_VALUE",
158
+ // created_at: "TIMESTAMP",
159
+ // updated_at: "TIMESTAMP",
160
+ // }
161
+ ```
162
+
163
+ #### `org.sites(options?)`
164
+
165
+ List all sites within the organization. Supports pagination, sorting, and filtering.
166
+
167
+ ```typescript
168
+ const { items } = await org.sites({
169
+ // Pagination, sorting, and filtering options
170
+ page: 1, // Page number to fetch (1-indexed)
171
+ items: 20, // Number of items per page
172
+ sort_attribute: 'site_name', // Attribute to sort by (e.g. 'id', 'uuid', 'site_name', 'domain_name', 'created_at', 'updated_at', 'last_synced', 'last_compiled', 'storage_provider', 'stable_domain', 'subpath', 'sync_error')
173
+ sort_direction: 'DESC', // Sort direction: 'ASC' or 'DESC'
174
+ filters: {
175
+ // Optional filters
176
+ search: 'marketing', // Search term
177
+ site_name: 'My Site', // Filter by site name
178
+ domain_name: 'example.com', // Filter by domain name
179
+ stable_domain: 'my-site', // Filter by stable domain
180
+ ssg: 'hugo', // Filter by static site generator
181
+ storage_provider: 'github', // Filter by source provider
182
+ output_storage_provider: 'github', // Filter by output provider
183
+ hosting_choice: 'cloudcannon', // Filter by hosting choice
184
+ authentication: 'password', // Filter by authentication type
185
+ force_ssl: true, // Filter by SSL enforcement
186
+ editing_locked: false, // Filter by editing lock status
187
+ uploads_locked: false, // Filter by uploads lock status
188
+ browsing_locked: false, // Filter by browsing lock status
189
+ building_locked: false, // Filter by building lock status
190
+ uses_i18n: false, // Filter by i18n usage
191
+ sync_error: 'none', // Filter by sync error status
192
+ compile_error: 'none', // Filter by compile error status
193
+ project_uuid: 'project-uuid', // Filter by project UUID
194
+ base_domain_uuid: 'domain-uuid', // Filter by base domain UUID
195
+ dam_uuid: 'dam-uuid', // Filter by DAM UUID
196
+ inbox_uuid: 'inbox-uuid', // Filter by inbox UUID
197
+ uuid: 'site-uuid', // Filter by site UUID
198
+ id: 123, // Filter by site ID
199
+ // Date range filters
200
+ created_at_lt: '2024-01-01T00:00:00Z',
201
+ created_at_gt: '2023-01-01T00:00:00Z',
202
+ created_at_lte: '2024-01-01T00:00:00Z',
203
+ created_at_gte: '2023-01-01T00:00:00Z',
204
+ updated_at_lt: '2024-01-01T00:00:00Z',
205
+ updated_at_gt: '2023-01-01T00:00:00Z',
206
+ updated_at_lte: '2024-01-01T00:00:00Z',
207
+ updated_at_gte: '2023-01-01T00:00:00Z',
208
+ last_synced: '2024-01-01T00:00:00Z',
209
+ last_compiled: '2024-01-01T00:00:00Z',
210
+ },
211
+ });
212
+ // { // PaginatedResponse<Site>
213
+ // items: [
214
+ // { // Site
215
+ // uuid: "STRING_VALUE",
216
+ // id: 123,
217
+ // site_name: "STRING_VALUE",
218
+ // stable_domain: "STRING_VALUE",
219
+ // domain_name: "STRING_VALUE",
220
+ // ssg: "STRING_VALUE",
221
+ // storage_provider: "STRING_VALUE",
222
+ // hosting_choice: "STRING_VALUE",
223
+ // created_at: "TIMESTAMP",
224
+ // updated_at: "TIMESTAMP",
225
+ // }
226
+ // ],
227
+ // current_page: 1,
228
+ // total_items: 10,
229
+ // total_pages: 1,
230
+ // }
231
+ ```
232
+
233
+ #### `org.createSite(name)`
234
+
235
+ Create a new site in the organization.
236
+
237
+ ```typescript
238
+ const site = await org.createSite('My New Site');
239
+ // { // Site
240
+ // uuid: "STRING_VALUE",
241
+ // id: 123,
242
+ // site_name: "My New Site",
243
+ // stable_domain: "my-site",
244
+ // domain_name: "STRING_VALUE",
245
+ // ssg: "STRING_VALUE",
246
+ // storage_provider: "STRING_VALUE",
247
+ // hosting_choice: "STRING_VALUE",
248
+ // created_at: "TIMESTAMP",
249
+ // updated_at: "TIMESTAMP",
250
+ // }
251
+ ```
252
+
253
+ #### `org.connectSite(name, providerDetails)`
254
+
255
+ Create a new site connected to a Git provider.
256
+
257
+ ```typescript
258
+ const site = await org.connectSite(
259
+ 'My Site',
260
+ {
261
+ provider: 'github', // Git provider (e.g. 'github', 'gitlab', 'bitbucket')
262
+ repository: 'owner/repo', // Repository identifier (owner/name)
263
+ branch: 'main', // Branch to connect
264
+ folder: 'src', // Optional subfolder within the repository
265
+ },
266
+ );
267
+ // { // Site
268
+ // uuid: "STRING_VALUE",
269
+ // id: 123,
270
+ // site_name: "My Site",
271
+ // stable_domain: "my-site",
272
+ // storage_provider: "github",
273
+ // domain_name: "STRING_VALUE",
274
+ // created_at: "TIMESTAMP",
275
+ // updated_at: "TIMESTAMP",
276
+ // }
277
+ ```
278
+
279
+ #### `org.getInboxes(options?)`
280
+
281
+ List inboxes belonging to the organization. Supports pagination, sorting, and filtering.
282
+
283
+ ```typescript
284
+ const { items } = await org.getInboxes({
285
+ page: 1,
286
+ items: 20,
287
+ sort_attribute: 'name', // Sort by 'created_at', 'updated_at', 'id', 'key', 'name', or 'uuid'
288
+ sort_direction: 'ASC',
289
+ filters: {
290
+ search: 'contact',
291
+ name: 'Contact Form',
292
+ captcha_type: 'recaptcha',
293
+ uuid: 'inbox-uuid',
294
+ id: 123,
295
+ // Date range filters
296
+ created_at_lt: '2024-01-01T00:00:00Z',
297
+ created_at_gt: '2023-01-01T00:00:00Z',
298
+ created_at_lte: '2024-01-01T00:00:00Z',
299
+ created_at_gte: '2023-01-01T00:00:00Z',
300
+ updated_at_lt: '2024-01-01T00:00:00Z',
301
+ updated_at_gt: '2023-01-01T00:00:00Z',
302
+ updated_at_lte: '2024-01-01T00:00:00Z',
303
+ updated_at_gte: '2023-01-01T00:00:00Z',
304
+ },
305
+ });
306
+ // { // PaginatedResponse<Inbox>
307
+ // items: [
308
+ // { // Inbox
309
+ // uuid: "STRING_VALUE",
310
+ // id: 123,
311
+ // name: "STRING_VALUE",
312
+ // key: "STRING_VALUE",
313
+ // monthly_quota: 1000,
314
+ // created_at: "TIMESTAMP",
315
+ // updated_at: "TIMESTAMP",
316
+ // }
317
+ // ],
318
+ // current_page: 1,
319
+ // total_items: 10,
320
+ // total_pages: 1,
321
+ // }
322
+ ```
323
+
324
+ #### `org.createInbox(body)`
325
+
326
+ Create a new inbox.
327
+
328
+ ```typescript
329
+ const inbox = await org.createInbox({
330
+ name: 'Contact Form', // Display name for the inbox
331
+ key: 'contact-form', // Unique key/slug for the inbox
332
+ monthly_quota: 1000, // Optional monthly submission quota
333
+ keep_form_hook_days: 30, // Optional number of days to retain submissions
334
+ captcha_key: 'site-key', // Optional reCAPTCHA site key
335
+ captcha_secret: 'secret', // Optional reCAPTCHA secret key
336
+ captcha_type: 'recaptcha', // Optional captcha type
337
+ });
338
+ // { // Inbox
339
+ // uuid: "STRING_VALUE",
340
+ // id: 123,
341
+ // name: "Contact Form",
342
+ // key: "contact-form",
343
+ // monthly_quota: 1000,
344
+ // created_at: "TIMESTAMP",
345
+ // updated_at: "TIMESTAMP",
346
+ // }
347
+ ```
348
+
349
+ #### `org.getDams(options?)`
350
+
351
+ List DAMs (Digital Asset Managers) connected to the organization. Supports pagination, sorting, and filtering.
352
+
353
+ ```typescript
354
+ const { items } = await org.getDams({
355
+ page: 1,
356
+ items: 20,
357
+ sort_attribute: 'name', // Sort by 'id', 'uuid', 'name', 'type', or 'base_url'
358
+ sort_direction: 'ASC',
359
+ filters: {
360
+ search: 'assets',
361
+ name: 'My DAM',
362
+ dam_type: 's3', // Filter by DAM type (e.g. 's3', 'cloudinary', 'azure')
363
+ uuid: 'dam-uuid',
364
+ id: 123,
365
+ unlinked_site_uuid: 'site-uuid', // Filter DAMs not linked to a specific site
366
+ site_uuid: 'site-uuid', // Filter DAMs linked to a specific site
367
+ // Date range filters
368
+ created_at_lt: '2024-01-01T00:00:00Z',
369
+ created_at_gt: '2023-01-01T00:00:00Z',
370
+ created_at_lte: '2024-01-01T00:00:00Z',
371
+ created_at_gte: '2023-01-01T00:00:00Z',
372
+ updated_at_lt: '2024-01-01T00:00:00Z',
373
+ updated_at_gt: '2023-01-01T00:00:00Z',
374
+ updated_at_lte: '2024-01-01T00:00:00Z',
375
+ updated_at_gte: '2023-01-01T00:00:00Z',
376
+ },
377
+ });
378
+ // { // PaginatedResponse<Dam>
379
+ // items: [
380
+ // { // Dam
381
+ // uuid: "STRING_VALUE",
382
+ // id: 123,
383
+ // name: "STRING_VALUE",
384
+ // dam_type: "s3",
385
+ // base_url: "STRING_VALUE",
386
+ // created_at: "TIMESTAMP",
387
+ // updated_at: "TIMESTAMP",
388
+ // }
389
+ // ],
390
+ // current_page: 1,
391
+ // total_items: 10,
392
+ // total_pages: 1,
393
+ // }
394
+ ```
395
+
396
+ #### `org.createDam(body)`
397
+
398
+ Create a new DAM connection.
399
+
400
+ ```typescript
401
+ const dam = await org.createDam({
402
+ dam_type: 's3', // DAM type: 's3', 'tenovos', 'cloudinary', 'azure', 'google', 'cloudflare', or 'digitalocean'
403
+ name: 'My Asset Library', // Display name for the DAM
404
+ config: JSON.stringify({ // DAM-specific configuration as a JSON string
405
+ bucket: 'my-bucket',
406
+ region: 'us-east-1',
407
+ }),
408
+ base_url: 'https://cdn.example.com', // Base URL for assets
409
+ access_key: 'access-key', // Optional access key
410
+ access_secret: 'secret', // Optional access secret
411
+ max_upload_size: 10485760, // Optional maximum upload size in bytes
412
+ });
413
+ // { // Dam
414
+ // uuid: "STRING_VALUE",
415
+ // id: 123,
416
+ // name: "My Asset Library",
417
+ // dam_type: "s3",
418
+ // base_url: "https://cdn.example.com",
419
+ // created_at: "TIMESTAMP",
420
+ // updated_at: "TIMESTAMP",
421
+ // }
422
+ ```
423
+
424
+ #### `org.getRepositories(provider)`
425
+
426
+ List repositories available from a given provider (e.g. `github`, `gitlab`, `bitbucket`).
427
+
428
+ ```typescript
429
+ const repos = await org.getRepositories('github');
430
+ // [ // RepositorySchema[]
431
+ // {
432
+ // full_name: "owner/repo",
433
+ // name: "repo",
434
+ // language: "typescript",
435
+ // private: true,
436
+ // avatar_url: "STRING_VALUE",
437
+ // size: 123,
438
+ // permissions: {
439
+ // admin: true,
440
+ // push: true,
441
+ // pull: true,
442
+ // },
443
+ // }
444
+ // ]
445
+ ```
446
+
447
+ ---
448
+
449
+ ### Sites (`client.site(uuid)`)
450
+
451
+ ```typescript
452
+ const site = client.site('site-uuid');
453
+ ```
454
+
455
+ #### `site.get()`
456
+
457
+ Get site details.
458
+
459
+ ```typescript
460
+ const siteDetails = await site.get();
461
+ // { // Site
462
+ // uuid: "STRING_VALUE",
463
+ // id: 123,
464
+ // site_name: "STRING_VALUE",
465
+ // stable_domain: "STRING_VALUE",
466
+ // domain_name: "STRING_VALUE",
467
+ // ssg: "STRING_VALUE",
468
+ // storage_provider: "STRING_VALUE",
469
+ // hosting_choice: "STRING_VALUE",
470
+ // created_at: "TIMESTAMP",
471
+ // updated_at: "TIMESTAMP",
472
+ // }
473
+ ```
474
+
475
+ #### `site.update(body)`
476
+
477
+ Update site settings.
478
+
479
+ ```typescript
480
+ const updatedSite = await site.update({
481
+ site_name: 'Updated Site Name', // New display name for the site
482
+ editing_locked: false, // Whether editing is locked
483
+ active_quest: 'onboarding', // Optional active quest/flow identifier
484
+ cloudcannon_config_path: '/cloudcannon.config.yml', // Optional path to CloudCannon config file
485
+ flags: { // Optional site flags/settings object
486
+ custom_flag: true,
487
+ },
488
+ });
489
+ // { // Site
490
+ // uuid: "STRING_VALUE",
491
+ // id: 123,
492
+ // site_name: "Updated Site Name",
493
+ // stable_domain: "STRING_VALUE",
494
+ // domain_name: "STRING_VALUE",
495
+ // ssg: "STRING_VALUE",
496
+ // storage_provider: "STRING_VALUE",
497
+ // hosting_choice: "STRING_VALUE",
498
+ // created_at: "TIMESTAMP",
499
+ // updated_at: "TIMESTAMP",
500
+ // }
501
+ ```
502
+
503
+ #### `site.delete()`
504
+
505
+ Delete the site.
506
+
507
+ ```typescript
508
+ await site.delete();
509
+ // Returns: void
510
+ ```
511
+
512
+ #### `site.copy(body)`
513
+
514
+ Copy the site to a new site.
515
+
516
+ ```typescript
517
+ const newSite = await site.copy({
518
+ site_name: 'Copy of My Site', // Name for the new copied site
519
+ editing_locked: false, // Whether the new site should have editing locked
520
+ active_quest: null, // Optional active quest for the new site
521
+ cloudcannon_config_path: null, // Optional config path for the new site
522
+ flags: {}, // Optional flags for the new site
523
+ publish_mode: null, // Optional publish mode
524
+ destroy_on_publish: false, // Whether to destroy the site on publish
525
+ });
526
+ // { // Site
527
+ // uuid: "STRING_VALUE",
528
+ // id: 123,
529
+ // site_name: "Copy of My Site",
530
+ // stable_domain: "copy-of-my-site",
531
+ // domain_name: "STRING_VALUE",
532
+ // ssg: "STRING_VALUE",
533
+ // storage_provider: "STRING_VALUE",
534
+ // hosting_choice: "STRING_VALUE",
535
+ // created_at: "TIMESTAMP",
536
+ // updated_at: "TIMESTAMP",
537
+ // }
538
+ ```
539
+
540
+ #### `site.updateBuildConfig(options)`
541
+
542
+ Update the build configuration for the site.
543
+
544
+ ```typescript
545
+ await site.updateBuildConfig({
546
+ default_locale: 'en', // Optional default locale for i18n
547
+ uses_i18n: true, // Whether the site uses internationalization
548
+ building_locked: false, // Whether building is locked
549
+ ssg: 'hugo', // Optional static site generator identifier
550
+ compile: {
551
+ install_command: 'npm install', // Command to run before building
552
+ build_command: 'hugo', // Build command
553
+ output_path: 'public', // Output directory for built files
554
+ environment_variables: [ // Optional environment variables
555
+ { key: 'HUGO_VERSION', value: '0.120.0' },
556
+ ],
557
+ hugoVersion: '0.120.0', // Optional Hugo version
558
+ denoVersion: '1.38.0', // Optional Deno version
559
+ rubyVersion: '3.2.0', // Optional Ruby version
560
+ nodeVersion: '20.0.0', // Optional Node.js version
561
+ preserved_paths: 'node_modules,dist/images', // Paths to preserve between builds (comma separated string)
562
+ preserveOutput: true, // Whether to preserve previous output
563
+ includeGit: false, // Whether to include Git history in build
564
+ manually_configure_urls: false, // Whether to manually configure URLs
565
+ },
566
+ });
567
+ // { // Site
568
+ // uuid: "STRING_VALUE",
569
+ // id: 123,
570
+ // site_name: "STRING_VALUE",
571
+ // stable_domain: "STRING_VALUE",
572
+ // ssg: "hugo",
573
+ // storage_provider: "STRING_VALUE",
574
+ // hosting_choice: "STRING_VALUE",
575
+ // created_at: "TIMESTAMP",
576
+ // updated_at: "TIMESTAMP",
577
+ // }
578
+ ```
579
+
580
+ #### `site.getBuilds(options?)`
581
+
582
+ List all builds for the site. Supports pagination, sorting, and filtering.
583
+
584
+ ```typescript
585
+ const { items } = await site.getBuilds({
586
+ page: 1,
587
+ items: 20,
588
+ sort_attribute: 'created_at', // Sort by 'id', 'uuid', or 'created_at'
589
+ sort_direction: 'DESC',
590
+ filters: {
591
+ search: 'build-123',
592
+ name: 'Production Build',
593
+ successful: true, // Filter by build success status
594
+ pinnable: true, // Filter by pinnable builds
595
+ site_uuid: 'site-uuid',
596
+ uuid: 'build-uuid',
597
+ id: 123,
598
+ completed_at: '2024-01-01T00:00:00Z',
599
+ // Date range filters
600
+ created_at_lt: '2024-01-01T00:00:00Z',
601
+ created_at_gt: '2023-01-01T00:00:00Z',
602
+ created_at_lte: '2024-01-01T00:00:00Z',
603
+ created_at_gte: '2023-01-01T00:00:00Z',
604
+ updated_at_lt: '2024-01-01T00:00:00Z',
605
+ updated_at_gt: '2023-01-01T00:00:00Z',
606
+ updated_at_lte: '2024-01-01T00:00:00Z',
607
+ updated_at_gte: '2023-01-01T00:00:00Z',
608
+ },
609
+ });
610
+ // { // PaginatedResponse<Build>
611
+ // items: [
612
+ // { // Build
613
+ // uuid: "STRING_VALUE",
614
+ // id: 123,
615
+ // name: "STRING_VALUE",
616
+ // site_id: 123,
617
+ // successful: true,
618
+ // completed_at: "TIMESTAMP",
619
+ // created_at: "TIMESTAMP",
620
+ // updated_at: "TIMESTAMP",
621
+ // }
622
+ // ],
623
+ // current_page: 1,
624
+ // total_items: 10,
625
+ // total_pages: 1,
626
+ // }
627
+ ```
628
+
629
+ #### `site.rebuild()`
630
+
631
+ Trigger a new build.
632
+
633
+ ```typescript
634
+ await site.rebuild();
635
+ // Returns: void
636
+ ```
637
+
638
+ #### `site.listBackups(options?)`
639
+
640
+ List backups/archives for the site. Supports pagination, sorting, and filtering.
641
+
642
+ ```typescript
643
+ const { items } = await site.listBackups({
644
+ page: 1,
645
+ items: 20,
646
+ sort_attribute: 'created_at', // Sort by 'id', 'uuid', or 'created_at'
647
+ sort_direction: 'DESC',
648
+ filters: {
649
+ search: 'backup-123',
650
+ uuid: 'backup-uuid',
651
+ id: 123,
652
+ size_gte: 1024, // Minimum backup size in bytes
653
+ size_lt: 104857600, // Maximum backup size (less than)
654
+ size_gt: 1024, // Minimum backup size (greater than)
655
+ size_lte: 104857600, // Maximum backup size (less than or equal)
656
+ // Date range filters
657
+ created_at_lt: '2024-01-01T00:00:00Z',
658
+ created_at_gt: '2023-01-01T00:00:00Z',
659
+ created_at_lte: '2024-01-01T00:00:00Z',
660
+ created_at_gte: '2023-01-01T00:00:00Z',
661
+ updated_at_lt: '2024-01-01T00:00:00Z',
662
+ updated_at_gt: '2023-01-01T00:00:00Z',
663
+ updated_at_lte: '2024-01-01T00:00:00Z',
664
+ updated_at_gte: '2023-01-01T00:00:00Z',
665
+ },
666
+ });
667
+ // { // PaginatedResponse<Backup>
668
+ // items: [
669
+ // { // SiteArchive
670
+ // uuid: "STRING_VALUE",
671
+ // id: 123,
672
+ // path: "STRING_VALUE",
673
+ // size: 123,
674
+ // created_at: "TIMESTAMP",
675
+ // updated_at: "TIMESTAMP",
676
+ // }
677
+ // ],
678
+ // current_page: 1,
679
+ // total_items: 10,
680
+ // total_pages: 1,
681
+ // }
682
+ ```
683
+
684
+ #### `site.createBackup(body?)`
685
+
686
+ Create a new backup. Returns an optional `socket_message_id` for real-time progress updates.
687
+
688
+ ```typescript
689
+ const result = await site.createBackup({
690
+ exclude_git: false, // Whether to exclude Git history from the backup
691
+ });
692
+ // { // { socket_message_id?: string }
693
+ // socket_message_id: "STRING_VALUE",
694
+ // }
695
+ ```
696
+
697
+ #### `site.listFiles()`
698
+
699
+ List files in the site's repository.
700
+
701
+ ```typescript
702
+ const files = await site.listFiles();
703
+ // [ // FileListing[]
704
+ // {
705
+ // md5: "STRING_VALUE",
706
+ // s3Path: "STRING_VALUE",
707
+ // sitePath: "STRING_VALUE",
708
+ // }
709
+ // ]
710
+ ```
711
+
712
+ #### `site.getFile(path)`
713
+
714
+ Fetch a raw file from the site's repository. Returns a `Response` object.
715
+
716
+ ```typescript
717
+ const resp = await site.getFile('README.md');
718
+ const text = await resp.text();
719
+ // Returns: Response — raw fetch Response for the requested file
720
+ ```
721
+
722
+ #### `site.getSyncs(options?)`
723
+
724
+ List syncs for the site. Supports pagination, sorting, and filtering.
725
+
726
+ ```typescript
727
+ const { items } = await site.getSyncs({
728
+ page: 1,
729
+ items: 20,
730
+ sort_attribute: 'created_at', // Sort by 'id', 'uuid', or 'created_at'
731
+ sort_direction: 'DESC',
732
+ filters: {
733
+ search: 'sync-123',
734
+ name: 'Main Sync',
735
+ successful: true, // Filter by sync success status
736
+ provider: 'github', // Filter by provider
737
+ identifier: 'main-branch', // Filter by sync identifier
738
+ after_identifier: 'prev-id', // Filter by after identifier
739
+ diff_id: 'diff-123', // Filter by diff ID
740
+ site_uuid: 'site-uuid',
741
+ uuid: 'sync-uuid',
742
+ id: 123,
743
+ completed_at: '2024-01-01T00:00:00Z',
744
+ // Date range filters
745
+ created_at_lt: '2024-01-01T00:00:00Z',
746
+ created_at_gt: '2023-01-01T00:00:00Z',
747
+ created_at_lte: '2024-01-01T00:00:00Z',
748
+ created_at_gte: '2023-01-01T00:00:00Z',
749
+ updated_at_lt: '2024-01-01T00:00:00Z',
750
+ updated_at_gt: '2023-01-01T00:00:00Z',
751
+ updated_at_lte: '2024-01-01T00:00:00Z',
752
+ updated_at_gte: '2023-01-01T00:00:00Z',
753
+ },
754
+ });
755
+ // { // PaginatedResponse<Sync>
756
+ // items: [
757
+ // { // Sync
758
+ // uuid: "STRING_VALUE",
759
+ // id: 123,
760
+ // name: "STRING_VALUE",
761
+ // successful: true,
762
+ // provider: "github",
763
+ // identifier: "main-branch",
764
+ // created_at: "TIMESTAMP",
765
+ // updated_at: "TIMESTAMP",
766
+ // }
767
+ // ],
768
+ // current_page: 1,
769
+ // total_items: 10,
770
+ // total_pages: 1,
771
+ // }
772
+ ```
773
+
774
+ #### `site.getScan()`
775
+
776
+ Get the latest site scan results.
777
+
778
+ ```typescript
779
+ const scan = await site.getScan();
780
+ // { // SiteScanner
781
+ // uuid: "STRING_VALUE",
782
+ // id: 123,
783
+ // files: 123,
784
+ // html_files: 123,
785
+ // css_files: 123,
786
+ // image_files: 123,
787
+ // js_files: 123,
788
+ // blog_posts: 123,
789
+ // data_files: 123,
790
+ // layouts: 123,
791
+ // total_size: 123,
792
+ // created_at: "TIMESTAMP",
793
+ // updated_at: "TIMESTAMP",
794
+ // }
795
+ ```
796
+
797
+ #### `site.getScreenshotHashes()`
798
+
799
+ Get MD5 hashes for site screenshots.
800
+
801
+ ```typescript
802
+ const hashes = await site.getScreenshotHashes();
803
+ // { // Record<string, string>
804
+ // "desktop": "d41d8cd98f00b204e9800998ecf8427e",
805
+ // "mobile": "d41d8cd98f00b204e9800998ecf8427e",
806
+ // }
807
+ ```
808
+
809
+ #### `site.getScreenshot(device, path)`
810
+
811
+ Fetch a screenshot for a specific path and device (`desktop` or `mobile`). Returns a `Response` object.
812
+
813
+ ```typescript
814
+ const screenshot = await site.getScreenshot('desktop', '/about');
815
+ // Returns: Response — raw image fetch Response
816
+ ```
817
+
818
+ #### `site.connectSourceProvider(options)`
819
+
820
+ Connect a Git repository as the source provider.
821
+
822
+ ```typescript
823
+ await site.connectSourceProvider({
824
+ provider: 'github', // Git provider (e.g. 'github', 'gitlab', 'bitbucket')
825
+ repository: 'owner/repo', // Repository identifier (owner/name)
826
+ branch: 'main', // Branch to connect
827
+ });
828
+ // { // Site
829
+ // uuid: "STRING_VALUE",
830
+ // id: 123,
831
+ // site_name: "STRING_VALUE",
832
+ // stable_domain: "STRING_VALUE",
833
+ // storage_provider: "github",
834
+ // domain_name: "STRING_VALUE",
835
+ // created_at: "TIMESTAMP",
836
+ // updated_at: "TIMESTAMP",
837
+ // }
838
+ ```
839
+
840
+ #### `site.updateSourceProvider(options)`
841
+
842
+ Update the connected source provider's branch or repository.
843
+
844
+ ```typescript
845
+ await site.updateSourceProvider({
846
+ repository: 'owner/new-repo', // Updated repository identifier
847
+ branch: 'develop', // Updated branch name
848
+ });
849
+ // { // Site
850
+ // uuid: "STRING_VALUE",
851
+ // id: 123,
852
+ // site_name: "STRING_VALUE",
853
+ // stable_domain: "STRING_VALUE",
854
+ // storage_provider: "github",
855
+ // domain_name: "STRING_VALUE",
856
+ // created_at: "TIMESTAMP",
857
+ // updated_at: "TIMESTAMP",
858
+ // }
859
+ ```
860
+
861
+ #### `site.disconnectSourceProvider()`
862
+
863
+ Remove the source provider connection.
864
+
865
+ ```typescript
866
+ const updatedSite = await site.disconnectSourceProvider();
867
+ // { // Site
868
+ // uuid: "STRING_VALUE",
869
+ // id: 123,
870
+ // site_name: "STRING_VALUE",
871
+ // stable_domain: "STRING_VALUE",
872
+ // storage_provider: null,
873
+ // domain_name: "STRING_VALUE",
874
+ // created_at: "TIMESTAMP",
875
+ // updated_at: "TIMESTAMP",
876
+ // }
877
+ ```
878
+
879
+ #### `site.connectOutputProvider(options)`
880
+
881
+ Connect a Git repository as the output (built site) provider.
882
+
883
+ ```typescript
884
+ await site.connectOutputProvider({
885
+ provider: 'github', // Git provider
886
+ repository: 'owner/output', // Output repository identifier
887
+ branch: 'gh-pages', // Output branch
888
+ });
889
+ // { // Site
890
+ // uuid: "STRING_VALUE",
891
+ // id: 123,
892
+ // site_name: "STRING_VALUE",
893
+ // stable_domain: "STRING_VALUE",
894
+ // output_storage_provider: "github",
895
+ // domain_name: "STRING_VALUE",
896
+ // created_at: "TIMESTAMP",
897
+ // updated_at: "TIMESTAMP",
898
+ // }
899
+ ```
900
+
901
+ #### `site.disconnectOutputProvider()`
902
+
903
+ Remove the output provider connection.
904
+
905
+ ```typescript
906
+ const updatedSite = await site.disconnectOutputProvider();
907
+ // { // Site
908
+ // uuid: "STRING_VALUE",
909
+ // id: 123,
910
+ // site_name: "STRING_VALUE",
911
+ // stable_domain: "STRING_VALUE",
912
+ // output_storage_provider: null,
913
+ // domain_name: "STRING_VALUE",
914
+ // created_at: "TIMESTAMP",
915
+ // updated_at: "TIMESTAMP",
916
+ // }
917
+ ```
918
+
919
+ #### `site.getInboxConnections()`
920
+
921
+ Get inboxes connected to this site.
922
+
923
+ ```typescript
924
+ const inboxes = await site.getInboxConnections();
925
+ // [ // SiteInbox
926
+ // {
927
+ // uuid: "STRING_VALUE",
928
+ // id: 123,
929
+ // inbox_uuid: "STRING_VALUE",
930
+ // default_inbox: true,
931
+ // visible: true,
932
+ // require_captcha: true,
933
+ // created_at: "TIMESTAMP",
934
+ // updated_at: "TIMESTAMP",
935
+ // }
936
+ // ]
937
+ ```
938
+
939
+ #### `site.connectInbox(body)`
940
+
941
+ Connect an inbox to this site.
942
+
943
+ ```typescript
944
+ const siteInbox = await site.connectInbox({
945
+ inbox_uuid: 'inbox-uuid', // UUID of the inbox to connect
946
+ default_inbox: true, // Whether this is the default inbox for the site
947
+ visible: true, // Whether the inbox is visible
948
+ require_captcha: true, // Whether to require captcha for submissions
949
+ });
950
+ // { // SiteInbox
951
+ // uuid: "STRING_VALUE",
952
+ // id: 123,
953
+ // inbox_uuid: "inbox-uuid",
954
+ // default_inbox: true,
955
+ // visible: true,
956
+ // require_captcha: true,
957
+ // created_at: "TIMESTAMP",
958
+ // updated_at: "TIMESTAMP",
959
+ // }
960
+ ```
961
+
962
+ #### `site.getDamConnections()`
963
+
964
+ Get DAMs connected to this site.
965
+
966
+ ```typescript
967
+ const dams = await site.getDamConnections();
968
+ // [ // SiteDam
969
+ // {
970
+ // uuid: "STRING_VALUE",
971
+ // id: 123,
972
+ // dam_uuid: "STRING_VALUE",
973
+ // uploads_locked: false,
974
+ // reference_key: "STRING_VALUE",
975
+ // created_at: "TIMESTAMP",
976
+ // updated_at: "TIMESTAMP",
977
+ // }
978
+ // ]
979
+ ```
980
+
981
+ #### `site.connectDam(body)`
982
+
983
+ Connect a DAM to this site.
984
+
985
+ ```typescript
986
+ const siteDam = await site.connectDam({
987
+ dam_uuid: 'dam-uuid', // UUID of the DAM to connect
988
+ uploads_locked: false, // Whether uploads to the DAM are locked
989
+ config: { // Optional DAM-specific configuration
990
+ folder: 'site-assets',
991
+ },
992
+ reference_key: 'main-assets', // Optional reference key
993
+ });
994
+ // { // SiteDam
995
+ // uuid: "STRING_VALUE",
996
+ // id: 123,
997
+ // dam_uuid: "dam-uuid",
998
+ // uploads_locked: false,
999
+ // reference_key: "main-assets",
1000
+ // created_at: "TIMESTAMP",
1001
+ // updated_at: "TIMESTAMP",
1002
+ // }
1003
+ ```
1004
+
1005
+ #### `site.getEditingSessions()`
1006
+
1007
+ List editing sessions for the site.
1008
+
1009
+ ```typescript
1010
+ const sessions = await site.getEditingSessions();
1011
+ // [ // EditingSession
1012
+ // {
1013
+ // uuid: "STRING_VALUE",
1014
+ // id: 123,
1015
+ // site_id: 123,
1016
+ // state: "STRING_VALUE",
1017
+ // base_commit_hash: "STRING_VALUE",
1018
+ // created_at: "TIMESTAMP",
1019
+ // updated_at: "TIMESTAMP",
1020
+ // }
1021
+ // ]
1022
+ ```
1023
+
1024
+ #### `site.createEditingSession()`
1025
+
1026
+ Create a new editing session.
1027
+
1028
+ ```typescript
1029
+ const session = await site.createEditingSession();
1030
+ // { // EditingSession
1031
+ // uuid: "STRING_VALUE",
1032
+ // id: 123,
1033
+ // site_id: 123,
1034
+ // state: "STRING_VALUE",
1035
+ // base_commit_hash: "STRING_VALUE",
1036
+ // created_at: "TIMESTAMP",
1037
+ // updated_at: "TIMESTAMP",
1038
+ // }
1039
+ ```
1040
+
1041
+ #### `site.getLatestEditingSession()`
1042
+
1043
+ Get the most recent editing session.
1044
+
1045
+ ```typescript
1046
+ const latestSession = await site.getLatestEditingSession();
1047
+ // { // EditingSession
1048
+ // uuid: "STRING_VALUE",
1049
+ // id: 123,
1050
+ // site_id: 123,
1051
+ // state: "STRING_VALUE",
1052
+ // base_commit_hash: "STRING_VALUE",
1053
+ // created_at: "TIMESTAMP",
1054
+ // updated_at: "TIMESTAMP",
1055
+ // }
1056
+ ```
1057
+
1058
+ #### `site.uploadFile(path, content, options?)`
1059
+
1060
+ Upload a file to the site through an editing session. Content is uploaded to S3 and committed through the editing session workflow.
1061
+
1062
+ ```typescript
1063
+ await site.uploadFile(
1064
+ 'content/posts/hello.md', // Path in the site's repository
1065
+ '# Hello World', // File content (string, Blob, ArrayBuffer, etc.)
1066
+ {
1067
+ type: 'text/markdown', // Optional MIME type (defaults to 'text/plain')
1068
+ overwriteExistingFile: true, // Whether to overwrite if the file already exists
1069
+ }
1070
+ );
1071
+ // Returns: void
1072
+ ```
1073
+
1074
+ #### `site.triggerPull()`
1075
+
1076
+ Manually trigger a pull from the source provider.
1077
+
1078
+ ```typescript
1079
+ await site.triggerPull();
1080
+ // Returns: void
1081
+ ```
1082
+
1083
+ ---
1084
+
1085
+ ### Inboxes (`client.inbox(uuid)`)
1086
+
1087
+ ```typescript
1088
+ const inbox = client.inbox('inbox-uuid');
1089
+ ```
1090
+
1091
+ #### `inbox.getSubmissions(options?)`
1092
+
1093
+ List form submissions for the inbox. Supports pagination, sorting, and filtering.
1094
+
1095
+ ```typescript
1096
+ const { items } = await inbox.getSubmissions({
1097
+ page: 1,
1098
+ items: 20,
1099
+ sort_attribute: 'last_sent_at', // Sort by 'last_sent_at', 'created_at', 'id', or 'uuid'
1100
+ sort_direction: 'DESC',
1101
+ filters: {
1102
+ category: 'pending', // Filter by status: 'spam', 'sent', 'errored', or 'pending'
1103
+ search: 'john@example.com',
1104
+ sent: true, // Filter by sent status
1105
+ spam_checked: true, // Filter by spam checked status
1106
+ automatically_marked_spam: false, // Filter by auto-marked spam
1107
+ explicitly_marked_status: 0, // Filter by explicit status
1108
+ has_error: false, // Filter by error presence
1109
+ has_spam_check_error: false, // Filter by spam check error
1110
+ ip: '192.168.1.1', // Filter by IP address
1111
+ host: 'example.com', // Filter by host
1112
+ inbox_uuid: 'inbox-uuid',
1113
+ site_uuid: 'site-uuid',
1114
+ uuid: 'submission-uuid',
1115
+ id: 123,
1116
+ // Date range filters for cleared_at
1117
+ cleared_at_lt: '2024-01-01T00:00:00Z',
1118
+ cleared_at_gt: '2023-01-01T00:00:00Z',
1119
+ cleared_at_lte: '2024-01-01T00:00:00Z',
1120
+ cleared_at_gte: '2023-01-01T00:00:00Z',
1121
+ // Date range filters for last_sent_at
1122
+ last_sent_at_lt: '2024-01-01T00:00:00Z',
1123
+ last_sent_at_gt: '2023-01-01T00:00:00Z',
1124
+ last_sent_at_lte: '2024-01-01T00:00:00Z',
1125
+ last_sent_at_gte: '2023-01-01T00:00:00Z',
1126
+ // Count filters
1127
+ sent_count_lt: 5,
1128
+ sent_count_gt: 0,
1129
+ sent_count_lte: 10,
1130
+ sent_count_gte: 1,
1131
+ // Standard date range filters
1132
+ created_at_lt: '2024-01-01T00:00:00Z',
1133
+ created_at_gt: '2023-01-01T00:00:00Z',
1134
+ created_at_lte: '2024-01-01T00:00:00Z',
1135
+ created_at_gte: '2023-01-01T00:00:00Z',
1136
+ updated_at_lt: '2024-01-01T00:00:00Z',
1137
+ updated_at_gt: '2023-01-01T00:00:00Z',
1138
+ updated_at_lte: '2024-01-01T00:00:00Z',
1139
+ updated_at_gte: '2023-01-01T00:00:00Z',
1140
+ },
1141
+ });
1142
+ // { // PaginatedResponse<FormSubmission>
1143
+ // items: [
1144
+ // { // FormHook
1145
+ // uuid: "STRING_VALUE",
1146
+ // id: 123,
1147
+ // sent: true,
1148
+ // ip: "STRING_VALUE",
1149
+ // host: "STRING_VALUE",
1150
+ // data: {},
1151
+ // created_at: "TIMESTAMP",
1152
+ // updated_at: "TIMESTAMP",
1153
+ // }
1154
+ // ],
1155
+ // current_page: 1,
1156
+ // total_items: 10,
1157
+ // total_pages: 1,
1158
+ // }
1159
+ ```
1160
+
1161
+ ---
1162
+
1163
+ ### Site Inboxes (`client.siteInbox(uuid)`)
1164
+
1165
+ ```typescript
1166
+ const siteInbox = client.siteInbox('site-inbox-uuid');
1167
+ ```
1168
+
1169
+ #### `siteInbox.update(body)`
1170
+
1171
+ Update a site-inbox connection.
1172
+
1173
+ ```typescript
1174
+ const updated = await siteInbox.update({
1175
+ inbox_uuid: 'inbox-uuid', // UUID of the inbox to link
1176
+ default_inbox: true, // Whether this is the default inbox for the site
1177
+ visible: true, // Whether the inbox is visible on the site
1178
+ require_captcha: true, // Whether to require captcha for form submissions
1179
+ });
1180
+ // { // SiteInbox
1181
+ // uuid: "STRING_VALUE",
1182
+ // id: 123,
1183
+ // inbox_uuid: "inbox-uuid",
1184
+ // default_inbox: true,
1185
+ // visible: true,
1186
+ // require_captcha: true,
1187
+ // created_at: "TIMESTAMP",
1188
+ // updated_at: "TIMESTAMP",
1189
+ // }
1190
+ ```
1191
+
1192
+ ---
1193
+
1194
+ ### Editing Sessions (`client.editingSession(uuid)`)
1195
+
1196
+ ```typescript
1197
+ const session = client.editingSession('session-uuid');
1198
+ ```
1199
+
1200
+ #### `session.get()`
1201
+
1202
+ Get editing session details.
1203
+
1204
+ ```typescript
1205
+ const sessionDetails = await session.get();
1206
+ // { // EditingSession
1207
+ // uuid: "STRING_VALUE",
1208
+ // id: 123,
1209
+ // site_id: 123,
1210
+ // state: "STRING_VALUE",
1211
+ // base_commit_hash: "STRING_VALUE",
1212
+ // created_at: "TIMESTAMP",
1213
+ // updated_at: "TIMESTAMP",
1214
+ // }
1215
+ ```
1216
+
1217
+ #### `session.getFiles()`
1218
+
1219
+ List files in the editing session.
1220
+
1221
+ ```typescript
1222
+ const files = await session.getFiles();
1223
+ // [ // EditingSessionFile
1224
+ // {
1225
+ // uuid: "STRING_VALUE",
1226
+ // id: 123,
1227
+ // editing_session_uuid: "STRING_VALUE",
1228
+ // path: "STRING_VALUE",
1229
+ // source_path: "STRING_VALUE",
1230
+ // edit_type: "STRING_VALUE",
1231
+ // created_at: "TIMESTAMP",
1232
+ // updated_at: "TIMESTAMP",
1233
+ // }
1234
+ // ]
1235
+ ```
1236
+
1237
+ #### `session.createFile(body)`
1238
+
1239
+ Create a new file in the editing session.
1240
+
1241
+ ```typescript
1242
+ const file = await session.createFile({
1243
+ edit_type: 'update', // Type of edit: 'update', 'delete'.
1244
+ path: 'content/new-post.md', // Target path for the file
1245
+ source_path: 'content/draft.md', // Optional source path (for move/copy operations)
1246
+ discard_unsaved: false, // Whether to discard any unsaved changes
1247
+ previous_content_hash: 'abc123', // Optional hash of the previous content
1248
+ metadata: { // Optional metadata object
1249
+ title: 'New Post',
1250
+ },
1251
+ });
1252
+ // { // EditingSessionFile
1253
+ // uuid: "STRING_VALUE",
1254
+ // id: 123,
1255
+ // editing_session_uuid: "STRING_VALUE",
1256
+ // path: "content/new-post.md",
1257
+ // edit_type: "create",
1258
+ // created_at: "TIMESTAMP",
1259
+ // updated_at: "TIMESTAMP",
1260
+ // }
1261
+ ```
1262
+
1263
+ #### `session.commit()`
1264
+
1265
+ Commit the editing session, pushing changes to the connected repository.
1266
+
1267
+ ```typescript
1268
+ const result = await session.commit();
1269
+ // { // CommitEditingSessionResponse
1270
+ // socket_message_id: "STRING_VALUE",
1271
+ // }
1272
+ ```
1273
+
1274
+ ---
1275
+
1276
+ ### Editing Session Files (`client.editingSessionFile(uuid)`)
1277
+
1278
+ ```typescript
1279
+ const file = client.editingSessionFile('file-uuid');
1280
+ ```
1281
+
1282
+ #### `file.get()`
1283
+
1284
+ Get details for an editing session file.
1285
+
1286
+ ```typescript
1287
+ const fileDetails = await file.get();
1288
+ // { // EditingSessionFile
1289
+ // uuid: "STRING_VALUE",
1290
+ // id: 123,
1291
+ // editing_session_uuid: "STRING_VALUE",
1292
+ // path: "STRING_VALUE",
1293
+ // source_path: "STRING_VALUE",
1294
+ // edit_type: "STRING_VALUE",
1295
+ // created_at: "TIMESTAMP",
1296
+ // updated_at: "TIMESTAMP",
1297
+ // }
1298
+ ```
1299
+
1300
+ #### `file.getContributions()`
1301
+
1302
+ List contributions (versions) for the file.
1303
+
1304
+ ```typescript
1305
+ const contributions = await file.getContributions();
1306
+ // [ // EditingSessionFileContribution
1307
+ // {
1308
+ // uuid: "STRING_VALUE",
1309
+ // id: 123,
1310
+ // editing_session_file_uuid: "STRING_VALUE",
1311
+ // session_uuid: "STRING_VALUE",
1312
+ // state: "STRING_VALUE",
1313
+ // file_contents: "STRING_VALUE",
1314
+ // content_hash: "STRING_VALUE",
1315
+ // created_at: "TIMESTAMP",
1316
+ // updated_at: "TIMESTAMP",
1317
+ // }
1318
+ // ]
1319
+ ```
1320
+
1321
+ #### `file.createContribution(body)`
1322
+
1323
+ Create a new contribution for the file.
1324
+
1325
+ ```typescript
1326
+ const contribution = await file.createContribution({
1327
+ s3_key: 'uploads/12345/content.md', // S3 key where the file content is stored
1328
+ content_hash: 'd41d8cd98f00b204e9800998ecf8427e', // MD5 hash of the new content
1329
+ previous_content_hash: 'abc123def456', // Optional hash of the previous content for conflict detection
1330
+ });
1331
+ // { // EditingSessionFileContribution
1332
+ // uuid: "STRING_VALUE",
1333
+ // id: 123,
1334
+ // editing_session_file_uuid: "STRING_VALUE",
1335
+ // session_uuid: "STRING_VALUE",
1336
+ // state: "STRING_VALUE",
1337
+ // file_contents: "STRING_VALUE",
1338
+ // content_hash: "d41d8cd98f00b204e9800998ecf8427e",
1339
+ // created_at: "TIMESTAMP",
1340
+ // updated_at: "TIMESTAMP",
1341
+ // }
1342
+ ```
1343
+
1344
+ #### `file.unlock(body)`
1345
+
1346
+ Unlock the file so other users can edit it.
1347
+
1348
+ ```typescript
1349
+ const contribution = await file.unlock({
1350
+ previous_content_hash: 'd41d8cd98f00b204e9800998ecf8427e', // Expected current content hash
1351
+ });
1352
+ // { // EditingSessionFileContribution
1353
+ // uuid: "STRING_VALUE",
1354
+ // id: 123,
1355
+ // editing_session_file_uuid: "STRING_VALUE",
1356
+ // session_uuid: "STRING_VALUE",
1357
+ // state: "STRING_VALUE",
1358
+ // file_contents: "STRING_VALUE",
1359
+ // content_hash: "STRING_VALUE",
1360
+ // created_at: "TIMESTAMP",
1361
+ // updated_at: "TIMESTAMP",
1362
+ // }
1363
+ ```
1364
+
1365
+ ---
1366
+
1367
+ ### Builds (`client.build(uuid)`)
1368
+
1369
+ ```typescript
1370
+ const build = client.build('build-uuid');
1371
+ ```
1372
+
1373
+ #### `build.get()`
1374
+
1375
+ Get build details. Returns a `Response` object.
1376
+
1377
+ ```typescript
1378
+ const resp = await build.get();
1379
+ const buildData = await resp.json();
1380
+ // { // Build
1381
+ // uuid: "STRING_VALUE",
1382
+ // id: 123,
1383
+ // name: "STRING_VALUE",
1384
+ // site_id: 123,
1385
+ // successful: true,
1386
+ // completed_at: "TIMESTAMP",
1387
+ // created_at: "TIMESTAMP",
1388
+ // updated_at: "TIMESTAMP",
1389
+ // }
1390
+ ```
1391
+
1392
+ ---
1393
+
1394
+ ### Backups (`client.backup(uuid)`)
1395
+
1396
+ ```typescript
1397
+ const backup = client.backup('backup-uuid');
1398
+ ```
1399
+
1400
+ #### `backup.download()`
1401
+
1402
+ Download a backup archive. Returns a `Response` object.
1403
+
1404
+ ```typescript
1405
+ const resp = await backup.download();
1406
+ // Returns: Response — raw binary fetch Response (consume the body stream)
1407
+ ```
1408
+
1409
+ ---
1410
+
1411
+ ### Syncs (`client.sync(uuid)`)
1412
+
1413
+ ```typescript
1414
+ const sync = client.sync('sync-uuid');
1415
+ ```
1416
+
1417
+ #### `sync.get()`
1418
+
1419
+ Get sync details. Returns a `Response` object.
1420
+
1421
+ ```typescript
1422
+ const resp = await sync.get();
1423
+ const syncData = await resp.json();
1424
+ // { // Sync
1425
+ // uuid: "STRING_VALUE",
1426
+ // id: 123,
1427
+ // name: "STRING_VALUE",
1428
+ // successful: true,
1429
+ // provider: "github",
1430
+ // identifier: "STRING_VALUE",
1431
+ // created_at: "TIMESTAMP",
1432
+ // updated_at: "TIMESTAMP",
1433
+ // }
1434
+ ```
1435
+
1436
+ ---
1437
+
1438
+ ## Pagination, sorting, and filtering
1439
+
1440
+ Many list methods support pagination, sorting, and filtering through a common options shape. The examples above show the available options for each endpoint. In general:
1441
+
1442
+ - `page` and `items` control pagination.
1443
+ - `sort_attribute` and `sort_direction` control ordering.
1444
+ - `filters` is an object of endpoint-specific query parameters.
1445
+
1446
+ Responses from paginated endpoints return:
1447
+
1448
+ ```typescript
1449
+ {
1450
+ items: T[]; // Array of results for the current page
1451
+ current_page?: number; // Current page number
1452
+ total_items?: number; // Total number of items across all pages
1453
+ total_pages?: number; // Total number of pages available
1454
+ }
1455
+ ```
1456
+
1457
+ ---
1458
+
1459
+ ## Error handling
1460
+
1461
+ The SDK throws standard `Error` objects for permission and not-found failures. For validation errors (HTTP 422), it throws an `ApiError` which includes the full validation messages, the request URL, and the original status code.
1462
+
1463
+ ```typescript
1464
+ import { ApiError } from '@cloudcannon/sdk';
1465
+
1466
+ try {
1467
+ await site.update({ site_name: '' });
1468
+ } catch (err) {
1469
+ if (err instanceof ApiError) {
1470
+ console.error(err.status); // 422
1471
+ console.error(err.errors); // Detailed validation errors from the API
1472
+ console.error(err.url); // The endpoint that failed
1473
+ }
1474
+ }
1475
+ ```
1476
+
1477
+ ---
1478
+
1479
+ ## Advanced: using the raw `client.fetch`
1480
+
1481
+ The root client exposes a strongly-typed `fetch` method that you can use to call any CloudCannon API endpoint directly. The URL and request body are typed against the OpenAPI schema, so TypeScript will autocomplete valid paths and validate request shapes.
1482
+
1483
+ ```typescript
1484
+ // GET request to an arbitrary endpoint
1485
+ const resp = await client.fetch('/orgs/my-org', {
1486
+ method: 'GET',
1487
+ });
1488
+ const org = await resp.json();
1489
+ ```
1490
+
1491
+ ```typescript
1492
+ // POST with a typed request body
1493
+ const resp = await client.fetch('/orgs/my-org/sites', {
1494
+ method: 'POST',
1495
+ body: {
1496
+ site_name: 'My New Site',
1497
+ },
1498
+ });
1499
+ const site = await resp.json();
1500
+ ```
1501
+
1502
+ `fetch` automatically injects your authentication headers and sets `Content-Type: application/json`. It returns a typed response object keyed by HTTP status codes, so you can handle success and error cases with full type safety.
1503
+
1504
+ ```typescript
1505
+ const resp = await client.fetch('/sites/site-uuid');
1506
+
1507
+ if (resp.status === 200) {
1508
+ const site = await resp.json();
1509
+ } else if (resp.status === 404) {
1510
+ // Handle not found
1511
+ }
1512
+ ```
1513
+
1514
+ This is useful when you need to access endpoints that are not yet covered by the high-level sub-clients, or when you need full control over headers and fetch options.