npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@fge-bo-vue/pdf-viewer

v1.0.2

Published

Componente Vue 3 para visualización de PDFs con soporte para HTTP Range Requests (Formerly pdf-fge-vue3)

Downloads

45

Readme

@fge-bo-vue/pdf-viewer

Vue 3 TypeScript pdfjs-dist

📦 Formerly: pdf-fge-vue3 (deprecated)

Componente Vue 3 para visualización de PDFs con soporte para HTTP Range Requests, caché inteligente y múltiples estrategias de carga.

🔄 Migrating from pdf-fge-vue3

If you're migrating from the old package:

# Uninstall old package
npm uninstall pdf-fge-vue3

# Install new package
npm install @fge-bo-vue/pdf-viewer

your imports:

import { PdfViewer, PdfViewerRange } from '@fge-bo-vue/pdf-viewer';

import '@fge-bo-vue/pdf-viewer/styles.css';

No breaking changes - All APIs remain the same!


🎯 Características

  • HTTP Range Requests: Descarga solo las partes necesarias del PDF
  • 3 Estrategias de Carga: on-demand, progressive, complete
  • Caché Inteligente: Persiste entre recargas (F5) con expiración configurable
  • Pre-validación de URLs: Captura errores HTTP (403, 404, etc.) antes de cargar
  • Arquitectura Modular: Composables y componentes reutilizables
  • TypeScript: Tipado completo
  • Optimización de Ancho de Banda: Modo on-demand carga solo páginas visibles

📦 Instalación

npm install @fge-bo-vue/pdf-viewer
# o
yarn add @fge-bo-vue/pdf-viewer

⚠️ Importación de Estilos (OBLIGATORIO)

IMPORTANTE: Los estilos CSS son obligatorios para el correcto funcionamiento del componente. Debes importarlos en tu aplicación:

import '@fge-bo-vue/pdf-viewer/styles.css';

📋 Componentes Disponibles

La librería incluye dos componentes principales:

1. PdfViewerRange (Recomendado)

  • Soporta HTTP Range Requests
  • 3 estrategias de carga: on-demand, progressive, complete
  • Caché inteligente con expiración configurable
  • Ideal para archivos grandes o conexiones lentas

2. PdfViewer (Clásico)

  • Carga completa del PDF desde URL, File o Base64
  • Soporte para integración con AGETIC
  • Marcas de agua configurables
  • Ideal para archivos pequeños o cuando no hay soporte de Range Requests

¿Cuál usar?

| Característica | PdfViewerRange | PdfViewer | |----------------|----------------|-----------| | Range Requests | ✅ Sí | ❌ No | | Caché inteligente | ✅ Sí | ❌ No | | Integración AGETIC | ❌ No | ✅ Sí | | Marcas de agua | ❌ No | ✅ Sí | | Base64 support | ❌ No | ✅ Sí | | File objects | ❌ No | ✅ Sí | | Optimizado para | Archivos grandes | Archivos pequeños | | Ancho de banda | Mínimo | Completo |

Recomendación:

  • Usa PdfViewerRange si trabajas con archivos grandes (>5MB) y tu backend soporta Range Requests
  • Usa PdfViewer si necesitas integración con AGETIC, marcas de agua, o trabajas con archivos pequeños

🚀 Uso de PdfViewerRange

Importación con defineAsyncComponent (Recomendado)

<script setup lang="ts">
import { defineAsyncComponent, ref } from 'vue';
import '@fge-bo-vue/pdf-viewer/styles.css'; // ⚠️ OBLIGATORIO

const PdfViewerRange = defineAsyncComponent(() => 
  import('@fge-bo-vue/pdf-viewer').then((module) => module.PdfViewerRange)
);

const pdfUrl = ref('https://api.example.com/files/document.pdf');
const headers = ref({ Authorization: 'Bearer token123' });
</script>

<template>
  <PdfViewerRange
    :range-url="pdfUrl"
    :http-headers="headers"
    load-strategy="on-demand"
    :cache-enabled="true"
    :cache-expiration-minutes="5"
  />
</template>

Importación Directa

