@embedpdf/plugin-signature 3.0.0-next.13 → 3.0.0-next.15

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../src/blank-page.ts","../src/capability.ts","../src/handler.ts","../src/reducer.ts","../src/signature.plugin.ts"],"sourcesContent":["/** A one-page blank PDF: the appearance that clears a visual fill. */\n// A content stream that draws NOTHING but is not empty (`q Q`): the engine\n// turns the page into a form XObject, and a page with no content at all has\n// nothing to turn — it refuses; a saved/restored state passes and paints\n// nothing.\nconst CONTENT = 'q Q';\nconst OBJECTS = [\n '<< /Type /Catalog /Pages 2 0 R >>',\n '<< /Type /Pages /Kids [3 0 R] /Count 1 >>',\n '<< /Type /Page /Parent 2 0 R /MediaBox [0 0 200 60] /Contents 4 0 R /Resources << >> >>',\n `<< /Length ${CONTENT.length} >>\\nstream\\n${CONTENT}\\nendstream`,\n];\n\nlet cached: Uint8Array | null = null;\n\nexport function blankPagePdf(): Uint8Array {\n if (cached) return new Uint8Array(cached);\n let body = '%PDF-1.7\\n';\n const offsets: number[] = [];\n OBJECTS.forEach((object, index) => {\n offsets.push(body.length);\n body += `${index + 1} 0 obj\\n${object}\\nendobj\\n`;\n });\n const xref = body.length;\n body += `xref\\n0 ${OBJECTS.length + 1}\\n0000000000 65535 f \\n`;\n for (const offset of offsets) body += `${String(offset).padStart(10, '0')} 00000 n \\n`;\n body += `trailer\\n<< /Size ${OBJECTS.length + 1} /Root 1 0 R >>\\nstartxref\\n${xref}\\n%%EOF\\n`;\n cached = new TextEncoder().encode(body);\n return new Uint8Array(cached);\n}\n","import { createEventHook, type PluginContext } from '@embedpdf/core';\nimport {\n certificateCommonName,\n sign,\n validateSignatures,\n type SignatureVerdict,\n type SignerPort,\n type ValidationTime,\n} from '@embedpdf/core-signature';\nimport {\n resolveBinarySource,\n type AnalyzeInput,\n type BinarySource,\n type ChangeAnalysis,\n type DocumentEvent,\n type DocumentProtection,\n type FormFieldRef,\n type SignatureCompleteResult,\n type SignatureDTO,\n type SignatureSnapshot,\n} from '@embedpdf/engine-core/runtime';\nimport { AnnotationToken, type StampPlacement } from '@embedpdf/plugin-annotation/contract';\nimport { FormToken } from '@embedpdf/plugin-form/contract';\nimport { StampToken } from '@embedpdf/plugin-stamp/contract';\n\nimport { blankPagePdf } from './blank-page';\nimport type {\n Mark,\n SignatureAction,\n SignatureCapability,\n SignatureChange,\n SignatureConfig,\n SignatureMode,\n SignatureState,\n SignFieldInput,\n} from './types';\n\nconst sameRef = (a: FormFieldRef, b: FormFieldRef): boolean =>\n a.kind === 'objectNumber' && b.kind === 'objectNumber'\n ? a.fieldObjectNumber === b.fieldObjectNumber\n : a.kind === 'fqn' && b.kind === 'fqn'\n ? a.name === b.name\n : false;\n\nconst sameProtection = (a: DocumentProtection | null, b: DocumentProtection | null): boolean =>\n JSON.stringify(a) === JSON.stringify(b);\n\nexport function createSignatureCapability(\n ctx: PluginContext<SignatureState, SignatureAction>,\n config: SignatureConfig = {},\n): SignatureCapability {\n const form = ctx.get(FormToken);\n const changed = createEventHook<SignatureChange>((error) =>\n globalThis.console?.error('[signature] listener failed:', error),\n );\n ctx.cleanup(() => changed.dispose());\n\n const state = () => ctx.getState();\n const requireDoc = () => {\n const doc = ctx.doc;\n if (!doc) throw new Error('[signature] no document bound');\n return doc;\n };\n const requireSignatures = () => {\n const doc = requireDoc();\n if (!doc.signatures) throw new Error('[signature] this engine does not implement signatures');\n return { doc, signatures: doc.signatures };\n };\n const stamp = () => ctx.tryGet(StampToken);\n const documentId = () => {\n const id = ctx.documentId;\n if (!id) throw new Error('[signature] no document id');\n return id;\n };\n\n // ── mode and signer ─────────────────────────────────────────────────────\n const mode = (): SignatureMode => config.mode ?? (config.signer ? 'sign' : 'visual');\n const resolveSigner = async (): Promise<SignerPort> => {\n const signer = config.signer;\n if (!signer) throw new Error('[signature] no signer configured (mode \"sign\" needs one)');\n return typeof signer === 'function' ? signer() : signer;\n };\n const allows = (cap: 'doc.sign' | 'doc.sign.certify' | 'doc.forms.fill'): boolean =>\n ctx.doc?.security.allows(cap) ?? false;\n\n // ── snapshot + verdicts ─────────────────────────────────────────────────\n const refresh = async (): Promise<SignatureSnapshot | null> => {\n const doc = ctx.doc;\n if (!doc?.signatures) {\n ctx.dispatch({ type: 'SNAPSHOT', snapshot: null });\n return null;\n }\n const before = state().snapshot?.protection ?? null;\n const snapshot = await doc.signatures.list();\n ctx.dispatch({ type: 'SNAPSHOT', snapshot });\n if (!sameProtection(before, snapshot.protection)) {\n changed.emit({ type: 'protectionChanged', protection: snapshot.protection });\n }\n return snapshot;\n };\n\n const validate = async (opts?: {\n at?: ValidationTime;\n until?: 'persisted' | 'working-copy';\n }): Promise<SignatureVerdict[]> => {\n const doc = ctx.doc;\n if (!doc?.signatures) return [];\n const verdicts = await validateSignatures(doc, {\n trust: config.trust ?? null,\n at: opts?.at,\n until: opts?.until ?? 'working-copy',\n });\n const before = state().verdicts;\n ctx.dispatch({ type: 'VERDICTS', verdicts });\n changed.emit({ type: 'validated', verdicts });\n // Acrobat's warning, after the fact and only on the edge: a signature that\n // held (or was never judged) now reads invalid because of unsaved edits.\n for (const v of verdicts) {\n if (v.modifications.basis !== 'working-copy' || v.summary !== 'invalid') continue;\n const was = before?.find((b) => b.signature.index === v.signature.index);\n if (was && was.summary === 'invalid') continue;\n changed.emit({\n type: 'invalidating',\n field: v.signature.field,\n detail: v.modifications.detail ?? '',\n });\n }\n return verdicts;\n };\n\n // Every edit that could count as a modification re-judges the working copy.\n // Coalesced: a pen stroke is many events, one analysis.\n let revalidateTimer: ReturnType<typeof setTimeout> | null = null;\n const revalidateSoon = (): void => {\n if (!state().snapshot?.signatures.some((s) => s.signed)) return;\n if (revalidateTimer) clearTimeout(revalidateTimer);\n revalidateTimer = setTimeout(() => {\n revalidateTimer = null;\n void validate().catch((error) =>\n globalThis.console?.error('[signature] re-validation failed:', error),\n );\n }, 300);\n };\n ctx.cleanup(() => {\n if (revalidateTimer) clearTimeout(revalidateTimer);\n });\n\n const analyze = (input: AnalyzeInput): Promise<ChangeAnalysis> =>\n requireSignatures().signatures.analyze(input);\n\n const signatureOf = (\n field: FormFieldRef | { annotObjectNumber: number },\n ): SignatureDTO | null => {\n const snapshot = state().snapshot;\n if (!snapshot) return null;\n if ('annotObjectNumber' in field) {\n const byWidget = snapshot.signatures.find(\n (s) => s.widget?.annotObjectNumber === field.annotObjectNumber,\n );\n if (byWidget) return byWidget;\n const owner = form.fieldForWidget(field.annotObjectNumber);\n return owner ? signatureOf(owner.ref) : null;\n }\n return (\n snapshot.signatures.find((s) =>\n field.kind === 'fqn' ? s.fieldName === field.name : sameRef(s.field, field),\n ) ?? null\n );\n };\n const verdictOf = (\n field: FormFieldRef | { annotObjectNumber: number },\n ): SignatureVerdict | null => {\n const signature = signatureOf(field);\n if (!signature) return null;\n return state().verdicts?.find((v) => v.signature.index === signature.index) ?? null;\n };\n\n // ── marks → bytes ───────────────────────────────────────────────────────\n const bytesOf = async (source: BinarySource): Promise<Uint8Array> =>\n new Uint8Array((await resolveBinarySource(source)).bytes);\n const markBytes = async (mark: Mark): Promise<Uint8Array> => {\n if ('assetId' in mark) {\n const bytes = stamp()?.assetBytes(mark.assetId);\n if (!bytes) throw new Error(`[signature] unknown mark '${mark.assetId}'`);\n return bytes;\n }\n return bytesOf(mark.source);\n };\n\n const withBusy = async <T>(work: () => Promise<T>): Promise<T> => {\n ctx.dispatch({ type: 'BUSY', busy: true });\n try {\n return await work();\n } finally {\n ctx.dispatch({ type: 'BUSY', busy: false });\n }\n };\n\n // ── the act ─────────────────────────────────────────────────────────────\n const signField = (input: SignFieldInput): Promise<SignatureCompleteResult> =>\n withBusy(async () => {\n const { doc } = requireSignatures();\n const signer = await resolveSigner();\n // The certificate's subject is the default /Name; the caller's facts win.\n const subject =\n signer.kind === 'raw' && signer.certificateChain[0]\n ? certificateCommonName(signer.certificateChain[0])\n : null;\n const attribution = { ...(subject ? { name: subject } : {}), ...input.attribution };\n // The appearance IS the mark: its page is drawn into the widget by the engine.\n const appearance = input.appearance\n ? await bytesOf(input.appearance)\n : await markBytes(input.mark);\n const result = await sign(doc, {\n field: input.field,\n signer,\n attribution,\n certify: input.certify,\n lock: input.lock,\n appearance: { pdf: appearance, pageIndex: 0 },\n });\n if (state().target && sameRef(state().target!, input.field)) setTarget(null);\n await refresh();\n void validate().catch((error) =>\n globalThis.console?.error('[signature] validation after signing failed:', error),\n );\n changed.emit({ type: 'signed', field: input.field, result });\n return result;\n });\n\n const setAppearance = async (field: FormFieldRef, pdf: Uint8Array): Promise<void> => {\n const doc = requireDoc();\n if (!doc.forms.setSignatureAppearance) {\n throw new Error('[signature] this engine cannot draw into a signature field');\n }\n const signature = signatureOf(field);\n if (signature?.signed) throw new Error(`[signature] '${signature.fieldName}' is signed`);\n await doc.forms.setSignatureAppearance(field, { pdf, pageIndex: 0 });\n await form.refresh();\n };\n\n const fillField = (field: FormFieldRef, mark: Mark): Promise<void> =>\n withBusy(async () => {\n await setAppearance(field, await markBytes(mark));\n if (state().target && sameRef(state().target!, field)) setTarget(null);\n changed.emit({ type: 'filled', field });\n });\n\n const clearField = (field: FormFieldRef): Promise<void> =>\n withBusy(async () => {\n await setAppearance(field, blankPagePdf());\n changed.emit({ type: 'cleared', field });\n });\n\n const placeMark = async (\n mark: Mark,\n target: { field: FormFieldRef } | StampPlacement,\n ): Promise<void> => {\n if (!('field' in target)) {\n // Free placement: a stamp, as in Preview — one placement law, the stamp plugin's.\n if ('assetId' in mark) {\n const library = stamp();\n if (!library) throw new Error('[signature] no stamp plugin to place an asset');\n await library.placeAsset(documentId(), mark.assetId, target);\n } else {\n await ctx.get(AnnotationToken).placeStamp({ source: mark.source }, target);\n }\n return;\n }\n switch (mode()) {\n case 'sign':\n // The first signature is the one that can certify: when the config\n // allows a certification, let the chrome offer the choice (its sign\n // dialog) instead of sealing a plain approval on the spot.\n if (config.allowCertify && !state().snapshot?.signatures.some((s) => s.signed)) {\n changed.emit({ type: 'ask', field: target.field, mark });\n return;\n }\n await signField({ field: target.field, mark });\n return;\n case 'visual':\n await fillField(target.field, mark);\n return;\n case 'ask':\n changed.emit({ type: 'ask', field: target.field, mark });\n return;\n }\n };\n\n const setTarget = (field: FormFieldRef | null): void => {\n const current = state().target;\n if (current === field || (current && field && sameRef(current, field))) return;\n ctx.dispatch({ type: 'TARGET', field });\n changed.emit({ type: 'target', field });\n };\n\n // ── live: pendings, versions, remote signings ───────────────────────────\n const doc = ctx.doc;\n if (doc) {\n const unsubscribe = doc.events.subscribe((event: DocumentEvent) => {\n switch (event.type) {\n case 'signature.prepared':\n ctx.dispatch({\n type: 'PENDING',\n pending: { signingId: event.signingId, field: event.field },\n });\n return;\n case 'signature.aborted':\n ctx.dispatch({ type: 'PENDING', pending: null });\n return;\n case 'signature.completed':\n ctx.dispatch({ type: 'PENDING', pending: null });\n return;\n case 'document.versioned':\n case 'stream.desynced':\n // Byte-level facts moved: re-read them and re-judge.\n void refresh()\n .then(() => validate())\n .catch((error) => globalThis.console?.error('[signature] refresh failed:', error));\n return;\n case 'form.fieldCreated':\n case 'form.fieldDeleted':\n case 'form.widgetAttached':\n case 'form.widgetDetached':\n case 'form.imported':\n case 'form.repaired':\n // The field set changed (a signature field authored or removed, here\n // or remotely): the snapshot lists fields, so re-read it — and the\n // change is a modification of the working copy, so re-judge.\n void refresh()\n .then(() => revalidateSoon())\n .catch((error) => globalThis.console?.error('[signature] refresh failed:', error));\n return;\n case 'annotation.created':\n case 'annotation.updated':\n case 'annotation.deleted':\n case 'annotation.moved':\n case 'form.valueChanged':\n case 'form.fieldUpdated':\n case 'form.effectsApplied':\n // An edit of the working copy: what a save would write changed, so\n // what a validator would say about it may have too.\n revalidateSoon();\n return;\n default:\n return;\n }\n });\n ctx.cleanup(unsubscribe);\n }\n\n return {\n snapshot: () => state().snapshot,\n verdicts: () => state().verdicts,\n protection: () => state().snapshot?.protection ?? null,\n pending: () => state().pending,\n target: () => state().target,\n busy: () => state().busy,\n mode,\n signatureOf,\n verdictOf,\n canSign: () => allows('doc.sign') && config.signer != null,\n canFill: () => allows('doc.forms.fill') && ctx.doc?.forms.setSignatureAppearance != null,\n canCertify: () => config.allowCertify === true && allows('doc.sign.certify'),\n signField,\n fillField,\n clearField,\n placeMark,\n setTarget,\n inspect: (field) => changed.emit({ type: 'inspect', field }),\n refresh,\n validate,\n analyze,\n revisionBytes: (revisionIndex) => requireSignatures().signatures.revisionBytes(revisionIndex),\n onChanged: changed.on,\n };\n}\n","import type { InteractionHandler } from '@embedpdf/plugin-interaction/contract';\nimport {\n ANNOTATION_EDIT_PRIORITY,\n ARMED_STAMP_TOOL_ID,\n} from '@embedpdf/plugin-annotation/contract';\nimport type { FormCapability } from '@embedpdf/plugin-form/contract';\nimport type { StampCapability } from '@embedpdf/plugin-stamp/contract';\n\nimport { SIGNATURES_LIBRARY_KIND, type SignatureCapability } from './types';\n\n/**\n * The armed mark over a field. The annotation plugin places an armed stamp\n * on click (`annotation-place`, priority 95) and selects an existing\n * annotation under the pointer before that (`annotation-edit`, 100 — a\n * widget is an annotation). This handler sits above BOTH, enabled for the\n * armed stamp's tool only, and captures exactly when the armed asset is a\n * person's mark (a library of kind `signatures`) and the pointer is over a\n * signature field: then the destination decides — the mark goes INTO the\n * field (`placeMark` by mode) instead of onto the page. Everywhere else it\n * declines and the click stays a stamp placement, as in Preview.\n */\nexport function createArmedMarkHandler(\n documentId: string,\n signature: SignatureCapability,\n form: FormCapability,\n stamp: StampCapability,\n): InteractionHandler {\n return {\n id: 'signature:armed-mark-on-field',\n priority: ANNOTATION_EDIT_PRIORITY + 1,\n enabledFor: (tool) => tool.id === ARMED_STAMP_TOOL_ID,\n onDown: (sample) => {\n if (!sample.page) return false;\n const armed = stamp.armedAsset(documentId);\n if (!armed || stamp.library(armed.libraryId)?.kind !== SIGNATURES_LIBRARY_KIND) return false;\n const hit = form.widgetAt(sample.page.pon, sample.page.point);\n if (!hit || hit.field.family !== 'signature') return false;\n // A signed field is final: consume the click (no stamp lands on it) and do nothing.\n if (signature.signatureOf(hit.field.ref)?.signed || hit.field.valueEntry.kind !== 'none') {\n return true;\n }\n stamp.disarm(documentId);\n void signature\n .placeMark({ assetId: armed.id }, { field: hit.field.ref })\n .catch((error) => globalThis.console?.error('[signature] placing the mark failed:', error));\n return true;\n },\n };\n}\n","import type { SignatureAction, SignatureState } from './types';\n\nexport const initialSignatureState = (): SignatureState => ({\n snapshot: null,\n verdicts: null,\n target: null,\n pending: null,\n busy: false,\n});\n\nexport function signatureReducer(state: SignatureState, action: SignatureAction): SignatureState {\n switch (action.type) {\n case 'SNAPSHOT':\n return { ...state, snapshot: action.snapshot };\n case 'VERDICTS':\n return { ...state, verdicts: action.verdicts };\n case 'TARGET':\n return { ...state, target: action.field };\n case 'PENDING':\n return { ...state, pending: action.pending };\n case 'BUSY':\n return { ...state, busy: action.busy };\n default:\n return state;\n }\n}\n","import { definePlugin } from '@embedpdf/core';\nimport { FormToken } from '@embedpdf/plugin-form/contract';\nimport { InteractionToken } from '@embedpdf/plugin-interaction/contract';\nimport { StampToken } from '@embedpdf/plugin-stamp/contract';\nimport { AnnotationToken } from '@embedpdf/plugin-annotation/contract';\n\nimport { createSignatureCapability } from './capability';\nimport { createArmedMarkHandler } from './handler';\nimport { initialSignatureState, signatureReducer } from './reducer';\nimport { SignatureToken } from './types';\nimport type {\n SignatureAction,\n SignatureCapability,\n SignatureConfig,\n SignatureState,\n} from './types';\n\n/**\n * The signature plugin — the ACT of signing, document-scoped. It owns no\n * mark: marks are stamp-library assets (or bytes the embedder brings), and\n * the mark IS the appearance the engine draws into the field. Signing goes\n * through `@embedpdf/core-signature` with the configured signer port; the\n * engine seals; on the cloud the server publishes the new version.\n *\n * With the interaction hub and the stamp plugin present, an armed mark from\n * a `signatures` library dropped over an unsigned signature field goes into\n * the field (sign / visual fill / ask, by mode) instead of onto the page.\n */\nexport const signaturePlugin = (config: SignatureConfig = {}) =>\n definePlugin<SignatureState, SignatureAction, SignatureCapability>({\n id: 'signature',\n token: SignatureToken,\n scope: 'document',\n requires: [FormToken],\n optional: [InteractionToken, StampToken, AnnotationToken],\n initialState: initialSignatureState,\n reduce: signatureReducer,\n capability: (ctx) => createSignatureCapability(ctx, config),\n init: (ctx) => {\n const signature = ctx.get(SignatureToken);\n void signature\n .refresh()\n .then((snapshot) =>\n snapshot?.signatures.some((s) => s.signed) ? signature.validate() : null,\n )\n .catch((error) => globalThis.console?.error('[signature] initial read failed:', error));\n const interaction = ctx.tryGet(InteractionToken);\n const stamp = ctx.tryGet(StampToken);\n if (interaction && stamp && ctx.documentId) {\n ctx.cleanup(\n interaction.registerHandler(\n createArmedMarkHandler(ctx.documentId, signature, ctx.get(FormToken), stamp),\n ),\n );\n }\n },\n });\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../src/tools/armed-mark.ts","../src/connect.ts","../src/services/errors.ts","../src/read/judging.ts","../src/model.ts","../src/read/signatures.ts","../src/services/authority.ts","../src/services/events.ts","../src/services/marks.ts","../src/services/siblings.ts","../src/services/store.ts","../src/services/index.ts","../src/sync/signatures.ts","../src/sync/validation.ts","../src/blank-page.ts","../src/write/fill.ts","../src/write/place.ts","../src/write/sign.ts","../src/controller.ts","../src/signature.plugin.ts","../src/state.ts"],"sourcesContent":["import type { InteractionHandler } from '@embedpdf/plugin-interaction/contract/host';\nimport {\n ANNOTATION_EDIT_PRIORITY,\n ARMED_STAMP_TOOL_ID,\n} from '@embedpdf/plugin-annotation/contract/host';\nimport type { FormCapability } from '@embedpdf/plugin-form/contract';\nimport type { StampCapability } from '@embedpdf/plugin-stamp/contract';\n\nimport { SIGNATURES_LIBRARY_KIND, type SignatureCapability } from '../contract';\n\n/**\n * The armed mark over a field. The annotation plugin places an armed stamp\n * on click (`annotation-place`, priority 95) and selects an existing\n * annotation under the pointer before that (`annotation-edit`, 100; a\n * widget is an annotation). This handler sits above both, enabled for the\n * armed stamp's tool only, and captures exactly when the armed asset is a\n * person's mark (a library of kind `signatures`) and the pointer is over a\n * signature field: then the destination decides, and the mark goes into the\n * field (`placeMark` by mode) instead of onto the page. Everywhere else it\n * declines and the click stays a stamp placement, as in Preview.\n */\nexport function createArmedMarkHandler(\n documentId: string,\n signature: SignatureCapability,\n form: FormCapability,\n stamp: StampCapability,\n): InteractionHandler {\n return {\n id: 'signature:armed-mark-on-field',\n priority: ANNOTATION_EDIT_PRIORITY + 1,\n enabledFor: (tool) => tool.id === ARMED_STAMP_TOOL_ID,\n onDown: (sample) => {\n if (!sample.page) return false;\n const armed = stamp.getArmedAsset(documentId);\n if (!armed || stamp.getLibrary(armed.libraryId)?.kind !== SIGNATURES_LIBRARY_KIND)\n return false;\n const hit = form.getWidgetAt(sample.page.ref, sample.page.point);\n if (!hit || hit.field.family !== 'signature') return false;\n // A signed field is final: consume the click (no stamp lands on it) and do nothing.\n if (signature.getSignature(hit.field.ref)?.signed || hit.field.valueEntry.kind !== 'none') {\n return true;\n }\n stamp.disarm(documentId);\n void signature\n .placeMark({ assetId: armed.id }, { field: hit.field.ref })\n .catch((error) => globalThis.console?.error('[signature] placing the mark failed:', error));\n return true;\n },\n };\n}\n","/**\n * Wiring to sibling plugins. With the interaction hub and the stamp plugin\n * present, an armed mark from a `signatures` library dropped over an\n * unsigned signature field goes into the field instead of onto the page.\n */\nimport { FormToken } from '@embedpdf/plugin-form/contract';\nimport { InteractionToken } from '@embedpdf/plugin-interaction/contract/host';\nimport { StampToken } from '@embedpdf/plugin-stamp/contract';\n\nimport type { SignatureCapability } from './contract';\nimport type { SignatureContext } from './services';\nimport { createArmedMarkHandler } from './tools/armed-mark';\n\nexport function connectSiblings(ctx: SignatureContext, signature: SignatureCapability): void {\n const interaction = ctx.tryGet(InteractionToken);\n const stamp = ctx.tryGet(StampToken);\n const documentId = ctx.documentId;\n if (!interaction || !stamp || !documentId) return;\n ctx.cleanup(\n interaction.registerHandler(\n createArmedMarkHandler(documentId, signature, ctx.get(FormToken), stamp),\n ),\n );\n}\n","import { toPluginError } from '@embedpdf/core';\n\n/**\n * A capability verb: whatever the engine, a signer port or the validator\n * rejects with reaches the caller as a `PluginError`.\n */\nexport const verb =\n <Args extends unknown[], Result>(run: (...args: Args) => Promise<Result>) =>\n async (...args: Args): Promise<Result> => {\n try {\n return await run(...args);\n } catch (error) {\n throw toPluginError('signature', error);\n }\n };\n","/**\n * The judging verbs: re-reading the facts, validating, and the byte-level\n * questions a verdict rests on (what changed after a signature, the exact\n * revision it covers).\n */\nimport { PluginError, type Mirror, type OperationOptions } from '@embedpdf/core';\nimport type { AnalyzeInput } from '@embedpdf/engine-core/runtime';\n\nimport type {\n SignatureCapability,\n SignatureFieldAddress,\n SignatureValidateOptions,\n} from '../contract';\nimport type { SignatureRecord } from '../model';\nimport type { SignatureContext, SignatureServices } from '../services';\nimport { verb } from '../services/errors';\nimport type { SignatureValidation } from '../sync/validation';\nimport type { SignatureReads } from './signatures';\n\nexport function createJudging(\n ctx: SignatureContext,\n { store }: Pick<SignatureServices, 'store'>,\n { validate }: Pick<SignatureValidation, 'validate'>,\n signatures: Mirror<SignatureRecord>,\n { getSignature, getVerdict }: Pick<SignatureReads, 'getSignature' | 'getVerdict'>,\n) {\n const { requireSignatures } = store;\n\n return {\n api: {\n refresh: verb(async (options?: OperationOptions) => {\n await ctx.cancellable(options?.signal, signatures.refresh());\n return signatures.get().snapshot;\n }),\n validate: verb(validate),\n validateField: verb(async (field: SignatureFieldAddress, options?: SignatureValidateOptions) => {\n await validate(options);\n const verdict = getVerdict(field);\n if (!verdict) {\n throw new PluginError('not-found', 'signature', 'no signed field at that address');\n }\n return verdict;\n }),\n analyzeChanges: verb(async (input: AnalyzeInput, options?: OperationOptions) =>\n ctx.cancellable(options?.signal, requireSignatures().analyze(input)),\n ),\n readRevision: verb(\n async (\n target: SignatureFieldAddress | { revisionIndex: number },\n options?: OperationOptions,\n ) => {\n ctx.assertAllowed('doc.download', 'signature.readRevision');\n const service = requireSignatures();\n let revisionIndex: number;\n if ('revisionIndex' in target) {\n revisionIndex = target.revisionIndex;\n } else {\n const signature = getSignature(target);\n if (!signature?.signed || signature.revisionIndex === null) {\n throw new PluginError('not-found', 'signature', 'no signed revision at that address');\n }\n revisionIndex = signature.revisionIndex;\n }\n return ctx.cancellable(options?.signal, service.downloadRevision(revisionIndex));\n },\n ),\n } satisfies Partial<SignatureCapability>,\n };\n}\n","/**\n * The signature plugin's state, in two kinds. Session state (the last\n * validation, the sign-here target, the busy flag) changes only through the\n * pure transitions below. The signature facts (the snapshot and the parked\n * two-phase signing) are engine data: a mirror folds them from confirmed\n * document events with {@link foldSignatureEvent}.\n */\nimport { reload, type MirrorReload } from '@embedpdf/core';\nimport type { SignatureVerdict } from '@embedpdf/core-signature';\nimport type {\n DocumentEvent,\n FormFieldRef,\n SignatureCompleteResult,\n SignatureSnapshot,\n} from '@embedpdf/engine-core/runtime';\n\nimport type { SignaturePending } from './contract';\n\nexport interface SignatureState {\n /** The last validation; null until one ran. */\n readonly verdicts: readonly SignatureVerdict[] | null;\n /** The field the user chose to sign next (\"select the field, then pick a mark\"). */\n readonly target: FormFieldRef | null;\n /** A sign or fill call is in flight. */\n readonly busy: boolean;\n}\n\nexport const initialSignatureState = (): SignatureState => ({\n verdicts: null,\n target: null,\n busy: false,\n});\n\nexport const sameFieldRef = (left: FormFieldRef, right: FormFieldRef): boolean =>\n left.kind === 'objectNumber' && right.kind === 'objectNumber'\n ? left.objectNumber === right.objectNumber\n : left.kind === 'fqn' && right.kind === 'fqn'\n ? left.name === right.name\n : false;\n\n// ── transitions ──\n\nexport function setVerdicts(\n state: SignatureState,\n verdicts: readonly SignatureVerdict[] | null,\n): SignatureState {\n return state.verdicts === verdicts ? state : { ...state, verdicts };\n}\n\n/** Name the sign-here target; the same field (by ref) changes nothing. */\nexport function setTarget(state: SignatureState, field: FormFieldRef | null): SignatureState {\n const current = state.target;\n if (current === field || (current && field && sameFieldRef(current, field))) return state;\n return { ...state, target: field };\n}\n\nexport function setBusy(state: SignatureState, busy: boolean): SignatureState {\n return state.busy === busy ? state : { ...state, busy };\n}\n\n// ── projections ──\n\n/**\n * The verdicts that turned invalid because of unsaved edits: judged on the\n * working copy, invalid now, and not already invalid in the previous\n * validation (a signature that held, or was never judged).\n */\nexport function newlyInvalidated(\n previous: readonly SignatureVerdict[] | null,\n next: readonly SignatureVerdict[],\n): SignatureVerdict[] {\n return next.filter((verdict) => {\n if (verdict.modifications.basis !== 'working-copy' || verdict.summary !== 'invalid') {\n return false;\n }\n const before = previous?.find((earlier) => earlier.signature.index === verdict.signature.index);\n return !before || before.summary !== 'invalid';\n });\n}\n\n// ── the signatures mirror ──\n\n/** The mirrored signature facts: every signature field, and the parked signing. */\nexport interface SignatureRecord {\n /** Every signature field and its facts; null until the first load, or without engine support. */\n readonly snapshot: SignatureSnapshot | null;\n /** A signing candidate is parked (here or, on the cloud, elsewhere): the document is read-only. */\n readonly pending: SignaturePending | null;\n}\n\nexport const emptySignatureRecord = (): SignatureRecord => ({ snapshot: null, pending: null });\n\nexport const hasSignedField = (snapshot: SignatureSnapshot | null): boolean =>\n snapshot?.signatures.some((signature) => signature.signed) ?? false;\n\ntype SignatureCompletedEvent = Extract<DocumentEvent, { type: 'signatures.completed' }>;\n\n/** The result a `signatures.completed` event carries, without the event envelope. */\nexport const completeResultOf = (event: SignatureCompletedEvent): SignatureCompleteResult => ({\n status: event.status,\n signature: event.signature,\n version: event.version,\n previous: event.previous,\n protection: event.protection,\n meta: event.meta,\n});\n\n/**\n * A completed signing, applied to the snapshot: the sealed field's facts and\n * the protection now in force. The revisions change as well; the\n * `document.versioned` event that follows every completion reloads them.\n */\nfunction withCompletedSignature(\n snapshot: SignatureSnapshot | null,\n event: SignatureCompletedEvent,\n): SignatureSnapshot | null {\n if (!snapshot) return null;\n const sealed = event.signature;\n return {\n ...snapshot,\n signatures: snapshot.signatures.map((signature) =>\n sameFieldRef(signature.field, sealed.field) ? sealed : signature,\n ),\n protection: event.protection,\n };\n}\n\n/** Events that change which signature fields exist; the snapshot lists fields, so it is re-read. */\nconst FIELD_SET_EVENTS: ReadonlySet<DocumentEvent['type']> = new Set([\n 'forms.created',\n 'forms.deleted',\n 'forms.widgetAdded',\n 'forms.widgetRemoved',\n 'forms.repaired',\n]);\n\n/** Apply one confirmed document event to the signature facts. Pure, the same for every origin. */\nexport function foldSignatureEvent(\n record: SignatureRecord,\n event: DocumentEvent,\n): SignatureRecord | MirrorReload {\n switch (event.type) {\n case 'signatures.prepared':\n return { ...record, pending: { signingId: event.signingId, field: event.field } };\n case 'signatures.cancelled':\n return record.pending ? { ...record, pending: null } : record;\n case 'signatures.completed':\n return { snapshot: withCompletedSignature(record.snapshot, event), pending: null };\n default:\n return FIELD_SET_EVENTS.has(event.type) ? reload() : record;\n }\n}\n","/** Reads over the signature facts and the last validation. The lists are\n * memoized per snapshot so they stay reference-stable for selectors. */\nimport { memo, type Mirror } from '@embedpdf/core';\nimport type { SignatureVerdict } from '@embedpdf/core-signature';\nimport type {\n AnnotationRef,\n FormFieldRef,\n FormWidget,\n SignatureDTO,\n} from '@embedpdf/engine-core/runtime';\n\nimport type { SignatureCapability, SignatureFieldAddress, SignatureInfo } from '../contract';\nimport { sameFieldRef, type SignatureRecord } from '../model';\nimport type { SignatureContext, SignatureServices } from '../services';\n\nconst EMPTY_SIGNATURES: readonly SignatureInfo[] = [];\nconst EMPTY_FIELDS: readonly FormFieldRef[] = [];\n\n/** The widget an address names, or null for a field ref. */\nconst widgetOf = (\n field: SignatureFieldAddress,\n): Extract<AnnotationRef, { kind: 'objectNumber' }> | FormWidget | null => {\n if (!('kind' in field)) return field;\n // An annotation ref names its page; a field ref doesn't.\n if (field.kind === 'objectNumber' && 'page' in field) return field;\n return null;\n};\n\nconst isFieldRef = (field: SignatureFieldAddress): field is FormFieldRef =>\n 'kind' in field &&\n (field.kind === 'fqn' || (field.kind === 'objectNumber' && !('page' in field)));\n\nexport function createSignatureReads(\n ctx: SignatureContext,\n { authority, siblings }: Pick<SignatureServices, 'authority' | 'siblings'>,\n signatures: Mirror<SignatureRecord>,\n) {\n const { form } = siblings;\n const snapshot = () => signatures.get().snapshot;\n\n const lists = memo(\n () => [snapshot(), ctx.state.get().verdicts],\n (current, verdicts) => {\n if (!current) return { signed: EMPTY_SIGNATURES, unsigned: EMPTY_FIELDS };\n const verdictOf = (signature: SignatureDTO): SignatureVerdict | null =>\n verdicts?.find((verdict) => verdict.signature.index === signature.index) ?? null;\n return {\n signed: current.signatures\n .filter((signature) => signature.signed)\n .map((signature): SignatureInfo => ({ ...signature, verdict: verdictOf(signature) })),\n unsigned: current.signatures\n .filter((signature) => !signature.signed)\n .map((signature) => signature.field),\n };\n },\n );\n\n const getSignature = (field: SignatureFieldAddress): SignatureDTO | null => {\n const current = snapshot();\n if (!current) return null;\n const widget = widgetOf(field);\n if (widget) {\n const byWidget = current.signatures.find(\n (signature) => signature.widget?.objectNumber === widget.objectNumber,\n );\n if (byWidget) return byWidget;\n const owner = form.getFieldForWidget(widget);\n return owner ? getSignature(owner.ref) : null;\n }\n if (!isFieldRef(field)) return null;\n return (\n current.signatures.find((signature) =>\n field.kind === 'fqn'\n ? signature.fieldName === field.name\n : sameFieldRef(signature.field, field),\n ) ?? null\n );\n };\n const getVerdict = (field: SignatureFieldAddress): SignatureVerdict | null => {\n const signature = getSignature(field);\n if (!signature) return null;\n return (\n ctx.state.get().verdicts?.find((verdict) => verdict.signature.index === signature.index) ??\n null\n );\n };\n\n return {\n snapshot,\n getSignature,\n getVerdict,\n api: {\n getSnapshot: snapshot,\n getStatus: signatures.getStatus,\n listSignatures: () => lists().signed,\n listUnsignedFields: () => lists().unsigned,\n getSignature,\n listVerdicts: () => ctx.state.get().verdicts,\n getVerdict,\n getProtection: () => snapshot()?.protection ?? null,\n getPending: () => signatures.get().pending,\n isBusy: () => ctx.state.get().busy,\n getMode: authority.mode,\n getTarget: () => ctx.state.get().target,\n } satisfies Partial<SignatureCapability>,\n };\n}\nexport type SignatureReads = ReturnType<typeof createSignatureReads>;\n","/**\n * The mode and the key, read from the settings where they're used, so a change\n * applies at once; and who may sign or fill in which field, by the field's\n * group (`ctx.allowsField`), as the engine checks it.\n */\nimport { PluginError } from '@embedpdf/core';\nimport type { SignerPort } from '@embedpdf/core-signature';\nimport type { FormFieldRef } from '@embedpdf/engine-core/runtime';\n\nimport type { SignatureKey, SignatureMode } from '../contract';\nimport type { SignatureContext } from './context';\nimport type { SignatureSiblings } from './siblings';\n\nexport function createAuthority(ctx: SignatureContext, { form }: Pick<SignatureSiblings, 'form'>) {\n const settings = ctx.settings();\n const mode = (): SignatureMode => {\n const { mode: chosen, key } = settings.get();\n return chosen ?? (key ? 'sign' : 'visual');\n };\n const resolveKey = async (override?: SignatureKey): Promise<SignerPort> => {\n const key = override ?? settings.get().key;\n if (!key) {\n throw new PluginError(\n 'invalid-input',\n 'signature',\n 'no key: set the `key` setting or pass one with the call',\n );\n }\n return typeof key === 'function' ? key() : key;\n };\n /** Whether the session may `action` this field; `false` for a field the form doesn't have. */\n const allowsField = (action: 'fill' | 'sign', ref: FormFieldRef): boolean => {\n const field = form.get(ref);\n return field !== null && ctx.allowsField(action, field);\n };\n /** Refuse a write to this field the session may not make, before anything starts. */\n const assertAllowedField = (action: 'fill' | 'sign', ref: FormFieldRef, operation: string) => {\n const field = form.get(ref);\n // A field the form doesn't show yet is the engine's to answer (`not-found`).\n if (field) ctx.assertAllowedField(action, field, operation);\n };\n return {\n mode,\n resolveKey,\n assertAllowedField,\n canSign: (field: FormFieldRef) => allowsField('sign', field),\n canFill: (field: FormFieldRef) => allowsField('fill', field),\n canCertify: () => settings.get().allowCertify && ctx.allows('doc.sign.certify'),\n canReadRevision: () => ctx.allows('doc.download'),\n };\n}\nexport type SignatureAuthority = ReturnType<typeof createAuthority>;\n","/**\n * The capability's events, minted on the instance so they are disposed with\n * it. The state-change events (`onTargetChanged`, `onInvalidationPredicted`)\n * are derived here, in one place, from each committed state change.\n */\nimport type {\n SignatureClearedEvent,\n SignatureFilledEvent,\n SignatureInspectionRequestedEvent,\n SignatureInvalidationPredictedEvent,\n SignatureProtectionChangedEvent,\n SignatureSignedEvent,\n SignatureSignRequestedEvent,\n SignatureTargetChangedEvent,\n SignatureValidatedEvent,\n} from '../contract';\nimport { newlyInvalidated } from '../model';\nimport type { SignatureContext } from './context';\n\nexport function createEvents(ctx: SignatureContext) {\n const events = {\n signed: ctx.events.source<SignatureSignedEvent>(),\n filled: ctx.events.source<SignatureFilledEvent>(),\n cleared: ctx.events.source<SignatureClearedEvent>(),\n validated: ctx.events.source<SignatureValidatedEvent>(),\n protectionChanged: ctx.events.source<SignatureProtectionChangedEvent>(),\n invalidationPredicted: ctx.events.source<SignatureInvalidationPredictedEvent>(),\n targetChanged: ctx.events.source<SignatureTargetChangedEvent>(),\n signRequested: ctx.events.source<SignatureSignRequestedEvent>(),\n inspectionRequested: ctx.events.source<SignatureInspectionRequestedEvent>(),\n };\n\n ctx.state.onChange(({ previous, next }) => {\n if (previous.target !== next.target) events.targetChanged.emit({ field: next.target });\n if (previous.verdicts !== next.verdicts && next.verdicts) {\n // Acrobat's warning, after the fact and only on the edge: a signature\n // that held (or was never judged) now reads invalid because of unsaved edits.\n for (const verdict of newlyInvalidated(previous.verdicts, next.verdicts)) {\n events.invalidationPredicted.emit({\n field: verdict.signature.field,\n detail: verdict.modifications.detail ?? '',\n });\n }\n }\n });\n\n return events;\n}\nexport type SignatureEvents = ReturnType<typeof createEvents>;\n","/** Marks → the one-page appearance bytes the engine draws into a field. */\nimport { PluginError } from '@embedpdf/core';\nimport { resolveBinarySource, type BinarySource } from '@embedpdf/engine-core/runtime';\n\nimport type { Mark } from '../contract';\nimport type { SignatureSiblings } from './siblings';\n\nexport function createMarks({ stamp }: Pick<SignatureSiblings, 'stamp'>) {\n const bytesOf = async (source: BinarySource): Promise<Uint8Array> =>\n new Uint8Array((await resolveBinarySource(source)).bytes);\n const markBytes = async (mark: Mark): Promise<Uint8Array> => {\n if ('assetId' in mark) {\n const bytes = stamp()?.readAssetBytes(mark.assetId);\n if (!bytes) throw new PluginError('not-found', 'signature', `unknown mark '${mark.assetId}'`);\n return bytes;\n }\n return bytesOf(mark.source);\n };\n return { bytesOf, markBytes };\n}\nexport type SignatureMarks = ReturnType<typeof createMarks>;\n","/** The sibling planes: the form plugin (required), the stamp and annotation plugins (optional). */\nimport { AnnotationToken } from '@embedpdf/plugin-annotation/contract';\nimport { FormToken } from '@embedpdf/plugin-form/contract';\nimport { StampToken } from '@embedpdf/plugin-stamp/contract';\n\nimport type { SignatureContext } from './context';\n\nexport function resolveSiblings(ctx: SignatureContext) {\n return {\n form: ctx.get(FormToken),\n stamp: () => ctx.tryGet(StampToken),\n annotation: () => ctx.tryGet(AnnotationToken),\n };\n}\nexport type SignatureSiblings = ReturnType<typeof resolveSiblings>;\n","/** The busy bracket and the engine doors every area needs. */\nimport { PluginError } from '@embedpdf/core';\n\nimport { setBusy } from '../model';\nimport type { SignatureContext } from './context';\n\nexport function createStore(ctx: SignatureContext) {\n const withBusy = async <T>(work: () => Promise<T>): Promise<T> => {\n ctx.state.update(setBusy, true);\n try {\n return await work();\n } finally {\n ctx.state.update(setBusy, false);\n }\n };\n const requireSignatures = () => {\n const signatures = ctx.doc.signatures;\n if (!signatures) {\n throw new PluginError(\n 'unsupported',\n 'signature',\n 'this engine does not implement signatures',\n );\n }\n return signatures;\n };\n const documentId = () => {\n const id = ctx.documentId;\n if (!id) throw new PluginError('not-ready', 'signature', 'no document id');\n return id;\n };\n return { withBusy, requireSignatures, documentId };\n}\nexport type SignatureStore = ReturnType<typeof createStore>;\n","/**\n * Plugin-private services every area is built on (not the kernel): the\n * events, the busy bracket and engine doors, authority, the sibling plugins\n * and mark resolution.\n */\nimport { createAuthority, type SignatureAuthority } from './authority';\nimport type { SignatureContext } from './context';\nimport { createEvents, type SignatureEvents } from './events';\nimport { createMarks, type SignatureMarks } from './marks';\nimport { resolveSiblings, type SignatureSiblings } from './siblings';\nimport { createStore, type SignatureStore } from './store';\n\nexport type { SignatureContext } from './context';\n\nexport interface SignatureServices {\n readonly events: SignatureEvents;\n readonly store: SignatureStore;\n readonly authority: SignatureAuthority;\n readonly siblings: SignatureSiblings;\n readonly marks: SignatureMarks;\n}\n\nexport function createServices(ctx: SignatureContext): SignatureServices {\n const siblings = resolveSiblings(ctx);\n return {\n events: createEvents(ctx),\n store: createStore(ctx),\n authority: createAuthority(ctx, siblings),\n siblings,\n marks: createMarks(siblings),\n };\n}\n","/**\n * The signature facts, mirrored from the engine: every signature field with\n * its signed state, the protection in force, and the parked two-phase\n * signing. They change only by loads and by confirmed document events,\n * whoever caused them, and this is the one place the fact events fire\n * (`onSigned`, `onProtectionChanged`). The judgement reacts here too: a\n * load re-judges at once when anything is signed; a changed snapshot and\n * every edit of the working copy re-judge once the edits pause.\n */\nimport type { Mirror } from '@embedpdf/core';\nimport type { DocumentEvent, DocumentProtection } from '@embedpdf/engine-core/runtime';\n\nimport {\n completeResultOf,\n emptySignatureRecord,\n foldSignatureEvent,\n hasSignedField,\n type SignatureRecord,\n} from '../model';\nimport type { SignatureContext, SignatureServices } from '../services';\nimport type { SignatureValidation } from './validation';\n\n/** Edits of the working copy: what a save would write changed, so a verdict may have too. */\nconst WORKING_COPY_EDITS: ReadonlySet<DocumentEvent['type']> = new Set([\n 'annotations.created',\n 'annotations.updated',\n 'annotations.deleted',\n 'annotations.reordered',\n 'forms.valueSet',\n 'forms.updated',\n]);\n\nconst sameProtection = (\n left: DocumentProtection | null,\n right: DocumentProtection | null,\n): boolean => JSON.stringify(left) === JSON.stringify(right);\n\nexport function createSignaturesMirror(\n ctx: SignatureContext,\n { events }: Pick<SignatureServices, 'events'>,\n { validateNow, revalidateSoon }: Pick<SignatureValidation, 'validateNow' | 'revalidateSoon'>,\n) {\n const { signed, protectionChanged } = events;\n\n /** Parked signings the engine answered it does not know: no event will clear them. */\n const disowned = new Set<string>();\n\n const mirror: Mirror<SignatureRecord> = ctx.mirror<SignatureRecord>({\n name: 'signatures',\n initial: emptySignatureRecord,\n // The engine's snapshot says nothing about a parked signing: a load\n // keeps the one the events announced, unless the engine disowned it.\n load: async (doc) => {\n const snapshot = doc.signatures ? await doc.signatures.list() : null;\n const pending = mirror.get().pending;\n return {\n value: {\n snapshot,\n pending: pending && !disowned.has(pending.signingId) ? pending : null,\n },\n };\n },\n fold: foldSignatureEvent,\n changed: ({ cause, event, previous, next }) => {\n const protection = next.snapshot?.protection ?? null;\n if (protection && !sameProtection(previous.snapshot?.protection ?? null, protection)) {\n protectionChanged.emit({ protection });\n }\n if (event?.type === 'signatures.completed') {\n signed.emit({\n field: event.signature.field,\n result: completeResultOf(event),\n origin: event.origin,\n });\n }\n if (!hasSignedField(next.snapshot)) return;\n if (cause === 'load') validateNow();\n else if (previous.snapshot !== next.snapshot) revalidateSoon();\n },\n });\n\n return {\n mirror,\n /**\n * The engine does not know this parked signing (its cancel answered\n * `unknown`), so no event will ever clear it: reload without it.\n */\n disown(signingId: string): Promise<void> {\n disowned.add(signingId);\n return mirror.refresh();\n },\n connect(): void {\n ctx.listen(ctx.doc.events, (event) => {\n if (WORKING_COPY_EDITS.has(event.type) && hasSignedField(mirror.get().snapshot)) {\n revalidateSoon();\n }\n });\n },\n };\n}\nexport type SignaturesMirror = ReturnType<typeof createSignaturesMirror>;\n","/**\n * Judging the signatures. The viewer judges the working copy by default\n * (unsaved edits count), so the verdict is the one the file a save produces\n * will get. Verdicts are session state: each validation commits its own, and\n * `onValidated` fires where one completes. Re-judging after an edit waits\n * for a pause: a pen stroke is many events, one analysis.\n */\nimport type { SignatureVerdict } from '@embedpdf/core-signature';\n\nimport type { SignatureValidateOptions } from '../contract';\nimport { setVerdicts } from '../model';\nimport type { SignatureContext, SignatureServices } from '../services';\n\nconst REVALIDATE_DELAY_MS = 300;\n\nexport function createValidation(\n ctx: SignatureContext,\n { events }: Pick<SignatureServices, 'events'>,\n) {\n const { validated } = events;\n const settings = ctx.settings();\n\n const validate = async (\n options?: SignatureValidateOptions,\n ): Promise<readonly SignatureVerdict[]> => {\n if (!ctx.doc.signatures) return [];\n // The cryptography loads the first time a signature is checked.\n const { validateSignatures } = await ctx.cancellable(\n options?.signal,\n import('@embedpdf/core-signature'),\n );\n const verdicts = await ctx.cancellable(\n options?.signal,\n validateSignatures(ctx.doc, {\n trust: settings.get().trust,\n at: options?.at,\n until: options?.until ?? 'working-copy',\n }),\n );\n ctx.state.update(setVerdicts, verdicts);\n validated.emit({ verdicts });\n return verdicts;\n };\n\n let cancelRevalidate: (() => void) | null = null;\n const cancelScheduled = (): void => {\n cancelRevalidate?.();\n cancelRevalidate = null;\n };\n const validateInBackground = (): void => {\n void validate().catch((error) =>\n globalThis.console?.error('[signature] validation failed:', error),\n );\n };\n\n return {\n validate,\n /** Judge now; a scheduled re-judgement is superseded. */\n validateNow: (): void => {\n cancelScheduled();\n validateInBackground();\n },\n /** Judge once the edits pause. */\n revalidateSoon: (): void => {\n cancelScheduled();\n cancelRevalidate = ctx.clock.after(REVALIDATE_DELAY_MS, () => {\n cancelRevalidate = null;\n validateInBackground();\n });\n },\n };\n}\nexport type SignatureValidation = ReturnType<typeof createValidation>;\n","/** A one-page blank PDF: the appearance that clears a visual fill. */\n// A content stream that draws nothing but is not empty (`q Q`): the engine\n// turns the page into a form XObject, and refuses a page with no content at\n// all; a saved and restored state passes and paints nothing.\nconst CONTENT = 'q Q';\nconst OBJECTS = [\n '<< /Type /Catalog /Pages 2 0 R >>',\n '<< /Type /Pages /Kids [3 0 R] /Count 1 >>',\n '<< /Type /Page /Parent 2 0 R /MediaBox [0 0 200 60] /Contents 4 0 R /Resources << >> >>',\n `<< /Length ${CONTENT.length} >>\\nstream\\n${CONTENT}\\nendstream`,\n];\n\nlet cached: Uint8Array | null = null;\n\nexport function blankPagePdf(): Uint8Array {\n if (cached) return new Uint8Array(cached);\n let body = '%PDF-1.7\\n';\n const offsets: number[] = [];\n OBJECTS.forEach((object, index) => {\n offsets.push(body.length);\n body += `${index + 1} 0 obj\\n${object}\\nendobj\\n`;\n });\n const xref = body.length;\n body += `xref\\n0 ${OBJECTS.length + 1}\\n0000000000 65535 f \\n`;\n for (const offset of offsets) body += `${String(offset).padStart(10, '0')} 00000 n \\n`;\n body += `trailer\\n<< /Size ${OBJECTS.length + 1} /Root 1 0 R >>\\nstartxref\\n${xref}\\n%%EOF\\n`;\n cached = new TextEncoder().encode(body);\n return new Uint8Array(cached);\n}\n","/** Visual fills: the mark becomes the widget's appearance, nothing is sealed. */\nimport { PluginError, type OperationOptions } from '@embedpdf/core';\nimport type { FormFieldRef } from '@embedpdf/engine-core/runtime';\n\nimport { blankPagePdf } from '../blank-page';\nimport type { Mark, SignatureCapability } from '../contract';\nimport type { SignatureReads } from '../read/signatures';\nimport type { SignatureContext, SignatureServices } from '../services';\nimport { verb } from '../services/errors';\n\nexport function createFills(\n ctx: SignatureContext,\n {\n events,\n store,\n marks,\n authority,\n }: Pick<SignatureServices, 'events' | 'store' | 'marks' | 'authority'>,\n { getSignature }: Pick<SignatureReads, 'getSignature'>,\n target: { clearIfTarget(field: FormFieldRef): void },\n) {\n const { filled, cleared } = events;\n const { withBusy } = store;\n const { markBytes } = marks;\n\n const setAppearance = async (\n field: FormFieldRef,\n pdf: Uint8Array,\n options?: OperationOptions,\n ): Promise<void> => {\n const forms = ctx.doc.forms;\n if (!forms.setSignatureAppearance) {\n throw new PluginError(\n 'unsupported',\n 'signature',\n 'this engine cannot draw into a signature field',\n );\n }\n const signature = getSignature(field);\n if (signature?.signed) {\n throw new PluginError('conflict', 'signature', `'${signature.fieldName}' is signed`);\n }\n await ctx.cancellable(options?.signal, forms.setSignatureAppearance(field, { pdf }));\n };\n\n const fillField = async (\n field: FormFieldRef,\n mark: Mark,\n options?: OperationOptions,\n ): Promise<void> => {\n authority.assertAllowedField('fill', field, 'signature.fillField');\n return withBusy(async () => {\n await setAppearance(field, await markBytes(mark), options);\n target.clearIfTarget(field);\n filled.emit({ field });\n });\n };\n\n const clearField = async (field: FormFieldRef, options?: OperationOptions): Promise<void> => {\n authority.assertAllowedField('fill', field, 'signature.clearField');\n return withBusy(async () => {\n await setAppearance(field, blankPagePdf(), options);\n cleared.emit({ field });\n });\n };\n\n return {\n fillField,\n api: {\n fillField: verb(fillField),\n clearField: verb(clearField),\n } satisfies Partial<SignatureCapability>,\n };\n}\nexport type SignatureFills = ReturnType<typeof createFills>;\n","/**\n * The destination rule and the sign-here flow: a mark over a field is\n * signed, drawn, or handed to the chrome by mode; a free placement is a\n * stamp (one placement law, the stamp plugin's).\n */\nimport { PluginError, type OperationOptions } from '@embedpdf/core';\nimport type { FormFieldRef, SignatureCompleteResult } from '@embedpdf/engine-core/runtime';\nimport type { StampPlacement } from '@embedpdf/plugin-annotation/contract';\n\nimport type { Mark, PlaceMarkResult, SignatureCapability, SignFieldInput } from '../contract';\nimport { hasSignedField, sameFieldRef, setTarget } from '../model';\nimport type { SignatureReads } from '../read/signatures';\nimport type { SignatureContext, SignatureServices } from '../services';\nimport { verb } from '../services/errors';\n\nexport function createTarget(\n ctx: SignatureContext,\n { events }: Pick<SignatureServices, 'events'>,\n { getSignature }: Pick<SignatureReads, 'getSignature'>,\n) {\n const { inspectionRequested } = events;\n /** One field, whether a ref names it by object number or by name. */\n const sameField = (left: FormFieldRef, right: FormFieldRef): boolean => {\n if (sameFieldRef(left, right)) return true;\n const signature = getSignature(left);\n return signature !== null && signature.index === getSignature(right)?.index;\n };\n /** A field that was just signed or filled is no longer the target. */\n const clearIfTarget = (field: FormFieldRef): void => {\n const current = ctx.state.get().target;\n if (current && sameField(current, field)) ctx.state.update(setTarget, null);\n };\n return {\n clearIfTarget,\n api: {\n setTarget: (field) => ctx.state.update(setTarget, field),\n requestInspection: (field) => inspectionRequested.emit({ field }),\n } satisfies Partial<SignatureCapability>,\n };\n}\nexport type SignatureTarget = ReturnType<typeof createTarget>;\n\nexport function createPlacement(\n ctx: SignatureContext,\n {\n events,\n store,\n authority,\n siblings,\n }: Pick<SignatureServices, 'events' | 'store' | 'authority' | 'siblings'>,\n { snapshot }: Pick<SignatureReads, 'snapshot'>,\n {\n sign,\n }: { sign(input: SignFieldInput, options?: OperationOptions): Promise<SignatureCompleteResult> },\n {\n fillField,\n }: { fillField(field: FormFieldRef, mark: Mark, options?: OperationOptions): Promise<void> },\n) {\n const { signRequested } = events;\n const { documentId } = store;\n const { mode } = authority;\n const { stamp, annotation } = siblings;\n const settings = ctx.settings();\n\n const placeMark = async (\n mark: Mark,\n target: { field: FormFieldRef } | StampPlacement,\n options?: OperationOptions,\n ): Promise<PlaceMarkResult> => {\n if (!('field' in target)) {\n // Free placement: a stamp, as in Preview; one placement law, the stamp plugin's.\n if ('assetId' in mark) {\n const library = stamp();\n if (!library) {\n throw new PluginError('unsupported', 'signature', 'no stamp plugin to place an asset');\n }\n const placed = await library.placeAsset(mark.assetId, target, {\n documentId: documentId(),\n signal: options?.signal,\n });\n return { kind: 'placed', annotation: placed.annotation.ref };\n }\n const annotations = annotation();\n if (!annotations) {\n throw new PluginError('unsupported', 'signature', 'no annotation plugin to place a mark');\n }\n const placed = await annotations.stamps.place({ source: mark.source }, target, options);\n return { kind: 'placed', annotation: placed.annotation.ref };\n }\n switch (mode()) {\n case 'sign':\n // The first signature is the one that can certify: when the settings\n // allow a certification, let the chrome offer the choice (its sign\n // dialog) instead of sealing a plain approval on the spot.\n if (settings.get().allowCertify && !hasSignedField(snapshot())) {\n signRequested.emit({ field: target.field, mark });\n return { kind: 'requested', field: target.field };\n }\n return {\n kind: 'signed',\n field: target.field,\n result: await sign({ field: target.field, mark }, options),\n };\n case 'visual':\n await fillField(target.field, mark, options);\n return { kind: 'filled', field: target.field };\n case 'ask':\n signRequested.emit({ field: target.field, mark });\n return { kind: 'requested', field: target.field };\n }\n };\n\n return { api: { placeMark: verb(placeMark) } satisfies Partial<SignatureCapability> };\n}\n","/**\n * The act of sealing. One-shot: `sign` (prepare, the key, complete,\n * through `@embedpdf/core-signature`). Two-phase: `prepareSignature` parks\n * the signing and hands out the digest; `completeSignature` seals it with a\n * detached CMS; `cancelPending` cancels. The parked signing, the sealed\n * field's facts and `onSigned` come from the confirmed events the engine\n * publishes for each step (`sync/signatures.ts`), for every session alike.\n */\nimport { PluginError, type OperationOptions } from '@embedpdf/core';\nimport type {\n DocumentHandle,\n FormFieldRef,\n SignatureCompleteResult,\n SignaturePrepared,\n} from '@embedpdf/engine-core/runtime';\n\nimport type { PrepareSignatureInput, SignatureCapability, SignFieldInput } from '../contract';\nimport type { SignatureReads } from '../read/signatures';\nimport type { SignatureContext, SignatureServices } from '../services';\nimport { verb } from '../services/errors';\nimport type { SignaturesMirror } from '../sync/signatures';\n\nexport function createSigning(\n ctx: SignatureContext,\n { store, authority, marks }: Pick<SignatureServices, 'store' | 'authority' | 'marks'>,\n { api: reads }: Pick<SignatureReads, 'api'>,\n target: { clearIfTarget(field: FormFieldRef): void },\n signatures: Pick<SignaturesMirror, 'disown'>,\n) {\n const { withBusy, requireSignatures } = store;\n const { resolveKey, assertAllowedField } = authority;\n const { bytesOf, markBytes } = marks;\n\n /** Two-phase signings this session prepared: the version each one must complete against. */\n const prepared = new Map<string, SignaturePrepared>();\n\n const cancelled = (signal: AbortSignal): PluginError =>\n new PluginError('operation-cancelled', 'signature', 'signing cancelled', {\n cause: signal.reason,\n });\n\n /**\n * The document as one-shot signing sees it, with the caller's signal checked\n * right before the seal: a signal that fired by then leaves nothing signed\n * (the signing gives the prepared candidate up), and after it the seal is\n * done.\n */\n const sealUnlessCancelled = (signal: AbortSignal | undefined): DocumentHandle => {\n const signatures = requireSignatures();\n if (!signal) return ctx.doc;\n return {\n signatures: {\n prepare: (input: Parameters<typeof signatures.prepare>[0]) => signatures.prepare(input),\n cancel: (signingId: string) => signatures.cancel(signingId),\n complete: (input: Parameters<typeof signatures.complete>[0]) => {\n if (signal.aborted) return Promise.reject(cancelled(signal));\n return signatures.complete(input);\n },\n },\n } as unknown as DocumentHandle;\n };\n\n /**\n * Refused before anything starts: signing the field (`doc.sign`, or\n * `fields:sign` for its group), and `doc.sign.certify` for a certification.\n */\n const assertMaySign = (\n input: { field: FormFieldRef; certify?: unknown },\n operation: string,\n ): void => {\n assertAllowedField('sign', input.field, operation);\n if (input.certify) ctx.assertAllowed('doc.sign.certify', operation);\n };\n\n const appearanceOf = async (input: {\n mark?: SignFieldInput['mark'];\n appearance?: SignFieldInput['appearance'];\n }) => {\n if (input.appearance) return bytesOf(input.appearance);\n if (input.mark) return markBytes(input.mark);\n return null;\n };\n\n const sign = async (\n input: SignFieldInput,\n options?: OperationOptions,\n ): Promise<SignatureCompleteResult> => {\n assertMaySign(input, 'signature.sign');\n if (options?.signal?.aborted) throw cancelled(options.signal);\n return withBusy(async () => {\n const doc = sealUnlessCancelled(options?.signal);\n // The cryptography loads the first time someone signs.\n const { certificateCommonName, sign: signDocument } =\n await import('@embedpdf/core-signature');\n const key = await resolveKey(input.key);\n // The certificate's subject is the default /Name; the caller's facts win.\n const subject =\n key.kind === 'raw' && key.certificateChain[0]\n ? certificateCommonName(key.certificateChain[0])\n : null;\n const signer = { ...(subject ? { name: subject } : {}), ...input.signer };\n // The appearance is the mark: its page is drawn into the widget by the engine.\n const appearance = (await appearanceOf(input))!;\n const result = await signDocument(doc, {\n field: input.field,\n key,\n signer,\n certify: input.certify,\n lock: input.lock,\n appearance: { pdf: appearance },\n });\n target.clearIfTarget(input.field);\n return result;\n });\n };\n\n const prepareSignature = async (\n input: PrepareSignatureInput,\n options?: OperationOptions,\n ): Promise<SignaturePrepared> => {\n assertMaySign(input, 'signature.prepareSignature');\n return withBusy(async () => {\n const signatures = requireSignatures();\n const appearance = await appearanceOf(input);\n const pending = signatures.prepare({\n field: input.field,\n signer: input.signer,\n certify: input.certify,\n lock: input.lock,\n subFilter: input.subFilter,\n digest: input.digest,\n ...(appearance ? { appearance: { pdf: appearance } } : {}),\n });\n const result = await ctx.cancellable(options?.signal, pending);\n prepared.set(result.signingId, result);\n return result;\n });\n };\n\n const completeSignature = async (\n signingId: string,\n cms: Uint8Array,\n options?: OperationOptions,\n ): Promise<SignatureCompleteResult> => {\n // Its field was checked when it was prepared; the engine checks it again.\n if (options?.signal?.aborted) throw cancelled(options.signal);\n return withBusy(async () => {\n const signatures = requireSignatures();\n const parked = prepared.get(signingId);\n if (!parked) {\n throw new PluginError(\n 'not-found',\n 'signature',\n `no signing '${signingId}' was prepared in this session`,\n );\n }\n const result = await signatures.complete({\n signingId,\n cms,\n expectedVersion: parked.expectedVersion,\n });\n prepared.delete(signingId);\n target.clearIfTarget(result.signature.field);\n return result;\n });\n };\n\n const cancelPending = async (options?: OperationOptions): Promise<void> => {\n const pending = reads.getPending();\n if (!pending) return;\n assertAllowedField('sign', pending.field, 'signature.cancelPending');\n const { status } = await ctx.cancellable(\n options?.signal,\n requireSignatures().cancel(pending.signingId),\n );\n prepared.delete(pending.signingId);\n // A cancel or a completion clears the signing through its event; an\n // unknown signing has none.\n if (status === 'unknown') await signatures.disown(pending.signingId);\n };\n\n return {\n sign,\n api: {\n sign: verb(sign),\n prepareSignature: verb(prepareSignature),\n completeSignature: verb(completeSignature),\n cancelPending: verb(cancelPending),\n } satisfies Partial<SignatureCapability>,\n };\n}\nexport type SignatureSigning = ReturnType<typeof createSigning>;\n","/**\n * The signature controller: the composition root. It builds the plugin's\n * services once, wires each area with the services it declares, and\n * assembles the capability from the areas' API slices. No behavior lives\n * here: every verb and read has a home in `read/`, `write/` or `sync/`.\n */\nimport { composeApi } from '@embedpdf/core';\n\nimport { connectSiblings } from './connect';\nimport type { SignatureCapability } from './contract';\nimport { createJudging } from './read/judging';\nimport { createSignatureReads } from './read/signatures';\nimport { createServices, type SignatureContext } from './services';\nimport { createSignaturesMirror } from './sync/signatures';\nimport { createValidation } from './sync/validation';\nimport { createFills } from './write/fill';\nimport { createPlacement, createTarget } from './write/place';\nimport { createSigning } from './write/sign';\n\nexport function createSignatureController(ctx: SignatureContext) {\n const services = createServices(ctx);\n const { events, authority } = services;\n const settings = ctx.settings();\n\n // Sync: the engine's facts, mirrored, and the judgement that reacts to them.\n const validation = createValidation(ctx, services);\n const signatures = createSignaturesMirror(ctx, services, validation);\n\n // Reads: projections of the mirror and the session state.\n const reads = createSignatureReads(ctx, services, signatures.mirror);\n const judging = createJudging(ctx, services, validation, signatures.mirror, reads);\n\n // Writes: the sign-here target, sealing, visual fills, the destination rule.\n const target = createTarget(ctx, services, reads);\n const signing = createSigning(ctx, services, reads, target, signatures);\n const fills = createFills(ctx, services, reads, target);\n const placement = createPlacement(ctx, services, reads, signing, fills);\n\n const api: SignatureCapability = composeApi('signature', [\n settings.api,\n reads.api,\n judging.api,\n target.api,\n signing.api,\n fills.api,\n placement.api,\n {\n // Authority twins and the events are services, not areas.\n canSign: authority.canSign,\n canFill: authority.canFill,\n canCertify: authority.canCertify,\n canReadRevision: authority.canReadRevision,\n onSigned: events.signed.on,\n onFilled: events.filled.on,\n onCleared: events.cleared.on,\n onValidated: events.validated.on,\n onProtectionChanged: events.protectionChanged.on,\n onInvalidationPredicted: events.invalidationPredicted.on,\n onTargetChanged: events.targetChanged.on,\n onSignRequested: events.signRequested.on,\n onInspectionRequested: events.inspectionRequested.on,\n },\n ]);\n\n return {\n api,\n connect(): void {\n signatures.connect();\n connectSiblings(ctx, api);\n },\n };\n}\n","import { definePlugin } from '@embedpdf/core';\nimport { AnnotationToken } from '@embedpdf/plugin-annotation/contract';\nimport { FormToken } from '@embedpdf/plugin-form/contract';\nimport { InteractionToken } from '@embedpdf/plugin-interaction/contract/host';\nimport { StampToken } from '@embedpdf/plugin-stamp/contract';\n\nimport { SIGNATURE_DEFAULTS, SignatureToken, type SignatureConfig } from './contract';\nimport { createSignatureController } from './controller';\nimport { initialSignatureState } from './model';\n\n/**\n * The signature plugin: the act of signing, document-scoped. It owns no\n * mark: marks are stamp-library assets (or bytes the embedder brings), and\n * the mark is the appearance the engine draws into the field. Signing goes\n * through `@embedpdf/core-signature` with the `key` setting's signer port;\n * the engine seals; on the cloud the server publishes the new version.\n *\n * With the interaction hub and the stamp plugin present, an armed mark from\n * a `signatures` library dropped over an unsigned signature field goes into\n * the field (sign, visual fill or ask, by mode) instead of onto the page.\n * `config` is the settings the app registers, over {@link SIGNATURE_DEFAULTS}.\n */\nexport const signaturePlugin = (config?: SignatureConfig) =>\n definePlugin({\n id: 'signature',\n token: SignatureToken,\n scope: 'document',\n requires: [FormToken],\n optional: [InteractionToken, StampToken, AnnotationToken],\n state: initialSignatureState,\n // A key and a trust port are one value each: a change replaces them, never merges into them.\n settings: { defaults: SIGNATURE_DEFAULTS, registered: config, whole: ['key', 'trust'] },\n create: createSignatureController,\n });\n","/**\n * The signatures page's State table as code: what `useSignatureState()`\n * returns, and the same fields in every other framework.\n */\nimport { defineState } from '@embedpdf/core';\n\nimport { SignatureToken, type SignatureInfo } from './contract';\n\nconst NO_SIGNATURES: readonly SignatureInfo[] = Object.freeze([]);\n\nexport const signatureState = defineState(SignatureToken, {\n read: (signature) => ({\n signatures: signature.listSignatures(),\n protection: signature.getProtection(),\n target: signature.getTarget(),\n busy: signature.isBusy(),\n pending: signature.getPending(),\n status: signature.getStatus(),\n }),\n empty: {\n signatures: NO_SIGNATURES,\n protection: null,\n target: null,\n busy: false,\n pending: null,\n status: 'idle',\n },\n});\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@embedpdf/plugin-signature",
3
- "version": "3.0.0-next.13",
3
+ "version": "3.0.0-next.15",
4
4
  "private": false,
