ecfx/ecf-dgii-php 问题修复 & 功能扩展

解决BUG、新增功能、兼容多环境部署,快速响应你的开发需求

邮箱:yvsm@zunyunkeji.com | QQ:316430983 | 微信:yvsm316

ecfx/ecf-dgii-php

Composer 安装命令:

composer require ecfx/ecf-dgii-php

包简介

PHP SDK for the ECF DGII electronic fiscal receipt API (Dominican Republic)

README 文档

README

Packagist Version Packagist Downloads License

PHP SDK para integrar la facturacion electronica (e-CF) en Republica Dominicana a traves de ECF SSD.

Packagist Version Packagist Downloads CI License

Que es ECF SSD

ECF SSD es una plataforma que simplifica la emision de comprobantes fiscales electronicos (e-CF) en Republica Dominicana. En vez de que cada empresa implemente todo el proceso de comunicacion con la DGII (firmado XML, autenticacion por semilla, manejo de certificados, reintentos, almacenamiento, etc.), ECF SSD lo hace por ti.

Tu solo envias el comprobante en JSON a traves de este SDK, y el servicio se encarga de:

  • Firmar el comprobante electronicamente (XML signing con tu certificado digital)
  • Autenticar con la DGII (semilla -> token)
  • Enviar el e-CF a la DGII
  • Validar emisor-receptor
  • Almacenar los comprobantes de forma segura
  • Reintentar automaticamente en caso de fallos
  • Gestionar tus certificados digitales

Usas WooCommerce? Tenemos un plugin listo para facturacion electronica sin escribir codigo.

Buscas otro lenguaje? Tambien disponible en .NET, TypeScript, React, Python, Java, Kotlin, Swift y C++. Ver todos los SDKs y plugins.

Instalacion

composer require ecfx/ecf-dgii-php

Requisitos

  • PHP 8.1+
  • ext-curl
  • ext-json
  • ext-mbstring

Como Empezar

Paso 1: Registrate en ECF SSD

Visita https://ecf.ssd.com.do y crea tu cuenta.

Paso 2: Obten tu API Key

  1. Una vez logueado, selecciona el ambiente Test en el selector de ambientes (esquina superior derecha)
  2. Ve a Settings > API Key > Generate API Key
  3. Copia tu API Key -- la usaras como bearer token para autenticarte con el SDK

Paso 3: Contacta a ECF SSD para la Integracion

Contacta al equipo de ECF SSD (contacto@ssd.com.do) para iniciar el proceso de integracion y certificacion de tu sistema (no de las empresas de tus clientes -- la certificacion es para tu plataforma). El equipo te guiara a traves del proceso usando el ambiente de certificacion (Cert).

Paso 4: Usa Produccion

Una vez que tu sistema este integrado y certificado, podras usar el ambiente de produccion (Prod) para emitir comprobantes fiscales electronicos reales.

Vienes de otro proveedor? ECF SSD soporta migracion desde otros proveedores de facturacion electronica. Contacta al equipo para coordinar la transicion.

Configuracion

use Ecfx\EcfDgii\Configuration;

$config = Configuration::getDefaultConfiguration()
    ->setHost('https://api.test.ecfx.ssd.com.do')
    ->setAccessToken('your-api-key-here');

Ambientes

Ambiente URL Uso
Test https://api.test.ecfx.ssd.com.do Desarrollo y pruebas internas
Cert https://api.cert.ecfx.ssd.com.do Proceso de certificacion con la DGII
Prod https://api.prod.ecfx.ssd.com.do Produccion

Autenticacion

El SDK utiliza JWT Bearer Token. Puedes configurar el token de dos formas:

  1. Directamente en el codigo: pasando el API Key con setAccessToken()
  2. Variable de entorno: ECF_DGII_TOKEN

Ejemplo: Factura de Consumo (ECF 32)

Cada tipo de ECF tiene su propio conjunto de clases con el prefijo del tipo (ej. Ecf32ECF, Ecf32Encabezado, Ecf32Item para Factura de Consumo).

<?php

require_once 'vendor/autoload.php';

