@cloudcannon/sdk 0.0.3 → 0.0.5

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