Files
suaveplan/openspec/specs/drive-react-sharing/spec.md
2026-05-27 23:29:53 +01:00

3.6 KiB

@suaveplan/drive-react-sharing — React Bindings for Drive Sharing

React-tier UI for managing partitioned drive resources. Wraps the real @suaveplan/drive-sharing engine (PartitionManager / GrantManager / TokenManager) behind a useSharing hook + three accessible components.

Requirements

Requirement: useSharing hook

The package SHALL expose useSharing(options): UseSharingResult that:

  • Holds a live recipients list synchronised with GrantManager.list().
  • Exposes async actions addRecipient, removeRecipient, updatePermission, refresh. Each action MUST surface failures as DriveReactSharingError (typed cause preserving the underlying DriveShareError).
  • Increments OTel counters drive.react.sharing.recipients_added_total, drive.react.sharing.recipients_removed_total, drive.react.sharing.permissions_updated_total{permission} on each successful action.
  • Threads AbortSignal through every async path.
  • Does NOT mock the engine — consumers pass real PartitionManager / GrantManager / TokenManager instances.

Scenario: updatePermission preserves expiresAt

  • WHEN updatePermission(grantId, newPermission) is called on a grant with expiresAt set
  • THEN the resulting grant MUST have the same expiresAt value as before (the hook revokes-then-creates internally since GrantManager has no atomic permission mutation).

Requirement: ShareDialog component

The package SHALL expose <ShareDialog> modal with:

  • role="dialog" + aria-modal="true" + aria-labelledby referencing the heading id.
  • ESC key dismisses (handler bound to dialog onKeyDown).
  • Backdrop is a real <button> with distinct aria-label.
  • Recipient input auto-focuses on open.
  • Permission select (read | write | admin) with explicit aria-label.
  • Revoke button per row with aria-label including recipient id.
  • Error banner rendered with role="alert".

Requirement: PartitionBadge component

The package SHALL expose <PartitionBadge> compact indicator with:

  • role="status" + composed aria-label (e.g. "Partition type shared, encrypted").
  • Decorative SVG marked aria-hidden="true".
  • Renders partition type (public | shared | private | encrypted) + an encryption icon when applicable.

Requirement: FileAccessList component

The package SHALL expose <FileAccessList> read-only list:

  • Semantic <ul> / <li> markup (no redundant explicit role).
  • Revoke button per row with aria-label including recipient id.
  • Delete / Backspace keyboard shortcuts on focused row trigger revoke.

Requirement: Canonical Permission union

The package SHALL re-export Permission from @suaveplan/drive-sharing as its canonical type and MUST NOT define a parallel union. Components accept "read" | "write" | "admin" strings; the hook validates against the engine's known permission set.

Requirement: Storybook coverage

Each component SHALL ship a .stories.tsx with Default + Playground + state variants (loading / error / populated / empty as applicable). The Playground story for <ShareDialog> MUST wire state through useSharing to exercise the hook end-to-end without an addon story type.

Requirement: Real-engine tests

Tests MUST construct real MemoryPartitionManager / MemoryGrantManager / MemoryTokenManager instances. NO vi.mock, NO vi.stubGlobal. Rendering uses @suaveplan/testing-dom. All test imports come from @suaveplan/testing/runner.

Requirement: Coverage + gate

bunx turbo lint typecheck test:coverage --filter=@suaveplan/drive-react-sharing MUST be green and istanbul coverage MUST be 100% on every touched module before any release.