Initial Commit
This commit is contained in:
91
openspec/specs/drive-react-sharing/spec.md
Normal file
91
openspec/specs/drive-react-sharing/spec.md
Normal file
@@ -0,0 +1,91 @@
|
||||
# @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.
|
||||
Reference in New Issue
Block a user