<script setup lang="ts">
import { ref } from 'vue';
import { PdfViewerRange } from '@fge-bo-vue/pdf-viewer';
import '@fge-bo-vue/pdf-viewer/styles.css'; // ⚠️ OBLIGATORIO

const pdfUrl = ref('https://api.example.com/files/document.pdf');
</script>

<template>
  <PdfViewerRange :range-url="pdfUrl" />
</template>

Ejemplo Completo con PdfViewerRange

<script setup lang="ts">
import { ref } from 'vue';
import { PdfViewerRange } from '@fge-bo-vue/pdf-viewer';
import '@fge-bo-vue/pdf-viewer/styles.css'; // ⚠️ OBLIGATORIO

const pdfUrl = ref('https://api.example.com/files/document.pdf?token=abc123');
const headers = ref({
  Authorization: 'Bearer token123',
});

const handleError = (message: string) => {
  console.error('Error al cargar PDF:', message);
};

const handleLoaded = (pages: number) => {
  console.log(`PDF cargado con ${pages} páginas`);
};
</script>

<template>
  <PdfViewerRange
    :range-url="pdfUrl"
    :http-headers="headers"
    :load-strategy="'on-demand'"
    :cache-enabled="true"
    :cache-expiration-minutes="5"
    :download-name="'documento.pdf'"
    :show-progress="true"
    @error="handleError"
    @loaded="handleLoaded"
  />
</template>

Props de PdfViewerRange

| Prop | Tipo | Default | Descripción | |------|------|---------|-------------| | rangeUrl | string | requerido | URL del endpoint que soporta Range Requests | | httpHeaders | Record<string, string> | {} | Headers HTTP adicionales (ej: Authorization) | | loadStrategy | 'on-demand' \| 'progressive' \| 'complete' | 'on-demand' | Estrategia de carga del PDF | | cacheEnabled | boolean | true | Habilitar caché del PDF | | cacheExpirationMinutes | number | 1 | Tiempo de expiración del caché en minutos | | rangeChunkSize | number | 65536 | Tamaño del chunk en bytes (64KB) | | downloadName | string | 'documento.pdf' | Nombre del archivo al descargar | | showProgress | boolean | true | Mostrar barra de progreso | | pageScale | PageScale | 'auto' | Escala inicial de la página | | pageNumber | number | 1 | Número de página inicial | | toolbar | Partial<Toolbar> | Ver abajo | Configuración de la barra de herramientas |

Toolbar por Defecto

{
  search: true,
  paginator: true,
  zoom: true,
  fullscreen: true,
  download: true,
  print: true,
}

📊 Estrategias de Carga

1. On-Demand (Recomendado para archivos grandes)

Carga solo las páginas visibles cuando el usuario navega a ellas.

Ventajas:

  • Mínimo ancho de banda
  • Carga inicial rápida (~100KB-1MB de metadatos)
  • Ideal para documentos grandes (>10MB)

Uso:

<PdfViewerRange
  :range-url="url"
  :load-strategy="'on-demand'"
/>

2. Progressive (Balance)

Precarga páginas cercanas anticipadamente mientras el usuario navega.

Ventajas:

  • Balance entre velocidad y ancho de banda
  • Experiencia de usuario fluida
  • Bueno para documentos medianos (5-10MB)

Uso:

<PdfViewerRange
  :range-url="url"
  :load-strategy="'progressive'"
/>

3. Complete (Máximo rendimiento local)

Descarga todo el PDF de una vez.

Ventajas:

  • Navegación instantánea después de cargar
  • Sin esperas al cambiar de página
  • Ideal para documentos pequeños (<5MB)

Uso:

<PdfViewerRange
  :range-url="url"
  :load-strategy="'complete'"
/>

🎨 Uso de PdfViewer

El componente PdfViewer es ideal para cuando:

  • No necesitas HTTP Range Requests
  • Trabajas con archivos pequeños
  • Necesitas integración con AGETIC
  • Requieres marcas de agua
  • El PDF viene de File, Base64 o URL simple

Importación con defineAsyncComponent (Recomendado)

<script setup lang="ts">
import { defineAsyncComponent, ref } from 'vue';
import '@fge-bo-vue/pdf-viewer/styles.css'; // ⚠️ OBLIGATORIO

