// `sync.reset` — DESCRIPTOR (browser-safe). // // Rewind the sync. By default it clears ONLY the cursor — a following // `sync.pull` then re-reads from the start but SKIPS everything, because the // idempotency markers survive independently (proof the two KV concerns don't // depend on each other). Pass `markers: true` to also drop the markers, which // makes the next `sync.pull` re-ingest from scratch. import { defineAction } from '@voltro/protocol' import { Schema } from 'effect' export const syncReset = defineAction({ name: 'sync.reset', // Open — but note what bounds the blast radius, because it is a deliberate // choice in the executor and not a property of "reset": it deletes only keys // under `sync::`, never `ctx.kv.clear()`, which would drop // the app's ENTIRE KV namespace across every tenant in one call. It destroys // no rows; a following `sync.pull` rebuilds the watermark. // // No auth strategy and no rbac ship here, so a scope guard would deny every // caller rather than the wrong ones. An operational reset is a good candidate // for a `guards: [{ scope: 'sync:admin' }]` the moment you have an identity. openAccess: 'deletes only the request tenant\'s own `sync::` keys — never `ctx.kv.clear()`, ' + 'which would wipe every tenant\'s namespace — and destroys no rows; the next `sync.pull` ' + 'rebuilds the watermark. An operational reset: guard it once an identity exists.', input: Schema.Struct({ // Also delete the idempotency markers (default: keep them). markers: Schema.optional(Schema.Boolean), }), output: Schema.Struct({ cursorCleared: Schema.Boolean, // did a cursor exist? markersCleared: Schema.Int, // how many markers were dropped }), })