5
5
  "description": "Document-scoped digital signing: sign a signature field with a mark (a stamp-library asset or bytes you bring) through a signer port, fill it visually without sealing, validate what is signed, and drop an armed mark onto a field. Owns the act, never a mark — marks are the stamp plugin's.",
6
6
  "type": "module",
@@ -22,18 +22,18 @@
22
22
  "dist"
23
23
  ],
24
24
  "dependencies": {
25
- "@embedpdf/core": "3.0.0-next.13",
26
- "@embedpdf/core-signature": "3.0.0-next.13",
27
- "@embedpdf/engine-core": "3.0.0-next.13",
28
- "@embedpdf/plugin-annotation": "3.0.0-next.13",
29
- "@embedpdf/plugin-interaction": "3.0.0-next.13",
30
- "@embedpdf/plugin-stamp": "3.0.0-next.13",
31
- "@embedpdf/plugin-form": "3.0.0-next.13"
25
+ "@embedpdf/core": "3.0.0-next.15",
26
+ "@embedpdf/core-signature": "3.0.0-next.15",
27
+ "@embedpdf/plugin-annotation": "3.0.0-next.15",
28
+ "@embedpdf/plugin-form": "3.0.0-next.15",
29
+ "@embedpdf/plugin-interaction": "3.0.0-next.15",
30
+ "@embedpdf/engine-core": "3.0.0-next.15",
31
+ "@embedpdf/plugin-stamp": "3.0.0-next.15"
32
32
  },
