Keep a mirror or index in sync with a drive: delta queries
(root/delta), a sync-changes loop that walks every page to the
new delta link, 410 Gone resync handling, and change-notification
subscriptions for the drive root.
Sync loop
- Once:
link ::delta/latest-delta-link()("changes from now on"), orsync-changes(null)to enumerate everything first. - Each run (a schedule, or when a notification arrives):
set ::delta/sync-changes(link); upsertchanged-items(set), dropdeleted-ids(set), storeset.delta-link. - When
set.resyncis true, Graph threw the old link away (410) andsetis a full enumeration: withresync-mode"resyncChangesApplyDifferences"replace local state with it (delete local ids not in the set:stale-ids); with"resyncChangesUploadDifferences"keep local-only items and reconcile them yourself.
Rules from Graph. Track items by id (delta omits paths, and an
item can appear more than once: the last one wins). Deleted items
carry a deleted facet and may have no name. On OneDrive for work
or school and SharePoint, delta works only from the drive root.
Push. subscribe asks Graph to POST to your HTTPS endpoint when
anything in the drive changes (updated on the root is the only
option for drives). Notifications carry no item data: treat one as
"run sync-changes now". Subscriptions last at most 42,300 minutes
(under 30 days); renew from a schedule with renew-subscription.
Permissions. Files.Read / Files.Read.All (delegated),
Files.Read.All or Sites.Read.All (app-only). Prefer headers
such as hierarchicalsharing or deltashowsharingchanges go in
opts.prefer.
Values
DEFAULT_MAX_PAGES
DEFAULT_MAX_PAGES: Int 5000
DELTA_LOCAL_KEYS
DELTA_LOCAL_KEYS: Vec [
"delta-token",
"prefer",
"max-pages"
]
RESYNC_CODES
RESYNC_CODES: Vec [
"resyncChangesApplyDifferences",
"resyncChangesUploadDifferences",
"resyncRequired"
]
Functions
build-delta-set
fn (items: Vec, delta-link: Str, pages: Int, resync-mode: Str?): DeltaSet
Assemble a DeltaSet from collected items (pure).
changed-files
fn (set: Any): Vec
changed-items without folders and packages (pure).
changed-items
fn (set: Any): Vec
The live (not deleted) items of a DeltaSet (or a Vec of driveItems) as DocFiles, folders included; filter on is-folder for files only (pure).
classify-delta-response
fn (response: Result): DeltaPage
Interpret a delta HTTP response (pure): a DeltaPage, with gone for 410; an Err for other failures.
deleted-ids
fn (set: Any): Vec
The ids a DeltaSet (or a Vec of driveItems) deleted (pure). Delete a folder locally only once it is empty after applying the set.
delta-headers
fn (opts: Map): Map
delta-page
fn (link: Str?): DeltaPage
fn (link: Str?, opts: Map): DeltaPage
Fetch one delta page: GET link (a nextLink or deltaLink) when given,
else the drive's first delta URL (delta-path). Returns a
DeltaPage; a 410 is returned as gone: true rather than an Err.
delta-path
fn (opts: Map): Str
The first delta URL for a drive (pure): {drive}/root/delta, with token=latest / a token / a timestamp from opts.delta-token, and OData options (select, top, expand).
is-deleted
fn (item: Map): Bool
True when a delta item carries a deleted facet (pure).
latest-by-id
fn (items: Vec): Vec
Keep the last occurrence of each item id, in order of last appearance (pure). Items without an id are dropped.
latest-delta-link
fn (): Str
fn (opts: Map): Str
GET {drive}/root/delta?token=latest - a delta link for "changes from now on", without enumerating the drive. Store it and pass it to sync-changes.
renew-subscription
fn (subscription-id: Str): Map
fn (subscription-id: Str, opts: Map): Map
Extend a drive subscription to the maximum lifetime (minus an hour),
or opts.expires-in-minutes. Run it from a schedule well inside the
lifetime, e.g. weekly.
renew-onedrive-subscription
meta {schedule: "0 5 * * 1"}
fn (event) {
sub-id ::hot::store/get(::hot::store/Map({name: "onedrive-sync"}), "subscription-id")
::microsoft::onedrive::delta/renew-subscription(sub-id)
}
stale-ids
fn (local-ids: Vec, set: Map): Vec
For a resync set (resync-mode resyncChangesApplyDifferences): the
local-ids that the full enumeration no longer contains, which you
should delete locally (pure). Empty for a normal incremental set.
subscribe
fn (notification-url: Str): Map
fn (notification-url: Str, opts: Map): Map
Subscribe notification-url to changes anywhere in a drive
(updated on its root; the only change type drives support). opts
takes drive, client-state (recommended; at most 128 characters),
lifecycle-url, expires-in-minutes (default the 42,300-minute cap
minus an hour) and credentials. Returns the subscription; keep its
id.
sub ::microsoft::onedrive::delta/subscribe("https://api.example.com/onedrive/hook", {
client-state: ::hot::ctx/get("microsoft.graph.client-state")
})
subscription-resource
fn (opts: Map): Str
The subscription resource for a drive's root (pure): me/drive/root, drives/{id}/root, users/{id}/drive/root, ...
sync-changes
fn (delta-link: Str?): DeltaSet
fn (delta-link: Str?, opts: Map): DeltaSet
Read every delta page since delta-link (null: enumerate the whole
drive) and return a DeltaSet with the link to use next time. A
410 Gone restarts the enumeration from Graph's Location and
marks the set resync (see the namespace doc). opts takes drive,
select, top, prefer, max-pages (default 5000) and credentials.
::delta ::microsoft::onedrive::delta
set ::delta/sync-changes(saved-link)
upserts ::delta/changed-items(set) // DocFiles to (re)index
deletes ::delta/deleted-ids(set) // ids to drop
saved-link set.delta-link
sync-loop
fn (link: Str?, opts: Map, acc: Vec, pages: Int, resync-mode: Str?, max-pages: Int): DeltaSet
Types
DeltaPage
DeltaPage type {
items: Vec,
next-link: Str?,
delta-link: Str?,
gone: Bool,
resync-code: Str?,
restart-link: Str?
}
One delta response: items (value), next-link, delta-link, or
for a 410 Gone: gone: true, resync-code (Graph's error code)
and restart-link (the Location header to enumerate from scratch,
null when Graph sent none).
DeltaSet
DeltaSet type {
items: Vec,
deleted-ids: Vec,
delta-link: Str,
pages: Int,
resync: Bool,
resync-mode: Str?
}
Everything that changed since a delta link.
items- driveItems in feed order, latest occurrence per iddeleted-ids- ids of items with adeletedfacet (not seen alive later)delta-link- store it and pass it to the nextsync-changespages- how many pages were readresync- true when Graph answered 410 and this is a full enumerationresync-mode- Graph's code (resyncChangesApplyDifferences,resyncChangesUploadDifferences), whenresync