const PdfViewer = defineAsyncComponent(() => 
  import('@fge-bo-vue/pdf-viewer').then((module) => module.PdfViewer)
);

const pdfFile = ref({
  src: 'https://api.example.com/files/document.pdf',
  downloadName: 'documento.pdf',
});
</script>

<template>
  <PdfViewer
    :file="pdfFile"
    :token="'your-token'"
    @error="(msg) => console.error(msg)"
  />
</template>

Importación Directa

<script setup lang="ts">
import { ref } from 'vue';
import { PdfViewer } from '@fge-bo-vue/pdf-viewer';
import '@fge-bo-vue/pdf-viewer/styles.css'; // ⚠️ OBLIGATORIO

const pdfFile = ref({
  src: { url: 'https://api.example.com/files/document.pdf' },
  downloadName: 'documento.pdf',
});
</script>

<template>
  <PdfViewer :file="pdfFile" :token="'your-token'" />
</template>

Ejemplo Completo con PdfViewer

<script setup lang="ts">
import { ref } from 'vue';
import { PdfViewer } from '@fge-bo-vue/pdf-viewer';
import '@fge-bo-vue/pdf-viewer/styles.css'; // ⚠️ OBLIGATORIO

const pdfFile = ref({
  src: {
    url: 'https://api.example.com/files/document.pdf',
    httpHeaders: {
      authorization: 'Bearer token123',
    },
  },
  downloadName: 'documento.pdf',
  msFileId: 'file-id-123', // Para integración con AGETIC
});

const token = ref('your-session-token');

const handleError = (message: string) => {
  alert(`Error: ${message}`);
};

const handleFileApproved = (data: any) => {
  console.log('Archivo aprobado:', data);
};
</script>

<template>
  <PdfViewer
    :file="pdfFile"
    :token="token"
    :toolbar="{
      search: true,
      paginator: true,
      zoom: true,
      fullscreen: true,
      download: true,
      print: true,
      agetic: {
        enableSign: true
      }
    }"
    @error="handleError"
    @fileApprovedCD="handleFileApproved"
  />
</template>

Props de PdfViewer

| Prop | Tipo | Default | Descripción | |------|------|---------|-------------| | file | FileSrcPdf | undefined | Objeto con la fuente del PDF | | token | string | requerido | Token de sesión | | pageScale | PageScale | 'auto' | Escala inicial de la página | | pageNumber | number | 1 | Número de página inicial | | toolbar | Partial<Toolbar> | Ver abajo | Configuración de la barra de herramientas | | tokenAgetic | string | undefined | Token para integración AGETIC | | modeAgetic | MODE_AGETIC | MODE_AGETIC.DEV | Modo de AGETIC (DEV/PROD) | | verifyFgeEmployee | boolean | false | Verificar empleado FGE | | watermark | WatermarkType | undefined | Configuración de marca de agua | | isFetchV2 | boolean | false | Usar API v2 para obtener PDF | | isBase64 | boolean | false | El PDF viene en formato Base64 | | v2ParamsType | V2ParamsType | undefined | Parámetros para API v2 |

Tipo FileSrcPdf

interface FileSrcPdf {
  src: PDFSrc; // URL string, File object, or { url: string, httpHeaders?: {} }
  downloadName?: string;
  msFileId?: string; // Para integración AGETIC
}

Toolbar de PdfViewer

{
  search: true,
  paginator: true,
  zoom: true,
  fullscreen: true,
  download: true,
  print: true,
  agetic: {
    enableSign: boolean; // Habilitar firma digital AGETIC
  }
}

Eventos de PdfViewer

interface PdfViewerEvents {
  error: (message: string) => void;
  fileApprovedCD: (data: ApprobationData) => void; // Cuando se aprueba con firma AGETIC
}

💾 Sistema de Caché (PdfViewerRange)

  • ✅ Persiste entre recargas (F5) y navegación
  • ✅ Usa Cache Storage API + localStorage
  • ✅ Expiración configurable por tiempo
  • ✅ Limpieza automática de caché antiguo

Configuración de Caché

<PdfViewerRange
  :cache-enabled="true"
  :cache-expiration-minutes="5"
/>

Limpiar Caché Manualmente

<script setup>
const pdfViewer = ref();