33
33
  "devDependencies": {
34
34
  "typescript": "^5.0.0",
35
35
  "vitest": "^2.1.9",
36
- "@embedpdf/engine": "3.0.0-next.13",
36
+ "@embedpdf/engine": "3.0.0-next.15",
37
37
  "@embedpdf/tooling-build": "0.0.0"
38
38
  },
39
39
  "license": "Apache-2.0",
@@ -1,176 +0,0 @@
1
- import { EventHook } from "@embedpdf/core";
2
- import { SignatureVerdict, SignatureVerdict as SignatureVerdict$1, SignerPort, SignerPort as SignerPort$1, TrustPort, TrustPort as TrustPort$1, ValidationTime, ValidationTime as ValidationTime$1 } from "@embedpdf/core-signature";
3
- import { AnalyzeInput, AnalyzeInput as AnalyzeInput$1, BinarySource, ChangeAnalysis, ChangeAnalysis as ChangeAnalysis$1, DocMdpPermission, DocMdpPermission as DocMdpPermission$1, DocumentProtection, DocumentProtection as DocumentProtection$1, FieldLockSpec, FieldLockSpec as FieldLockSpec$1, FormFieldRef, FormFieldRef as FormFieldRef$1, SignatureCompleteResult, SignatureCompleteResult as SignatureCompleteResult$1, SignatureDTO, SignatureDTO as SignatureDTO$1, SignatureSnapshot, SignatureSnapshot as SignatureSnapshot$1 } from "@embedpdf/engine-core/runtime";
4
- import { StampPlacement } from "@embedpdf/plugin-annotation/contract";
5
- import { StampAsset } from "@embedpdf/plugin-stamp/contract";
6
- //#region src/types.d.ts
7
- /**
8
- * What placing a mark on a signature field does:
9
- * - `sign` seal the field with the configured signer (the mark is the appearance);
10
- * - `visual` draw the mark into the field without sealing (Preview's "signature");
11
- * - `ask` neither — emit `ask` so the chrome can open its dialog and decide.
12
- * Default `sign` when a signer is configured, else `visual`.
13
- */
14
- type SignatureMode = 'sign' | 'visual' | 'ask';
15
- interface SignatureConfig {
16
- mode?: SignatureMode;
17
- /** The key holder: a raw signer (the CMS is built here) or a CMS signer (a service builds it). A thunk resolves per signing. */
18
- signer?: SignerPort | (() => Promise<SignerPort>);
19
- /** Trust anchors for validation. None → every verdict tops out at `valid-untrusted`. */
20
- trust?: TrustPort;
21
- /** Let the UI offer a certification (still needs `doc.sign.certify`). Default false. */
22
- allowCertify?: boolean;
23
- }
24
- /** The mark: a stamp-plugin asset, or bytes the embedder brings (PNG, JPEG, or a one-page PDF). */
25
- type Mark = {
26
- assetId: string;
27
- } | {
28
- source: BinarySource;
29
- };
30
- interface SignFieldInput {
31
- field: FormFieldRef;
32
- mark: Mark;
33
- /** What the signature dictionary says (`/Name` `/Reason` `/Location` `/ContactInfo`); the name defaults to the certificate's subject. */
34
- attribution?: {
35
- name?: string;
36
- reason?: string;
37
- location?: string;
38
- contactInfo?: string;
39
- };
40
- /** Instead of the mark: a ready one-page appearance PDF the embedder composed itself. */
41
- appearance?: BinarySource;
42
- certify?: {
43
- permission: DocMdpPermission;
44
- };
45
- lock?: FieldLockSpec;
46
- }
47
- /** The stamp-library kind that holds people's marks: one library per person. */
48
- declare const SIGNATURES_LIBRARY_KIND = "signatures";
49
- /** The asset identifiers inside a signatures library: the full signature and the initials. */
50
- declare const SIGNATURE_MARK_NAME = "signature";
51
- declare const INITIALS_MARK_NAME = "initials";
52
- type MarkRole = 'signature' | 'initials';
53
- /** Which mark an asset of a signatures library is (anything not named `initials` is a signature). */
54
- declare const markRoleOf: (asset: Pick<StampAsset, "name">) => MarkRole;
55
- interface SignaturePending {
56
- signingId: string;
57
- field: FormFieldRef;
58
- }
59
- interface SignatureState {
60
- snapshot: SignatureSnapshot | null;
61
- verdicts: SignatureVerdict[] | null;
62
- /** The field the user chose to sign next ("select the field, then pick a mark"). */
63
- target: FormFieldRef | null;
64
- /** A signing candidate is parked (here or, on the cloud, elsewhere): the document is read-only. */
65
- pending: SignaturePending | null;
66
- /** A sign/fill call is in flight. */
67
- busy: boolean;
68
- }
69
- type SignatureAction = {
70
- type: 'SNAPSHOT';
71
- snapshot: SignatureSnapshot | null;
72
- } | {
73
- type: 'VERDICTS';
74
- verdicts: SignatureVerdict[] | null;
75
- } | {
76
- type: 'TARGET';
77
- field: FormFieldRef | null;
78
- } | {
79
- type: 'PENDING';
80
- pending: SignaturePending | null;
81
- } | {
82
- type: 'BUSY';
83
- busy: boolean;
84
- };
85
- type SignatureChange = {
86
- type: 'signed';
87
- field: FormFieldRef;
88
- result: SignatureCompleteResult;
89
- } | {
90
- type: 'filled';
91
- field: FormFieldRef;
92
- } | {
93
- type: 'cleared';
94
- field: FormFieldRef;
95
- } |
96
- /** Mode `ask`: a mark met a field and the chrome decides (open its dialog, then `signField`/`fillField`). */
97
- {
98
- type: 'ask';
99
- field: FormFieldRef;
100
- mark: Mark;
101
- } |
102
- /** A signed field was activated: show what its signature says. */
103
- {
104
- type: 'inspect';
105
- field: FormFieldRef;
106
- } | {
107
- type: 'target';
108
- field: FormFieldRef | null;
109
- } | {
110
- type: 'validated';
111
- verdicts: SignatureVerdict[];
112
- } |
113
- /** An unsaved edit just turned a signature that held into one a save would invalidate. Once per edge. */
114
- {
115
- type: 'invalidating';
116
- field: FormFieldRef;
117
- detail: string;
118
- } | {
119
- type: 'protectionChanged';
120
- protection: DocumentProtection;
121
- };
122
- interface SignatureCapability {
123
- snapshot(): SignatureSnapshot | null;
124
- verdicts(): SignatureVerdict[] | null;
125
- protection(): DocumentProtection | null;
126
- pending(): SignaturePending | null;
127
- target(): FormFieldRef | null;
128
- busy(): boolean;
129
- mode(): SignatureMode;
130
- /** The signature facts of one field, by ref or by widget, from the last snapshot. */
131
- signatureOf(field: FormFieldRef | {
132
- annotObjectNumber: number;
133
- }): SignatureDTO | null;
134
- /** The verdict of one signed field from the last validation. */
135
- verdictOf(field: FormFieldRef | {
136
- annotObjectNumber: number;
137
- }): SignatureVerdict | null;
138
- /** `doc.sign` is granted and a signer is configured (or resolvable). */
139
- canSign(): boolean;
140
- /** Visual fills ride `doc.forms.fill`. */
141
- canFill(): boolean;
142
- /** `allowCertify` and `doc.sign.certify`. */
143
- canCertify(): boolean;
144
- /** Seal the field: the mark's page becomes the widget's appearance, the configured signer signs. */
145
- signField(input: SignFieldInput): Promise<SignatureCompleteResult>;
146
- /** Visual only: the mark becomes the widget's appearance; nothing is sealed. Refused on a signed field. */
147
- fillField(field: FormFieldRef, mark: Mark): Promise<void>;
148
- /** Undo a visual fill (a blank appearance). Refused on a signed field. */
149
- clearField(field: FormFieldRef): Promise<void>;
150
- /** The destination rule in one call: a field (sign, fill, or ask by mode) or a free placement (a stamp). */
151
- placeMark(mark: Mark, target: {
152
- field: FormFieldRef;
153
- } | StampPlacement): Promise<void>;
154
- /** Name the field the next picked mark goes to (the chrome's "Sign here"); null clears. */
155
- setTarget(field: FormFieldRef | null): void;
156
- /** Ask the chrome to show a signed field's facts (`inspect`). */
157
- inspect(field: FormFieldRef): void;
158
- refresh(): Promise<SignatureSnapshot | null>;
159
- /**
160
- * Judge every signature. The viewer's default is the WORKING COPY: unsaved
161
- * edits count, so the verdict is the one the file a save produces will get.
162
- * `until: 'persisted'` judges the loaded bytes only.
163
- */
164
- validate(opts?: {
165
- at?: ValidationTime;
166
- until?: 'persisted' | 'working-copy';
167
- }): Promise<SignatureVerdict[]>;
168
- analyze(input: AnalyzeInput): Promise<ChangeAnalysis>;
169
- /** The exact bytes a signature's revision covers (`doc.signatures.revisionBytes`) — rides `doc.download`. */
170
- revisionBytes(revisionIndex: number): Promise<Uint8Array>;
171
- onChanged: EventHook<SignatureChange>;
172
- }
173
- declare const SignatureToken: import("@embedpdf/core").CapabilityToken<SignatureCapability>;
174
- //#endregion
175
- export { SignatureConfig as C, SignatureToken as D, SignatureState as E, markRoleOf as O, SignatureChange as S, SignaturePending as T, SIGNATURES_LIBRARY_KIND as _, FieldLockSpec$1 as a, SignatureAction as b, SignatureDTO$1 as c, SignerPort$1 as d, TrustPort$1 as f, MarkRole as g, Mark as h, DocumentProtection$1 as i, SignatureSnapshot$1 as l, INITIALS_MARK_NAME as m, ChangeAnalysis$1 as n, FormFieldRef$1 as o, ValidationTime$1 as p, DocMdpPermission$1 as r, SignatureCompleteResult$1 as s, AnalyzeInput$1 as t, SignatureVerdict$1 as u, SIGNATURE_MARK_NAME as v, SignatureMode as w, SignatureCapability as x, SignFieldInput as y };
176
- //# sourceMappingURL=contract-BvHa9Zl_.d.cts.map
@@ -1,14 +0,0 @@
1
- import { createCapabilityToken } from "@embedpdf/core";
2
- //#region src/types.ts
3
- /** The stamp-library kind that holds people's marks: one library per person. */
4
- const SIGNATURES_LIBRARY_KIND = "signatures";
5
- /** The asset identifiers inside a signatures library: the full signature and the initials. */
6
- const SIGNATURE_MARK_NAME = "signature";
7
- const INITIALS_MARK_NAME = "initials";
8
- /** Which mark an asset of a signatures library is (anything not named `initials` is a signature). */
9
- const markRoleOf = (asset) => asset.name === "initials" ? "initials" : "signature";
10
- const SignatureToken = createCapabilityToken("signature");
11
- //#endregion
12
- export { markRoleOf as a, SignatureToken as i, SIGNATURES_LIBRARY_KIND as n, SIGNATURE_MARK_NAME as r, INITIALS_MARK_NAME as t };
13
-
14
- //# sourceMappingURL=contract-C3nQtwGf.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"contract-C3nQtwGf.js","names":[],"sources":["../src/types.ts"],"sourcesContent":["import { createCapabilityToken, type EventHook } from '@embedpdf/core';\nimport type {\n SignatureVerdict,\n SignerPort,\n TrustPort,\n ValidationTime,\n} from '@embedpdf/core-signature';\nimport type {\n AnalyzeInput,\n BinarySource,\n ChangeAnalysis,\n DocMdpPermission,\n DocumentProtection,\n FieldLockSpec,\n FormFieldRef,\n SignatureCompleteResult,\n SignatureDTO,\n SignatureSnapshot,\n} from '@embedpdf/engine-core/runtime';\nimport type { StampPlacement } from '@embedpdf/plugin-annotation/contract';\nimport type { StampAsset } from '@embedpdf/plugin-stamp/contract';\n\n/**\n * What placing a mark on a signature field does:\n * - `sign` seal the field with the configured signer (the mark is the appearance);\n * - `visual` draw the mark into the field without sealing (Preview's \"signature\");\n * - `ask` neither — emit `ask` so the chrome can open its dialog and decide.\n * Default `sign` when a signer is configured, else `visual`.\n */\nexport type SignatureMode = 'sign' | 'visual' | 'ask';\n\nexport interface SignatureConfig {\n mode?: SignatureMode;\n /** The key holder: a raw signer (the CMS is built here) or a CMS signer (a service builds it). A thunk resolves per signing. */\n signer?: SignerPort | (() => Promise<SignerPort>);\n /** Trust anchors for validation. None → every verdict tops out at `valid-untrusted`. */\n trust?: TrustPort;\n /** Let the UI offer a certification (still needs `doc.sign.certify`). Default false. */\n allowCertify?: boolean;\n}\n\n/** The mark: a stamp-plugin asset, or bytes the embedder brings (PNG, JPEG, or a one-page PDF). */\nexport type Mark = { assetId: string } | { source: BinarySource };\n\nexport interface SignFieldInput {\n field: FormFieldRef;\n mark: Mark;\n /** What the signature dictionary says (`/Name` `/Reason` `/Location` `/ContactInfo`); the name defaults to the certificate's subject. */\n attribution?: { name?: string; reason?: string; location?: string; contactInfo?: string };\n /** Instead of the mark: a ready one-page appearance PDF the embedder composed itself. */\n appearance?: BinarySource;\n certify?: { permission: DocMdpPermission };\n lock?: FieldLockSpec;\n}\n\n/** The stamp-library kind that holds people's marks: one library per person. */\nexport const SIGNATURES_LIBRARY_KIND = 'signatures';\n/** The asset identifiers inside a signatures library: the full signature and the initials. */\nexport const SIGNATURE_MARK_NAME = 'signature';\nexport const INITIALS_MARK_NAME = 'initials';\nexport type MarkRole = 'signature' | 'initials';\n/** Which mark an asset of a signatures library is (anything not named `initials` is a signature). */\nexport const markRoleOf = (asset: Pick<StampAsset, 'name'>): MarkRole =>\n asset.name === INITIALS_MARK_NAME ? 'initials' : 'signature';\n\nexport interface SignaturePending {\n signingId: string;\n field: FormFieldRef;\n}\n\nexport interface SignatureState {\n snapshot: SignatureSnapshot | null;\n verdicts: SignatureVerdict[] | null;\n /** The field the user chose to sign next (\"select the field, then pick a mark\"). */\n target: FormFieldRef | null;\n /** A signing candidate is parked (here or, on the cloud, elsewhere): the document is read-only. */\n pending: SignaturePending | null;\n /** A sign/fill call is in flight. */\n busy: boolean;\n}\n\nexport type SignatureAction =\n | { type: 'SNAPSHOT'; snapshot: SignatureSnapshot | null }\n | { type: 'VERDICTS'; verdicts: SignatureVerdict[] | null }\n | { type: 'TARGET'; field: FormFieldRef | null }\n | { type: 'PENDING'; pending: SignaturePending | null }\n | { type: 'BUSY'; busy: boolean };\n\nexport type SignatureChange =\n | { type: 'signed'; field: FormFieldRef; result: SignatureCompleteResult }\n | { type: 'filled'; field: FormFieldRef }\n | { type: 'cleared'; field: FormFieldRef }\n /** Mode `ask`: a mark met a field and the chrome decides (open its dialog, then `signField`/`fillField`). */\n | { type: 'ask'; field: FormFieldRef; mark: Mark }\n /** A signed field was activated: show what its signature says. */\n | { type: 'inspect'; field: FormFieldRef }\n | { type: 'target'; field: FormFieldRef | null }\n | { type: 'validated'; verdicts: SignatureVerdict[] }\n /** An unsaved edit just turned a signature that held into one a save would invalidate. Once per edge. */\n | { type: 'invalidating'; field: FormFieldRef; detail: string }\n | { type: 'protectionChanged'; protection: DocumentProtection };\n\nexport interface SignatureCapability {\n // ── selectors ──\n snapshot(): SignatureSnapshot | null;\n verdicts(): SignatureVerdict[] | null;\n protection(): DocumentProtection | null;\n pending(): SignaturePending | null;\n target(): FormFieldRef | null;\n busy(): boolean;\n mode(): SignatureMode;\n /** The signature facts of one field, by ref or by widget, from the last snapshot. */\n signatureOf(field: FormFieldRef | { annotObjectNumber: number }): SignatureDTO | null;\n /** The verdict of one signed field from the last validation. */\n verdictOf(field: FormFieldRef | { annotObjectNumber: number }): SignatureVerdict | null;\n /** `doc.sign` is granted and a signer is configured (or resolvable). */\n canSign(): boolean;\n /** Visual fills ride `doc.forms.fill`. */\n canFill(): boolean;\n /** `allowCertify` and `doc.sign.certify`. */\n canCertify(): boolean;\n // ── the act ──\n /** Seal the field: the mark's page becomes the widget's appearance, the configured signer signs. */\n signField(input: SignFieldInput): Promise<SignatureCompleteResult>;\n /** Visual only: the mark becomes the widget's appearance; nothing is sealed. Refused on a signed field. */\n fillField(field: FormFieldRef, mark: Mark): Promise<void>;\n /** Undo a visual fill (a blank appearance). Refused on a signed field. */\n clearField(field: FormFieldRef): Promise<void>;\n /** The destination rule in one call: a field (sign, fill, or ask by mode) or a free placement (a stamp). */\n placeMark(mark: Mark, target: { field: FormFieldRef } | StampPlacement): Promise<void>;\n /** Name the field the next picked mark goes to (the chrome's \"Sign here\"); null clears. */\n setTarget(field: FormFieldRef | null): void;\n /** Ask the chrome to show a signed field's facts (`inspect`). */\n inspect(field: FormFieldRef): void;\n // ── reading ──\n refresh(): Promise<SignatureSnapshot | null>;\n /**\n * Judge every signature. The viewer's default is the WORKING COPY: unsaved\n * edits count, so the verdict is the one the file a save produces will get.\n * `until: 'persisted'` judges the loaded bytes only.\n */\n validate(opts?: {\n at?: ValidationTime;\n until?: 'persisted' | 'working-copy';\n }): Promise<SignatureVerdict[]>;\n analyze(input: AnalyzeInput): Promise<ChangeAnalysis>;\n /** The exact bytes a signature's revision covers (`doc.signatures.revisionBytes`) — rides `doc.download`. */\n revisionBytes(revisionIndex: number): Promise<Uint8Array>;\n onChanged: EventHook<SignatureChange>;\n}\n\nexport const SignatureToken = createCapabilityToken<SignatureCapability>('signature');\n"],"mappings":";;;AAwDA,MAAa,0BAA0B;;AAEvC,MAAa,sBAAsB;AACnC,MAAa,qBAAqB;;AAGlC,MAAa,cAAc,UACzB,MAAM,SAAA,aAA8B,aAAa;AAwFnD,MAAa,iBAAiB,sBAA2C,WAAW"}
@@ -1,43 +0,0 @@
1
- let _embedpdf_core = require("@embedpdf/core");
2
- //#region src/types.ts
3
- /** The stamp-library kind that holds people's marks: one library per person. */
4
- const SIGNATURES_LIBRARY_KIND = "signatures";
5
- /** The asset identifiers inside a signatures library: the full signature and the initials. */
6
- const SIGNATURE_MARK_NAME = "signature";
7
- const INITIALS_MARK_NAME = "initials";
8
- /** Which mark an asset of a signatures library is (anything not named `initials` is a signature). */
9
- const markRoleOf = (asset) => asset.name === "initials" ? "initials" : "signature";
10
- const SignatureToken = (0, _embedpdf_core.createCapabilityToken)("signature");
11
- //#endregion
12
- Object.defineProperty(exports, "INITIALS_MARK_NAME", {
13
- enumerable: true,
14
- get: function() {
15
- return INITIALS_MARK_NAME;
16
- }
17
- });
18
- Object.defineProperty(exports, "SIGNATURES_LIBRARY_KIND", {
19
- enumerable: true,
20
- get: function() {
21
- return SIGNATURES_LIBRARY_KIND;
22
- }
23
- });
24
- Object.defineProperty(exports, "SIGNATURE_MARK_NAME", {
25
- enumerable: true,
26
- get: function() {
27
- return SIGNATURE_MARK_NAME;
28
- }
29
- });
30
- Object.defineProperty(exports, "SignatureToken", {
31
- enumerable: true,
32
- get: function() {
33
- return SignatureToken;
34
- }
35
- });
36
- Object.defineProperty(exports, "markRoleOf", {
37
- enumerable: true,
38
- get: function() {
39
- return markRoleOf;
40
- }
41
- });
42
-
43
- //# sourceMappingURL=contract-CojqGdMH.cjs.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"contract-CojqGdMH.cjs","names":[],"sources":["../src/types.ts"],"sourcesContent":["import { createCapabilityToken, type EventHook } from '@embedpdf/core';\nimport type {\n SignatureVerdict,\n SignerPort,\n TrustPort,\n ValidationTime,\n} from '@embedpdf/core-signature';\nimport type {\n AnalyzeInput,\n BinarySource,\n ChangeAnalysis,\n DocMdpPermission,\n DocumentProtection,\n FieldLockSpec,\n FormFieldRef,\n SignatureCompleteResult,\n SignatureDTO,\n SignatureSnapshot,\n} from '@embedpdf/engine-core/runtime';\nimport type { StampPlacement } from '@embedpdf/plugin-annotation/contract';\nimport type { StampAsset } from '@embedpdf/plugin-stamp/contract';\n\n/**\n * What placing a mark on a signature field does:\n * - `sign` seal the field with the configured signer (the mark is the appearance);\n * - `visual` draw the mark into the field without sealing (Preview's \"signature\");\n * - `ask` neither — emit `ask` so the chrome can open its dialog and decide.\n * Default `sign` when a signer is configured, else `visual`.\n */\nexport type SignatureMode = 'sign' | 'visual' | 'ask';\n\nexport interface SignatureConfig {\n mode?: SignatureMode;\n /** The key holder: a raw signer (the CMS is built here) or a CMS signer (a service builds it). A thunk resolves per signing. */\n signer?: SignerPort | (() => Promise<SignerPort>);\n /** Trust anchors for validation. None → every verdict tops out at `valid-untrusted`. */\n trust?: TrustPort;\n /** Let the UI offer a certification (still needs `doc.sign.certify`). Default false. */\n allowCertify?: boolean;\n}\n\n/** The mark: a stamp-plugin asset, or bytes the embedder brings (PNG, JPEG, or a one-page PDF). */\nexport type Mark = { assetId: string } | { source: BinarySource };\n\nexport interface SignFieldInput {\n field: FormFieldRef;\n mark: Mark;\n /** What the signature dictionary says (`/Name` `/Reason` `/Location` `/ContactInfo`); the name defaults to the certificate's subject. */\n attribution?: { name?: string; reason?: string; location?: string; contactInfo?: string };\n /** Instead of the mark: a ready one-page appearance PDF the embedder composed itself. */\n appearance?: BinarySource;\n certify?: { permission: DocMdpPermission };\n lock?: FieldLockSpec;\n}\n\n/** The stamp-library kind that holds people's marks: one library per person. */\nexport const SIGNATURES_LIBRARY_KIND = 'signatures';\n/** The asset identifiers inside a signatures library: the full signature and the initials. */\nexport const SIGNATURE_MARK_NAME = 'signature';\nexport const INITIALS_MARK_NAME = 'initials';\nexport type MarkRole = 'signature' | 'initials';\n/** Which mark an asset of a signatures library is (anything not named `initials` is a signature). */\nexport const markRoleOf = (asset: Pick<StampAsset, 'name'>): MarkRole =>\n asset.name === INITIALS_MARK_NAME ? 'initials' : 'signature';\n\nexport interface SignaturePending {\n signingId: string;\n field: FormFieldRef;\n}\n\nexport interface SignatureState {\n snapshot: SignatureSnapshot | null;\n verdicts: SignatureVerdict[] | null;\n /** The field the user chose to sign next (\"select the field, then pick a mark\"). */\n target: FormFieldRef | null;\n /** A signing candidate is parked (here or, on the cloud, elsewhere): the document is read-only. */\n pending: SignaturePending | null;\n /** A sign/fill call is in flight. */\n busy: boolean;\n}\n\nexport type SignatureAction =\n | { type: 'SNAPSHOT'; snapshot: SignatureSnapshot | null }\n | { type: 'VERDICTS'; verdicts: SignatureVerdict[] | null }\n | { type: 'TARGET'; field: FormFieldRef | null }\n | { type: 'PENDING'; pending: SignaturePending | null }\n | { type: 'BUSY'; busy: boolean };\n\nexport type SignatureChange =\n | { type: 'signed'; field: FormFieldRef; result: SignatureCompleteResult }\n | { type: 'filled'; field: FormFieldRef }\n | { type: 'cleared'; field: FormFieldRef }\n /** Mode `ask`: a mark met a field and the chrome decides (open its dialog, then `signField`/`fillField`). */\n | { type: 'ask'; field: FormFieldRef; mark: Mark }\n /** A signed field was activated: show what its signature says. */\n | { type: 'inspect'; field: FormFieldRef }\n | { type: 'target'; field: FormFieldRef | null }\n | { type: 'validated'; verdicts: SignatureVerdict[] }\n /** An unsaved edit just turned a signature that held into one a save would invalidate. Once per edge. */\n | { type: 'invalidating'; field: FormFieldRef; detail: string }\n | { type: 'protectionChanged'; protection: DocumentProtection };\n\nexport interface SignatureCapability {\n // ── selectors ──\n snapshot(): SignatureSnapshot | null;\n verdicts(): SignatureVerdict[] | null;\n protection(): DocumentProtection | null;\n pending(): SignaturePending | null;\n target(): FormFieldRef | null;\n busy(): boolean;\n mode(): SignatureMode;\n /** The signature facts of one field, by ref or by widget, from the last snapshot. */\n signatureOf(field: FormFieldRef | { annotObjectNumber: number }): SignatureDTO | null;\n /** The verdict of one signed field from the last validation. */\n verdictOf(field: FormFieldRef | { annotObjectNumber: number }): SignatureVerdict | null;\n /** `doc.sign` is granted and a signer is configured (or resolvable). */\n canSign(): boolean;\n /** Visual fills ride `doc.forms.fill`. */\n canFill(): boolean;\n /** `allowCertify` and `doc.sign.certify`. */\n canCertify(): boolean;\n // ── the act ──\n /** Seal the field: the mark's page becomes the widget's appearance, the configured signer signs. */\n signField(input: SignFieldInput): Promise<SignatureCompleteResult>;\n /** Visual only: the mark becomes the widget's appearance; nothing is sealed. Refused on a signed field. */\n fillField(field: FormFieldRef, mark: Mark): Promise<void>;\n /** Undo a visual fill (a blank appearance). Refused on a signed field. */\n clearField(field: FormFieldRef): Promise<void>;\n /** The destination rule in one call: a field (sign, fill, or ask by mode) or a free placement (a stamp). */\n placeMark(mark: Mark, target: { field: FormFieldRef } | StampPlacement): Promise<void>;\n /** Name the field the next picked mark goes to (the chrome's \"Sign here\"); null clears. */\n setTarget(field: FormFieldRef | null): void;\n /** Ask the chrome to show a signed field's facts (`inspect`). */\n inspect(field: FormFieldRef): void;\n // ── reading ──\n refresh(): Promise<SignatureSnapshot | null>;\n /**\n * Judge every signature. The viewer's default is the WORKING COPY: unsaved\n * edits count, so the verdict is the one the file a save produces will get.\n * `until: 'persisted'` judges the loaded bytes only.\n */\n validate(opts?: {\n at?: ValidationTime;\n until?: 'persisted' | 'working-copy';\n }): Promise<SignatureVerdict[]>;\n analyze(input: AnalyzeInput): Promise<ChangeAnalysis>;\n /** The exact bytes a signature's revision covers (`doc.signatures.revisionBytes`) — rides `doc.download`. */\n revisionBytes(revisionIndex: number): Promise<Uint8Array>;\n onChanged: EventHook<SignatureChange>;\n}\n\nexport const SignatureToken = createCapabilityToken<SignatureCapability>('signature');\n"],"mappings":";;;AAwDA,MAAa,0BAA0B;;AAEvC,MAAa,sBAAsB;AACnC,MAAa,qBAAqB;;AAGlC,MAAa,cAAc,UACzB,MAAM,SAAA,aAA8B,aAAa;AAwFnD,MAAa,kBAAA,GAAA,eAAA,sBAAA,CAA4D,WAAW"}