use GuzzleHttp\Client;
use Ecfx\EcfDgii\Configuration;
use Ecfx\EcfDgii\Api\EcfApi;
use Ecfx\EcfDgii\ApiException;
use Ecfx\EcfDgii\Model\Ecf32ECF;
use Ecfx\EcfDgii\Model\Ecf32Encabezado;
use Ecfx\EcfDgii\Model\Ecf32IdDoc;
use Ecfx\EcfDgii\Model\Ecf32Emisor;
use Ecfx\EcfDgii\Model\Ecf32Comprador;
use Ecfx\EcfDgii\Model\Ecf32Totales;
use Ecfx\EcfDgii\Model\Ecf32Item;
use Ecfx\EcfDgii\Model\Ecf32FormaDePago;
use Ecfx\EcfDgii\Model\Ecf32VersionType;
use Ecfx\EcfDgii\Model\Ecf32TipoPagoType;
use Ecfx\EcfDgii\Model\Ecf32FormaPagoType;
use Ecfx\EcfDgii\Model\Ecf32IndicadorFacturacionType;
use Ecfx\EcfDgii\Model\Ecf32IndicadorBienoServicioType;
use Ecfx\EcfDgii\Model\Ecf32TipoIngresosValidationType;
use Ecfx\EcfDgii\Model\TipoeCFType;
use Ecfx\EcfDgii\Model\IndicadorMontoGravadoType;
use Ecfx\EcfDgii\Model\UnidadMedidaType;

// 1. Configurar
$config = Configuration::getDefaultConfiguration()
    ->setHost('https://api.test.ecfx.ssd.com.do')
    ->setAccessToken(getenv('ECF_DGII_TOKEN'));

// 2. Crear el cliente API
$ecfApi = new EcfApi(new Client(), $config);

// 3. Construir el ECF 32 (Factura de Consumo)
$ecf = new Ecf32ECF([
    'encabezado' => new Ecf32Encabezado([
        'version' => Ecf32VersionType::VERSION1_0,
        'id_doc' => new Ecf32IdDoc([
            'tipoe_cf' => TipoeCFType::FACTURA_DE_CONSUMO_ELECTRONICA,
            'encf' => 'E320000000019',
            'indicador_monto_gravado' => IndicadorMontoGravadoType::CON_ITBIS_INCLUIDO,
            'tipo_ingresos' => Ecf32TipoIngresosValidationType::_01,
            'tipo_pago' => Ecf32TipoPagoType::CONTADO,
            'tabla_formas_pago' => [
                new Ecf32FormaDePago([
                    'forma_pago' => Ecf32FormaPagoType::EFECTIVO,
                    'monto_pago' => 590,
                ]),
            ],
        ]),
        'emisor' => new Ecf32Emisor([
            'rnc_emisor' => 'TODO_YOUR_RNC',           // TODO: Reemplaza con tu RNC
            'razon_social_emisor' => 'TODO_YOUR_RAZON_SOCIAL', // TODO: Reemplaza con tu razon social
            'direccion_emisor' => 'TODO_YOUR_ADDRESS',  // TODO: Reemplaza con tu direccion
            'numero_factura_interna' => '21',
            'fecha_emision' => new \DateTime('2026-03-13'),
        ]),
        'comprador' => new Ecf32Comprador(),
        'totales' => new Ecf32Totales([
            'monto_gravado_total' => 500,
            'monto_gravado_i1' => 500,
            'itbi_s1' => 18,
            'total_itbis' => 90,
            'total_itbis1' => 90,
            'monto_total' => 590,
            'monto_periodo' => 590,
        ]),
    ]),
    'detalles_items' => [
        new Ecf32Item([
            'numero_linea' => 1,
            'indicador_facturacion' => Ecf32IndicadorFacturacionType::ITBIS1_18_PERCENT,
            'nombre_item' => 'Servicio Digital',
            'indicador_bieno_servicio' => Ecf32IndicadorBienoServicioType::SERVICIO,
            'cantidad_item' => 1,
            'unidad_medida' => UnidadMedidaType::UNIDAD,
            'precio_unitario_item' => 500,
            'monto_item' => 500,
        ]),
    ],
]);

// 4. Enviar el ECF
try {
    $result = $ecfApi->recepcionEcf32($ecf);

    echo "ECF enviado!\n";
    echo "Message ID: " . $result->getMessageId() . "\n";
} catch (ApiException $e) {
    echo "Error: " . $e->getMessage() . "\n";
    echo "Response: " . $e->getResponseBody() . "\n";
}

