> For the complete documentation index, see [llms.txt](https://academy.shade.inc/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://academy.shade.inc/developers/guides/synchronizing-file-state.md).

# Syncing & reacting to file changes

### Sync

#### This docs page is for you if you

* Are trying to keep the state of your drive file tree in sync with something else
  * "Something else" being a database, a spreadsheet, a local file system, or a remote file system
* Want to make some automation off of a created/deleted/moved file or folder

#### This page is NOT for you if

* You're not a developer — we'll be making an easier-to-use version of this soon

### Theory

The most reliable way to sync two systems is to give references to the changes over time, allowing the client\
trying to perform the sync to acknowledge, replay, apply the diff before ensuring database integrity\
and moving onto the next change

An example of this is like in git VCS where there are a series of commits and the difference between\
two commits is given by a "patch" if you want to end up with the current state of the tree you apply\
these patches to your local system which will add together to end up with the resultant state\
(ok not exactly like that, but it works in this example).

The sync is similar though in this case where you query our servers for a patch, if there's a new patch\
you apply that patch to your system — at the end of the day when you sum everything it will be correct.

### How to

#### Getting the patch diff

1. Get an API key
2. Set up your listener system to periodically use that key to redeem a ShadeFS JWT using the route `GET https://api.shade.inc/workspaces/drives/{drive_id}/shade-fs-token`
   * The account the API key belongs to needs edit access to the drive
   * This will return a JWT that is currently valid for one hour — read its `exp` claim and fetch a new one before it expires
3. Now you can use that JWT to see the current "head" for your drive, this is a hash that represents the current state
   * Do this by calling `GET https://fs.shade.inc/{drive_id}/heads/current`, with your JWT as the "Authorization" header — this will return a hash like `972d06bb83b2979f7bd5d2e1e98aa0da2b763ffa7a5a408fee27c1d561e45754`
4. To get your first patch diff you can get the lifetime history of the drive
   * Do this by calling `GET https://fs.shade.inc/{drive_id}/heads/compare?to=your_hash_you_got`
   * This will give back a JSON object with `drive`, `startCommit`, `endCommit`, and a `patchDiff` object containing the changes (see below)
5. As heads come in, the result returned by `heads/current`, compare that against the previous patch head you applied,\
   if they're different, then perform the patch diff with `GET https://fs.shade.inc/{drive_id}/heads/compare?from=previous_head&to=new_head`

#### What's in the patch diff

All changes are under the `patchDiff` key. Every path is an array of path segments relative to the drive root, for example `["Project", "Ep 1", "clip.mov"]`.

| Key                      | Contents                                                              |
| ------------------------ | --------------------------------------------------------------------- |
| `deletedFolders`         | Folders that were deleted                                             |
| `deletedFiles`           | All deleted files, including null, draft, and main files              |
| `renames`                | Moves and renames. Each entry has a `before` path and an `after` path |
| `createdMainFiles`       | New files that are fully uploaded                                     |
| `createdDraftFiles`      | New files that are still uploading                                    |
| `createdNullFiles`       | New empty files                                                       |
| `nullOrDraftToMainFiles` | Existing null or draft files that are now fully uploaded              |
| `mainOrNullToDraftFiles` | Existing main or null files that are being uploaded again             |
| `draftOrMainToNullFiles` | Existing draft or main files that became empty                        |
| `modifiedMainFiles`      | Main files whose contents changed                                     |
| `modifiedDraftFiles`     | Draft files whose contents changed                                    |
| `createdFolders`         | Folders that were created                                             |

#### Applying the patch diff

Now that you have a diff it can be parsed into changes fairly easily\
An entry for the "blob state" must be kept as well if its "null" "draft" or "main"\
Null means an empty file, draft means a file thats still being uploaded and is inaccessible and main means a fully uploaded and accessible file

1. First delete the folders in `deletedFolders`, along with everything inside them
2. Delete the files in `deletedFiles`
3. Apply the `renames` by moving each file or folder from its `before` path to its `after` path. A rename whose `after` path is inside `.trash` means the item was moved to the trash
4. Upsert the files as main if they're in `createdMainFiles` or `nullOrDraftToMainFiles`
5. Upsert the files as draft if they're in `createdDraftFiles` or `mainOrNullToDraftFiles`
6. Upsert the files as null if they're in `createdNullFiles` or `draftOrMainToNullFiles`
7. Delete and reinsert the asset if it's in `modifiedMainFiles` (as main) or `modifiedDraftFiles` (as draft)
8. Finally create the folders in `createdFolders`

You should end up with all of your files in sync

Order matters for folders. For example, if you move a folder out and then delete its parent, applying the operations in the wrong order can accidentally delete all files\
under the directory and then "attempt and fail" to move the files in it out of it — so follow the order above, and if your system creates folders implicitly,\
it's generally safer to create a folder when a file needs it and delete it once it goes empty.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://academy.shade.inc/developers/guides/synchronizing-file-state.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `build a script that syncs our docs to a CMS` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
