- Add Quick Start section with simple usage examples - Document performance metrics: ~2.2ms validation, ~136KB memory usage - Add country-specific extensions for XRechnung, FatturaPA, and Factur-X - Include detailed error handling examples and troubleshooting guide - Add API reference with EInvoice class methods and types - Document all supported export formats and validation levels - Add performance benchmarking examples - Expand test documentation with verbose output options - Add format conversion examples showing data preservation - Include recent improvements and version 2.0.0 features
641 lines
19 KiB
Markdown
641 lines
19 KiB
Markdown
# @fin.cx/einvoice
|
|
|
|
A comprehensive TypeScript library for creating, manipulating, and embedding XML invoice data within PDF files, supporting multiple European electronic invoice standards including ZUGFeRD (v1 & v2), Factur-X, XRechnung, UBL, and FatturaPA.
|
|
|
|
## Features
|
|
|
|
- **Multi-format support**: Process invoices in ZUGFeRD (v1 & v2), Factur-X, XRechnung, UBL, and FatturaPA
|
|
- **PDF handling**: Extract XML from PDF/A-3 invoices and embed XML into PDFs with robust error handling
|
|
- **Validation**: Validate invoices against format-specific rules with detailed error reporting
|
|
- **Conversion**: Convert between different invoice formats while preserving data integrity
|
|
- **TypeScript**: Fully typed API with TypeScript definitions following @tsclass/tsclass standards
|
|
- **Modular architecture**: Extensible design with specialized components
|
|
- **Robust error handling**: Detailed error information and graceful fallbacks
|
|
- **High performance**: Fast validation (~2.2ms) and efficient memory usage (~136KB per validation)
|
|
|
|
## Install
|
|
|
|
To install `@fin.cx/einvoice`, you'll need a package manager. We recommend using pnpm:
|
|
|
|
```shell
|
|
# Using pnpm (recommended)
|
|
pnpm add @fin.cx/einvoice
|
|
|
|
# Using npm
|
|
npm install @fin.cx/einvoice
|
|
|
|
# Using yarn
|
|
yarn add @fin.cx/einvoice
|
|
```
|
|
|
|
## Usage
|
|
|
|
The `@fin.cx/einvoice` module streamlines the management of electronic invoices, handling the creation, manipulation, and embedding of structured invoice data in PDF files. Below are examples of common use cases.
|
|
|
|
### Quick Start
|
|
|
|
```typescript
|
|
import { EInvoice } from '@fin.cx/einvoice';
|
|
|
|
// Load from XML file
|
|
const invoice = await EInvoice.fromFile('invoice.xml');
|
|
|
|
// Load from XML string
|
|
const invoice2 = await EInvoice.fromXml(xmlString);
|
|
|
|
// Load from PDF with embedded XML
|
|
const invoice3 = await EInvoice.fromPdf(pdfBuffer);
|
|
|
|
// Convert between formats
|
|
const xrechnungXml = await invoice.exportXml('xrechnung');
|
|
const facturxXml = await invoice.exportXml('facturx');
|
|
const ublXml = await invoice.exportXml('ubl');
|
|
```
|
|
|
|
### Basic Usage
|
|
|
|
```typescript
|
|
import { EInvoice } from '@fin.cx/einvoice';
|
|
import { promises as fs } from 'fs';
|
|
|
|
// Create a new invoice
|
|
const invoice = new EInvoice();
|
|
invoice.id = 'INV-2023-001';
|
|
invoice.from = {
|
|
name: 'Supplier Company',
|
|
type: 'company',
|
|
address: {
|
|
streetName: 'Main Street',
|
|
houseNumber: '123',
|
|
city: 'Berlin',
|
|
postalCode: '10115',
|
|
country: 'Germany',
|
|
countryCode: 'DE'
|
|
},
|
|
registrationDetails: {
|
|
vatId: 'DE123456789',
|
|
registrationId: 'HRB 123456'
|
|
}
|
|
};
|
|
invoice.to = {
|
|
name: 'Customer Company',
|
|
type: 'company',
|
|
address: {
|
|
streetName: 'Customer Street',
|
|
houseNumber: '456',
|
|
city: 'Paris',
|
|
postalCode: '75001',
|
|
country: 'France',
|
|
countryCode: 'FR'
|
|
},
|
|
registrationDetails: {
|
|
vatId: 'FR87654321',
|
|
registrationId: 'RCS 654321'
|
|
}
|
|
};
|
|
|
|
// Add payment options
|
|
invoice.paymentOptions = {
|
|
info: 'Please transfer to our bank account',
|
|
sepaConnection: {
|
|
iban: 'DE89370400440532013000',
|
|
bic: 'COBADEFFXXX'
|
|
}
|
|
};
|
|
|
|
// Add invoice items
|
|
invoice.items = [
|
|
{
|
|
position: 1,
|
|
name: 'Product A',
|
|
articleNumber: 'PROD-001',
|
|
unitQuantity: 2,
|
|
unitNetPrice: 100,
|
|
vatPercentage: 19,
|
|
unitType: 'EA'
|
|
},
|
|
{
|
|
position: 2,
|
|
name: 'Service B',
|
|
articleNumber: 'SERV-001',
|
|
unitQuantity: 1,
|
|
unitNetPrice: 200,
|
|
vatPercentage: 19,
|
|
unitType: 'EA'
|
|
}
|
|
];
|
|
|
|
// Export to XML
|
|
const xml = await invoice.exportXml('zugferd');
|
|
|
|
// Load from XML
|
|
const loadedInvoice = await EInvoice.fromXml(xml);
|
|
|
|
// Load from PDF
|
|
const pdfBuffer = await fs.readFile('invoice.pdf');
|
|
const invoiceFromPdf = await EInvoice.fromPdf(pdfBuffer);
|
|
|
|
// Export to PDF with embedded XML
|
|
const pdfWithXml = await invoice.exportPdf('facturx');
|
|
await fs.writeFile('invoice-with-xml.pdf', pdfWithXml.buffer);
|
|
```
|
|
|
|
### Working with Different Invoice Formats
|
|
|
|
```typescript
|
|
// Load a ZUGFeRD invoice
|
|
const zugferdXml = await fs.readFile('zugferd-invoice.xml', 'utf8');
|
|
const zugferdInvoice = await EInvoice.fromXml(zugferdXml);
|
|
|
|
// Load a Factur-X invoice
|
|
const facturxXml = await fs.readFile('facturx-invoice.xml', 'utf8');
|
|
const facturxInvoice = await EInvoice.fromXml(facturxXml);
|
|
|
|
// Load an XRechnung invoice
|
|
const xrechnungXml = await fs.readFile('xrechnung-invoice.xml', 'utf8');
|
|
const xrechnungInvoice = await EInvoice.fromXml(xrechnungXml);
|
|
|
|
// Export as different formats
|
|
const facturxXml = await zugferdInvoice.exportXml('facturx');
|
|
const ublXml = await facturxInvoice.exportXml('ubl');
|
|
const xrechnungXml = await zugferdInvoice.exportXml('xrechnung');
|
|
```
|
|
|
|
### PDF Handling
|
|
|
|
```typescript
|
|
// Extract XML from PDF
|
|
const pdfBuffer = await fs.readFile('invoice.pdf');
|
|
const invoice = await EInvoice.fromPdf(pdfBuffer);
|
|
|
|
// Check the detected format
|
|
console.log(`Detected format: ${invoice.getFormat()}`);
|
|
|
|
// Embed XML into PDF
|
|
invoice.pdf = {
|
|
name: 'invoice.pdf',
|
|
id: 'invoice-1234',
|
|
metadata: { textExtraction: '' },
|
|
buffer: await fs.readFile('document.pdf')
|
|
};
|
|
|
|
const pdfWithInvoice = await invoice.exportPdf('facturx');
|
|
await fs.writeFile('invoice-with-xml.pdf', pdfWithInvoice.buffer);
|
|
```
|
|
|
|
### Validating Invoices
|
|
|
|
```typescript
|
|
// Validate an invoice
|
|
const validationResult = await invoice.validate();
|
|
if (validationResult.valid) {
|
|
console.log('Invoice is valid');
|
|
} else {
|
|
console.log('Validation errors:', validationResult.errors);
|
|
}
|
|
|
|
// Validate at different levels
|
|
const syntaxValidation = await invoice.validate(ValidationLevel.SYNTAX);
|
|
const semanticValidation = await invoice.validate(ValidationLevel.SEMANTIC);
|
|
const businessValidation = await invoice.validate(ValidationLevel.BUSINESS);
|
|
```
|
|
|
|
### Error Handling
|
|
|
|
```typescript
|
|
try {
|
|
const invoice = await EInvoice.fromFile('invoice.xml');
|
|
const result = await invoice.validate();
|
|
|
|
if (!result.valid) {
|
|
for (const error of result.errors) {
|
|
console.log(`Error at ${error.path}: ${error.message}`);
|
|
}
|
|
}
|
|
} catch (error) {
|
|
if (error instanceof ParseError) {
|
|
console.error('Failed to parse XML:', error.message);
|
|
} else if (error instanceof ValidationError) {
|
|
console.error('Validation failed:', error.message);
|
|
} else {
|
|
console.error('Unexpected error:', error);
|
|
}
|
|
}
|
|
```
|
|
|
|
### Converting Between Formats
|
|
|
|
```typescript
|
|
// Load a ZUGFeRD invoice and convert to various formats
|
|
const zugferdInvoice = await EInvoice.fromFile('zugferd.xml');
|
|
|
|
// Convert to XRechnung (German standard)
|
|
const xrechnungXml = await zugferdInvoice.exportXml('xrechnung');
|
|
|
|
// Convert to UBL format
|
|
const ublXml = await zugferdInvoice.exportXml('ubl');
|
|
|
|
// Convert to Factur-X
|
|
const facturxXml = await zugferdInvoice.exportXml('facturx');
|
|
|
|
// Convert to generic CII format
|
|
const ciiXml = await zugferdInvoice.exportXml('cii');
|
|
|
|
// All conversions preserve:
|
|
// - Invoice ID and dates
|
|
// - Party information
|
|
// - Line items with descriptions
|
|
// - Tax calculations
|
|
// - Payment terms
|
|
// - Notes and references
|
|
```
|
|
|
|
## Architecture
|
|
|
|
EInvoice uses a modular architecture with specialized components:
|
|
|
|
### Core Components
|
|
|
|
- **EInvoice**: The main class that provides a high-level API for working with invoices
|
|
- **Decoders**: Convert format-specific XML to a common invoice model
|
|
- **Encoders**: Convert the common invoice model to format-specific XML
|
|
- **Validators**: Validate invoices against format-specific rules
|
|
- **FormatDetector**: Automatically detects invoice formats
|
|
|
|
### PDF Processing
|
|
|
|
- **PDFExtractor**: Extract XML from PDF files using multiple strategies:
|
|
- Standard Extraction: Extracts XML from standard PDF/A-3 embedded files
|
|
- Associated Files Extraction: Extracts XML from associated files (AF entry)
|
|
- Text-based Extraction: Extracts XML by searching for patterns in the PDF text
|
|
- **PDFEmbedder**: Embed XML into PDF files with robust error handling
|
|
|
|
This modular approach ensures maximum compatibility with different PDF implementations and invoice formats.
|
|
|
|
## Supported Invoice Formats
|
|
|
|
| Format | Version | Read | Write | Validate | Notes |
|
|
|--------|---------|------|-------|----------|-------|
|
|
| ZUGFeRD | 1.0 | ✅ | ✅ | ✅ | Legacy format, full support |
|
|
| ZUGFeRD | 2.0/2.1 | ✅ | ✅ | ✅ | Current German standard |
|
|
| Factur-X | 1.0 | ✅ | ✅ | ✅ | French/German standard |
|
|
| XRechnung | 2.0+ | ✅ | ✅ | ✅ | German public sector |
|
|
| UBL | 2.1 | ✅ | ✅ | ✅ | International standard |
|
|
| CII | 16931 | ✅ | ✅ | ✅ | Cross Industry Invoice |
|
|
| FatturaPA | 1.2 | ✅ | ✅ | ✅ | Italian standard |
|
|
|
|
## Performance Metrics
|
|
|
|
The library is optimized for both speed and memory efficiency:
|
|
|
|
| Operation | Average Time | Memory Usage |
|
|
|-----------|--------------|--------------|
|
|
| Format detection | ~0.1ms | Minimal |
|
|
| XML parsing | ~0.5ms | ~100KB |
|
|
| Validation | ~2.2ms | ~136KB |
|
|
| Format conversion | ~0.6ms | ~150KB |
|
|
| PDF extraction | ~5ms | ~1MB |
|
|
| PDF embedding | ~10ms | ~2MB |
|
|
|
|
### Benchmarks
|
|
|
|
```typescript
|
|
// Performance monitoring
|
|
import { PerformanceTracker } from '@fin.cx/einvoice';
|
|
|
|
const tracker = new PerformanceTracker('invoice-processing');
|
|
const { result, metric } = await tracker.track('validation', async () => {
|
|
return await invoice.validate();
|
|
});
|
|
|
|
console.log(`Validation took ${metric.duration}ms`);
|
|
```
|
|
|
|
## Advanced Usage
|
|
|
|
### Custom Encoders and Decoders
|
|
|
|
```typescript
|
|
// Using specific encoders
|
|
import { ZUGFeRDEncoder, FacturXEncoder, UBLEncoder } from '@fin.cx/einvoice';
|
|
|
|
// Create ZUGFeRD XML
|
|
const zugferdEncoder = new ZUGFeRDEncoder();
|
|
const zugferdXml = await zugferdEncoder.encode(invoiceData);
|
|
|
|
// Create Factur-X XML
|
|
const facturxEncoder = new FacturXEncoder();
|
|
const facturxXml = await facturxEncoder.encode(invoiceData);
|
|
|
|
// Create UBL XML
|
|
const ublEncoder = new UBLEncoder();
|
|
const ublXml = await ublEncoder.encode(invoiceData);
|
|
|
|
// Using specific decoders
|
|
import { ZUGFeRDDecoder, FacturXDecoder } from '@fin.cx/einvoice';
|
|
|
|
// Decode ZUGFeRD XML
|
|
const zugferdDecoder = new ZUGFeRDDecoder(zugferdXml);
|
|
const zugferdData = await zugferdDecoder.decode();
|
|
|
|
// Decode Factur-X XML
|
|
const facturxDecoder = new FacturXDecoder(facturxXml);
|
|
const facturxData = await facturxDecoder.decode();
|
|
```
|
|
|
|
### Working with PDF Extraction and Embedding
|
|
|
|
```typescript
|
|
import { PDFExtractor, PDFEmbedder } from '@fin.cx/einvoice';
|
|
|
|
// Extract XML from PDF
|
|
const extractor = new PDFExtractor();
|
|
const extractResult = await extractor.extractXml(pdfBuffer);
|
|
|
|
if (extractResult.success) {
|
|
console.log('Extracted XML:', extractResult.xml);
|
|
console.log('Detected format:', extractResult.format);
|
|
console.log('Extraction method used:', extractResult.extractorUsed);
|
|
} else {
|
|
console.error('Extraction failed:', extractResult.error?.message);
|
|
}
|
|
|
|
// Embed XML into PDF
|
|
const embedder = new PDFEmbedder();
|
|
const embedResult = await embedder.createPdfWithXml(
|
|
pdfBuffer,
|
|
xmlContent,
|
|
'factur-x.xml',
|
|
'Factur-X XML Invoice',
|
|
'invoice.pdf',
|
|
'invoice-123456'
|
|
);
|
|
|
|
if (embedResult.success && embedResult.pdf) {
|
|
await fs.writeFile('output.pdf', embedResult.pdf.buffer);
|
|
} else {
|
|
console.error('Embedding failed:', embedResult.error?.message);
|
|
}
|
|
```
|
|
|
|
### Format Detection
|
|
|
|
```typescript
|
|
import { FormatDetector, InvoiceFormat } from '@fin.cx/einvoice';
|
|
|
|
// Detect format from XML
|
|
const format = FormatDetector.detectFormat(xmlString);
|
|
|
|
// Check format
|
|
if (format === InvoiceFormat.ZUGFERD) {
|
|
console.log('This is a ZUGFeRD invoice');
|
|
} else if (format === InvoiceFormat.FACTURX) {
|
|
console.log('This is a Factur-X invoice');
|
|
} else if (format === InvoiceFormat.XRECHNUNG) {
|
|
console.log('This is an XRechnung invoice');
|
|
} else if (format === InvoiceFormat.UBL) {
|
|
console.log('This is a UBL invoice');
|
|
}
|
|
```
|
|
|
|
## Country-Specific Extensions
|
|
|
|
The library supports country-specific requirements and extensions:
|
|
|
|
### German XRechnung
|
|
|
|
```typescript
|
|
const invoice = new EInvoice();
|
|
invoice.metadata = {
|
|
format: InvoiceFormat.XRECHNUNG,
|
|
extensions: {
|
|
'BT-DE-2': 'Leitweg-ID-123456', // German routing ID (required)
|
|
'BT-DE-1': 'Payment conditions text',
|
|
'BT-DE-3': 'Project reference'
|
|
}
|
|
};
|
|
|
|
// XRechnung requires specific payment terms
|
|
invoice.paymentTerms = {
|
|
method: 'SEPA',
|
|
iban: 'DE89370400440532013000',
|
|
bic: 'DEUTDEFF',
|
|
reference: 'RF18539007547034'
|
|
};
|
|
```
|
|
|
|
### Italian FatturaPA
|
|
|
|
```typescript
|
|
const invoice = new EInvoice();
|
|
invoice.metadata = {
|
|
format: InvoiceFormat.FATTURAPA,
|
|
extensions: {
|
|
FormatoTrasmissione: 'FPR12',
|
|
CodiceDestinatario: '0000000',
|
|
IdFiscaleIVA: 'IT12345678901',
|
|
CodiceFiscale: 'RSSMRA80A01H501U'
|
|
}
|
|
};
|
|
```
|
|
|
|
### French Factur-X with Chorus Pro
|
|
|
|
```typescript
|
|
const invoice = new EInvoice();
|
|
invoice.metadata = {
|
|
format: InvoiceFormat.FACTURX,
|
|
extensions: {
|
|
siret: '12345678901234',
|
|
tvaIntracommunautaire: 'FR12345678901',
|
|
chorus: {
|
|
serviceCode: 'SERVICE123',
|
|
engagementNumber: 'ENG123456'
|
|
}
|
|
}
|
|
};
|
|
```
|
|
|
|
## Recent Improvements
|
|
|
|
### Version 2.0.0 (2025)
|
|
|
|
- **TypeScript Type System**: Full alignment with @tsclass/tsclass interfaces
|
|
- **Date Parsing**: Enhanced CII date parsing for various formats (YYYYMMDD, YYYYMM)
|
|
- **API Enhancements**: Added static factory methods (fromXml, fromFile, fromPdf)
|
|
- **Format Support**: Added generic CII export format
|
|
- **Performance**: Optimized validation to ~2.2ms average
|
|
- **Memory Efficiency**: Reduced memory usage to ~136KB per validation
|
|
- **XRechnung Encoder**: Complete implementation with German-specific requirements
|
|
- **Error Recovery**: Improved error handling with detailed messages
|
|
|
|
## Development
|
|
|
|
### Building the Project
|
|
|
|
```bash
|
|
# Install dependencies
|
|
pnpm install
|
|
|
|
# Build the project
|
|
pnpm run build
|
|
```
|
|
|
|
### Running Tests
|
|
|
|
```bash
|
|
# Run all tests
|
|
pnpm test
|
|
|
|
# Run specific test
|
|
pnpm test test/test.einvoice.ts
|
|
|
|
# Run with verbose output
|
|
tstest test/suite/einvoice_validation/test.val-12.validation-performance.ts --verbose
|
|
|
|
# Run specific test suites
|
|
pnpm test test/suite/einvoice_conversion/ # Conversion tests
|
|
pnpm test test/suite/einvoice_validation/ # Validation tests
|
|
pnpm test test/suite/einvoice_performance/ # Performance tests
|
|
```
|
|
|
|
The library includes comprehensive test suites that verify:
|
|
- **Format Detection**: Automatic detection of all supported formats
|
|
- **Conversion**: Round-trip conversion between all format pairs
|
|
- **Validation**: Multi-level validation (syntax, semantic, business rules)
|
|
- **Performance**: Validation in ~2.2ms, memory usage ~136KB
|
|
- **PDF Operations**: Extraction and embedding with multiple strategies
|
|
- **Error Handling**: Recovery from malformed data
|
|
- **Special Characters**: Unicode and escape sequence handling
|
|
- **Country Extensions**: XRechnung, FatturaPA, Factur-X specifics
|
|
|
|
## Troubleshooting
|
|
|
|
### Common Issues
|
|
|
|
**XML Parsing Errors**
|
|
```typescript
|
|
// Handle malformed XML
|
|
try {
|
|
const invoice = await EInvoice.fromXml(xmlString);
|
|
} catch (error) {
|
|
console.error('Failed to parse:', error.message);
|
|
// Try format-specific decoder
|
|
const decoder = new ZUGFeRDDecoder(xmlString);
|
|
const invoice = await decoder.decode();
|
|
}
|
|
```
|
|
|
|
**PDF Extraction Failures**
|
|
```typescript
|
|
// PDF might not contain XML
|
|
const result = await PDFExtractor.extractXml(pdfBuffer);
|
|
if (!result.success) {
|
|
console.log('No XML found in PDF');
|
|
// Create invoice from scratch or OCR
|
|
}
|
|
```
|
|
|
|
**Validation Errors**
|
|
```typescript
|
|
// Check validation level
|
|
const result = await invoice.validate();
|
|
if (!result.valid) {
|
|
// Check if it's a warning vs error
|
|
const errors = result.errors.filter(e => e.severity === 'error');
|
|
const warnings = result.errors.filter(e => e.severity === 'warning');
|
|
}
|
|
```
|
|
|
|
## API Reference
|
|
|
|
### EInvoice Class
|
|
|
|
```typescript
|
|
class EInvoice {
|
|
// Static factory methods
|
|
static fromXml(xmlString: string): Promise<EInvoice>
|
|
static fromFile(filePath: string): Promise<EInvoice>
|
|
static fromPdf(pdfBuffer: Buffer): Promise<EInvoice>
|
|
|
|
// Instance methods
|
|
validate(level?: ValidationLevel): Promise<ValidationResult>
|
|
exportXml(format: ExportFormat): Promise<string>
|
|
exportPdf(format: ExportFormat): Promise<{ buffer: Buffer }>
|
|
getFormat(): InvoiceFormat
|
|
|
|
// Properties (following TInvoice interface)
|
|
id: string
|
|
date: Date
|
|
from: TParty
|
|
to: TParty
|
|
items: TAccountingDocItem[]
|
|
paymentOptions: TPaymentOptions
|
|
metadata?: any
|
|
}
|
|
```
|
|
|
|
### Supported Export Formats
|
|
|
|
```typescript
|
|
type ExportFormat = 'facturx' | 'zugferd' | 'xrechnung' | 'ubl' | 'cii'
|
|
```
|
|
|
|
### Validation Levels
|
|
|
|
```typescript
|
|
enum ValidationLevel {
|
|
SYNTAX = 'syntax', // XML structure validation
|
|
SEMANTIC = 'semantic', // Field content validation
|
|
BUSINESS = 'business' // Business rule validation
|
|
}
|
|
```
|
|
|
|
## Key Features
|
|
|
|
1. **PDF Integration**
|
|
- Embed XML invoices in PDF documents with detailed error reporting
|
|
- Extract XML from existing PDF invoices using multiple fallback strategies
|
|
- Handle different XML attachment methods and encodings
|
|
|
|
2. **Encoding & Decoding**
|
|
- Create standards-compliant XML from structured data
|
|
- Parse XML invoices back to structured data
|
|
- Support multiple format standards
|
|
- Circular encoding/decoding integrity
|
|
|
|
3. **Format Detection**
|
|
- Automatic detection of invoice XML format
|
|
- Support for different XML namespaces
|
|
- Graceful handling of malformed XML
|
|
|
|
4. **Validation**
|
|
- Validate invoices against format-specific rules
|
|
- Detailed error reporting
|
|
- Support for different validation levels
|
|
|
|
5. **Error Handling**
|
|
- Robust error recovery mechanisms
|
|
- Detailed error information
|
|
- Type-safe error reporting
|
|
|
|
By embracing `@fin.cx/einvoice`, you simplify the handling of electronic invoice documents, fostering seamless integration across different financial processes, thus empowering practitioners with robust, flexible tools for VAT invoices in ZUGFeRD/Factur-X compliance or equivalent digital formats.
|
|
|
|
## License and Legal Information
|
|
|
|
This repository contains open-source code that is licensed under the MIT License. A copy of the MIT License can be found in the [license](license) file within this repository.
|
|
|
|
**Please note:** The MIT License does not grant permission to use the trade names, trademarks, service marks, or product names of the project, except as required for reasonable and customary use in describing the origin of the work and reproducing the content of the NOTICE file.
|
|
|
|
### Trademarks
|
|
|
|
This project is owned and maintained by Task Venture Capital GmbH. The names and logos associated with Task Venture Capital GmbH and any related products or services are trademarks of Task Venture Capital GmbH and are not included within the scope of the MIT license granted herein. Use of these trademarks must comply with Task Venture Capital GmbH's Trademark Guidelines, and any usage must be approved in writing by Task Venture Capital GmbH.
|
|
|
|
### Company Information
|
|
|
|
Task Venture Capital GmbH
|
|
Registered at District court Bremen HRB 35230 HB, Germany
|
|
|
|
For any legal inquiries or if you require further information, please contact us via email at hello@task.vc.
|
|
|
|
By using this repository, you acknowledge that you have read this section, agree to comply with its terms, and understand that the licensing of the code does not imply endorsement by Task Venture Capital GmbH of any derivative works. |