Usando EcfService (auto-routing + polling)

El EcfService enruta automaticamente al endpoint correcto segun el tipo de ECF y hace polling hasta que la DGII termine de procesar:

use Ecfx\EcfDgii\EcfService;
use Ecfx\EcfDgii\EcfProcessingException;
use Ecfx\EcfDgii\EcfPollingTimeoutException;

$service = new EcfService($ecfApi, pollingMaxAttempts: 30, pollingIntervalSeconds: 2);

try {
    $result = $service->sendEcf($ecf);

    echo "ECF aceptado!\n";
    echo "Status: " . $result->getEstatus() . "\n";
    echo "ENCF: " . $result->getEncf() . "\n";
} catch (EcfProcessingException $e) {
    echo "ECF rechazado: " . $e->getMessage() . "\n";
} catch (EcfPollingTimeoutException $e) {
    echo "Polling timeout: " . $e->getMessage() . "\n";
}

Como Funciona sendEcf

Tu sistema                          ECF SSD                         DGII
   |                                   |                              |
   |-- sendEcf(ecf) ----------------->|                              |
   |                                   |-- firma XML ----------------|
   |                                   |-- autenticacion (semilla) ->|
   |                                   |-- envio e-CF -------------->|
   |                                   |<-- trackId ----------------|
   |                                   |-- polling estado ---------->|
   |                                   |<-- resultado final --------|
   |<-- EcfResponse ------------------|                              |
   |                                   |                              |
  1. Enrutamiento automatico: Determina el endpoint correcto (/ecf/31, /ecf/32, etc.) basandose en el tipoeCF
  2. Envio: POST al endpoint correspondiente
  3. Polling: Consulta periodicamente el estado hasta que la DGII responda (Finished o Error)
  4. Resultado: Retorna el EcfResponse con el estado final, codigo de seguridad, URL de impresion, etc.

Respuesta (EcfResponse)

Al completarse el envio, recibes un EcfResponse con los datos necesarios para cumplir con los requisitos de impresion de la DGII:

Campo Descripcion
ImpresionUrl URL para generar el codigo QR requerido por la DGII en el comprobante impreso
CodSec Codigo de seguridad -- debe aparecer en el comprobante impreso
FechaFirma Fecha y hora de la firma digital del comprobante
Estatus Estado DGII: Aceptado, AceptadoCondicional, Rechazado
Progress Estado del procesamiento: Queued, Sending, Polling, Finished, Error
Encf Numero de comprobante fiscal electronico (eNCF)
Mensaje Mensaje de respuesta de la DGII
Errors Detalle de errores (si los hay)
MontoTotal Monto total del comprobante

QR e Impresion

La DGII requiere que todo comprobante impreso incluya un codigo QR. El campo ImpresionUrl contiene la URL que debe codificarse como QR. Adicionalmente, el CodSec (codigo de seguridad) y la FechaFirma deben aparecer impresos en el comprobante.

$result = $service->sendEcf($ecf);

$urlQr = $result->getImpresionUrl();         // codificar como QR
$codigoSeguridad = $result->getCodSec();     // imprimir en el comprobante
$fechaFirma = $result->getFechaFirma();      // fecha de firma digital

Tipos de Comprobantes (ECF)

Cada tipo de ECF tiene su propio conjunto de clases. Usa las clases que correspondan a tu tipo de documento:

Tipo Prefijo eNCF Descripcion Endpoint
31 Ecf31* E31 Factura de Credito Fiscal recepcionEcf31()
32 Ecf32* E32 Factura de Consumo recepcionEcf32()
33 Ecf33* E33 Nota de Debito recepcionEcf33()
34 Ecf34* E34 Nota de Credito recepcionEcf34()
41 Ecf41* E41 Compras recepcionEcf41()
43 Ecf43* E43 Gastos Menores recepcionEcf43()
44 Ecf44* E44 Regimenes Especiales recepcionEcf44()
45 Ecf45* E45 Gubernamental recepcionEcf45()
46 Ecf46* E46 Exportaciones recepcionEcf46()
47 Ecf47* E47 Pagos al Exterior recepcionEcf47()

Por ejemplo, para enviar una Factura de Credito Fiscal usa Ecf31ECF, Ecf31Encabezado, Ecf31Item, etc. y llama $ecfApi->recepcionEcf31($ecf).

