lib/clipboard-sync
Client/server clipboard synchronization, shared by both transports.
The pieces are factories the cores compose: createClipboardSync owns the
server-clipboard cache and the change-only signature (unchanged content
never re-crosses the transport in either direction), createIncomingClipboard
is the server-to-client path (reassembly through createMultipartClipboardState,
the cache, and the local write, issued when a payload is announced),
createSecretClipboardGuard takes a secret the session copied back off the
local clipboard, createTaggedClipboardFetch marks the connect-time
cache-only fetch,
createLocalClipboardSender is the focus-driven local-to-server path,
createDeferredClipboardWriter keeps a write the engine refused (no focus,
no user activation) for the next gesture, localClipboardBlocker names what
stops a local write at all, and createClipboardGestures wires the copy and
paste keystrokes. The transports differ only in the hooks they inject: how
a request or payload is sent and the enablement gates, which are closures
re-read per event so runtime settings changes apply immediately.
Interfaces
MultipartClipboardState
Defined in: lib/clipboard-sync.js:182
Properties
begin
begin: (mime, total) => void;Defined in: lib/clipboard-sync.js:183
Arms a transfer.
Parameters
| Parameter | Type |
|---|---|
mime | string |
total | number |
Returns
void
push
push: (b64) => void;Defined in: lib/clipboard-sync.js:184
Hands one base64 chunk to the worker.
Parameters
| Parameter | Type |
|---|---|
b64 | string |
Returns
void
finish
finish: () => Promise<{
result: any;
mimeType: string;
byteLength: number;
}>;Defined in: lib/clipboard-sync.js:185
Resolves with the decoded payload and resets; rejects when no transfer is in progress.
Returns
Promise<{
result: any;
mimeType: string;
byteLength: number;
}>
reset
reset: () => void;Defined in: lib/clipboard-sync.js:188
Drops the transfer.
Returns
void
inProgress
inProgress: boolean;Defined in: lib/clipboard-sync.js:189
mimeType
mimeType: string;Defined in: lib/clipboard-sync.js:190
totalSize
totalSize: number;Defined in: lib/clipboard-sync.js:191
Declared size in bytes.
receivedSize
receivedSize: number;Defined in: lib/clipboard-sync.js:192
Decoded bytes accumulated so far.
TaggedClipboardFetch
Defined in: lib/clipboard-sync.js:261
Properties
arm
arm: () => void;Defined in: lib/clipboard-sync.js:262
Records that the server tags the reply.
Returns
void
armLegacyWindow
armLegacyWindow: (ms) => void;Defined in: lib/clipboard-sync.js:263
Starts the timed fallback
after sending cr.
Parameters
| Parameter | Type |
|---|---|
ms | number |
Returns
void
consume
consume: () => boolean;Defined in: lib/clipboard-sync.js:265
Whether the next payload is the fetch reply.
Returns
boolean
LocalClipboardSender
Defined in: lib/clipboard-sync.js:326
Properties
readAndSend
readAndSend: () => Promise<void>;Defined in: lib/clipboard-sync.js:327
Reads the local clipboard and pushes any content to the server.
Returns
Promise<void>
sendExplicit
sendExplicit: (data, mime?, onSkip?) => Promise<void>;Defined in: lib/clipboard-sync.js:329
Pushes content the user named, outranking a concurrent readAndSend.
Parameters
| Parameter | Type |
|---|---|
data | string | ArrayBuffer | Blob |
mime? | string |
onSkip? | Function |
Returns
Promise<void>
maybeInitial
maybeInitial: () => Promise<void>;Defined in: lib/clipboard-sync.js:331
The connect-time send: once a page, and again at a connection after a read whose push found none.
Returns
Promise<void>
getSendInFlight
getSendInFlight: () => Promise<void>;Defined in: lib/clipboard-sync.js:333
The send the
paste-ordering hold awaits, or null.
Returns
Promise<void>
DeferredClipboardWriter
Defined in: lib/clipboard-sync.js:508
Properties
write
write: (attempt, options?) => Promise<boolean>;Defined in: lib/clipboard-sync.js:509
Runs an async clipboard write now, stashing it for the next gesture on
an activation rejection. settled, when given, resolves once the
write's payload is complete.
Parameters
| Parameter | Type |
|---|---|
attempt | () => Promise<void> |
options? | { onSuccess?: () => void | Promise<any>; onFailure?: (err) => void; settled?: Promise<any>; } |
options.onSuccess? | () => void | Promise<any> |
options.onFailure? | (err) => void |
options.settled? | Promise<any> |
Returns
Promise<boolean>
flush
flush: () => void;Defined in: lib/clipboard-sync.js:513
Retries the stashed write.
Returns
void
getInFlight
getInFlight: () => Promise<boolean>;Defined in: lib/clipboard-sync.js:514
The most recent
attempt, immediate or flushed, or null.
Returns
Promise<boolean>
getLanding
getLanding: () => Promise<boolean>;Defined in: lib/clipboard-sync.js:516
The most recent
attempt once its payload is complete, or null.
Returns
Promise<boolean>
hasPending
hasPending: () => boolean;Defined in: lib/clipboard-sync.js:518
Whether a write is stashed or in flight.
Returns
boolean
issued
issued: () => number;Defined in: lib/clipboard-sync.js:519
How many writes have been issued, which tells whether one was issued since a given moment.
Returns
number
SecretClipboardGuard
Defined in: lib/clipboard-sync.js:626
Properties
landed
landed: (text) => void;Defined in: lib/clipboard-sync.js:627
A secret reached the local clipboard: it is taken back once its time is up.
Parameters
| Parameter | Type |
|---|---|
text | string |
Returns
void
holds
holds: (text) => boolean;Defined in: lib/clipboard-sync.js:629
Whether text is the secret
being watched.
Parameters
| Parameter | Type |
|---|---|
text | string |
Returns
boolean
retract
retract: () => void;Defined in: lib/clipboard-sync.js:631
The session's clipboard moved on: the secret is taken back now.
Returns
void
IncomingClipboard
Defined in: lib/clipboard-sync.js:721
Properties
begin
begin: (mime, total, cacheOnly, secret?) => void;Defined in: lib/clipboard-sync.js:722
Announces a multipart payload of total bytes.
Parameters
| Parameter | Type |
|---|---|
mime | string |
total | number |
cacheOnly | boolean |
secret? | boolean |
Returns
void
push
push: (b64) => void;Defined in: lib/clipboard-sync.js:724
Hands one base64 chunk on.
Parameters
| Parameter | Type |
|---|---|
b64 | string |
Returns
void
finish
finish: () => void;Defined in: lib/clipboard-sync.js:725
Ends the multipart payload.
Returns
void
single
single: (mime, b64, cacheOnly, secret?) => void;Defined in: lib/clipboard-sync.js:726
Takes a whole payload carried by one message.
Parameters
| Parameter | Type |
|---|---|
mime | string |
b64 | string |
cacheOnly | boolean |
secret? | boolean |
Returns
void
markSecret
markSecret: () => void;Defined in: lib/clipboard-sync.js:728
Marks the next payload secret, for a transport that says so in a message of its own ahead of it.
Returns
void
copySecret
copySecret: () => Promise<boolean>;Defined in: lib/clipboard-sync.js:730
Writes the session's secret to the local clipboard, inside the gesture of a user who asked for it.
Returns
Promise<boolean>
reset
reset: () => void;Defined in: lib/clipboard-sync.js:732
Drops a payload in progress.
Returns
void
ClipboardSync
Defined in: lib/clipboard-sync.js:1099
Properties
sig
sig: (data, mime?) => string;Defined in: lib/clipboard-sync.js:1100
Content signature.
Parameters
| Parameter | Type |
|---|---|
data | string | ArrayBuffer | Blob | Uint8Array<ArrayBufferLike> |
mime? | string |
Returns
string
shouldSend
shouldSend: (data, mime?) => boolean;Defined in: lib/clipboard-sync.js:1102
Change-only gate.
Parameters
| Parameter | Type |
|---|---|
data | string | ArrayBuffer | Blob | Uint8Array<ArrayBufferLike> |
mime? | string |
Returns
boolean
markSynced
markSynced: (data, mime?) => void;Defined in: lib/clipboard-sync.js:1104
Records content as synced, on transfer success.
Parameters
| Parameter | Type |
|---|---|
data | string | ArrayBuffer | Blob | Uint8Array<ArrayBufferLike> |
mime? | string |
Returns
void
localSig
localSig: (data, mime?) => Promise<string>;Defined in: lib/clipboard-sync.js:1106
Signature of content read from the local clipboard.
Parameters
| Parameter | Type |
|---|---|
data | string | ArrayBuffer |
mime? | string |
Returns
Promise<string>
noteLocal
noteLocal: (s) => boolean;Defined in: lib/clipboard-sync.js:1108
Records what the local clipboard holds now; whether that differs from what it held before.
Parameters
| Parameter | Type |
|---|---|
s | string |
Returns
boolean
noteExplicit
noteExplicit: () => void;Defined in: lib/clipboard-sync.js:1110
Records that a push the user asked for made whatever the local clipboard holds older than the session's.
Returns
void
forget
forget: () => void;Defined in: lib/clipboard-sync.js:1112
Forgets the synced value and what the local clipboard held, once this page emptied the local clipboard.
Returns
void
forgetLocal
forgetLocal: (s) => void;Defined in: lib/clipboard-sync.js:1114
Forgets that the local
clipboard held s, where its push never left, so the next read sends it.
Parameters
| Parameter | Type |
|---|---|
s | string |
Returns
void
echoes
echoes: (text) => boolean;Defined in: lib/clipboard-sync.js:1116
Whether a local read's text is the value last synced in either direction, come back in another form.
Parameters
| Parameter | Type |
|---|---|
text | string |
Returns
boolean
resolveServer
resolveServer: (text?, blob?, mime?, bytes?) => void;Defined in: lib/clipboard-sync.js:1118
Caches fresh server data and settles pending requests.
Parameters
| Parameter | Type |
|---|---|
text? | string |
blob? | Blob |
mime? | string |
bytes? | Uint8Array |
Returns
void
captureLocalImageSig
captureLocalImageSig: () => Promise<void>;Defined in: lib/clipboard-sync.js:1120
Records the browser's re-encoded form of the image just written locally, digesting it through the worker where the caller supplied one.
Returns
Promise<void>
request
request: (wantBinary) => Promise<string | Blob>;Defined in: lib/clipboard-sync.js:1123
Requests the server clipboard.
Parameters
| Parameter | Type |
|---|---|
wantBinary | boolean |
Returns
Promise<string | Blob>
copyViaExecCommand
copyViaExecCommand: (textPromise) => Promise<void>;Defined in: lib/clipboard-sync.js:1125
Last-resort copy through execCommand.
Parameters
| Parameter | Type |
|---|---|
textPromise | Promise<string> |
Returns
Promise<void>
lastText
lastText: string;Defined in: lib/clipboard-sync.js:1127
lastBlob
lastBlob: Blob;Defined in: lib/clipboard-sync.js:1128
lastMime
lastMime: string;Defined in: lib/clipboard-sync.js:1129
Type Aliases
LocalClipboardContent
type LocalClipboardContent =
| {
kind: "text";
text: string;
}
| {
kind: "image";
blob: Blob;
mime: string;
};Defined in: lib/clipboard-sync.js:29
Type Parameters
| Type Parameter |
|---|
Variables
CLIPBOARD_FLAVOURS_MIME
const CLIPBOARD_FLAVOURS_MIME: "application/x-selkies-clipboard-flavours" = 'application/x-selkies-clipboard-flavours';Defined in: lib/clipboard-sync.js:94
Wire type for a copy carrying more than one flavour: the markup and the plain text its source wrote for it, as a JSON object of mime to content. It never reaches a clipboard itself; the flavours inside it do.
SECRET_CLIPBOARD_TTL_MS
const SECRET_CLIPBOARD_TTL_MS: 60000 = 60000;Defined in: lib/clipboard-sync.js:623
How long a secret the session copied may stay on the local clipboard.
CLIPBOARD_PREVIEW_LIMIT
const CLIPBOARD_PREVIEW_LIMIT: number;Defined in: lib/clipboard-sync.js:1070
Longest server clipboard text the dashboards are shown, in characters.
Functions
digestedPayload()
function digestedPayload(byteLength, hash): object;Defined in: lib/clipboard-sync.js:44
A payload the clipboard worker has already digested, standing in for its bytes wherever a signature is taken.
The worker walks every byte of a clipboard payload anyway, to decode or encode it, and digests it on the way through; passing the result here is what keeps the page from running the same per-byte loop over a payload of any size, several times per transfer.
Parameters
| Parameter | Type | Description |
|---|---|---|
byteLength | number | Size of the payload. |
hash | number | Its digest, seeded and computed as hashBytes does. |
Returns
object
byteLength
byteLength: number;hash
hash: number;reencodeBlobAsPng()
function reencodeBlobAsPng(blob): Promise<Blob>;Defined in: lib/clipboard-sync.js:58
Re-encodes a raster blob as PNG.
Chromium's async clipboard accepts only image/png on write, but a source
may offer only JPEG, BMP, or WebP, so the blob is decoded with the browser's
own decoders and re-encoded first.
Parameters
| Parameter | Type | Description |
|---|---|---|
blob | Blob | The image. |
Returns
Promise<Blob>
The PNG.
Throws
When the blob is undecodable (a dimensionless SVG) or the encode fails.
localClipboardBlocker()
function localClipboardBlocker(): string;Defined in: lib/clipboard-sync.js:82
Why the browser cannot be asked to write the local clipboard, or null
when it can.
Both engines expose navigator.clipboard in a secure context only, so a
deployment served over http:// on anything but localhost has no clipboard
API at all: a server image then lands nowhere, and saying so is the
difference between a bug report and a certificate.
Returns
string
The reason, ready to show.
packClipboardFlavours()
function packClipboardFlavours(__namedParameters): ArrayBuffer;Defined in: lib/clipboard-sync.js:97
The wire payload for one copy's flavours.
Parameters
| Parameter | Type |
|---|---|
__namedParameters | { html: any; text: any; } |
__namedParameters.html | any |
__namedParameters.text | any |
Returns
ArrayBuffer
unpackClipboardFlavours()
function unpackClipboardFlavours(bytes): object;Defined in: lib/clipboard-sync.js:104
The flavours a wire payload carries, as {html, text}.
Parameters
| Parameter | Type |
|---|---|
bytes | any |
Returns
object
html
html: any;text
text: any;textOfMarkup()
function textOfMarkup(html): string;Defined in: lib/clipboard-sync.js:117
The text a markup flavour reads as, for a copy whose source wrote no plain text beside it: the item's types are declared before its data arrive, so it carries a plain flavour either way, and an empty one would paste nothing into a plain field.
Parameters
| Parameter | Type | Description |
|---|---|---|
html | string | The markup. |
Returns
string
readLocalClipboard()
function readLocalClipboard(binaryEnabled): Promise<LocalClipboardContent>;Defined in: lib/clipboard-sync.js:135
Reads the local clipboard for the focus and gesture send path.
Chromium's read()/getType() throw DataError on large text and some
images while readText() still returns the text, so every such failure
falls back to it rather than dropping the sync.
Parameters
| Parameter | Type | Description |
|---|---|---|
binaryEnabled | boolean | Whether images may be read. |
Returns
Promise<LocalClipboardContent>
The content, or null when empty.
Throws
Only genuinely unexpected errors, for the caller to log.
createMultipartClipboardState()
function createMultipartClipboardState(openStream): MultipartClipboardState;Defined in: lib/clipboard-sync.js:209
Multipart server-to-client clipboard download state.
Chunks go straight to the worker as they arrive and the decoded byte count
is tracked from their base64 lengths, so a multi-MB clipboard is never held
on the main thread, let alone joined into one string there and copied again
into the message carrying it off. A truncated stream must never be
delivered as content: callers compare receivedSize against totalSize
before finishing, or the decoded byte length after, and discard on a
mismatch.
Parameters
| Parameter | Type | Description |
|---|---|---|
openStream | (mime) => object | Opens the worker-side accumulation for one transfer. |
Returns
createTaggedClipboardFetch()
function createTaggedClipboardFetch(): TaggedClipboardFetch;Defined in: lib/clipboard-sync.js:278
Tracker for the connect-time cache-only clipboard fetch (cr).
The reply must populate the sync cache and preview but never be written to the local clipboard, which would clobber whatever the user copied just before connecting. A tagging server marks the answering payload deterministically; for a server that never tags, a short timed window stands in, so a dropped reply cannot swallow a later genuine push.
Returns
createLocalClipboardSender()
function createLocalClipboardSender(hooks): LocalClipboardSender;Defined in: lib/clipboard-sync.js:367
Focus and gesture driven local-to-server clipboard sync.
readAndSend is serialized so the paste-ordering hold can hold Ctrl/Cmd+V
until the send settles. maybeInitial covers a focused Chromium tab, which
gets no focus event after connect and would otherwise leave the server on
its stale clipboard until the first alt-tab; it runs only when clipboard
read is already granted, since it must never raise a prompt at load.
sendExplicit carries the dashboard's own pushes -- the clipboard box and
the image upload -- and outranks a read while it runs and briefly after:
choosing a file blurs the page and refocuses it, and the read that refocus
fires would put the local clipboard straight back over the upload. It reads
a Blob itself, so the push is on record from the call rather than from
whenever its bytes arrive; a copy made later reaches the session on the next
focus or paste.
Parameters
| Parameter | Type | Description |
|---|---|---|
hooks | { isChromium: boolean; isSharedMode: () => boolean; canSync: () => boolean; canRead: () => boolean; binaryEnabled: () => boolean; sendClipboardData: (data, mime?, onSkip?) => Promise<void>; clipboardSync: ClipboardSync; getDeferredWriteInFlight?: () => Promise<any>; } | - |
hooks.isChromium | boolean | Engine flag. |
hooks.isSharedMode | () => boolean | Viewer sessions never send. |
hooks.canSync | () => boolean | Clipboard sync enabled. |
hooks.canRead | () => boolean | Local-to-server direction enabled. |
hooks.binaryEnabled | () => boolean | Whether images are sent. |
hooks.sendClipboardData | (data, mime?, onSkip?) => Promise<void> | Transport send. |
hooks.clipboardSync | ClipboardSync | The clipboard state, which knows what the local clipboard last held. |
hooks.getDeferredWriteInFlight? | () => Promise<any> | The deferred writer's pending write, awaited before reading. |
Returns
explicitHasPrecedence()
function explicitHasPrecedence(): boolean;Defined in: lib/clipboard-sync.js:386
Whether a push the user asked for is still the session's latest word.
Returns
boolean
asSendInFlight()
function asSendInFlight(work): Promise<void>;Defined in: lib/clipboard-sync.js:392
Runs work as the send the paste-ordering hold waits on.
Parameters
| Parameter | Type |
|---|---|
work | any |
Returns
Promise<void>
readAndSend()
function readAndSend(): Promise<void>;Defined in: lib/clipboard-sync.js:420
Reads the local clipboard and sends it when it holds something the page has not seen there before.
Content already read or written here is older than whatever the session took since -- an upload, or a session copy whose local write the browser refused -- so sending it again would put a stale value over a newer one; only a change is the user's latest copy. A read while a push the user asked for has precedence still records what it found, so the clipboard the user had before the upload never counts as a change.
A server push still settling through the deferred writer must land before this read: reading around it returns the pre-push content, which would then read as a change. The wait is bounded, since a push whose bytes stopped arriving never settles.
Returns
Promise<void>
sendExplicit()
function sendExplicit(
data,
mime,
onSkip
): Promise<void>;Defined in: lib/clipboard-sync.js:477
Pushes content the user named. A Blob is read here, so the push counts from this call rather than from whenever its bytes arrive.
Parameters
| Parameter | Type |
|---|---|
data | any |
mime | any |
onSkip | any |
Returns
Promise<void>
createDeferredClipboardWriter()
function createDeferredClipboardWriter(): DeferredClipboardWriter;Defined in: lib/clipboard-sync.js:545
Deferred local-clipboard writer for server pushes.
Engines decide whether a clipboard write may happen when write() is
called: Chromium rejects it from an unfocused document, Firefox and WebKit
without a user activation a few seconds old at most, and a server push
handler holds neither once the user has moved on. On such a rejection the
write is stashed and retried on the next real gesture instead of being
lost. Only the newest write is kept, since the clipboard is
last-value-wins: issuing a write drops any older stash whatever becomes of
it, and a write refused after a newer one was issued is dropped rather than
stashed, so no retry can land an older value over a newer one. An attempt
rejected with AbortError was withdrawn by its caller and is neither
stashed nor reported. The paste-ordering hold awaits the landing attempt
(getLanding) so a server-to-client write lands before a paste reads the
local clipboard; otherwise the stash flushes on the paste's own keydown and
lands just after the read, and the first paste is one behind. The flush
rides keydown and pointerdown, which carry a user activation, and focus and
visibilitychange, which land the write the instant Chromium accepts it
again, well before the user's next paste.
Returns
attemptOnce()
function attemptOnce(w): Promise<boolean>;Defined in: lib/clipboard-sync.js:574
Runs one write. An activation rejection (a synthetic event, or a
blurred tab) stashes it for the next gesture unless a newer write was
issued meanwhile, which the stash would otherwise land over once
flushed; any other error but a withdrawal reaches onFailure. The
attempt settles only after onSuccess has, so whoever waits on it
also waits for what the landing set off.
The attempt is started inside a promise chain so that a caller passing
a plain expression -- navigator.clipboard.write(...), which throws
outright where the browser exposes no clipboard -- fails the same way
an async one does, instead of throwing past onFailure.
Parameters
| Parameter | Type |
|---|---|
w | any |
Returns
Promise<boolean>
write()
function write(attempt, __namedParameters?): Promise<boolean>;Defined in: lib/clipboard-sync.js:604
Runs attempt now; on an activation or focus rejection queues it for
the next gesture. onSuccess fires whenever the write eventually lands,
onFailure only for errors that are neither activation nor withdrawal.
Parameters
| Parameter | Type |
|---|---|
attempt | any |
__namedParameters? | { } |
Returns
Promise<boolean>
createSecretClipboardGuard()
function createSecretClipboardGuard(hooks): SecretClipboardGuard;Defined in: lib/clipboard-sync.js:663
Takes a secret the session copied back off the local clipboard.
A password manager marks what it copies so that no clipboard history keeps
it, and empties its own clipboard after a while. A page can put no such mark
on what it writes, so a secret written here is taken back instead:
SECRET_CLIPBOARD_TTL_MS after it landed, or as soon as the session's
clipboard moves on, whichever comes first -- and only while the local
clipboard still holds it, since anything else there is a copy made since.
The check waits a task, so the write of the payload that retracted the
secret is issued first; a write issued before the check lands before it,
and one issued during it cancels the clear, since either replaces the
secret itself.
Only Chromium lets a page read and write the clipboard without a user gesture, and only with the clipboard-read permission granted (asking from a timer would raise the prompt) and the document focused, so an unfocused page takes the secret back when it is focused again. Firefox and WebKit refuse both outside a gesture, and a read inside one raises their paste prompt whenever another application's copy is on the clipboard, so there nothing is watched and the secret stays until something replaces it.
Parameters
| Parameter | Type | Description |
|---|---|---|
hooks | { isChromium: boolean; writer: DeferredClipboardWriter; onCleared: () => void; } | - |
hooks.isChromium | boolean | Engine flag. |
hooks.writer | DeferredClipboardWriter | The local writer, whose writes settle first. |
hooks.onCleared | () => void | The secret was taken back. |
Returns
createIncomingClipboard()
function createIncomingClipboard(hooks): IncomingClipboard;Defined in: lib/clipboard-sync.js:787
The server-to-client clipboard, shared by both transports: reassembly, the cache and preview, and the local write.
The local write of a multipart payload is issued the moment the payload is
announced, with its bytes still crossing, as a ClipboardItem whose data are
Promises. Engines decide whether a write may happen when write() is
called -- Chromium wants the document focused, Firefox and WebKit a user
activation a few seconds old at most -- and let the data settle long
after, while a multi-megabyte image takes seconds to arrive: a write issued
only then finds the user already back in the application they copied for,
is refused, and lands on their next gesture, one copy behind. Whether the
payload repeats what the client already holds is known only once its bytes
are digested, so a repeat, a payload that arrived broken, and one a newer
payload superseded all withdraw the write by rejecting its data, which
leaves the local clipboard as it was. A whole payload in one message is
written as soon as it is decoded. Every write goes through writer, which
stashes one the engine refuses until the next gesture, and an older write
still waiting for its data is withdrawn when a newer one is issued, so a
slow conversion can never land an older value over a newer one.
A payload superseded before it landed is dropped whole, its cache update
included: the newer one carries the session's clipboard, and a repeat of the
dropped content would otherwise read as already held and never land.
cacheOnly marks the reply to the connect-time fetch, which fills the cache
and preview but never the local clipboard.
A secret payload is text a password manager copied in the session. Its
preview reaches the dashboards masked, never as the text, and nothing of it
is stored anywhere but this module's memory; written locally, it is watched
by createSecretClipboardGuard, which takes it back when its time is up or
when any later payload shows the session's clipboard moved on. An empty
secret is that retraction without a replacement: the session's clipboard no
longer holds the secret, so nothing is written, and the local copy is taken
back where it is still there.
Parameters
| Parameter | Type | Description |
|---|---|---|
hooks | { worker: { decode: Function; decodeStream: Function; }; clipboardSync: ClipboardSync; writer: DeferredClipboardWriter; toPng: (blob) => Promise<Blob>; canWriteLocal: () => boolean; binaryEnabled: () => boolean; onPreview: (text, secret) => void; onImageWritten: (mime) => void | Promise<any>; onImageWriteFailed: (err) => void; isChromium?: boolean; } | - |
hooks.worker | { decode: Function; decodeStream: Function; } | The clipboard worker bridge. |
hooks.worker.decode | Function | - |
hooks.worker.decodeStream | Function | - |
hooks.clipboardSync | ClipboardSync | The server-clipboard state. |
hooks.writer | DeferredClipboardWriter | The local writer. |
hooks.toPng | (blob) => Promise<Blob> | Off-thread PNG conversion. |
hooks.canWriteLocal | () => boolean | Whether server content may reach the local clipboard now. |
hooks.binaryEnabled | () => boolean | Whether images are taken. |
hooks.onPreview | (text, secret) => void | Shows server text to the dashboards, a secret masked. |
hooks.onImageWritten | (mime) => void | Promise<any> | An image landed locally; what it returns is awaited before the landing counts as done. |
hooks.onImageWriteFailed | (err) => void | An image write failed for good. |
hooks.isChromium? | boolean | Engine flag, for the secret guard. |
Returns
armStallTimer()
function armStallTimer(): void;Defined in: lib/clipboard-sync.js:810
A payload whose chunks stopped arriving is dropped, so its write settles rather than holding every later paste decision on a value that is never coming.
Returns
void
withdraw()
function withdraw(landing, reason): void;Defined in: lib/clipboard-sync.js:851
Withdraws a write still waiting for its data; the local clipboard keeps its value.
Parameters
| Parameter | Type |
|---|---|
landing | any |
reason | any |
Returns
void
issue()
function issue(
kind,
mime,
secret
): object;Defined in: lib/clipboard-sync.js:862
Issues a local write whose data settle later: one Promise per type the item carries, declared now because a ClipboardItem cannot add a type. A secret is handed to the guard once it landed.
Parameters
| Parameter | Type |
|---|---|
kind | any |
mime | any |
secret | any |
Returns
object
parts
parts: object = {};settled
settled: boolean = false;withdrawn
withdrawn: boolean = false;failed
failed: any = null;localSig
localSig: any = null;fulfill()
function fulfill(
landing,
kind,
content
): void;Defined in: lib/clipboard-sync.js:900
Hands a landing its data. A conversion still running when a newer write withdraws this one resolves nothing: the part was rejected first.
Parameters
| Parameter | Type |
|---|---|
landing | any |
kind | any |
content | any |
Returns
void
land()
function land(t, decoded): void;Defined in: lib/clipboard-sync.js:926
Caches a complete payload, shows its preview, and lands it locally through the write already issued for it or a new one.
Parameters
| Parameter | Type |
|---|---|
t | any |
decoded | any |
Returns
void
writeText()
function writeText(text, secret): Promise<boolean>;Defined in: lib/clipboard-sync.js:979
Writes text locally through the writer, a secret into the guard's care.
Parameters
| Parameter | Type |
|---|---|
text | any |
secret | any |
Returns
Promise<boolean>
open()
function open(
mime,
cacheOnly,
secret
): object;Defined in: lib/clipboard-sync.js:990
Opens a payload, superseding whatever was still arriving.
Parameters
| Parameter | Type |
|---|---|
mime | any |
cacheOnly | any |
secret | any |
Returns
object
kind
kind: string;mime
mime: any;cacheOnly
cacheOnly: any;secret
secret: boolean;gen
gen: number = ++generation;landing
landing: any = null;clipboardPreviewMessage()
function clipboardPreviewMessage(text, secret?): object;Defined in: lib/clipboard-sync.js:1087
The clipboardContentUpdate message carrying server clipboard text to the
dashboards.
A multi-MB payload structured-clones through postMessage and lands in a
controlled textarea, freezing the page, while the UI only needs a bounded
preview. The truncated flag tells the dashboard to render it read-only so
a blur cannot echo the cut-down text back over the real server clipboard.
A secret travels as the secret flag alone, never as its text or length:
the dashboards show it masked, read-only for the same reason, with a button
that posts clipboardCopySecret for the core to write it locally.
Parameters
| Parameter | Type | Default value | Description |
|---|---|---|---|
text | string | undefined | The server clipboard text. |
secret? | boolean | false | Whether the text is a secret. |
Returns
object
type
type: string;text
text: string;truncated
truncated: boolean;totalLength
totalLength: number;secret
secret: boolean;sameLines()
function sameLines(text): string;Defined in: lib/clipboard-sync.js:1163
Text as the session and the browser both mean it: line ends are LF. Chromium on Windows keeps plain text with CRLF line ends whatever was written, so the session's own text reads back from the local clipboard with its line ends changed, which must not read as a copy.
Parameters
| Parameter | Type | Description |
|---|---|---|
text | string | - |
Returns
string
createClipboardSync()
function createClipboardSync(__namedParameters): object;Defined in: lib/clipboard-sync.js:1167
Parameters
| Parameter | Type |
|---|---|
__namedParameters | { sendRequest: any; digestBytes: any; isChromium?: boolean; canRead?: () => boolean; } |
__namedParameters.sendRequest | any |
__namedParameters.digestBytes | any |
__namedParameters.isChromium? | boolean |
__namedParameters.canRead? | () => boolean |
Returns
sig
sig: (data, mime) => string;Parameters
| Parameter | Type |
|---|---|
data | any |
mime | any |
Returns
string
shouldSend
shouldSend: (data, mime) => boolean;Change-only gate: true while this content and mime differ from the last
synced value. Read-only: the caller marks the content synced through
markSynced only after the transfer completes, so a failed transfer
never permanently suppresses re-sending the same content. The legacy
compare suppresses echoes of content whose receive-side signature was
stored without bytes.
Parameters
| Parameter | Type |
|---|---|
data | any |
mime | any |
Returns
boolean
markSynced
markSynced: (data, mime) => void;Records content as synced; called on transfer success.
Parameters
| Parameter | Type |
|---|---|
data | any |
mime | any |
Returns
void
localSig
localSig: (data, mime) => Promise<string>;Signature of content read from the local clipboard, in the form
shouldSend compares. Bytes are digested by the worker where the
caller supplied one, from a copy, since they are still to be sent.
Parameters
| Parameter | Type |
|---|---|
data | any |
mime | any |
Returns
Promise<string>
noteLocal
noteLocal: (s) => boolean;Records what the local clipboard holds now, from a read or from a write
made here (null when its form there is unknown).
Parameters
| Parameter | Type |
|---|---|
s | any |
Returns
boolean
Whether that differs from what it held last time; the first look after a push the user asked for finds what the clipboard held before it, which is no change.
noteExplicit
noteExplicit: () => void;A push the user asked for (an upload, the clipboard box) made the session's clipboard newer than whatever the local one holds, seen here or not: an engine that reads the local clipboard only as a paste delivers it has never seen it.
Returns
void
forget
forget: () => void;After this page emptied the local clipboard (a secret taken back), the session's next copy of the same content has to land again, and whatever the user copies next is a change.
Returns
void
forgetLocal
forgetLocal: (s) => void;A push of the local clipboard that never left (no connection, or it dropped mid-send) leaves the content still news to the session: the next read finds it a change again. A newer reading, or a push the user asked for since, stands.
Parameters
| Parameter | Type |
|---|---|
s | any |
Returns
void
resolveServer
resolveServer: (text, blob, mime, bytes) => void;Caches fresh server data and settles pending requests through the
one-behind guard. bytes, when the receive path has them, make the
stored signature content-hashed so it matches what shouldSend
computes for the same data.
Parameters
| Parameter | Type |
|---|---|
text | any |
blob | any |
mime | any |
bytes | any |
Returns
void
captureLocalImageSig
captureLocalImageSig: () => Promise<void>;After a server image is written to the local clipboard, records the browser's re-encoded representation so the next focus read is recognized as the same content instead of echoed back. Needs clipboard read permission and focus and is silently skipped otherwise; the worst case is one redundant round trip, never a loop. The capture is anchored to the synced signature at entry: a sync in either direction landing mid-read makes it stale, and storing it would suppress a legitimate later copy.
Returns
Promise<void>
request
request: (wantBinary) => Promise<string | Blob>;Requests the server clipboard and resolves with the next fresh value.
After two seconds the request settles so the ClipboardItem promise, and the browser's transient-activation window, can never hang: with a cached value that differs from the baseline recorded at request time it resolves, otherwise it rejects, since resolving with the baseline-equal cache would settle the copy with stale content exactly when the session-start cache is empty or stale.
Parameters
| Parameter | Type | Description |
|---|---|---|
wantBinary | boolean | Whether an image is wanted rather than text. |
Returns
Promise<string | Blob>
copyViaExecCommand
copyViaExecCommand: (textPromise) => Promise<void>;Last-resort copy for browsers that reject navigator.clipboard.write
(older Firefox and Safari): execCommand('copy') from a hidden
textarea. Awaiting the promise first can outlive the Ctrl/Cmd+C
transient activation, hence last resort. A rejected request or an empty
value writes nothing: either would clobber the user's local clipboard
with pre-copy content.
Parameters
| Parameter | Type | Description |
|---|---|---|
textPromise | Promise<string> | The pending server text. |
Returns
Promise<void>
lastText
Get Signature
get lastText(): string;Returns
string
echoes
echoes: (text) => boolean;Whether text read from the local clipboard is the value last synced, come back in another form: what the session sent, or what this page sent it, so sending it would only take the session's clipboard from its owner (a file manager's cut is the owner's alone).
Parameters
| Parameter | Type | Description |
|---|---|---|
text | string | The read's plain text. |
Returns
boolean
lastBlob
Get Signature
get lastBlob(): any;Returns
any
lastMime
Get Signature
get lastMime(): string;Returns
string
sigOf()
function sigOf(data, mime): object;Defined in: lib/clipboard-sync.js:1197
Both signature forms of a value. Text and byte-backed values are
content-hashed so two distinct payloads of equal size still differ; a
bare Blob, whose bytes are not in hand, gets the size-only legacy
form, which also rides along with hashed binary signatures so the two
can be cross-matched.
Parameters
| Parameter | Type |
|---|---|
data | any |
mime | any |
Returns
object
full
full: string;legacy
legacy: string;shouldSend()
function shouldSend(data, mime): boolean;Defined in: lib/clipboard-sync.js:1233
Change-only gate: true while this content and mime differ from the last
synced value. Read-only: the caller marks the content synced through
markSynced only after the transfer completes, so a failed transfer
never permanently suppresses re-sending the same content. The legacy
compare suppresses echoes of content whose receive-side signature was
stored without bytes.
Parameters
| Parameter | Type |
|---|---|
data | any |
mime | any |
Returns
boolean
markSynced()
function markSynced(data, mime): void;Defined in: lib/clipboard-sync.js:1240
Records content as synced; called on transfer success.
Parameters
| Parameter | Type |
|---|---|
data | any |
mime | any |
Returns
void
echoes()
function echoes(text): boolean;Defined in: lib/clipboard-sync.js:1251
Whether text read from the local clipboard is the value last synced, come back in another form: what the session sent, or what this page sent it, so sending it would only take the session's clipboard from its owner (a file manager's cut is the owner's alone).
Parameters
| Parameter | Type | Description |
|---|---|---|
text | string | The read's plain text. |
Returns
boolean
localSig()
function localSig(data, mime): Promise<string>;Defined in: lib/clipboard-sync.js:1260
Signature of content read from the local clipboard, in the form
shouldSend compares. Bytes are digested by the worker where the
caller supplied one, from a copy, since they are still to be sent.
Parameters
| Parameter | Type |
|---|---|
data | any |
mime | any |
Returns
Promise<string>
noteLocal()
function noteLocal(s): boolean;Defined in: lib/clipboard-sync.js:1272
Records what the local clipboard holds now, from a read or from a write
made here (null when its form there is unknown).
Parameters
| Parameter | Type |
|---|---|
s | any |
Returns
boolean
Whether that differs from what it held last time; the first look after a push the user asked for finds what the clipboard held before it, which is no change.
noteExplicit()
function noteExplicit(): void;Defined in: lib/clipboard-sync.js:1284
A push the user asked for (an upload, the clipboard box) made the session's clipboard newer than whatever the local one holds, seen here or not: an engine that reads the local clipboard only as a paste delivers it has never seen it.
Returns
void
forget()
function forget(): void;Defined in: lib/clipboard-sync.js:1293
After this page emptied the local clipboard (a secret taken back), the session's next copy of the same content has to land again, and whatever the user copies next is a change.
Returns
void
forgetLocal()
function forgetLocal(s): void;Defined in: lib/clipboard-sync.js:1304
A push of the local clipboard that never left (no connection, or it dropped mid-send) leaves the content still news to the session: the next read finds it a change again. A newer reading, or a push the user asked for since, stands.
Parameters
| Parameter | Type |
|---|---|
s | any |
Returns
void
resolveServer()
function resolveServer(
text,
blob,
mime,
bytes
): void;Defined in: lib/clipboard-sync.js:1314
Caches fresh server data and settles pending requests through the
one-behind guard. bytes, when the receive path has them, make the
stored signature content-hashed so it matches what shouldSend
computes for the same data.
Parameters
| Parameter | Type |
|---|---|
text | any |
blob | any |
mime | any |
bytes | any |
Returns
void
captureLocalImageSig()
function captureLocalImageSig(): Promise<void>;Defined in: lib/clipboard-sync.js:1345
After a server image is written to the local clipboard, records the browser's re-encoded representation so the next focus read is recognized as the same content instead of echoed back. Needs clipboard read permission and focus and is silently skipped otherwise; the worst case is one redundant round trip, never a loop. The capture is anchored to the synced signature at entry: a sync in either direction landing mid-read makes it stale, and storing it would suppress a legitimate later copy.
Returns
Promise<void>
request()
function request(wantBinary): Promise<string | Blob>;Defined in: lib/clipboard-sync.js:1382
Requests the server clipboard and resolves with the next fresh value.
After two seconds the request settles so the ClipboardItem promise, and the browser's transient-activation window, can never hang: with a cached value that differs from the baseline recorded at request time it resolves, otherwise it rejects, since resolving with the baseline-equal cache would settle the copy with stale content exactly when the session-start cache is empty or stale.
Parameters
| Parameter | Type | Description |
|---|---|---|
wantBinary | boolean | Whether an image is wanted rather than text. |
Returns
Promise<string | Blob>
copyViaExecCommand()
function copyViaExecCommand(textPromise): Promise<void>;Defined in: lib/clipboard-sync.js:1417
Last-resort copy for browsers that reject navigator.clipboard.write
(older Firefox and Safari): execCommand('copy') from a hidden
textarea. Awaiting the promise first can outlive the Ctrl/Cmd+C
transient activation, hence last resort. A rejected request or an empty
value writes nothing: either would clobber the user's local clipboard
with pre-copy content.
Parameters
| Parameter | Type | Description |
|---|---|---|
textPromise | Promise<string> | The pending server text. |
Returns
Promise<void>
createClipboardGestures()
function createClipboardGestures(hooks): object;Defined in: lib/clipboard-sync.js:1515
Keyboard and paste gesture wiring for clipboard sync.
Owns the three window-level pieces around the per-transport read and send functions:
- Paste-ordering hold: a Ctrl/Cmd+V arriving while the local clipboard is still being read or sent would depart the ordered channel before the clipboard content and paste the previous value on the server. The chord's key events are swallowed, held until the send flushes (bounded), then replayed in order for the input stack; outside Chromium every chord is held for the send its own paste event starts. In Chromium the chord starts a read of its own and is held for it, since the clipboard can change without the window losing focus: a copy in another tab or from a tool outside the page leaves the focus read's value stale.
- Non-Chromium Ctrl/Cmd+C: Safari and Firefox reject
navigator.clipboardfrom focus and message handlers, which have no transient activation, so the server clipboard is written inside the copy gesture through a ClipboardItem whose blob is a Promise, withexecCommand('copy')as last resort. - Non-Chromium paste-to-server: driven by the
pasteevent's synchronousclipboardData. There is deliberately no Ctrl/Cmd+Vnavigator.clipboardread: WebKit rejects it from keydown, Firefox re-raises its paste prompt, and it would double-send next to the paste event. While a session value is still on its way to the local clipboard the local one is older than the session's, so the paste sends nothing and the chord pastes the session's.
Gestures in page form fields (the settings UI) are left alone; the stream's
overlay input is exempt. Consumed gestures are never preventDefaulted
outside the Chromium hold: the chord must still reach the remote session,
and outside Chromium its default action is the paste event itself. That
paste event is canceled once the stream takes it, so its text is not also
inserted into the stream's input.
Parameters
| Parameter | Type | Description |
|---|---|---|
hooks | { isChromium: boolean; clipboardSync: ClipboardSync; sendClipboardData: (data, mime?) => Promise<void>; canSync: () => boolean; canRead: () => boolean; canWrite: () => boolean; binaryEnabled: () => boolean; getSendInFlight: () => Promise<any>; getDeferredWriteLanding?: () => Promise<any>; hasPendingServerWrite?: () => boolean; readLocalClipboard?: () => Promise<void>; } | - |
hooks.isChromium | boolean | Engine flag. |
hooks.clipboardSync | ClipboardSync | The server-clipboard state. |
hooks.sendClipboardData | (data, mime?) => Promise<void> | Transport send. |
hooks.canSync | () => boolean | Clipboard sync enabled. |
hooks.canRead | () => boolean | Local-to-server direction enabled. |
hooks.canWrite | () => boolean | Server-to-local direction enabled. |
hooks.binaryEnabled | () => boolean | Whether images are sent. |
hooks.getSendInFlight | () => Promise<any> | The local sender's pending send. |
hooks.getDeferredWriteLanding? | () => Promise<any> | The deferred writer's write whose data are complete, still landing. |
hooks.hasPendingServerWrite? | () => boolean | Whether a session value has yet to land in the local clipboard. |
hooks.readLocalClipboard? | () => Promise<void> | Chromium's read and send of the local clipboard, which a paste chord starts. |
Returns
object
Listener registration.
wire
wire: () => void;Returns
void
unwire
unwire: () => void;Returns
void
dropHeldPasteKeydowns()
function dropHeldPasteKeydowns(): void;Defined in: lib/clipboard-sync.js:1565
The in-flight transfer failed or never settled: injecting the held V now would paste stale content, so the held keydowns are dropped. The swallowed keyups (V and the chord's modifiers) are still replayed, as losing a modifier keyup would leave it stuck server-side.
Returns
void
holdPasteWhileClipboardInFlight()
function holdPasteWhileClipboardInFlight(ev): void;Defined in: lib/clipboard-sync.js:1598
Capture-phase key listener implementing the paste-ordering hold.
A paste chord is held while a send is in flight or a server-to-client
local-clipboard write is still landing, since the paste would otherwise
read the old value; any KeyV event is held while a replay is queued, so
its keyup cannot overtake the held keydown, and so are the chord's
modifier keyups, since a Ctrl keyup overtaking the replayed V would
break the chord server-side and type a literal v. The hold waits for
the current read/send and deferred write, then re-checks, as a
follow-on transfer may have started meanwhile (the deferred write
flushed by this very keydown); replay happens only once nothing is
pending, and on failure or an expired bound the paste is dropped rather
than injected with stale content.
Outside Chromium the local clipboard reaches the page only through the chord's own paste event, which the engine dispatches once this keydown has been, so every chord is held for it: its V would otherwise reach the session ahead of what it pastes, and the first paste of every copy would paste the one before. There the keydown keeps its default action, since that action is the paste.
In Chromium the chord's keydown starts the read and send itself and is held for it, the counterpart of the paste event elsewhere.
Parameters
| Parameter | Type | Description |
|---|---|---|
ev | KeyboardEvent | - |
Returns
void
onCopyKeydown()
function onCopyKeydown(event): void;Defined in: lib/clipboard-sync.js:1662
Non-Chromium Ctrl/Cmd+C: writes the server clipboard inside the gesture.
Only text/plain is advertised: a Ctrl/Cmd+C cannot synchronously know
whether the server's current clipboard is an image, and a stale cached
MIME type would build a malformed ClipboardItem. Server images are
delivered by the push handler instead. Autorepeat is ignored so it
cannot spam REQUEST_CLIPBOARD.
Parameters
| Parameter | Type | Description |
|---|---|---|
event | KeyboardEvent | - |
Returns
void
onPaste()
function onPaste(event): void;Defined in: lib/clipboard-sync.js:1698
Non-Chromium paste-to-server from the event's synchronous clipboard data, preferring an image when binary clipboard is on and the payload carries one. Only content the page has not seen on the local clipboard is sent: what it has seen there is older than whatever the session took since, an upload or a copy made in the session.
Parameters
| Parameter | Type | Description |
|---|---|---|
event | ClipboardEvent | - |
Returns
void
wire()
function wire(): void;Defined in: lib/clipboard-sync.js:1733
Registers the listeners; called before input attaches so the hold runs first.
Returns
void
unwire()
function unwire(): void;Defined in: lib/clipboard-sync.js:1743
Removes the listeners wire registered.
Returns
void