// Limpiar caché del PDF actual
pdfViewer.value?.clearPdfCache();

// Limpiar todo el caché de PDFs
pdfViewer.value?.clearAllPdfCache();
</script>

<template>
  <PdfViewerRange ref="pdfViewer" :range-url="url" />
</template>

🔒 Manejo de Errores HTTP

El componente captura y muestra errores HTTP del backend automáticamente:

  • 403 Forbidden: URL firmada expirada, sin permisos
  • 404 Not Found: Documento no encontrado
  • 401 Unauthorized: Sesión expirada

Ejemplo de Respuesta del Backend

{
  "error": true,
  "message": "URL firmada expirada.",
  "response": null,
  "status": 403
}

El componente mostrará una pantalla de error elegante con el mensaje del backend.

🎨 Métodos Expuestos

Ambos componentes exponen métodos para controlar el visor programáticamente.

Métodos Comunes (PdfViewer y PdfViewerRange)

interface CommonMethods {
  setZoom(zoom: PageScale | number): void;
  setPage(page: number): void;
  rotatePDF(): void;
  downloadClick(): void;
  printPDF(): void;
  search(query?: string, findPrevious?: boolean): void;
}

Métodos Exclusivos de PdfViewerRange

interface PdfViewerRangeMethods extends CommonMethods {
  clearPdfCache(): Promise<void>;      // Limpiar caché del PDF actual
  clearAllPdfCache(): Promise<void>;   // Limpiar todo el caché
}

Uso de Métodos

<script setup>
import { ref } from 'vue';
import { PdfViewerRange, PdfViewer } from '@fge-bo-vue/pdf-viewer';
import '@fge-bo-vue/pdf-viewer/styles.css'; // ⚠️ OBLIGATORIO

// Funciona con ambos componentes
const pdfViewerRange = ref();
const pdfViewer = ref();

// Métodos comunes (disponibles en ambos)
const zoomIn = () => {
  pdfViewerRange.value?.setZoom(1.5);
  pdfViewer.value?.setZoom(1.5);
};

const goToPage = (page: number) => {
  pdfViewerRange.value?.setPage(page);
  pdfViewer.value?.setPage(page);
};

const rotate = () => {
  pdfViewerRange.value?.rotatePDF();
  pdfViewer.value?.rotatePDF();
};

const searchText = () => {
  pdfViewerRange.value?.search('texto a buscar');
  pdfViewer.value?.search('texto a buscar');
};

// Métodos exclusivos de PdfViewerRange
const clearCache = () => {
  pdfViewerRange.value?.clearPdfCache();
};

const clearAllCache = () => {
  pdfViewerRange.value?.clearAllPdfCache();
};
</script>

<template>
  <!-- Con PdfViewerRange -->
  <PdfViewerRange ref="pdfViewerRange" :range-url="url" />
  
  <!-- Con PdfViewer -->
  <PdfViewer ref="pdfViewer" :file="file" :token="token" />
  
  <button @click="zoomIn">Zoom In</button>
  <button @click="goToPage(5)">Ir a página 5</button>
  <button @click="rotate">Rotar</button>
  <button @click="searchText">Buscar</button>
  <button @click="clearCache">Limpiar caché (solo Range)</button>
</template>

📡 Eventos

Eventos de PdfViewerRange

interface PdfViewerRangeEvents {
  error: (message: string) => void;
  loaded: (pages: number) => void;
  progress: (loaded: number, total: number) => void;
}

Ejemplo:

<template>
  <PdfViewerRange
    :range-url="url"
    @error="(msg) => console.error('Error:', msg)"
    @loaded="(pages) => console.log('Cargado:', pages, 'páginas')"
    @progress="(loaded, total) => console.log('Progreso:', loaded, '/', total)"
  />
</template>

Eventos de PdfViewer

interface PdfViewerEvents {
  error: (message: string) => void;
  fileApprovedCD: (data: ApprobationData) => void; // Solo cuando se usa AGETIC
}

Ejemplo:

<template>
  <PdfViewer
    :file="file"
    :token="token"
    @error="(msg) => alert(`Error: ${msg}`)"
    @fileApprovedCD="(data) => console.log('Archivo aprobado:', data)"
  />
</template>