Funcionalidades del API

Ademas de enviar comprobantes, el SDK expone todos los endpoints del API:

Clase Descripcion
EcfService Envio de ECF con auto-routing y polling
EcfApi Envio de ECF (tipos 31-47), consultas, busquedas, anulaciones
CompanyApi CRUD de empresas y gestion de certificados
DgiiApi Consultas DGII (directorio, estado, timbre, track IDs, etc.)
RecepcionApi Seguimiento de solicitudes de recepcion
ApiKeyApi Gestion de API keys

Funcionalidades adicionales

Funcionalidad Descripcion
Empresas Crear, consultar y eliminar empresas registradas
Certificados Subir y consultar certificados digitales
Consulta de e-CF Buscar comprobantes por RNC, eNCF, fecha, monto, etc.
Aprobacion Comercial Enviar aprobacion/rechazo comercial (ACECF)
Anulacion de Rangos Solicitar anulacion de secuencias de eNCF
Consultas DGII Directorio, estado, resultado, timbre, RFCE, track IDs
Estatus de Servicios Verificar disponibilidad de servicios DGII
API Keys Crear API keys para acceso programatico

Uso Directo de los Clientes API

Para control total, usa las clases API generadas directamente:

use GuzzleHttp\Client;
use Ecfx\EcfDgii\Configuration;
use Ecfx\EcfDgii\Api\CompanyApi;
use Ecfx\EcfDgii\Api\EcfApi;
use Ecfx\EcfDgii\Api\DgiiApi;
use Ecfx\EcfDgii\Api\RecepcionApi;
use Ecfx\EcfDgii\Api\ApiKeyApi;

$config = Configuration::getDefaultConfiguration()
    ->setHost('https://api.prod.ecfx.ssd.com.do')
    ->setAccessToken('your-api-key');

$client = new Client();

// Operaciones de empresas
$companyApi = new CompanyApi($client, $config);
$companies = $companyApi->getCompanies();
$company = $companyApi->getCompanyByRnc('123456789');

// Operaciones de ECF
$ecfApi = new EcfApi($client, $config);
$response = $ecfApi->recepcionEcf31($ecf);           // Factura de credito fiscal
$response = $ecfApi->recepcionEcf32($ecf);           // Factura de consumo
$results = $ecfApi->searchEcfs('123456789');           // Buscar ECFs por RNC
$ecfById = $ecfApi->getEcfById('123456789', $msgId);  // Obtener ECF por message ID
$ecfApi->aprobacionComercial('123456789', $encf, $acecfRequest); // Aprobacion comercial

// Consultas DGII
$dgiiApi = new DgiiApi($client, $config);
$directorio = $dgiiApi->consultaDirectorioListado('123456789');
$estado = $dgiiApi->consultaEstado('123456789', $rncEmisor, $ncf, $rncComprador, $codSeg);
$timbre = $dgiiApi->consultaTimbre('123456789', $rncEmisor, $encf, $monto, $codSeg);
$servicios = $dgiiApi->estatusServiciosObtenerEstatus('123456789');

// Seguimiento de recepcion
$recepcionApi = new RecepcionApi($client, $config);
$requests = $recepcionApi->searchEcfReceptionRequests();

Manejo de Errores

Excepcion Cuando
EcfProcessingException La DGII rechaza el ECF durante el procesamiento
EcfPollingTimeoutException El polling excede el maximo de intentos sin resultado final
ApiException Errores HTTP/red al comunicarse con el API
use Ecfx\EcfDgii\ApiException;
use Ecfx\EcfDgii\EcfProcessingException;
use Ecfx\EcfDgii\EcfPollingTimeoutException;

try {
    $result = $service->sendEcf($ecf);
} catch (EcfProcessingException $e) {
    // ECF rechazado por la DGII
    $response = $e->getEcfResponse();
    if ($response) {
        echo "Errores: " . $response->getErrors() . "\n";
    }
} catch (EcfPollingTimeoutException $e) {
    // El polling no obtuvo resultado a tiempo
    echo "Timeout: " . $e->getMessage() . "\n";
} catch (ApiException $e) {
    // Error HTTP (4xx, 5xx, red)
    echo "HTTP Error: " . $e->getCode() . "\n";
    echo "Body: " . $e->getResponseBody() . "\n";
}

