@nutrient-sdk/viewer
Version:
View and annotate PDF files in your web app. Full support for mobile and desktop. Runs in the browser using WASM.
1,365 lines (1,316 loc) • 1.09 MB
TypeScript
/**
* This class should be used to create custom Immutable Record. It will overwrite the default
* `Immutable#equals()` method to include the class name. if we don't do this, two different classes
* with the same default value set will be treated as equal.
*
* @example
* // With regular `Immutable.Record`
* class A extends Record({ foo: 'bar' }) {}
* class B extends Record({ foo: 'bar' }) {}
* const a = new A()
* const b = new B()
* is(a, b) // true
*
* // With `InheritableImmutableRecord`
* class A extends InheritableImmutableRecord {
* static defaultValues = { foo: 'bar' }
* }
* mergeImmutableRecordDefaults(A)
* class B extends InheritableImmutableRecord {
* static defaultValues = { foo: 'bar' }
* }
* mergeImmutableRecordDefaults(B)
* const a = new A()
* const b = new B()
* is(a, b) // false
*/
declare class __dangerousImmutableRecordFactory<TProps extends Record<string, unknown>> {
has(key: unknown): boolean;
get<K extends keyof TProps>(key: K): TProps[K];
set<K extends keyof TProps>(key: K, value: TProps[K]): this;
delete<K extends keyof TProps>(key: K): this;
clear(): this;
update<K extends keyof TProps>(key: K, updater: (value: TProps[K]) => TProps[K]): this;
merge(...collections: Array<Partial<TProps>>): this;
mergeWith(merger: (previous?: unknown, next?: unknown, key?: string) => unknown, ...collections: Array<Partial<TProps> | Iterable<[string, unknown]>>): this;
mergeDeep(...collections: Array<Partial<TProps> | Iterable<[string, unknown]>>): this;
mergeDeepWith(merger: (previous?: unknown, next?: unknown, key?: string) => unknown, ...collections: Array<Partial<TProps> | Iterable<[string, unknown]>>): this;
setIn(keyPath: Iterable<unknown>, value: unknown): this;
deleteIn(keyPath: Iterable<unknown>): this;
removeIn(keyPath: Iterable<unknown>): this;
updateIn(keyPath: Iterable<unknown>, notSetValue: unknown, updater: (value: unknown) => unknown): this;
updateIn(keyPath: Iterable<unknown>, updater: (value: unknown) => unknown): this;
mergeIn(keyPath: Iterable<unknown>, ...collections: Array<Partial<TProps> | Iterable<[string, unknown]>>): this;
mergeDeepIn(keyPath: Iterable<unknown>, ...collections: Array<Partial<TProps> | Iterable<[string, unknown]>>): this;
withMutations(mutator: (mutable: this) => unknown): this;
asMutable(): this;
asImmutable(): this;
getIn(keyPath: Iterable<unknown>, notSetValue?: unknown): unknown;
toJS(): TProps;
toJSON(): TProps;
equals(other: unknown): boolean;
toSeq(): Seq.Keyed<string, unknown>;
}
/**
* @class
* Base action type from which all Actions inherit. You can not instantiate from this type.
*
* It is an {@link https://immutable-js.com/docs/v5/Record/ | Immutable.Record}.
* @summary Base action type from which all Actions inherit.
*/
export declare abstract class Action extends InheritableImmutableRecord<ActionProperties> {
/**
* Actions can be chained by adding them to this immutable List.
*/
subActions?: Immutable.List<Action> | null | undefined;
protected constructor(args?: ActionProperties);
}
declare type ActionCreators = typeof textComparisonActionCreators;
declare type ActionFlags = 'includeExclude' | 'includeNoValueFields' | 'exportFormat' | 'getMethod' | 'submitCoordinated' | 'xfdf' | 'includeAppendSaves' | 'includeAnnotations' | 'submitPDF' | 'canonicalFormat' | 'excludeNonUserAnnotations' | 'excludeFKey' | 'embedForm';
/** @inline */
declare type ActionProperties = {
subActions?: Immutable.List<Action> | null;
};
export declare namespace Actions {
export {
Action,
GoToAction,
GoToEmbeddedAction,
GoToRemoteAction,
HideAction,
JavaScriptAction,
LaunchAction,
NamedAction,
ResetFormAction,
SubmitFormAction,
URIAction };
}
declare type ActionTriggerEventType = 'onPointerEnter' | 'onPointerLeave' | 'onPointerDown' | 'onPointerUp' | 'onPageOpen' | 'onPageClose' | 'onPageVisible' | 'onPageHidden';
declare interface AddPageConfiguration {
backgroundColor: Color;
pageWidth: number;
pageHeight: number;
rotateBy: Rotation;
insets?: Rect;
}
/**
* Payload for sending changes to AI services
*
* @public
*/
declare interface AIADocumentChangePayload {
id: string;
type: string;
text: string;
contextBefore: string;
contextAfter: string;
page: number;
}
/**
* Base response item from AI services representing a single document change.
* Contains the essential information about a text modification detected during comparison.
*
* @example
* // Typical structure of a change item
* {
* id: "change-456",
* type: "deletion",
* text: "old contract terms",
* page: 1,
* contextBefore: "The following ",
* contextAfter: " are no longer valid"
* }
*/
export declare interface AIADocumentChangeResponseItem {
/** Unique identifier for this change, used for tracking and correlation */
id: string;
/** Type of change operation (e.g., "insertion", "deletion", "modification") */
type: string;
/** The actual text content that was changed */
text: string;
/** Zero-based page number where this change occurred */
page: number;
/** Text content appearing before the change for context. */
contextBefore?: string;
/** Text content appearing after the change for context. */
contextAfter?: string;
}
/**
* Response from AI analysis service containing a high-level summary and categorization
* of document changes. This is returned when using `NutrientViewer.AIComparisonOperationType.ANALYZE`.
*
* @example
* // After running an ANALYZE operation
* if (NutrientViewer.isAIDocumentAnalysisResult(result)) {
* console.log(`Summary: ${result.summary}`);
* // Example: "The document has undergone significant legal revisions with updated terminology and new clauses."
*
* console.log(`Categories: ${result.categories.join(', ')}`);
* // Example: ["Legal Changes", "Terminology Updates", "Content Addition"]
*
* // Access detailed changes
* console.log(`Total changes: ${result.changes.changes.size}`);
* }
*/
export declare interface AIADocumentChangesAnalysisResponse {
/** AI-generated natural language summary describing the overall nature of changes between the compared documents */
summary: string;
/** Array of AI-detected change categories representing the types of modifications (e.g., "Formatting", "Content Addition", "Legal Changes", "Rewording") */
categories: string[];
/** The underlying standard document comparison result containing detailed text hunks and change operations */
changes: DocumentComparison.DocumentComparisonResult;
}
/**
* Response from AI tagging service containing categorized change information.
* This is returned when using `NutrientViewer.AIComparisonOperationType.TAG`.
*
* @example
* // After running a TAG operation
* if (NutrientViewer.isAIDocumentTaggingResult(result)) {
* result.references.forEach((ref, index) => {
* console.log(`Change ${index + 1}: ${ref.text}`);
* console.log(`Categories: ${ref.tag.join(', ')}`);
* console.log(`Page: ${ref.page}`);
* });
* }
*/
export declare interface AIADocumentChangesTaggingResponse {
/**
* Array where each
* item corresponds to a specific change and includes category tags assigned by the AI service.
* Each reference contains the change details plus an array of category strings that classify
* the type of modification (e.g., ["Legal", "Formatting"] for a legal change with formatting updates).
* */
references: AIADocumentChangeTaggingItem[];
}
/**
* Individual change item with AI-assigned category tags from the tagging service.
* Extends the base response item with categorization information.
*
* @example
* // Typical structure of a tagged change
* {
* id: "change-123",
* type: "insertion",
* text: "confidential information",
* page: 2,
* contextBefore: "regarding the ",
* contextAfter: " shall not be disclosed",
* tag: ["Legal", "Confidentiality"]
* }
*/
export declare interface AIADocumentChangeTaggingItem extends AIADocumentChangeResponseItem {
/** Array of category strings assigned by AI to classify this change. */
tag: string[];
}
/**
* AI Assistant configuration namespace containing all public types.
*
* This namespace provides TypeScript interfaces and configuration options for integrating
* the AI Assistant feature into your application. Use types from this namespace to
* configure AI Assistant behavior, security policies, and custom skills.
*
* @namespace
* @example
* ```typescript
* import { AIAssistant } from 'nutrient'
*
* const config: AIAssistant.Configuration = {
* sessionId: 'user-session-123',
* jwt: 'your-jwt-token',
* backendUrl: 'https://ai-assistant.example.com'
* }
* ```
*/
export declare namespace AIAssistant {
/**
* Configuration for the AI Assistant feature.
*
* Contains authentication details, backend connection information, and optional
* customization settings for AI Agent behavior.
*
* @example
* ```typescript
* NutrientViewer.load({
* // ... other config
* aiAssistant: {
* sessionId: 'session-123',
* jwt: 'eyJhbGciOiJIUzI1NiIs...',
* backendUrl: 'https://localhost:4000'
* }
* })
* ```
*/
export interface Configuration {
/**
* Session identifier for the AI Assistant conversation.
*
* Use a unique identifier to create a new session, or reuse an existing session ID
* to restore a previous conversation. The ID must contain only alphanumeric characters.
*
* @example
* ```typescript
* sessionId: 'userdocsession20250128'
* sessionId: 'session123abc'
* ```
*/
sessionId: string;
/**
* JSON Web Token (JWT) for authenticating requests to the AI Assistant backend.
*
* This token must be issued by your authentication service and should contain
* user identity claims. The token is sent with every request to the backend.
*
* @example
* ```typescript
* jwt: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...'
* ```
*/
jwt: string;
/**
* URL of the AI Assistant service backend.
*
* This should be the base URL where your AI Assistant service is deployed.
* The URL must include the protocol (http/https) but exclude trailing slashes.
*
* @example
* ```typescript
* backendUrl: 'https://ai-assistant.example.com' // ✓ correct
* backendUrl: 'https://ai-assistant.example.com/' // ✗ avoid trailing slash
* ```
*/
backendUrl: string;
/**
* Optional user identifier for tracking and rate limiting.
*
* Provide a unique identifier for the current user. This enables per-user
* rate limiting, usage analytics, and audit logging. Must contain only
* alphanumeric characters.
*
* @example
* ```typescript
* userId: 'userabc12345'
* userId: 'user123'
* ```
*/
userId?: string;
/**
* AI Agent preset or custom agent ID.
*
* Selects a base agent configuration with different capabilities and behavior.
*
* | Preset | Purpose |
* |------------|--------------------------------------------------------------------------------|
* | `chat` | Read-only Q&A mode. This agent can summarize, extract data, and answer questions. |
* | `agentic` | Full autonomous agent. This agent can read, write, add annotations, fill forms, and redact documents. |
* | `base` | Base configuration. This agent uses defaults for all settings and is intended for customization. |
*
* @default 'agentic'
* @example
* ```typescript
* agentId: 'chat' // Use the read-only chat preset
* ```
*/
agentId?: 'chat' | 'agentic' | 'base' | string;
/**
* Advanced configuration for customizing AI Assistant agent behavior.
*
* Customize the system prompt, define specialized skills, configure tool execution
* approval policies.
*
* @example
* ```typescript
* NutrientViewer.load({
* aiAssistant: {
* sessionId: 'session-123',
* jwt: 'token-here',
* backendUrl: 'https://localhost:4000',
* agentConfiguration: {
* systemPromptTemplate: 'You are an expert legal document assistant.',
* skills: [
* {
* name: 'contract-review',
* description: 'Analyze contracts for key terms',
* content: 'Focus on liability and payment terms...'
* }
* ],
* toolApproval: {
* defaults: { default: 'allow', write: 'ask' }
* }
* }
* }
* });
* ```
*/
agentConfiguration?: AgentConfiguration;
}
/**
* Advanced configuration for AI Agent behavior and capabilities.
*
* Customize the agent's system instructions, define domain-specific skills,
* control tool execution policies.
*
* This interface enables fine-grained control over how the AI Agent processes
* requests, what knowledge it has access to, and which operations require user approval.
*
* @example
* ```typescript
* const config: AIAssistant.AgentConfiguration = {
* systemPromptTemplate: 'You are an expert legal document assistant.',
* skills: [
* {
* name: 'contract-review',
* description: 'Analyze contracts for key terms and risks',
* content: '1. Identify all parties\n2. Extract key dates\n3. Highlight liability clauses'
* }
* ],
* toolApproval: {
* defaults: { default: 'allow', write: 'ask' }
* }
* }
* ```
*/
export interface AgentConfiguration {
/**
* Custom system prompt template for defining agent personality and behavior.
*
* Defines the base instructions, role, and guidelines that shape how the agent
* processes requests and responds to users. This is the primary mechanism for
* customizing the agent's expertise and behavior patterns.
*
* Keep prompts concise but descriptive. Focus on the agent's role, key principles,
* and important constraints.
*
* @example
* ```typescript
* systemPromptTemplate: `You are an expert legal document analyst.
* Your role is to:
* - Identify and explain key contractual terms
* - Highlight potential risks or unusual clauses
* - Always cite the specific section numbers
* - If uncertain, clearly state your limitations`
* ```
*
* @default A general-purpose document assistant prompt
*/
systemPromptTemplate?: string;
/**
* Seed messages for shaping agent behavior across all interactions.
*
* Messages injected before the conversation history on every model invocation.
* Useful for few-shot prompting, additional constraints, and behavioral priming
* that should persist across all conversation turns.
*
* **Important**: Seed messages are NOT persisted to the conversation history
* and are injected fresh on each request.
*
* **Common use cases**:
* - Few-shot learning: Include human/ai example pairs
* - Additional instructions: Constraints that complement systemPromptTemplate
* - Behavioral priming: Consistent patterns to reinforce across all responses
*
* @example
* ```typescript
* seedMessages: [
* {
* type: 'human',
* content: 'Analyze the indemnification clause in this contract.'
* },
* {
* type: 'ai',
* content: 'I found the indemnification clause on page 3, section 5.2...'
* }
* ]
* ```
*/
seedMessages?: Array<{
/**
* The sender type for this message.
*
* - `'human'`: User/human messages (used in few-shot examples)
* - `'ai'`: Assistant responses (used in few-shot examples)
*/
type: 'human' | 'ai';
/**
* The text content of the message.
*
* Use clear, concise language. For few-shot examples, make responses
* representative of the desired behavior.
*/
content: string;
}>;
/**
* User identifier for rate limiting and authorization.
*
* Provide a unique identifier for the current user to enable
* per-user rate limiting and usage tracking.
*
* @example
* ```typescript
* userId: 'user12345'
* ```
*/
userId?: string;
/**
* Domain-specific skills for the AI Agent.
*
* Define specialized knowledge, instructions, or workflows that the agent
* can access and apply when relevant to user requests. Skills allow you to
* inject domain expertise without modifying the system prompt.
*
* The agent decides when to use each skill based on the skill description
* and the user's request. Use descriptive names and clear instructions.
*
* @example
* ```typescript
* skills: [
* {
* name: 'contract-review',
* description: 'Analyze contracts for key terms and identify potential risks',
* content: `When reviewing a contract:
* 1. Identify all parties and signatories
* 2. Extract critical dates (effective date, expiration, renewal)
* 3. Summarize payment terms and amounts
* 4. Highlight liability and indemnification clauses
* 5. Flag unusual or potentially risky terms`
* }
* ]
* ```
*/
skills?: Array<{
/**
* Unique identifier for this skill.
*
* Used internally by the agent to reference and invoke this skill.
* Should be lowercase with hyphens (e.g., 'contract-analysis', 'data-extraction').
* Minimum 1 character, no spaces.
*
* @example
* ```typescript
* name: 'legal-clause-analysis'
* ```
*/
name: string;
/**
* Description of when and how to use this skill.
*
* Helps the agent decide when to apply this knowledge based on user requests.
* Be specific about the skill's purpose and ideal use cases. Keep it under
* 500 characters.
*
* @example
* ```typescript
* description: 'Use when analyzing legal contracts, identifying liability clauses, or explaining terms'
* ```
*/
description?: string;
/**
* Detailed knowledge and instructions for this skill.
*
* The actual content the agent uses when applying this skill. Include step-by-step
* instructions, examples, or knowledge the agent should follow. Maximum 50,000 characters.
*
* @example
* ```typescript
* content: `Legal Contract Analysis Process:
*
* 1. PARTIES: Identify all parties, signatories, and roles
* 2. DATES: Extract effective date, expiration, renewal dates
* 3. PAYMENT: Summarize amounts, payment terms, billing cycles
* 4. LIABILITY: Identify indemnification and liability caps
* 5. TERMINATION: Note termination conditions and notice periods`
* ```
*/
content: string;
}>;
/**
* Tool execution approval policies for security and user control.
*
* Controls which tools can execute automatically and which require user approval.
* Use this to implement security policies, prevent unintended modifications, or
* require confirmation for sensitive operations.
*
* **Resolution order** (first match wins):
* 1. Pattern-based rules (if defined)
* 2. Tool category defaults (read/write based on tool metadata)
* 3. Fallback default setting
*
* @example
* ```typescript
* // Basic: Allow reads, ask for writes
* toolApproval: {
* defaults: {
* default: 'allow',
* read: 'allow',
* write: 'ask'
* }
* }
* ```
*
* @example
* ```typescript
* // Advanced: Pattern-based rules with defaults
* toolApproval: {
* defaults: { default: 'allow' },
* rules: [
* { pattern: '*_delete_*', approval: 'deny' },
* { pattern: 'mcp__*_modify_*', approval: 'ask' }
* ]
* }
* ```
*/
toolApproval?: {
/**
* Default approval settings for tools by category.
*
* These defaults apply when no rule matches. The resolution order is:
* 1. Check if a pattern rule matches (first match wins)
* 2. Check tool's readOnlyHint - use 'read' or 'write' setting
* 3. Fall back to 'default' setting
*/
defaults: {
/**
* Fallback approval mode for all tools not matching a rule or category.
*
* Used when:
* - No pattern rule matches
* - Tool has no readOnlyHint annotation
* - No category-specific default is configured
*
* Values:
* - `"allow"`: Executes immediately without user intervention
* - `"ask"`: Pauses execution and requests user confirmation
* - `"deny"`: Rejects the tool call
*/
default: 'allow' | 'ask' | 'deny';
/**
* Approval mode for read-only tools.
*
* Applies to tools marked with `readOnlyHint: true`.
* Typically used for safe operations like searching, analyzing, or retrieving data.
*
* Values:
* - `"allow"`: Executes immediately without user intervention
* - `"ask"`: Pauses execution and requests user confirmation
* - `"deny"`: Rejects the tool call
*/
read?: 'allow' | 'ask' | 'deny';
/**
* Approval mode for write/modification tools.
*
* Applies to tools marked with `readOnlyHint: false` that modify documents or state.
* Recommended to set to 'ask' for user control over document changes.
*
* Values:
* - `"allow"`: Executes immediately without user intervention
* - `"ask"`: Pauses execution and requests user confirmation
* - `"deny"`: Rejects the tool call
*/
write?: 'allow' | 'ask' | 'deny';
};
/**
* Pattern-based rules for fine-grained tool control.
*
* Rules are evaluated in order - the first matching pattern determines the approval mode.
* Place more specific patterns before general ones.
*
* Patterns use standard glob syntax where `*` matches any characters.
*/
rules?: Array<{
/**
* Glob pattern to match against tool names.
*
* Tool names follow the format: `[namespace]__[server]__[function_name]`
*
* Common patterns:
* - `"mcp__nutrient_*"`: All Nutrient MCP tools
* - `"mcp__nutrient-ai-assistant__find_document"`: Specific tool
* - `"mcp__nutrient-web-sdk__read_annotations"`: Web SDK tool
* - `"mcp__*"`: All MCP tools from any server
* - `"mcp__*__*_delete_*"`: Any MCP tool with delete in the name
*
* @example
* ```typescript
* pattern: "mcp__nutrient-websdk__add_annotation"
* ```
*/
pattern: string;
/**
* Approval mode for tools matching this pattern.
*
* Values:
* - `"allow"`: Executes immediately without user intervention
* - `"ask"`: Pauses execution and requests user confirmation
* - `"deny"`: Rejects the tool call (will not execute)
*/
approval: 'allow' | 'ask' | 'deny';
}>;
};
}
}
declare function AIAssistantMixin<T extends Class<BaseMixin>>(Base: T): {
new (...args: any[]): {
};
} & T;
/**
* Data structure for AI comparison results
*/
export declare interface AIComparisonData {
/** AI-generated summary of document changes */
summary: string;
/** Array of AI-detected change categories */
categories: string[];
/** Standard document comparison result */
changes: DocumentComparison.DocumentComparisonResult;
/** Current phase of the AI comparison process */
phase: IAIComparisonPhase;
/** Error information if comparison failed */
error: AIComparisonError | null;
/** Changes tagged with categories (optional) */
taggedChanges?: AIADocumentChangeTaggingItem[];
/** Transformed changes for AI processing (optional) */
transformedChanges?: AIADocumentChangePayload[];
/** Enhanced changes with AI properties (optional) */
aiEnhancedChanges?: List<AIEnhancedTextComparisonChange>;
}
/**
* Error information for AI comparison
*/
export declare interface AIComparisonError {
/** The phase where the error occurred ('ANALYSIS' | 'TAGGING') */
phase: 'ANALYSIS' | 'TAGGING';
/** Human-readable error message */
message: string;
/** Additional error details (optional) */
details?: unknown;
}
/**
* Describes types of AI operations for document comparison.
* These operations can be used with `ComparisonOperationType.AI`.
*
* @enum
*/
declare const AIComparisonOperationType: {
/** Analyze and summarize differences between documents. */
readonly ANALYZE: "analyze";
/** Tag changes with specified categories. */
readonly TAG: "tag";
};
/**
* Phases of the AI comparison process
*/
declare enum AIComparisonPhase {
/** Initial state before comparison starts */
IDLE = "IDLE",
/** Loading documents or initializing */
LOADING = "LOADING",
/** AI is analyzing document differences */
ANALYZING = "ANALYZING",
/** AI is tagging changes with categories */
TAGGING = "TAGGING",
/** Comparison process completed successfully */
COMPLETED = "COMPLETED",
/** Error occurred during comparison */
ERROR = "ERROR",
}
/**
* Result returned by AI-powered document comparison operations. This union type represents
* the response from {@link NutrientViewer.Instance#compareDocuments} when using
* {@link NutrientViewer.ComparisonOperationType}.AI.
*
* The result type depends on the AI operation performed:
*
* - **Analysis Operation** (`NutrientViewer.AIComparisonOperationType.ANALYZE`):
* Returns {@link AIADocumentChangesAnalysisResponse} containing:
* - `summary`: AI-generated summary describing the overall nature of changes
* - `categories`: Array of AI-detected change types (e.g., "Formatting", "Content Addition")
* - `changes`: Standard {@link DocumentComparison.DocumentComparisonResult} with detailed differences
*
* - **Tagging Operation** (`NutrientViewer.AIComparisonOperationType.TAG`):
* Returns {@link AIADocumentChangesTaggingResponse} containing:
* - `references`: Array where each item corresponds to a change with assigned category tags
* - `changes`: Standard {@link DocumentComparison.DocumentComparisonResult} with detailed differences
*
* Use the provided type guards to determine which specific result type you received:
* - {@link NutrientViewer.isAIDocumentAnalysisResult} - Check for analysis results
* - {@link NutrientViewer.isAIDocumentTaggingResult} - Check for tagging results
* - {@link NutrientViewer.isAIDocumentComparisonResult} - Check for any AI result
*
* @example
* const analyzeOperation = new NutrientViewer.ComparisonOperation(
* NutrientViewer.ComparisonOperationType.AI,
* { operationType: NutrientViewer.AIComparisonOperationType.ANALYZE }
* );
*
* instance.compareDocuments(documents, analyzeOperation)
* .then((result) => {
* if (NutrientViewer.isAIDocumentAnalysisResult(result)) {
* console.log('Summary:', result.summary);
* console.log('Categories:', result.categories);
* }
* });
*
* @see {@link NutrientViewer.Instance#compareDocuments}
* @see {@link NutrientViewer.AIComparisonOperationType}
* @see {@link AIADocumentChangesAnalysisResponse}
* @see {@link AIADocumentChangesTaggingResponse}
* @see {@link NutrientViewer.isAIDocumentAnalysisResult}
* @see {@link NutrientViewer.isAIDocumentTaggingResult}
*/
export declare type AIDocumentComparisonResult = AIADocumentChangesAnalysisResponse | AIADocumentChangesTaggingResponse;
/**
* Enhanced TextComparisonChange with AI-related properties
*
* @inline
*/
declare interface AIEnhancedTextComparisonChange extends TextComparisonChange {
aiId?: string;
categories?: string[];
aiProcessed?: boolean;
}
/**
* Specifies the alignment of an UI element relative to its parent container.
*
* @enum
*/
declare const Alignment: {
/** Aligns the element to the start of the container (left in LTR, right in RTL layout). */
readonly START: "START";
/** Aligns the element to the end of the container (right in LTR, left in RTL layout). */
readonly END: "END";
};
declare const allowedTextComparisonInnerToolbarItem: string[];
declare const allowedTextComparisonToolbarItem: string[];
declare const allowedToolbarTypes: ((typeof extraToolbarTypes)[number] | (typeof defaultToolbarTypes)[number])[];
/**
* @class
* Base annotation type from which all annotations inherit. You can not instantiate from this type.
*
* It is an {@link https://immutable-js.com/docs/v5/Record/ | Immutable.Record}.
* @public
* @summary Base annotation type from which all annotations inherit.
* @hideconstructor
* @abstract
* @see {@link NutrientViewer.Instance#getSelectedAnnotations} | {@link NutrientViewer.Instance#setSelectedAnnotations}
* @see {@link NutrientViewer.Instance#setEditableAnnotationTypes} | {@link NutrientViewer.Instance#setIsEditableAnnotation}
* @see {@link NutrientViewer.Instance#create} | {@link NutrientViewer.Instance#delete}
* @see {@link NutrientViewer.Instance#getAnnotations} | {@link NutrientViewer.Instance#ensureChangesSaved}
* @see {@link NutrientViewer.Instance#hasUnsavedChanges} | {@link NutrientViewer.Instance#save}
* @see {@link NutrientViewer.Instance#setAnnotationCreatorName} | {@link NutrientViewer.Instance#update}
* @see {@link Configuration#editableAnnotationTypes} | {@link Configuration#isEditableAnnotation}
* @see {@link NutrientViewer.EventName.ANNOTATIONS_LOAD} | {@link NutrientViewer.EventName.ANNOTATIONS_CHANGE}
* @see {@link NutrientViewer.EventName.ANNOTATIONS_CREATE} | {@link NutrientViewer.EventName.ANNOTATIONS_UPDATE}
* @see {@link NutrientViewer.EventName.ANNOTATIONS_DELETE} | {@link NutrientViewer.EventName.ANNOTATIONS_PRESS}
* @see {@link NutrientViewer.EventName.ANNOTATIONS_WILL_SAVE} | {@link NutrientViewer.EventName.ANNOTATIONS_DID_SAVE}
* @see {@link NutrientViewer.EventName.ANNOTATIONS_FOCUS} | {@link NutrientViewer.EventName.ANNOTATIONS_BLUR}
* @see {@link NutrientViewer.EventName.ANNOTATIONS_WILL_CHANGE} | {@link NutrientViewer.EventName.ANNOTATION_SELECTION_CHANGE}
*/
export declare class Annotation<T extends AnnotationProperties = AnnotationProperties> extends InheritableImmutableRecord<T> {
/**
* A unique identifier to describe the annotation. When an annotation is created in the UI, the
* viewer has to generate a unique ID.
*
* When changes are saved to the underlying annotation provider, we call
* {@link Instance#ensureChangesSaved} to make sure the annotation has been persisted
* from the provider.
*/
id: ID;
/**
* An optional field that may be used to identify the annotation.
*
* By default, we'll set that to the same value as the automatically generated
* {@link Annotation#id}.
*/
name: null | string;
/**
* An optional annotation subject, representing a short description of
* the subject being addressed by the annotation. This property has no effect
* on the annotation rendering.
*/
subject: null | string;
/**
* When the annotation is extracted directly from a PDF file, the `pdfObjectId` refers to the
* identifier that was used in the PDF document.
*
* This ID is optional since newly created annotations using the SYNCProvider annotation provider
* won't have a `pdfObjectId` assigned.
*
* @default null
*/
pdfObjectId: null | number;
/**
* The page index on which the annotation is placed. It's important to notice that an annotation
* can only ever be on one page. If you create for example an ink annotation with lines on two
* pages, two annotation records will be created.
*
* `pageIndex` is zero-based and has a maximum value of `totalPageCount - 1`.
*/
pageIndex: number;
/**
* Position of this annotation on the page. It's necessary that this spans all visible points of
* the annotation, otherwise hit testing and other features may not work.
*/
boundingBox: Rect;
/**
* A transparency value that is applied to the complete annotation. The value is capped between 0
* and 1 inclusive.
*
* @default 1
*/
opacity: number;
/**
* An optional note that can be set on any annotation.
*
* This value is displayed in the Nutrient Web SDK UI for all annotations except
* {@link NutrientViewer.Annotations.NoteAnnotation | NoteAnnotation}, {@link NutrientViewer.Annotations.TextAnnotation | TextAnnotation}, {@link NutrientViewer.Annotations.WidgetAnnotation | WidgetAnnotation} and {@link NutrientViewer.Annotations.CommentMarkerAnnotation | CommentMarkerAnnotation}.
*/
note: null | string;
/**
* The name of the creator of the annotation. This is a general purpose string which can easily be
* spoofed and might not reflect the actual creator of the annotation.
*/
creatorName: null | string;
/**
* The date of the annotation creation.
*/
createdAt: Date;
/**
* The date of last annotation update.
*/
updatedAt: Date;
/**
* The annotation flag that prevents the annotation from being rendered in the UI.
*
* The annotation may still be part of the printed page, depending of the value of the
* {@link Annotations.Annotation#noPrint} flag.
*
* @default false
*/
noView: boolean;
/**
* The annotation flag that prevents the annotation from being printed.
*
* @default false
*/
noPrint: boolean;
/**
* The annotation flag that prevents the annotation from being modified.
*
* @default false
*/
locked: boolean;
/**
* The annotation flag that prevents the annotation content from being modified.
*
* @default false
*/
lockedContents: boolean;
/**
* The annotation flag that makes the annotation read only.
*
* @default false
*/
readOnly: boolean;
/**
* If set, do not display or print the annotation or allow it to interact with the user.
*
* @default false
*/
hidden: boolean;
/**
* Annotations can store additional user-specified data.
*
* NutrientViewer will not use or evaluate `customData` in the UI directly.
* You have full control over this property. For new annotations, this defaults to null.
*
* customData will be stored as JSON through `JSON.serialize()` and `JSON.parse()`, and
* so must be a plain JSON-serializable object.
*
* @example
* Adding a new {@link EllipseAnnotation} with custom data attached:
* ```ts
* const annotation = new NutrientViewer.Annotations.EllipseAnnotation({
* pageIndex: 0,
* boundingBox: new NutrientViewer.Geometry.Rect({
* top: 10,
* left: 10,
* width: 100,
* height: 100
* }),
* customData: {
* circleId: "my-circle"
* }
* });
* ```
*/
customData: null | Record<string, unknown>;
noZoom: boolean;
noRotate: boolean;
additionalActions: AnnotationAdditionalActionsType | null;
rotation: number;
/**
* The blend mode defines how the color of the annotation will be applied to its background.
*
* @default "normal"
*/
blendMode: IBlendMode;
isCommentThreadRoot: boolean;
isAnonymous: boolean;
/**
* This property is used to define the permission scope for this annotation.
*
* It is only available when collaboration permissions is enabled on Server-Backed deployments.
*/
group?: string | null;
/**
* This property defines whether this annotation can be edited or not.
* The value of this field depends on the set of collaboration permissions defined in the JWT token.
*
* It is only available when collaboration permissions is enabled on Server-Backed deployments.
*/
readonly isEditable?: boolean;
/**
* This property defines whether this annotation can be deleted or not.
* The value of this field depends on the set of collaboration permissions defined in the JWT token.
*
* It is only available when collaboration permissions is enabled on Server-Backed deployments.
*/
readonly isDeletable?: boolean;
/**
* This property defines whether the user has permission to edit the group of this annotation.
*
* It is only available when collaboration permissions is enabled on Server-Backed deployments.
*/
readonly canSetGroup?: boolean;
canReply?: boolean;
APStreamCache?: {
cache: string;
} | {
attach: string;
};
action: Action | null;
constructor(options?: Partial<T>);
}
declare namespace Annotation_2 {
export {
Annotation,
HighlightAnnotation,
ImageAnnotation,
InkAnnotation,
ShapeAnnotation,
LineAnnotation,
RectangleAnnotation,
EllipseAnnotation,
PolygonAnnotation,
PolylineAnnotation,
LinkAnnotation,
NoteAnnotation,
SquiggleAnnotation,
StampAnnotation,
StrikeOutAnnotation,
TextAnnotation,
TextMarkupAnnotation,
UnderlineAnnotation,
UnknownAnnotation,
WidgetAnnotation,
CommentMarkerAnnotation,
RedactionAnnotation,
MediaAnnotation };
}
/** @inline */
declare type AnnotationAdditionalActionsType = {
onPointerEnter?: Action;
onPointerLeave?: Action;
onPointerDown?: Action;
onPointerUp?: Action;
onPageOpen?: Action;
onPageClose?: Action;
onPageVisible?: Action;
onPageHidden?: Action;
};
/** @inline */
declare type AnnotationBackendJSON<K extends BaseAnnotationJSON = Serializers.AnnotationJSONUnion, R extends string = never> = { [P in
keyof K]?: NonNullable<K[P]> } &
{ [P in
Intersection<keyof K, BackendRequiredKeys | R>]-?: Exclude<NonNullable<K[P]>, undefined> };
declare type AnnotationJSONToAnnotation<T extends {
type: keyof AnnotationSerializerTypeMap;
}> = AnnotationSerializerTypeMap[GetTypeFromAnnotationJSON<T>]['annotation'];
/**
* @deprecated Use {@link Serializers.AnnotationJSONUnion} instead.
* @hidden
*/
export declare type AnnotationJSONUnion = Serializers.AnnotationJSONUnion;
/**
* @class
*
* Represents an annotation note. Used as a note annotation when hovering over note icon or when
* the note icon is selected. This annotation is not persisted in the document nor returned by the public API.
*/
declare class AnnotationNote extends NoteAnnotation<AnnotationNoteProps> {
/**
* Root annotation this note belongs to.
*/
parentAnnotation?: AnnotationsUnion;
/**
* Calculated position of this note on the page in PDF coordinates.
*/
position: Point;
notePosition?: Point;
}
/** @inline */
declare interface AnnotationNoteProps extends INoteAnnotation {
parentAnnotation: AnnotationsUnion | null;
position: Point;
notePosition?: Point;
}
declare function AnnotationPermissionMixin<T extends Class<BaseMixin>>(Base: T): {
new (...args: any[]): {
/**
* Returns a deep copy of the latest editableAnnotationTypes. This value changes whenever
* {@link Instance.setEditableAnnotationTypes} is called.
*
* Mutating this object will have no effect.
*
* @public
*/
readonly editableAnnotationTypes: Set_2<Class<AnnotationsUnion>>;
/**
* This method is used to update the editable annotation types.
*
* When one of the supplied {@link NutrientViewer.Annotations.Annotation} is invalid, this method will throw an
* {@link Error} that contains a detailed error message.
*
* @example
* ```ts
* // Only allow editing ink annotations
* instance.setEditableAnnotationTypes([NutrientViewer.Annotations.InkAnnotation]);
* instance.editableAnnotationTypes === [NutrientViewer.Annotations.InkAnnotation]; // => true
* ```
*
* @public
* @throws {Error} Will throw an error when the supplied array is not valid.
*/
setEditableAnnotationTypes(editableAnnotationTypes: Class<AnnotationsUnion>[]): void;
/**
* This method is used to update the isEditableAnnotation callback
*
* When the supplied callback is invalid it will throw a {@link Error} that contains a
* detailed error message.
*
* @example
* Only allow editing annotations from a specific creator name
* ```ts
* instance.setIsEditableAnnotation((annotation) => annotation.creatorName === "Alice");
* ```
*
* @public
* @throws {Error} Will throw an error when the supplied array is not valid.
*/
setIsEditableAnnotation(isEditableAnnotationCallback: IsEditableAnnotationCallback): void;
};
} & T;
/**
* Describes and persists the properties of an annotation preset.
*
* Annotation presets are sets of property-value pairs for annotations that can be applied as default
* annotations settings for toolbar items. When an annotation toolbar setting is changed by the user,
* the annotation preset associated with the toolbar item that triggered the annotation toolbar is updated.
* If the associated annotation preset doesn't exist, it's created with the settings that have changed.
*
* For properties not included in an annotation preset, the default values used when creating
* an annotation are those of the annotation type.
*
* @example
* Creating an annotation preset and adding it to the available annotation presets.
* ```ts
* const myAnnotationPresets = instance.annotationPresets
* myAnnotationPresets['my-annotation-preset'] = {
* strokeWidth: 2,
* }
* instance.setAnnotationPresets(myAnnotationPresets);
* ```
*
* @summary Annotation preset properties.
* @see {@link Configuration#annotationPresets}
* @see {@link Instance#setAnnotationPresets}
* @see {@link Events.AnnotationPresetsUpdateEvent}
*/
export declare type AnnotationPreset = Record<string, unknown>;
declare type AnnotationPreset_2 = AnnotationPreset;
/**
* This callback can be used in the {@link NutrientViewer.Instance#setAnnotationPresets | setAnnotationPresets()}
* method to do atomic updates to the current annotation presets.
*
* @example
* Use ES2015 arrow functions and the update callback to reduce boilerplate
* ```ts
* instance.setAnnotationPresets(presets => {
* presets.custom = {
* strokeWidth: 10,
* };
* return presets;
* });
* ```
*
* @param currentAnnotationPresets - The current annotation presets
* @returns The new annotation presets
*/
export declare type AnnotationPresetCallback = (currentAnnotationPresets: Record<AnnotationPresetID, AnnotationPreset>) => Record<AnnotationPresetID, AnnotationPreset>;
/** @inline */
declare type AnnotationPresetID = string;
declare type AnnotationPresetID_2 = AnnotationPresetID;
export declare namespace AnnotationPresets {
export {
serializePreset as toSerializableObject,
unserializePreset as fromSerializableObject };
}
declare function AnnotationPresetsMixin<T extends Class<BaseMixin>>(Base: T): {
new (...args: any[]): {
/**
* Returns a deep copy of the latest annotation presets. This value changes whenever the user
* interacts with NutrientViewer or whenever {@link Instance.setAnnotationPresets} is called.
*
* Mutating this object will have no effect.
*/
readonly annotationPresets: {
[key: string]: AnnotationPreset;
};
/**
* Get the current active annotation preset ID
*/
readonly currentAnnotationPreset: string | null | undefined;
/**
* This method is used to update the annotation presets.
*
* It makes it possible to add new {@link AnnotationPreset | annotation presets} and edit or remove existing ones.
*
* When you pass in an `object` with keyed {@link AnnotationPreset}, the current annotation presets
* will be immediately updated. Calling this method is also idempotent.
*
* If you pass in a function, it will be immediately invoked and will receive the current annotation presets as argument. You can use this to modify the object based on its
* current value. This type of update is guaranteed to be atomic - the value of `currentAnnotationPresets` can't change in between. See: {@link AnnotationPresetCallback}
*
* When one of the supplied {@link AnnotationPreset} is invalid, this method will throw an {@link Error} that contains a detailed error message.
*
* Since `annotationPresets` is a regular JavaScript `object`, it can be manipulated using standard `Object`
* methods.
*
* @example
* The new changes will be applied immediately
* ```ts
* instance.setAnnotationPresets(newAnnotationPresets);
* instance.annotationPresets === newAnnotationPresets; // => true
* ```
*
* @example
* Adding an annotation preset for an ellipse annotation variant.
* ```ts
* const myAnnotationPreset = {
* dashedEllipse: {
* strokeDashArray: [3, 3],
* }
* }
* instance.setAnnotationPresets(annotationPresets => ({ ...annotationPresets, myAnnotationPreset }))
* ```
*
* @throws {Error} Will throw an error when the supplied annotation preset `object` is not valid.
* @param stateOrFunction - Either a
* new AnnotationPresets `object` which would overwrite the existing one, or a callback that will get
* invoked with the current annotation presets and is expected to return the new annotation presets `object`.
*/
setAnnotationPresets(stateOrFunction: Record<AnnotationPresetID, AnnotationPreset> | AnnotationPresetCallback): void;
/**
* This method is used to set the current active annotation preset.
*
* It makes it possible to specify what annotation preset should be used when new annotations
* are created in the UI by passing the annotation preset key string as argument.
*
* The current annotation preset is set when the toolbar annotation buttons are used to create
* annotations. This method allows to set the current annotation preset programmatically, as well
* as resetting it by passing `null` as argument.
*
* When the supplied key does not correspond with an existing {@link AnnotationPreset},
* this method will throw an {@link Error} that contains a detailed error message.
*
* @example
* The new changes will be applied immediately
* ```ts
* instance.setCurrentAnnotationPreset("ink");
* instance.currentAnnotationPreset === "ink"; // => true
* ```
*
* @example
* Setting an annotation preset for a closed arrow line annotation.
* ```ts
* instance.setAnnotationPresets(annotationPresets => {
* return {
* ...annotationPresets,
* line: {
* ...annotationPresets.line,
* lineCaps: {
* end: "closedArrow"
* }
* }
* }
* });
* instance.setCurrentAnnotationPreset("line");
* instance.setViewState(viewState =>
* viewState.set("interactionMode", NutrientViewer.InteractionMode.SHAPE_LINE),
* );
* ```
*
* @public
* @param annotationPresetID - Annotation preset name.
* @throws {Error} Will throw an error when the supplied annotation preset key does not exist.
*/
setCurrentAnnotationPreset(annotationPresetID?: string | null): void;
};
} & T;
/** @inline */
declare type AnnotationProperties = {
id: string | null;
name: string | null;
subject: string | null;
pdfObjectId: number | null;
pageIndex: number | null;
boundingBox: Rect | null;
opacity: number | null;
note: string | null;
creatorName: string | null;
createdAt: Date | null;
updatedAt: Date | null;
customData: Record<string, unknown> | null;
noView: boolean | null;
noPrint: boolean | null;
locked: boolean | null;
lockedContents: boolean | null;
readOnly: boolean | null;
hidden: boolean | null;
group: string | null | undefined;
isEditable: boolean | undefined;
isDeletable: boolean | undefined;
canSetGroup: boolean | undefined;
canReply: boolean | undefined;
rotation: number;
additionalActions: AnnotationAdditionalActionsType | null;
noZoom: boolean;
noRotate: boolean;
isCommentThreadRoot: boolean;
isAnonymous: boolean;
APStreamCache: {
cache: string;
} | {
attach: string;
} | undefined;
blendMode: IBlendMode;
action: Action | null;
[key: string]: unknown;
};
declare type AnnotationReference = {
fieldName: string;
} | {
pdfObjectId: number;
};
/**
* A comparator function that defines a strict total order for annotation rendering.