🏗️ Arquitectura Modular

Estructura de Archivos

src/
├── components/
│   ├── PdfViewerRange.vue           # Componente con Range Requests
│   ├── PdfViewer.vue                # Componente clásico con AGETIC
│   ├── AgeticSidebar.vue            # Integración con firma AGETIC
│   ├── PdfErrorDisplay.vue          # Pantalla de errores HTTP
│   ├── PdfLoadingProgress.vue       # Indicador de progreso
│   ├── LoadingComponent.vue         # Componente de carga
│   ├── ValidationItem.vue           # Item de validación
│   └── PDFToolbar.vue               # Barra de herramientas
├── composables/
│   ├── usePdfCache.ts               # Manejo de caché
│   ├── usePdfLoader.ts              # Carga de PDFs con Range Requests
│   ├── usePdfValidation.ts          # Pre-validación de URLs
│   ├── usePdfViewer.ts              # Lógica del visor PDF
│   ├── usePdfSearch.ts              # Búsqueda en PDF
│   └── usePdfActions.ts             # Acciones (descargar, imprimir, etc.)
├── hooks/
│   └── useAgetic.ts                 # Hook para integración AGETIC
└── types/
    └── index.ts                     # Tipos TypeScript

Composables

usePdfCache (PdfViewerRange)

const { getCachedPdf, cachePdf, clearCache, clearAllCache } = usePdfCache();

Funciones:

  • getCachedPdf(url, expirationMinutes): Buscar PDF en caché
  • cachePdf(url, data, strategy): Guardar PDF en caché
  • clearCache(url): Limpiar caché de un PDF
  • clearAllCache(): Limpiar todo el caché

usePdfLoader

const { isLoading, loadProgress, loadPdf, getPdfData } = usePdfLoader();

Funciones:

  • loadPdf(options, onProgress): Cargar PDF con Range Requests
  • getPdfData(pdfDoc): Obtener datos completos del PDF

usePdfValidation

const { validateUrl } = usePdfValidation();

Funciones:

  • validateUrl(url, headers): Pre-validar URL antes de cargar

🔧 Requisitos del Backend

El backend debe soportar HTTP Range Requests (RFC 7233):

Headers Requeridos

Accept-Ranges: bytes
Content-Range: bytes 0-1023/1234567
Content-Length: 1024

Respuestas HTTP

  • 206 Partial Content: Para requests con Range header
  • 416 Range Not Satisfiable: Si el rango solicitado es inválido
  • 200 OK: Para requests sin Range header (fallback)

Ejemplo de Implementación NestJS

Ver el backend de ejemplo en: /ms-files-v2/src/modules/file/file-range.service.ts

🐛 Troubleshooting

Los estilos no se aplican correctamente

Solución: Verifica que hayas importado los estilos:

import '@fge-bo-vue/pdf-viewer/styles.css';

Esta importación es obligatoria y debe estar en el componente donde uses PdfViewer o PdfViewerRange.

El PDF no carga en modo on-demand (PdfViewerRange)

Verifica en DevTools → Network:

  • Los requests deben tener header Range: bytes=X-Y
  • Las respuestas deben ser 206 Partial Content
  • Backend debe enviar header Accept-Ranges: bytes

El caché no funciona (PdfViewerRange)

  • Verifica que cacheEnabled={true}
  • Revisa la consola del navegador
  • El caché solo funciona en HTTPS o localhost
  • Solo aplica para PdfViewerRange, no para PdfViewer

El componente no se importa correctamente

Si usas defineAsyncComponent:

import '@fge-bo-vue/pdf-viewer/styles.css';
const PdfViewerRange = defineAsyncComponent(() => 
  import('@fge-bo-vue/pdf-viewer').then((module) => module.PdfViewerRange)
);

Si usas importación directa:

import { PdfViewerRange, PdfViewer } from '@fge-bo-vue/pdf-viewer';
import '@fge-bo-vue/pdf-viewer/styles.css';

Errores CORS (PdfViewerRange)

El backend debe permitir estos headers:

Access-Control-Allow-Headers: Range
Access-Control-Expose-Headers: Content-Range, Accept-Ranges

📄 Licencia

UNLICENSED - FGE Internal Use Only