Variables de Entorno

Variable Descripcion
ECF_DGII_TOKEN API key para autenticacion (desde ecf.ssd.com.do Settings > API Key)

Ejemplos

Regenerar desde OpenAPI Spec

openapi-generator generate \
  -i path/to/openapi/v1.json \
  -g php \
  -c openapi-generator-config.json \
  -o . \
  --skip-validate-spec

Contribuir

  1. Fork el repositorio
  2. Crea tu feature branch (git checkout -b feature/mi-feature)
  3. Haz commit de tus cambios (git commit -m 'Agregar mi feature')
  4. Push al branch (git push origin feature/mi-feature)
  5. Abre un Pull Request

Los tests corren automaticamente via GitHub Actions en cada push y PR.

Documentacion del API

La documentacion completa del API de ECF SSD esta disponible en:

https://ecf.ssd.com.do/documentacion/api-ecf-ssd

Incluye referencia de todos los endpoints, schemas, codigos de error y ejemplos de request/response.

Arquitectura Backend / Frontend

sequenceDiagram
    participant C as Cliente (Browser/App)
    participant BE as Backend
    participant ECF as ECF API

    C->>BE: POST /invoice (datos de factura)
    Note over BE: Valida, guarda y convierte a formato ECF

    BE->>ECF: POST /ecf/{tipo} (enviar ECF)
    ECF-->>BE: { messageId }
    BE-->>C: { messageId }

    Note over C: No espera — puede continuar

    alt Token en cache
        C->>C: Usar token existente
    else Sin token o expirado
        C->>BE: GET /ecf-token
        BE->>ECF: POST /apikey (solo lectura, scoped a RNC)
        ECF-->>BE: { apiKey }
        BE-->>C: { apiKey }
        C->>C: Almacenar token en cache
    end

    loop Polling hasta completar
        C->>ECF: GET /ecf/{rnc}/{encf} (token solo lectura)
        ECF-->>C: { progress, codSec, ... }
    end
Loading

Flujo detallado

  1. El cliente (browser/app) envía los datos de la factura al backend (POST /invoice, /order, /sale)
  2. El backend valida, guarda y convierte la factura interna al formato ECF
  3. El backend envía el ECF a la API de ECF SSD (POST /ecf/{tipo}) y recibe un messageId
  4. El backend retorna el messageId al cliente — el cliente no espera, puede continuar
  5. Cuando el cliente necesita consultar el estado del ECF, usa EcfFrontendClient que internamente:
    • Verifica si hay un token de solo lectura en cache
    • Si no existe o expiró: llama a getToken() (que el consumidor provee — típicamente un fetch('/ecf-token') a su backend), luego llama a cacheToken(token) para almacenarlo
    • Si la API retorna 401: automáticamente llama a getToken() de nuevo, actualiza el cache, y reintenta
  6. El cliente hace polling directamente contra la API de ECF SSD (GET /ecf/{rnc}/{encf}) hasta que progress sea Finished

Ejemplo: Backend (PHP)

use GuzzleHttp\Client;
use Ecfx\EcfDgii\Configuration;
use Ecfx\EcfDgii\Api\EcfApi;
use Ecfx\EcfDgii\Api\ApiKeyApi;
use Ecfx\EcfDgii\EcfService;

$config = Configuration::getDefaultConfiguration()
    ->setHost('https://api.prod.ecfx.ssd.com.do')
    ->setAccessToken(getenv('ECF_DGII_TOKEN'));

$client = new Client();
$ecfApi = new EcfApi($client, $config);
$service = new EcfService($ecfApi);

// Endpoint de facturacion — tu logica de negocio + envio a ECF SSD
// POST /api/v1/invoices
$invoice = validateAndSave($request);
$ecf = convertToEcf($invoice);
$result = $service->sendEcf($ecf);
// Retorna el messageId al cliente para que haga polling desde el frontend
return json_encode(['messageId' => $result->getMessageId(), 'encf' => $result->getEncf()]);

// Generar token de solo lectura para el cliente
// GET /api/v1/ecf-token
$apiKeyApi = new ApiKeyApi($client, $config);
$apiKey = $apiKeyApi->createApiKey($rnc);
return json_encode(['apiKey' => $apiKey->getToken()]);

Ejemplo: Frontend (TypeScript con EcfFrontendClient)

