first commit
This commit is contained in:
142
docs/foundation/data/clipboard/src/manager/manager.md
Normal file
142
docs/foundation/data/clipboard/src/manager/manager.md
Normal file
@@ -0,0 +1,142 @@
|
||||
# `manager/manager.ts`
|
||||
|
||||
<!-- begin:auto-docs -->
|
||||
_(no submodules)_
|
||||
<!-- end:auto-docs -->
|
||||
|
||||
## Purpose
|
||||
|
||||
`ClipboardManager` is the orchestrator class for `@suaveplan/clipboard`.
|
||||
It composes the navigator + window seams, the FIFO `AsyncQueue`, the
|
||||
typed error registry, the OpenTelemetry observability bundle, the
|
||||
secure-context guard, the permission probe, and the fallback path into a
|
||||
single ergonomic facade. Every public method records counters, the
|
||||
operation latency histogram, and per-code error totals so production
|
||||
deployments observe clipboard health without any caller-side wiring.
|
||||
|
||||
## Features
|
||||
|
||||
- `copyText`, `copyRichContent`, `readText`, `readRichContent` with
|
||||
consistent `ClipboardResult` returns.
|
||||
- `checkPermissions` + `onPermissionChange` for permission lifecycle.
|
||||
- `isSupported`, `isSecure`, `dispose` for environment + lifecycle.
|
||||
- Configurable serialization (`serialize: true` by default).
|
||||
- Configurable secure-context guard (`requireSecureContext`).
|
||||
- Optional sanitizer hook applied to inbound HTML.
|
||||
- Optional pre-built observability bundle.
|
||||
- Focus-aware retry on `NotAllowedError: Document is not focused`.
|
||||
|
||||
## Usage: Basic
|
||||
|
||||
```ts
|
||||
import { ClipboardManager } from "@suaveplan/clipboard";
|
||||
|
||||
const clipboard = new ClipboardManager();
|
||||
const result = await clipboard.copyText("hello");
|
||||
if (!result.success) {
|
||||
console.warn("copy failed:", result.code, result.error);
|
||||
}
|
||||
```
|
||||
|
||||
## Usage: Advanced
|
||||
|
||||
```ts
|
||||
import {
|
||||
ClipboardManager,
|
||||
createClipboardObservability,
|
||||
createTagAllowlistSanitizer,
|
||||
} from "@suaveplan/clipboard";
|
||||
|
||||
const observability = createClipboardObservability();
|
||||
const clipboard = new ClipboardManager({
|
||||
useFallback: true,
|
||||
requireSecureContext: true,
|
||||
serialize: true,
|
||||
focusRetry: true,
|
||||
sanitizer: createTagAllowlistSanitizer(["p", "b", "i", "br"]),
|
||||
pasteTimeoutMs: 2000,
|
||||
observability,
|
||||
});
|
||||
|
||||
const png = await loadPngBlob();
|
||||
await clipboard.copyRichContent({
|
||||
text: "fallback text",
|
||||
html: "<b>bold</b>",
|
||||
image: png,
|
||||
});
|
||||
|
||||
const unsub = await clipboard.onPermissionChange((snapshot, name) => {
|
||||
console.info("permission change", name, snapshot);
|
||||
});
|
||||
|
||||
// later: unsub(); await clipboard.dispose();
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
### `new ClipboardManager(options?, nav?, win?)`
|
||||
|
||||
Construct a manager. `options` is merged on top of
|
||||
`DEFAULT_CLIPBOARD_OPTIONS`. `nav` and `win` default to the global
|
||||
`navigator` and `window`; either may be supplied as a structural shape
|
||||
for SSR or unit tests.
|
||||
|
||||
### `copyText(text): Promise<ClipboardResult<string>>`
|
||||
|
||||
Copy plain text. Uses the async API when available; falls back to the
|
||||
hidden-textarea path on rejection or absence when `useFallback` is true.
|
||||
Short-circuits with `CLIPBOARD.INSECURE_CONTEXT` when
|
||||
`requireSecureContext` is set and the bound window is insecure.
|
||||
|
||||
### `copyRichContent(data): Promise<ClipboardResult<ClipboardData>>`
|
||||
|
||||
Copy rich content (text / html / image / blobs) via `ClipboardItem`. The
|
||||
fallback path requires `data.text`; rich-only payloads without text
|
||||
short-circuit with `CLIPBOARD.NO_CONTENT`. Empty payloads also surface
|
||||
`CLIPBOARD.NO_CONTENT`.
|
||||
|
||||
### `readText(): Promise<ClipboardResult<string>>`
|
||||
|
||||
Read plain text. Falls back to the paste-event capture when the API is
|
||||
unavailable or rejects (and `useFallback` is true).
|
||||
|
||||
### `readRichContent(): Promise<ClipboardResult<ClipboardData>>`
|
||||
|
||||
Read rich content. Returns `CLIPBOARD.API_UNAVAILABLE` when no async API
|
||||
is present (rich content has no usable fallback). Applies the optional
|
||||
sanitizer to inbound HTML.
|
||||
|
||||
### `checkPermissions(): Promise<PermissionResult>`
|
||||
|
||||
Snapshot of `clipboard-read` + `clipboard-write` permission state.
|
||||
|
||||
### `onPermissionChange(cb): Promise<() => void>`
|
||||
|
||||
Subscribe to permission changes. Returns an unsubscribe function.
|
||||
|
||||
### `isSupported(): boolean`
|
||||
|
||||
True when `navigator.clipboard` is defined on the bound navigator.
|
||||
|
||||
### `isSecure(): boolean`
|
||||
|
||||
True when the bound window does not flag `isSecureContext: false`.
|
||||
|
||||
### `dispose(): Promise<void>`
|
||||
|
||||
Drain the internal queue. After dispose, queued operations resolve with
|
||||
their current outcomes; new enqueues reject.
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
The manager keeps a single `OperationContext` reference (navigator,
|
||||
window, options, observability) shared with the pure operation functions
|
||||
in `operations.ts`. This split keeps the class under the 300-line file
|
||||
budget while preserving the public API. The internal `run` method wraps
|
||||
every operation in a latency-measuring closure and either enqueues it
|
||||
via the `AsyncQueue` (when `serialize: true`) or invokes it directly. The
|
||||
`recordResult` helper updates counters per-call and per-error-code so
|
||||
the OTel pipeline measures both the macro-shape (copy vs. read) and the
|
||||
micro-shape (which `CLIPBOARD.*` code fired). The constructor is SSR-
|
||||
safe: missing globals collapse to a fully-typed empty navigator and an
|
||||
undefined window so import-time evaluation never throws on a server.
|
||||
Reference in New Issue
Block a user