El cliente envía la factura al backend PHP, recibe el messageId y encf, y luego usa EcfFrontendClient para consultar el estado directamente contra la API de ECF SSD:

import { createFrontendClient } from '@ssddo/ecf-sdk';

const frontend = createFrontendClient({
  getToken: async () => {
    const res = await fetch('/api/v1/ecf-token');
    const { apiKey } = await res.json();
    return apiKey;
  },
  environment: 'prod',
  // cacheToken y getCachedToken usan localStorage por defecto
});

// 1. Enviar factura al backend PHP
const invoiceRes = await fetch('/api/v1/invoices', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify(invoiceData),
});
const { messageId, encf } = await invoiceRes.json();

// 2. Consultar estado del ECF directamente contra ECF SSD (solo lectura)
const { data: ecf } = await frontend.queryEcf('131880681', encf);
console.log(ecf.progress);    // 'Finished'
console.log(ecf.codSec);      // Codigo de seguridad para imprimir
console.log(ecf.impresionUrl); // URL para generar QR

// 3. Buscar ECFs por RNC
const { data: ecfs } = await frontend.searchEcfs('131880681');

Plugin WooCommerce

Si usas WooCommerce, tenemos un plugin listo para facturacion electronica sin escribir codigo:

ECF SSD para WooCommerce

Soporte

Otros SDKs y Plugins

Este SDK es parte de una coleccion de SDKs oficiales para multiples plataformas:

Plataforma Paquete Instalacion
.NET NuGet dotnet add package SSDDO.ECF_DGII.SDK
TypeScript npm npm install ecf-dgii-client
React npm npm install ecf-dgii-react
Python PyPI pip install ecf-dgii-client
PHP Packagist composer require ecfx/ecf-dgii-php
Java Maven Central Ver java/README.md
Kotlin Maven Central Ver kotlin/README.md
iOS/Swift Swift Package Manager Ver ios/README.md
C++ vcpkg / Conan Ver C++/README.md
WooCommerce GitHub Plugin WordPress

Licencia

MIT

Hecho con platano power por SSD Smart Software Development SRL

ecfx/ecf-dgii-php 适用场景与选型建议

ecfx/ecf-dgii-php 是一款 基于 PHP 开发的 Composer 扩展包,目前已累计 12 次下载、GitHub Stars 达 0, 最近一次更新时间为 2026 年 03 月 14 日, 在 PHP 生态内属于活跃度较高的组件。

它主要适用于以下技术方向: 「php」 「sdk」 「fiscal」 「dgii」 「ncf」 「ecf」 等业务场景。在实际项目中,围绕这些方向常见需要落地的问题包括:接口对接、性能调优、并发安全、与既有框架(Laravel / ThinkPHP / Yii / Webman 等)的兼容适配,以及生产环境的日志埋点与稳定性保障。

我们在过去多个企业项目中使用过 ecfx/ecf-dgii-php 或与其功能相近的方案,如果你在选型或落地过程中遇到问题,例如 版本兼容、二次改造、私有化封装、与内部系统对接、生产 BUG 排查,欢迎联系我们协助评估。

围绕 ecfx/ecf-dgii-php 我们能提供哪些服务?
定制开发 / 二次开发

基于 ecfx/ecf-dgii-php 在你已有业务上做功能扩展、字段裁剪、UI 适配、与内部账号 / 权限 / 日志系统的深度对接。

BUG 修复 & 性能优化

线上偶发问题、内存泄漏、慢查询、并发异常等排查修复;针对高流量场景做缓存、队列、索引层面的调优。

项目外包 & 长期维护

承接完整的项目从需求 → 设计 → 开发 → 上线 → 长期运维;也可按月提供技术保姆服务。

yvsm@zunyunkeji.com QQ:316430983 微信:yvsm316 西安尊云信息科技 · 专注 PHP / Go / 分布式系统研发

统计信息

  • 总下载量: 12
  • 月度下载量: 0
  • 日度下载量: 0
  • 收藏数: 0
  • 点击次数: 32
  • 依赖项目数: 0
  • 推荐数: 0

GitHub 信息

  • Stars: 0
  • Watchers: 0
  • Forks: 1
  • 开发语言: PHP

其他信息

  • 授权协议: MIT
  • 更新时间: 2026-03-14