Browse Source

Merge pull request #974 from firefly-iii/develop

🤖 Automatically merge the PR into the main branch.
pull/975/head v1.8.0
github-actions[bot] 2 months ago
committed by GitHub
parent
commit
528044fb0f
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 117
      .ci/php-cs-fixer/composer.lock
  2. 2
      .github/release-notes/develop.md
  3. 4
      app/Console/AutoImports.php
  4. 2
      app/Console/Commands/Import.php
  5. 51
      app/Console/Commands/ValidateJsonFile.php
  6. 66
      app/Console/Commands/ValidateJsonFiles.php
  7. 32
      app/Console/VerifyJSON.php
  8. 22
      app/Events/ImportedTransactions.php
  9. 1
      app/Handlers/Events/ImportedTransactionsEventHandler.php
  10. 16
      app/Http/Controllers/Import/DownloadController.php
  11. 13
      app/Http/Controllers/Import/UploadController.php
  12. 2
      app/Mail/ImportReportMail.php
  13. 73
      app/Services/Nordigen/Model/Transaction.php
  14. 10
      app/Services/Nordigen/Request/GetTransactionsRequest.php
  15. 22
      app/Services/Nordigen/Response/GetTransactionsResponse.php
  16. 16
      app/Services/Shared/Configuration/Configuration.php
  17. 34
      app/Services/Shared/Import/Routine/ApiSubmitter.php
  18. 52
      app/Services/SimpleFIN/SimpleFINService.php
  19. 18
      changelog.md
  20. 6
      composer.json
  21. 739
      composer.lock
  22. 4
      config/importer.php
  23. 439
      package-lock.json
  24. 187
      resources/schemas/v3.json
  25. 10
      resources/views/v2/components/conversion-messages.blade.php
  26. 2
      resources/views/v2/emails/import/report.blade.php

117
.ci/php-cs-fixer/composer.lock

@ -402,16 +402,16 @@
},
{
"name": "friendsofphp/php-cs-fixer",
"version": "v3.86.0",
"version": "v3.87.2",
"source": {
"type": "git",
"url": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer.git",
"reference": "4a952bd19dc97879b0620f495552ef09b55f7d36"
"reference": "da5f0a7858c79b56fc0b8c36d3efcfe5f37f0992"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/4a952bd19dc97879b0620f495552ef09b55f7d36",
"reference": "4a952bd19dc97879b0620f495552ef09b55f7d36",
"url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/da5f0a7858c79b56fc0b8c36d3efcfe5f37f0992",
"reference": "da5f0a7858c79b56fc0b8c36d3efcfe5f37f0992",
"shasum": ""
},
"require": {
@ -422,39 +422,38 @@
"ext-hash": "*",
"ext-json": "*",
"ext-tokenizer": "*",
"fidry/cpu-core-counter": "^1.2",
"fidry/cpu-core-counter": "^1.3",
"php": "^7.4 || ^8.0",
"react/child-process": "^0.6.6",
"react/event-loop": "^1.5",
"react/promise": "^3.2",
"react/promise": "^3.3",
"react/socket": "^1.16",
"react/stream": "^1.4",
"sebastian/diff": "^4.0.6 || ^5.1.1 || ^6.0.2 || ^7.0",
"symfony/console": "^5.4.47 || ^6.4.13 || ^7.0",
"symfony/event-dispatcher": "^5.4.45 || ^6.4.13 || ^7.0",
"symfony/filesystem": "^5.4.45 || ^6.4.13 || ^7.0",
"symfony/finder": "^5.4.45 || ^6.4.17 || ^7.0",
"symfony/options-resolver": "^5.4.45 || ^6.4.16 || ^7.0",
"symfony/polyfill-mbstring": "^1.32",
"symfony/polyfill-php80": "^1.32",
"symfony/polyfill-php81": "^1.32",
"symfony/process": "^5.4.47 || ^6.4.20 || ^7.2",
"symfony/stopwatch": "^5.4.45 || ^6.4.19 || ^7.0"
"symfony/console": "^5.4.47 || ^6.4.24 || ^7.0",
"symfony/event-dispatcher": "^5.4.45 || ^6.4.24 || ^7.0",
"symfony/filesystem": "^5.4.45 || ^6.4.24 || ^7.0",
"symfony/finder": "^5.4.45 || ^6.4.24 || ^7.0",
"symfony/options-resolver": "^5.4.45 || ^6.4.24 || ^7.0",
"symfony/polyfill-mbstring": "^1.33",
"symfony/polyfill-php80": "^1.33",
"symfony/polyfill-php81": "^1.33",
"symfony/process": "^5.4.47 || ^6.4.24 || ^7.2",
"symfony/stopwatch": "^5.4.45 || ^6.4.24 || ^7.0"
},
"require-dev": {
"facile-it/paraunit": "^1.3.1 || ^2.6",
"facile-it/paraunit": "^1.3.1 || ^2.7",
"infection/infection": "^0.29.14",
"justinrainbow/json-schema": "^5.3 || ^6.4",
"justinrainbow/json-schema": "^6.5",
"keradus/cli-executor": "^2.2",
"mikey179/vfsstream": "^1.6.12",
"php-coveralls/php-coveralls": "^2.8",
"php-cs-fixer/accessible-object": "^1.1",
"php-cs-fixer/phpunit-constraint-isidenticalstring": "^1.6",
"php-cs-fixer/phpunit-constraint-xmlmatchesxsd": "^1.6",
"phpunit/phpunit": "^9.6.23 || ^10.5.47 || ^11.5.25",
"symfony/polyfill-php84": "^1.32",
"symfony/var-dumper": "^5.4.48 || ^6.4.23 || ^7.3.1",
"symfony/yaml": "^5.4.45 || ^6.4.23 || ^7.3.1"
"phpunit/phpunit": "^9.6.25 || ^10.5.53 || ^11.5.34",
"symfony/polyfill-php84": "^1.33",
"symfony/var-dumper": "^5.4.48 || ^6.4.24 || ^7.3.2",
"symfony/yaml": "^5.4.45 || ^6.4.24 || ^7.3.2"
},
"suggest": {
"ext-dom": "For handling output formats in XML",
@ -495,7 +494,7 @@
],
"support": {
"issues": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/issues",
"source": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/tree/v3.86.0"
"source": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/tree/v3.87.2"
},
"funding": [
{
@ -503,7 +502,7 @@
"type": "github"
}
],
"time": "2025-08-13T22:36:21+00:00"
"time": "2025-09-10T09:51:40+00:00"
},
{
"name": "psr/container",
@ -1253,16 +1252,16 @@
},
{
"name": "symfony/console",
"version": "v7.3.2",
"version": "v7.3.3",
"source": {
"type": "git",
"url": "https://github.com/symfony/console.git",
"reference": "5f360ebc65c55265a74d23d7fe27f957870158a1"
"reference": "cb0102a1c5ac3807cf3fdf8bea96007df7fdbea7"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/console/zipball/5f360ebc65c55265a74d23d7fe27f957870158a1",
"reference": "5f360ebc65c55265a74d23d7fe27f957870158a1",
"url": "https://api.github.com/repos/symfony/console/zipball/cb0102a1c5ac3807cf3fdf8bea96007df7fdbea7",
"reference": "cb0102a1c5ac3807cf3fdf8bea96007df7fdbea7",
"shasum": ""
},
"require": {
@ -1327,7 +1326,7 @@
"terminal"
],
"support": {
"source": "https://github.com/symfony/console/tree/v7.3.2"
"source": "https://github.com/symfony/console/tree/v7.3.3"
},
"funding": [
{
@ -1347,7 +1346,7 @@
"type": "tidelift"
}
],
"time": "2025-07-30T17:13:41+00:00"
"time": "2025-08-25T06:35:40+00:00"
},
{
"name": "symfony/deprecation-contracts",
@ -1418,16 +1417,16 @@
},
{
"name": "symfony/event-dispatcher",
"version": "v7.3.0",
"version": "v7.3.3",
"source": {
"type": "git",
"url": "https://github.com/symfony/event-dispatcher.git",
"reference": "497f73ac996a598c92409b44ac43b6690c4f666d"
"reference": "b7dc69e71de420ac04bc9ab830cf3ffebba48191"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/497f73ac996a598c92409b44ac43b6690c4f666d",
"reference": "497f73ac996a598c92409b44ac43b6690c4f666d",
"url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/b7dc69e71de420ac04bc9ab830cf3ffebba48191",
"reference": "b7dc69e71de420ac04bc9ab830cf3ffebba48191",
"shasum": ""
},
"require": {
@ -1478,7 +1477,7 @@
"description": "Provides tools that allow your application components to communicate with each other by dispatching events and listening to them",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/event-dispatcher/tree/v7.3.0"
"source": "https://github.com/symfony/event-dispatcher/tree/v7.3.3"
},
"funding": [
{
@ -1489,12 +1488,16 @@
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://github.com/nicolas-grekas",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
"time": "2025-04-22T09:11:45+00:00"
"time": "2025-08-13T11:49:31+00:00"
},
{
"name": "symfony/event-dispatcher-contracts",
@ -1712,16 +1715,16 @@
},
{
"name": "symfony/options-resolver",
"version": "v7.3.2",
"version": "v7.3.3",
"source": {
"type": "git",
"url": "https://github.com/symfony/options-resolver.git",
"reference": "119bcf13e67dbd188e5dbc74228b1686f66acd37"
"reference": "0ff2f5c3df08a395232bbc3c2eb7e84912df911d"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/options-resolver/zipball/119bcf13e67dbd188e5dbc74228b1686f66acd37",
"reference": "119bcf13e67dbd188e5dbc74228b1686f66acd37",
"url": "https://api.github.com/repos/symfony/options-resolver/zipball/0ff2f5c3df08a395232bbc3c2eb7e84912df911d",
"reference": "0ff2f5c3df08a395232bbc3c2eb7e84912df911d",
"shasum": ""
},
"require": {
@ -1759,7 +1762,7 @@
"options"
],
"support": {
"source": "https://github.com/symfony/options-resolver/tree/v7.3.2"
"source": "https://github.com/symfony/options-resolver/tree/v7.3.3"
},
"funding": [
{
@ -1779,7 +1782,7 @@
"type": "tidelift"
}
],
"time": "2025-07-15T11:36:08+00:00"
"time": "2025-08-05T10:16:07+00:00"
},
{
"name": "symfony/polyfill-ctype",
@ -2282,16 +2285,16 @@
},
{
"name": "symfony/process",
"version": "v7.3.0",
"version": "v7.3.3",
"source": {
"type": "git",
"url": "https://github.com/symfony/process.git",
"reference": "40c295f2deb408d5e9d2d32b8ba1dd61e36f05af"
"reference": "32241012d521e2e8a9d713adb0812bb773b907f1"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/process/zipball/40c295f2deb408d5e9d2d32b8ba1dd61e36f05af",
"reference": "40c295f2deb408d5e9d2d32b8ba1dd61e36f05af",
"url": "https://api.github.com/repos/symfony/process/zipball/32241012d521e2e8a9d713adb0812bb773b907f1",
"reference": "32241012d521e2e8a9d713adb0812bb773b907f1",
"shasum": ""
},
"require": {
@ -2323,7 +2326,7 @@
"description": "Executes commands in sub-processes",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/process/tree/v7.3.0"
"source": "https://github.com/symfony/process/tree/v7.3.3"
},
"funding": [
{
@ -2334,12 +2337,16 @@
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://github.com/nicolas-grekas",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
"time": "2025-04-17T09:11:12+00:00"
"time": "2025-08-18T09:42:54+00:00"
},
{
"name": "symfony/service-contracts",
@ -2488,16 +2495,16 @@
},
{
"name": "symfony/string",
"version": "v7.3.2",
"version": "v7.3.3",
"source": {
"type": "git",
"url": "https://github.com/symfony/string.git",
"reference": "42f505aff654e62ac7ac2ce21033818297ca89ca"
"reference": "17a426cce5fd1f0901fefa9b2a490d0038fd3c9c"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/string/zipball/42f505aff654e62ac7ac2ce21033818297ca89ca",
"reference": "42f505aff654e62ac7ac2ce21033818297ca89ca",
"url": "https://api.github.com/repos/symfony/string/zipball/17a426cce5fd1f0901fefa9b2a490d0038fd3c9c",
"reference": "17a426cce5fd1f0901fefa9b2a490d0038fd3c9c",
"shasum": ""
},
"require": {
@ -2555,7 +2562,7 @@
"utf8"
],
"support": {
"source": "https://github.com/symfony/string/tree/v7.3.2"
"source": "https://github.com/symfony/string/tree/v7.3.3"
},
"funding": [
{
@ -2575,7 +2582,7 @@
"type": "tidelift"
}
],
"time": "2025-07-10T08:47:49+00:00"
"time": "2025-08-25T06:35:40+00:00"
}
],
"packages-dev": [],

2
.github/release-notes/develop.md

@ -7,7 +7,7 @@ Development releases are created to test new features and fixes before they are
## Changelog
The changelog for this release may not be up-to-date, so it is not included. However, [changelog.md](https://github.com/firefly-iii/firefly-iii/blob/develop/changelog.md) may already contain entries for the future release.
The changelog for this release may not be up-to-date, so it is not included. However, [changelog.md](https://github.com/firefly-iii/data-importer/blob/develop/changelog.md) may already contain entries for the future release.
## Installation and upgrade instructions

4
app/Console/AutoImports.php

@ -255,6 +255,7 @@ trait AutoImports
// report about it anyway:
event(
new ImportedTransactions(
basename($jsonFile),
array_merge($this->conversionMessages, $this->importMessages),
array_merge($this->conversionWarnings, $this->importWarnings),
array_merge($this->conversionErrors, $this->importErrors),
@ -276,7 +277,7 @@ trait AutoImports
$messages = array_merge($this->importMessages, $this->conversionMessages);
$warnings = array_merge($this->importWarnings, $this->conversionWarnings);
$errors = array_merge($this->importErrors, $this->conversionErrors);
event(new ImportedTransactions($messages, $warnings, $errors, $this->conversionRateLimits));
event(new ImportedTransactions(basename($jsonFile), $messages, $warnings, $errors, $this->conversionRateLimits));
if (count($this->importErrors) > 0 || count($this->conversionRateLimits) > 0) {
Log::error(sprintf('Exit code is %s.', ExitCode::GENERAL_ERROR->name));
@ -651,6 +652,7 @@ trait AutoImports
$this->line('Done!');
event(
new ImportedTransactions(
basename($jsonFile),
array_merge($this->conversionMessages, $this->importMessages),
array_merge($this->conversionWarnings, $this->importWarnings),
array_merge($this->conversionErrors, $this->importErrors),

2
app/Console/Commands/Import.php

@ -160,7 +160,7 @@ final class Import extends Command
$warnings = array_merge($this->importWarnings, $this->conversionWarnings);
$errors = array_merge($this->importErrors, $this->conversionErrors);
event(new ImportedTransactions($messages, $warnings, $errors, $this->conversionRateLimits));
event(new ImportedTransactions(basename($config), $messages, $warnings, $errors, $this->conversionRateLimits));
if (0 !== count($this->importErrors)) {
$exitCode = ExitCode::GENERAL_ERROR->value;
Log::error(sprintf('Exit code is %s.', ExitCode::GENERAL_ERROR->name));

51
app/Console/Commands/ValidateJsonFile.php

@ -0,0 +1,51 @@
<?php
declare(strict_types=1);
namespace App\Console\Commands;
use App\Console\VerifyJSON;
use Illuminate\Console\Command;
use Symfony\Component\Console\Command\Command as CommandAlias;
class ValidateJsonFile extends Command
{
use VerifyJSON;
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'import:validate-json {file : The JSON file to validate}';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Checks if a JSON file is valid according to the v3 import configuration file standard.';
/**
* Execute the console command.
*/
public function handle(): int
{
$file = (string)$this->argument('file');
if (!is_file($file) || !is_readable($file)) {
$this->error(sprintf('File %s does not exist or is not readable.', $file));
return CommandAlias::FAILURE;
}
$result = $this->verifyJSON($file);
if (false === $result) {
$this->error('File is not valid JSON.');
return CommandAlias::FAILURE;
}
$this->info('File is valid JSON.');
return CommandAlias::SUCCESS;
}
}

66
app/Console/Commands/ValidateJsonFiles.php

@ -0,0 +1,66 @@
<?php
declare(strict_types=1);
namespace App\Console\Commands;
use App\Console\VerifyJSON;
use Illuminate\Console\Command;
use Symfony\Component\Console\Command\Command as CommandAlias;
use RecursiveDirectoryIterator;
use RecursiveIteratorIterator;
use RecursiveRegexIterator;
use RegexIterator;
class ValidateJsonFiles extends Command
{
use VerifyJSON;
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'import:validate-json-directory {directory : The directory with JSON files to validate}';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Recursively validate all JSON files in a directory. Stops after 100 files.';
/**
* Execute the console command.
*/
public function handle(): int
{
$directory = (string)$this->argument('directory');
if (!is_dir($directory) || !is_readable($directory)) {
$this->error(sprintf('Cannot read directory %s.', $directory));
return CommandAlias::FAILURE;
}
// check each file in the directory and see if it needs action.
// collect recursively:
$it = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($directory, RecursiveDirectoryIterator::SKIP_DOTS));
$Regex = new RegexIterator($it, '/^.+\.json$/i', RecursiveRegexIterator::GET_MATCH);
$fullPaths = [];
foreach ($Regex as $item) {
$path = $item[0];
$fullPaths[] = $path;
}
foreach ($fullPaths as $file) {
$result = $this->verifyJSON($file);
if (false === $result) {
$this->error(sprintf('File "%s" is not valid JSON.', $file));
return CommandAlias::FAILURE;
}
$this->info(sprintf('File "%s" is valid JSON.', $file));
}
return CommandAlias::SUCCESS;
}
}

32
app/Console/VerifyJSON.php

@ -27,22 +27,48 @@ namespace App\Console;
use Illuminate\Support\Facades\Log;
use JsonException;
use Swaggest\JsonSchema\Exception;
use Swaggest\JsonSchema\Schema;
/**
* Trait VerifyJSON
*/
trait VerifyJSON
{
protected string $errorMessage = '';
private function verifyJSON(string $file): bool
{
// basic check on the JSON.
$json = (string) file_get_contents($file);
$json = (string)file_get_contents($file);
try {
json_decode($json, true, 512, JSON_THROW_ON_ERROR);
$config = json_decode($json, null, 512, JSON_THROW_ON_ERROR);
} catch (JsonException $e) {
$message = sprintf('The importer can\'t import: could not decode the JSON in the config file: %s', $e->getMessage());
$message = sprintf('The importer can\'t import: could not decode the JSON in the config file: %s', $e->getMessage());
Log::error($message);
$this->errorMessage = $message;
return false;
}
// validate JSON schema.
$schemaFile = resource_path('schemas/v3.json');
if (!file_exists($schemaFile)) {
$message = sprintf('The schema file "%s" does not exist.', $schemaFile);
Log::error($message);
$this->errorMessage = $message;
return false;
}
$schema = json_decode(file_get_contents($schemaFile));
try {
Schema::import($schema)->in($config);
} catch (Exception|\Exception $e) {
$message = sprintf('Configuration file "%s" does not adhere to the v3 schema: %s', $file, $e->getMessage());
Log::error($message);
$this->errorMessage = $message;
return false;
}

22
app/Events/ImportedTransactions.php

@ -35,22 +35,24 @@ class ImportedTransactions
{
use SerializesModels;
public const int TEST = 3;
public const int TEST = 3;
public array $errors;
public array $messages;
public array $warnings;
public string $configurationFile = '';
public array $errors = [];
public array $messages = [];
public array $warnings = [];
public array $rateLimits;
public function __construct(array $messages, array $warnings, array $errors, array $rateLimits)
public function __construct(string $configurationFile, array $messages, array $warnings, array $errors, array $rateLimits)
{
Log::debug('Created event ImportedTransactions with filtering (2)');
Log::debug(sprintf('Created event ImportedTransactions("%s") with filtering (2)', $configurationFile));
// filter messages:
$this->messages = $this->filterArray('message(s)', $messages);
$this->warnings = $this->filterArray('warning(s)', $warnings);
$this->errors = $this->filterArray('error(s)', $errors);
$this->rateLimits = $this->filterArray('rate limit message(s)', $rateLimits);
$this->messages = $this->filterArray('message(s)', $messages);
$this->warnings = $this->filterArray('warning(s)', $warnings);
$this->errors = $this->filterArray('error(s)', $errors);
$this->rateLimits = $this->filterArray('rate limit message(s)', $rateLimits);
$this->configurationFile = $configurationFile;
}
/**

1
app/Handlers/Events/ImportedTransactionsEventHandler.php

@ -60,6 +60,7 @@ class ImportedTransactionsEventHandler
'warnings' => $event->warnings,
'errors' => $event->errors,
'rate_limits' => $event->rateLimits,
'config_file' => $event->configurationFile,
];
if (count($event->messages) > 0 || count($event->warnings) > 0 || count($event->errors) > 0) {
Log::info(sprintf('[%s] Will send report message.', config('importer.version')));

16
app/Http/Controllers/Import/DownloadController.php

@ -32,6 +32,7 @@ use Illuminate\Contracts\Foundation\Application;
use Illuminate\Contracts\Routing\ResponseFactory;
use Illuminate\Http\Response;
use JsonException;
use stdClass;
/**
* Class DownloadController
@ -48,6 +49,21 @@ class DownloadController extends Controller
// do something
$configuration = $this->restoreConfiguration();
$array = $configuration->toArray();
// make sure that "mapping" is an empty object when downloading.
if (is_array($array['mapping']) && 0 === count($array['mapping'])) {
$array['mapping'] = new stdClass();
}
// same for "accounts"
if (is_array($array['accounts']) && 0 === count($array['accounts'])) {
$array['accounts'] = new stdClass();
}
// same for "accounts"
if (is_array($array['nordigen_requisitions']) && 0 === count($array['nordigen_requisitions'])) {
$array['nordigen_requisitions'] = new stdClass();
}
$result = json_encode($array, JSON_PRETTY_PRINT | JSON_THROW_ON_ERROR);
$response = response($result);
$name = sprintf('import_config_%s.json', Carbon::now()->format('Y-m-d'));

13
app/Http/Controllers/Import/UploadController.php

@ -25,6 +25,7 @@ declare(strict_types=1);
namespace App\Http\Controllers\Import;
use App\Console\VerifyJSON;
use App\Exceptions\ImporterErrorException;
use App\Http\Controllers\Controller;
use App\Http\Middleware\UploadControllerMiddleware;
@ -53,6 +54,7 @@ use Storage;
class UploadController extends Controller
{
use RestoresConfiguration;
use VerifyJSON;
private string $configFileName;
private string $contentType;
@ -247,7 +249,16 @@ class UploadController extends Controller
// upload the file to a temp directory and use it from there.
if (0 === $errorNumber) {
Log::debug('Config file uploaded.');
$this->configFileName = StorageService::storeContent((string)file_get_contents($file->getPathname()));
$path = $file->getPathname();
$validation = $this->verifyJSON($path);
if (false === $validation) {
$errors->add('config_file', $this->errorMessage);
return $errors;
}
$content = (string)file_get_contents($path);
$this->configFileName = StorageService::storeContent($content);
session()->put(Constants::UPLOAD_CONFIG_FILE, $this->configFileName);

2
app/Mail/ImportReportMail.php

@ -44,6 +44,7 @@ class ImportReportMail extends Mailable
public string $url;
public string $version;
public array $warnings;
public string $configFile = '';
public array $rateLimits;
/**
@ -61,6 +62,7 @@ class ImportReportMail extends Mailable
$this->warnings = $log['warnings'] ?? [];
$this->messages = $log['messages'] ?? [];
$this->rateLimits = $log['rate_limits'] ?? [];
$this->configFile = $log['config_file'] ?? '';
}
/**

73
app/Services/Nordigen/Model/Transaction.php

@ -28,10 +28,10 @@ namespace App\Services\Nordigen\Model;
use App\Rules\Iban;
use Carbon\Carbon;
use Carbon\Exceptions\InvalidFormatException;
use Illuminate\Support\Facades\Log;
use Ramsey\Uuid\Uuid;
use DateTimeInterface;
use Illuminate\Support\Facades\Log;
use JsonException;
use Ramsey\Uuid\Uuid;
use Validator;
/**
@ -49,22 +49,22 @@ class Transaction
public string $creditorAccountBban;
public string $creditorAccountCurrency;
public string $creditorAccountIban; // is an array (see https://github.com/firefly-iii/firefly-iii/issues/5286)
public string $creditorAgent;
public string $creditorId;
public string $creditorName;
public string $currencyCode;
public array $currencyExchange;
public string $debtorAccountBban;
public string $debtorAccountCurrency;
public string $debtorAccountIban;
public string $debtorAgent;
public string $debtorName;
public string $endToEndId;
public string $entryReference;
public string $key;
public string $mandateId;
public string $merchantCategoryCode;
public string $proprietaryBank;
public string $creditorAgent;
public string $creditorId;
public string $creditorName;
public string $currencyCode;
public array $currencyExchange;
public string $debtorAccountBban;
public string $debtorAccountCurrency;
public string $debtorAccountIban;
public string $debtorAgent;
public string $debtorName;
public string $endToEndId;
public string $entryReference;
public string $key;
public string $mandateId;
public string $merchantCategoryCode;
public string $proprietaryBank;
// debtorAccount is an array, but is saved as strings
// iban, currency
@ -105,11 +105,7 @@ class Transaction
$object->additionalInformation = trim($array['additionalInformation'] ?? '');
$object->additionalInformationStructured = trim($array['additionalInformationStructured'] ?? '');
$object->bankTransactionCode = trim($array['bankTransactionCode'] ?? '');
$object->bookingDate = array_key_exists('bookingDate', $array) ? Carbon::createFromFormat(
'!Y-m-d',
$array['bookingDate'],
config('app.timezone')
) : null;
$object->bookingDate = array_key_exists('bookingDate', $array) ? Carbon::createFromFormat('!Y-m-d', $array['bookingDate'], config('app.timezone')) : null;
// overrule with "bookingDateTime" if present:
if (array_key_exists('bookingDateTime', $array)) {
@ -140,19 +136,14 @@ class Transaction
$object->transactionId = trim($array['transactionId'] ?? '');
$object->ultimateCreditor = trim($array['ultimateCreditor'] ?? '');
$object->ultimateDebtor = trim($array['ultimateDebtor'] ?? '');
$object->valueDate = array_key_exists('valueDate', $array) ? Carbon::createFromFormat(
'!Y-m-d',
$array['valueDate'],
config('app.timezone')
) : null;
$object->valueDate = array_key_exists('valueDate', $array) ? Carbon::createFromFormat('!Y-m-d', $array['valueDate'], config('app.timezone')) : null;
// undocumented values
$object->endToEndId = trim($array['endToEndId'] ?? ''); // from Rabobank NL
// overrule transaction id when empty using the internal ID:
if ('' === $object->transactionId) {
$object->transactionId = trim($array['internalTransactionId'] ?? '');
}
// 2025-09-07: switch to using internal transaction ID, never "transactionId".
$object->transactionId = trim($array['internalTransactionId'] ?? '');
// models:
if (array_key_exists('balanceAfterTransaction', $array) && is_array($array['balanceAfterTransaction'])) {
@ -167,13 +158,13 @@ class Transaction
}
// add "pending" or "booked" if it exists.
$key = (string) $array['key'];
$key = (string)$array['key'];
if ('' !== $key) {
$object->tags[] = $key;
}
// add merchant category code, if it exists:
$merchantCode = (string) ($array['merchant_category_code'] ?? '');
$merchantCode = (string)($array['merchant_category_code'] ?? '');
if ('' !== $merchantCode) {
$object->tags[] = $merchantCode;
}
@ -191,11 +182,11 @@ class Transaction
$object->currencyCode = trim($array['transactionAmount']['currency'] ?? '');
// other fields:
$object->accountIdentifier = '';
$object->accountIdentifier = $array['account_id'] ?? '';
// generate transactionID if empty:
if ('' === $object->transactionId) {
$hash = hash('sha256', (string) microtime());
$hash = hash('sha256', (string)microtime());
try {
$hash = hash('sha256', json_encode($array, JSON_THROW_ON_ERROR));
@ -273,14 +264,14 @@ class Transaction
// generate transactionID if empty:
if ('' === $object->transactionId) {
$hash = hash('sha256', (string) microtime());
$hash = hash('sha256', (string)microtime());
try {
$hash = hash('sha256', json_encode($array, JSON_THROW_ON_ERROR));
} catch (JsonException $e) {
Log::error(sprintf('Could not parse array into JSON: %s', $e->getMessage()));
}
$object->transactionId = (string) Uuid::uuid5(config('importer.namespace'), $hash);
$object->transactionId = sprintf('ff3-%s', Uuid::uuid5(config('importer.namespace'), $hash));
}
return $object;
@ -351,7 +342,13 @@ class Transaction
public function getTransactionId(): string
{
return substr(trim((string) preg_replace('/\s+/', ' ', $this->transactionId)), 0, 250);
// #10914 add account ID to transaction ID to make it unique.
$accountId = substr(trim((string)preg_replace('/\s+/', ' ', $this->accountIdentifier)), 0, 125);
$transactionId = substr(trim((string)preg_replace('/\s+/', ' ', $this->transactionId)), 0, 125);
Log::debug(sprintf('Returning transaction ID: %s and %s are joined.', $accountId, $transactionId));
return trim(sprintf('%s-%s', $accountId, $transactionId));
}
/**

10
app/Services/Nordigen/Request/GetTransactionsRequest.php

@ -38,8 +38,11 @@ use Illuminate\Support\Facades\Log;
*/
class GetTransactionsRequest extends Request
{
private string $identifier = '';
public function __construct(string $url, string $token, string $identifier)
{
$this->identifier = $identifier;
$this->setParameters([]);
$this->setBase($url);
$this->setToken($token);
@ -75,9 +78,12 @@ class GetTransactionsRequest extends Request
}
}
$total = count($return);
Log::debug(sprintf('Downloaded [%d:%d] transactions', $count, $total));
Log::debug(sprintf('Downloaded [%d:%d] transactions from bank account "%s"', $count, $total, $this->identifier));
$response = new GetTransactionsResponse($return);
$response->setAccountId($this->identifier);
$response->processData();
return new GetTransactionsResponse($return);
return $response;
}
public function post(): Response

22
app/Services/Nordigen/Response/GetTransactionsResponse.php

@ -30,6 +30,7 @@ use App\Services\Shared\Response\Response;
use Countable;
use Illuminate\Support\Collection;
use Iterator;
use Log;
/**
* Class GetTransactionsResponse
@ -38,15 +39,34 @@ class GetTransactionsResponse extends Response implements Iterator, Countable
{
private readonly Collection $collection;
private int $position = 0;
private string $accountId = '';
private array $data;
public function __construct(array $data)
{
$this->collection = new Collection();
$this->data = $data;
Log::debug('Created new GetTransactionsResponse');
}
public function setAccountId(string $accountId): void
{
$this->accountId = $accountId;
Log::debug(sprintf('Set account ID to "%s" in GetTransactionsResponse', $accountId));
}
public function processData(): void
{
Log::debug('Processing data in GetTransactionsResponse');
/** @var array $array */
foreach ($data as $array) {
foreach ($this->data as $array) {
$array['account_id'] = $this->accountId;
$this->collection->push(Transaction::fromArray($array));
}
Log::debug('Done processing data in GetTransactionsResponse');
}
/**

16
app/Services/Shared/Configuration/Configuration.php

@ -142,9 +142,6 @@ class Configuration
$this->nordigenRequisitions = [];
$this->nordigenMaxDays = '90';
// spectre + nordigen configuration
$this->accounts = [];
// spectre
$this->identifier = '0';
$this->connection = '0';
@ -244,6 +241,10 @@ class Configuration
$object->mapAllData = $data['map_all_data'] ?? false;
$object->accounts = $data['accounts'] ?? [];
// simplefin
$object->pendingTransactions = $data['pending_transactions'] ?? true;
$object->ignoreDuplicateTransactions = $data['ignore_duplicate_transactions'] ?? true;
Log::debug(sprintf('Configuration fromClassicFile: ignoreDuplicateTransactions = %s', var_export($object->ignoreDuplicateTransactions, true)));
@ -347,6 +348,8 @@ class Configuration
$object->contentType = $array['content_type'] ?? 'csv';
$object->customTag = $array['custom_tag'] ?? '';
Log::debug(sprintf('Configuration fromArray, default_account=%s', var_export($object->defaultAccount, true)));
// sort
ksort($object->doMapping);
ksort($object->mapping);
@ -379,6 +382,9 @@ class Configuration
$object->nordigenRequisitions = $array['nordigen_requisitions'] ?? [];
$object->nordigenMaxDays = $array['nordigen_max_days'] ?? '90';
// simplefin
$object->pendingTransactions = $array['pending_transactions'] ?? true;
// duplicate transaction detection
$object->duplicateDetectionMethod = $array['duplicate_detection_method'] ?? 'classic';
@ -451,6 +457,8 @@ class Configuration
$object->contentType = $array['content_type'] ?? 'csv';
$object->customTag = $array['custom_tag'] ?? '';
Log::debug(sprintf('Configuration fromRequest, default_account=%s', var_export($object->defaultAccount, true)));
// mapping for spectre + nordigen
$object->mapAllData = $array['map_all_data'] ?? false;
@ -618,6 +626,8 @@ class Configuration
public function getDefaultAccount(): ?int
{
Log::debug(sprintf('Configuration getDefaultAccount return %s', var_export($this->defaultAccount, true)));
return $this->defaultAccount;
}

34
app/Services/Shared/Import/Routine/ApiSubmitter.php

@ -25,12 +25,12 @@ declare(strict_types=1);
namespace App\Services\Shared\Import\Routine;
use Carbon\Carbon;
use App\Exceptions\ImporterErrorException;
use App\Services\Shared\Authentication\SecretManager;
use App\Services\Shared\Configuration\Configuration;
use App\Services\Shared\Import\Status\SubmissionStatusManager;
use App\Services\Shared\Submission\ProgressInformation;
use Carbon\Carbon;
use GrumpyDictator\FFIIIApiSupport\Exceptions\ApiHttpException;
use GrumpyDictator\FFIIIApiSupport\Model\Transaction;
use GrumpyDictator\FFIIIApiSupport\Model\TransactionGroup;
@ -166,9 +166,18 @@ class ApiSubmitter
continue;
}
$searchResult = $this->searchField($field, $value);
if (0 !== $searchResult) {
Log::debug(sprintf('Looks like field "%s" with value "%s" is not unique, found in group #%d. Return false', $field, $value, $searchResult));
$message = sprintf('[a115]: There is already a transaction with %s "%s" (<a href="%s/transactions/show/%d">link</a>).', $field, $value, $this->vanityURL, $searchResult);
if (null !== $searchResult) {
Log::debug(sprintf('Looks like field "%s" with value "%s" is not unique, found in group #%d. Return false', $field, $value, $searchResult['id']));
$message = sprintf(
'[a115]: There is already a transaction with %s "%s" (<a href="%s/transactions/show/%d">%s</a>, %s %s).',
$field,
$value,
$this->vanityURL,
$searchResult['id'],
e($searchResult['description']),
$searchResult['currency_code'],
bcround($searchResult['amount'], $searchResult['decimal_places'])
);
if (false === config('importer.ignore_duplicate_errors')) {
$this->addError($index, $message);
}
@ -184,7 +193,7 @@ class ApiSubmitter
/**
* Do a search at Firefly III and return the ID of the group found.
*/
private function searchField(string $field, string $value): int
private function searchField(string $field, string $value): ?array
{
// search for the exact description and not just a part of it:
$searchModifier = config(sprintf('csv.search_modifier.%s', $field));
@ -205,15 +214,22 @@ class ApiSubmitter
} catch (ApiHttpException $e) {
Log::error(sprintf('[%s]: %s', config('importer.version'), $e->getMessage()));
return 0;
return null;
}
if (0 === $response->count()) {
return 0;
return null;
}
$first = $response->current();
$array = [
'id' => $first->id,
'description' => $first->transactions[0]->description ?? '(no description)',
'currency_code' => $first->transactions[0]->currencyCode ?? '(no currency)',
'decimal_places' => $first->transactions[0]->currencyDecimalPlaces ?? 2,
'amount' => $first->transactions[0]->amount ?? '(unknown)',
];
Log::debug(sprintf('Found %d transaction(s). Return group ID #%d.', $response->count(), $first->id));
return $first->id;
return $array;
}
private function processTransaction(int $index, array $line): array
@ -237,7 +253,7 @@ class ApiSubmitter
$json = json_decode($body, true);
// before we complain, first check what the error is:
if (is_array($json) && array_key_exists('message', $json)) {
if (str_contains((string) $json['message'], '200032')) {
if (str_contains((string)$json['message'], '200032')) {
$isDeleted = true;
}
}

52
app/Services/SimpleFIN/SimpleFINService.php

@ -41,8 +41,8 @@ use Illuminate\Support\Facades\Log;
*/
class SimpleFINService
{
private string $accessToken = '';
private string $setupToken = '';
private string $accessToken = '';
private string $setupToken = '';
private Configuration $configuration;
/**
@ -73,10 +73,13 @@ class SimpleFINService
private function getFetchParams(string $accountId): array
{
$return = [
'pending' => $this->configuration->getPendingTransactions() ? 1 : 0,
// 'pending' => $this->configuration->getPendingTransactions() ? 1 : 0,
'start-date' => 0,
'account' => $accountId,
];
if ($this->configuration->getPendingTransactions()) {
$return['pending'] = 1;
}
$dateAfter = $this->configuration->getDateNotBefore();
$dateBefore = $this->configuration->getDateNotAfter();
@ -194,7 +197,13 @@ class SimpleFINService
return [];
}
/** @var array $transactions */
$transactions = $accounts[0]['transactions'] ?? [];
// add a little filter to remove transactions that are pending.
$transactions = $this->filterForPending($transactions);
Log::debug(sprintf('Found %d transactions.', $transactions));
return $transactions;
@ -214,7 +223,7 @@ class SimpleFINService
}
// Check if decoded string looks like a SimpleFIN claim URL
return (bool) preg_match('/^https?:\/\/.+\/simplefin\/claim\/.+$/', $decoded);
return (bool)preg_match('/^https?:\/\/.+\/simplefin\/claim\/.+$/', $decoded);
}
/**
@ -253,7 +262,7 @@ class SimpleFINService
'headers' => $headers,
]);
$accessUrl = (string) $response->getBody();
$accessUrl = (string)$response->getBody();
if ('' === $accessUrl) {
throw new ImporterErrorException('Empty access URL returned from SimpleFIN claim exchange');
@ -270,7 +279,7 @@ class SimpleFINService
} catch (ClientException $e) {
$statusCode = $e->getResponse()->getStatusCode();
$responseBody = (string) $e->getResponse()->getBody();
$responseBody = (string)$e->getResponse()->getBody();
Log::error(sprintf('SimpleFIN claim URL exchange failed with HTTP %d: %s', $statusCode, $e->getMessage()));
Log::error(sprintf('SimpleFIN 403 response body: %s', $responseBody));
@ -316,7 +325,7 @@ class SimpleFINService
private function getTimeout(): float
{
return (float) config('simplefin.connection_timeout', 30.0);
return (float)config('simplefin.connection_timeout', 30.0);
}
public function getAccessToken(): string
@ -339,4 +348,33 @@ class SimpleFINService
{
$this->accessToken = $accessToken;
}
private function filterForPending(array $transactions): array
{
Log::debug(sprintf('Filter pending transactions. Start with %d item(s)', count($transactions)));
if (0 === count($transactions)) {
Log::debug('Empty array, nothing to filter.');
return [];
}
$return = [];
$removePending = !$this->configuration->getPendingTransactions();
/** @var array $item */
foreach ($transactions as $item) {
$add = true;
// is pending and need to collect pending transactions? add it.
if (array_key_exists('pending', $item) && true === $item['pending'] && $removePending) {
Log::debug('Transaction is pending and removePending is true, skipping.');
$add = false;
}
if (true === $add) {
Log::debug('Transaction is not pending or removePending = false, add it.');
$return[] = $item;
}
}
Log::debug(sprintf('Done filtering pending transaction, return %d item(s)', count($return)));
return $return;
}
}

18
changelog.md

@ -2,6 +2,24 @@
All notable changes to this project will be documented in this file.
This project adheres to [Semantic Versioning](http://semver.org/).
## v1.8.0 - 2025-09-20
> [!WARNING]
> Some changes in this release may unexpectedly lead to duplicate transactions. This is caused by changes in the data handling routines. This is unfortunate, but a result of new insights, changed APIs and other minor fixes. My apologies for any inconvenience. I try to avoid these kinds of changes, but it can't always be helped.
### Added
- [Issue 9045](https://github.com/firefly-iii/firefly-iii/issues/9045) (Data Importer - Add config filename or bank name into end-of-import email) reported by @Terry-JF
- [Issue 10923](https://github.com/firefly-iii/firefly-iii/issues/10923) ([Importer] CSV import broken in cli image (does not adhere to the v3 schema)) reported by @MacPaille
- JSON Schema validation for the configuration file.
### Changed
- [Issue 10863](https://github.com/firefly-iii/firefly-iii/issues/10863) (Data Importer: GoCardless: option to use internalTransactionId instead) reported by @diogotcorreia
- [Issue 10914](https://github.com/firefly-iii/firefly-iii/issues/10914) (GoCardless importer: external_id dedupe should be per account) reported by @Jazzmax
### Fixed
- Fix issue with restoring empty `accounts` array from configuration.
## v1.7.10 - 2025-08-23
### Deprecated

6
composer.json

@ -76,19 +76,21 @@
"ext-bcmath": "*",
"ext-json": "*",
"firefly-iii/api-support-classes": "@dev",
"genkgo/camt": ">=2.10.1",
"guzzlehttp/guzzle": "^7.9",
"laravel/framework": "^11",
"league/csv": "9.*",
"spatie/enum": "^3.10",
"swaggest/json-schema": "^0.12.43",
"symfony/http-client": "^7.3",
"symfony/mailgun-mailer": "^7.3",
"genkgo/camt": ">=2.10.1"
"thecodingmachine/safe": "^3.3"
},
"require-dev": {
"barryvdh/laravel-debugbar": "^3.16",
"barryvdh/laravel-ide-helper": "^3.5",
"driftingly/rector-laravel": "^2.0",
"ergebnis/phpstan-rules": "^2.10",
"ergebnis/phpstan-rules": "^2.12",
"fakerphp/faker": "^1.24",
"filp/whoops": "^2.18",
"larastan/larastan": "^3",

739
composer.lock
File diff suppressed because it is too large
View File

4
config/importer.php

@ -24,8 +24,8 @@
declare(strict_types=1);
return [
'version' => '1.7.10',
'build_time' => 1755971835,
'version' => '1.8.0',
'build_time' => 1758257539,
'flows' => ['nordigen', 'spectre', 'file', 'simplefin'],
'enabled_flows' => [
'nordigen' => true,

439
package-lock.json

@ -12,9 +12,9 @@
}
},
"node_modules/@esbuild/aix-ppc64": {
"version": "0.25.9",
"resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.9.tgz",
"integrity": "sha512-OaGtL73Jck6pBKjNIe24BnFE6agGl+6KxDtTfHhy1HmhthfKouEcOhqpSL64K4/0WCtbKFLOdzD/44cJ4k9opA==",
"version": "0.25.10",
"resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.10.tgz",
"integrity": "sha512-0NFWnA+7l41irNuaSVlLfgNT12caWJVLzp5eAVhZ0z1qpxbockccEt3s+149rE64VUI3Ml2zt8Nv5JVc4QXTsw==",
"cpu": [
"ppc64"
],
@ -29,9 +29,9 @@
}
},
"node_modules/@esbuild/android-arm": {
"version": "0.25.9",
"resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.9.tgz",
"integrity": "sha512-5WNI1DaMtxQ7t7B6xa572XMXpHAaI/9Hnhk8lcxF4zVN4xstUgTlvuGDorBguKEnZO70qwEcLpfifMLoxiPqHQ==",
"version": "0.25.10",
"resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.10.tgz",
"integrity": "sha512-dQAxF1dW1C3zpeCDc5KqIYuZ1tgAdRXNoZP7vkBIRtKZPYe2xVr/d3SkirklCHudW1B45tGiUlz2pUWDfbDD4w==",
"cpu": [
"arm"
],
@ -46,9 +46,9 @@
}
},
"node_modules/@esbuild/android-arm64": {
"version": "0.25.9",
"resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.9.tgz",
"integrity": "sha512-IDrddSmpSv51ftWslJMvl3Q2ZT98fUSL2/rlUXuVqRXHCs5EUF1/f+jbjF5+NG9UffUDMCiTyh8iec7u8RlTLg==",
"version": "0.25.10",
"resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.10.tgz",
"integrity": "sha512-LSQa7eDahypv/VO6WKohZGPSJDq5OVOo3UoFR1E4t4Gj1W7zEQMUhI+lo81H+DtB+kP+tDgBp+M4oNCwp6kffg==",
"cpu": [
"arm64"
],
@ -63,9 +63,9 @@
}
},
"node_modules/@esbuild/android-x64": {
"version": "0.25.9",
"resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.9.tgz",
"integrity": "sha512-I853iMZ1hWZdNllhVZKm34f4wErd4lMyeV7BLzEExGEIZYsOzqDWDf+y082izYUE8gtJnYHdeDpN/6tUdwvfiw==",
"version": "0.25.10",
"resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.10.tgz",
"integrity": "sha512-MiC9CWdPrfhibcXwr39p9ha1x0lZJ9KaVfvzA0Wxwz9ETX4v5CHfF09bx935nHlhi+MxhA63dKRRQLiVgSUtEg==",
"cpu": [
"x64"
],
@ -80,9 +80,9 @@
}
},
"node_modules/@esbuild/darwin-arm64": {
"version": "0.25.9",
"resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.9.tgz",
"integrity": "sha512-XIpIDMAjOELi/9PB30vEbVMs3GV1v2zkkPnuyRRURbhqjyzIINwj+nbQATh4H9GxUgH1kFsEyQMxwiLFKUS6Rg==",
"version": "0.25.10",
"resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.10.tgz",
"integrity": "sha512-JC74bdXcQEpW9KkV326WpZZjLguSZ3DfS8wrrvPMHgQOIEIG/sPXEN/V8IssoJhbefLRcRqw6RQH2NnpdprtMA==",
"cpu": [
"arm64"
],
@ -97,9 +97,9 @@
}
},
"node_modules/@esbuild/darwin-x64": {
"version": "0.25.9",
"resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.9.tgz",
"integrity": "sha512-jhHfBzjYTA1IQu8VyrjCX4ApJDnH+ez+IYVEoJHeqJm9VhG9Dh2BYaJritkYK3vMaXrf7Ogr/0MQ8/MeIefsPQ==",
"version": "0.25.10",
"resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.10.tgz",
"integrity": "sha512-tguWg1olF6DGqzws97pKZ8G2L7Ig1vjDmGTwcTuYHbuU6TTjJe5FXbgs5C1BBzHbJ2bo1m3WkQDbWO2PvamRcg==",
"cpu": [
"x64"
],
@ -114,9 +114,9 @@
}
},
"node_modules/@esbuild/freebsd-arm64": {
"version": "0.25.9",
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.9.tgz",
"integrity": "sha512-z93DmbnY6fX9+KdD4Ue/H6sYs+bhFQJNCPZsi4XWJoYblUqT06MQUdBCpcSfuiN72AbqeBFu5LVQTjfXDE2A6Q==",
"version": "0.25.10",
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.10.tgz",
"integrity": "sha512-3ZioSQSg1HT2N05YxeJWYR+Libe3bREVSdWhEEgExWaDtyFbbXWb49QgPvFH8u03vUPX10JhJPcz7s9t9+boWg==",
"cpu": [
"arm64"
],
@ -131,9 +131,9 @@
}
},
"node_modules/@esbuild/freebsd-x64": {
"version": "0.25.9",
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.9.tgz",
"integrity": "sha512-mrKX6H/vOyo5v71YfXWJxLVxgy1kyt1MQaD8wZJgJfG4gq4DpQGpgTB74e5yBeQdyMTbgxp0YtNj7NuHN0PoZg==",
"version": "0.25.10",
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.10.tgz",
"integrity": "sha512-LLgJfHJk014Aa4anGDbh8bmI5Lk+QidDmGzuC2D+vP7mv/GeSN+H39zOf7pN5N8p059FcOfs2bVlrRr4SK9WxA==",
"cpu": [
"x64"
],
@ -148,9 +148,9 @@
}
},
"node_modules/@esbuild/linux-arm": {
"version": "0.25.9",
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.9.tgz",
"integrity": "sha512-HBU2Xv78SMgaydBmdor38lg8YDnFKSARg1Q6AT0/y2ezUAKiZvc211RDFHlEZRFNRVhcMamiToo7bDx3VEOYQw==",
"version": "0.25.10",
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.10.tgz",
"integrity": "sha512-oR31GtBTFYCqEBALI9r6WxoU/ZofZl962pouZRTEYECvNF/dtXKku8YXcJkhgK/beU+zedXfIzHijSRapJY3vg==",
"cpu": [
"arm"
],
@ -165,9 +165,9 @@
}
},
"node_modules/@esbuild/linux-arm64": {
"version": "0.25.9",
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.9.tgz",
"integrity": "sha512-BlB7bIcLT3G26urh5Dmse7fiLmLXnRlopw4s8DalgZ8ef79Jj4aUcYbk90g8iCa2467HX8SAIidbL7gsqXHdRw==",
"version": "0.25.10",
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.10.tgz",
"integrity": "sha512-5luJWN6YKBsawd5f9i4+c+geYiVEw20FVW5x0v1kEMWNq8UctFjDiMATBxLvmmHA4bf7F6hTRaJgtghFr9iziQ==",
"cpu": [
"arm64"
],
@ -182,9 +182,9 @@
}
},
"node_modules/@esbuild/linux-ia32": {
"version": "0.25.9",
"resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.9.tgz",
"integrity": "sha512-e7S3MOJPZGp2QW6AK6+Ly81rC7oOSerQ+P8L0ta4FhVi+/j/v2yZzx5CqqDaWjtPFfYz21Vi1S0auHrap3Ma3A==",
"version": "0.25.10",
"resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.10.tgz",
"integrity": "sha512-NrSCx2Kim3EnnWgS4Txn0QGt0Xipoumb6z6sUtl5bOEZIVKhzfyp/Lyw4C1DIYvzeW/5mWYPBFJU3a/8Yr75DQ==",
"cpu": [
"ia32"
],
@ -199,9 +199,9 @@
}
},
"node_modules/@esbuild/linux-loong64": {
"version": "0.25.9",
"resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.9.tgz",
"integrity": "sha512-Sbe10Bnn0oUAB2AalYztvGcK+o6YFFA/9829PhOCUS9vkJElXGdphz0A3DbMdP8gmKkqPmPcMJmJOrI3VYB1JQ==",
"version": "0.25.10",
"resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.10.tgz",
"integrity": "sha512-xoSphrd4AZda8+rUDDfD9J6FUMjrkTz8itpTITM4/xgerAZZcFW7Dv+sun7333IfKxGG8gAq+3NbfEMJfiY+Eg==",
"cpu": [
"loong64"
],
@ -216,9 +216,9 @@
}
},
"node_modules/@esbuild/linux-mips64el": {
"version": "0.25.9",
"resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.9.tgz",
"integrity": "sha512-YcM5br0mVyZw2jcQeLIkhWtKPeVfAerES5PvOzaDxVtIyZ2NUBZKNLjC5z3/fUlDgT6w89VsxP2qzNipOaaDyA==",
"version": "0.25.10",
"resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.10.tgz",
"integrity": "sha512-ab6eiuCwoMmYDyTnyptoKkVS3k8fy/1Uvq7Dj5czXI6DF2GqD2ToInBI0SHOp5/X1BdZ26RKc5+qjQNGRBelRA==",
"cpu": [
"mips64el"
],
@ -233,9 +233,9 @@
}
},
"node_modules/@esbuild/linux-ppc64": {
"version": "0.25.9",
"resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.9.tgz",
"integrity": "sha512-++0HQvasdo20JytyDpFvQtNrEsAgNG2CY1CLMwGXfFTKGBGQT3bOeLSYE2l1fYdvML5KUuwn9Z8L1EWe2tzs1w==",
"version": "0.25.10",
"resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.10.tgz",
"integrity": "sha512-NLinzzOgZQsGpsTkEbdJTCanwA5/wozN9dSgEl12haXJBzMTpssebuXR42bthOF3z7zXFWH1AmvWunUCkBE4EA==",
"cpu": [
"ppc64"
],
@ -250,9 +250,9 @@
}
},
"node_modules/@esbuild/linux-riscv64": {
"version": "0.25.9",
"resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.9.tgz",
"integrity": "sha512-uNIBa279Y3fkjV+2cUjx36xkx7eSjb8IvnL01eXUKXez/CBHNRw5ekCGMPM0BcmqBxBcdgUWuUXmVWwm4CH9kg==",
"version": "0.25.10",
"resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.10.tgz",
"integrity": "sha512-FE557XdZDrtX8NMIeA8LBJX3dC2M8VGXwfrQWU7LB5SLOajfJIxmSdyL/gU1m64Zs9CBKvm4UAuBp5aJ8OgnrA==",
"cpu": [
"riscv64"
],
@ -267,9 +267,9 @@
}
},
"node_modules/@esbuild/linux-s390x": {
"version": "0.25.9",
"resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.9.tgz",
"integrity": "sha512-Mfiphvp3MjC/lctb+7D287Xw1DGzqJPb/J2aHHcHxflUo+8tmN/6d4k6I2yFR7BVo5/g7x2Monq4+Yew0EHRIA==",
"version": "0.25.10",
"resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.10.tgz",
"integrity": "sha512-3BBSbgzuB9ajLoVZk0mGu+EHlBwkusRmeNYdqmznmMc9zGASFjSsxgkNsqmXugpPk00gJ0JNKh/97nxmjctdew==",
"cpu": [
"s390x"
],
@ -284,9 +284,9 @@
}
},
"node_modules/@esbuild/linux-x64": {
"version": "0.25.9",
"resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.9.tgz",
"integrity": "sha512-iSwByxzRe48YVkmpbgoxVzn76BXjlYFXC7NvLYq+b+kDjyyk30J0JY47DIn8z1MO3K0oSl9fZoRmZPQI4Hklzg==",
"version": "0.25.10",
"resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.10.tgz",
"integrity": "sha512-QSX81KhFoZGwenVyPoberggdW1nrQZSvfVDAIUXr3WqLRZGZqWk/P4T8p2SP+de2Sr5HPcvjhcJzEiulKgnxtA==",
"cpu": [
"x64"
],
@ -301,9 +301,9 @@
}
},
"node_modules/@esbuild/netbsd-arm64": {
"version": "0.25.9",
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.9.tgz",
"integrity": "sha512-9jNJl6FqaUG+COdQMjSCGW4QiMHH88xWbvZ+kRVblZsWrkXlABuGdFJ1E9L7HK+T0Yqd4akKNa/lO0+jDxQD4Q==",
"version": "0.25.10",
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.10.tgz",
"integrity": "sha512-AKQM3gfYfSW8XRk8DdMCzaLUFB15dTrZfnX8WXQoOUpUBQ+NaAFCP1kPS/ykbbGYz7rxn0WS48/81l9hFl3u4A==",
"cpu": [
"arm64"
],
@ -318,9 +318,9 @@
}
},
"node_modules/@esbuild/netbsd-x64": {
"version": "0.25.9",
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.9.tgz",
"integrity": "sha512-RLLdkflmqRG8KanPGOU7Rpg829ZHu8nFy5Pqdi9U01VYtG9Y0zOG6Vr2z4/S+/3zIyOxiK6cCeYNWOFR9QP87g==",
"version": "0.25.10",
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.10.tgz",
"integrity": "sha512-7RTytDPGU6fek/hWuN9qQpeGPBZFfB4zZgcz2VK2Z5VpdUxEI8JKYsg3JfO0n/Z1E/6l05n0unDCNc4HnhQGig==",
"cpu": [
"x64"
],
@ -335,9 +335,9 @@
}
},
"node_modules/@esbuild/openbsd-arm64": {
"version": "0.25.9",
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.9.tgz",
"integrity": "sha512-YaFBlPGeDasft5IIM+CQAhJAqS3St3nJzDEgsgFixcfZeyGPCd6eJBWzke5piZuZ7CtL656eOSYKk4Ls2C0FRQ==",
"version": "0.25.10",
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.10.tgz",
"integrity": "sha512-5Se0VM9Wtq797YFn+dLimf2Zx6McttsH2olUBsDml+lm0GOCRVebRWUvDtkY4BWYv/3NgzS8b/UM3jQNh5hYyw==",
"cpu": [
"arm64"
],
@ -352,9 +352,9 @@
}
},
"node_modules/@esbuild/openbsd-x64": {
"version": "0.25.9",
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.9.tgz",
"integrity": "sha512-1MkgTCuvMGWuqVtAvkpkXFmtL8XhWy+j4jaSO2wxfJtilVCi0ZE37b8uOdMItIHz4I6z1bWWtEX4CJwcKYLcuA==",
"version": "0.25.10",
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.10.tgz",
"integrity": "sha512-XkA4frq1TLj4bEMB+2HnI0+4RnjbuGZfet2gs/LNs5Hc7D89ZQBHQ0gL2ND6Lzu1+QVkjp3x1gIcPKzRNP8bXw==",
"cpu": [
"x64"
],
@ -369,9 +369,9 @@
}
},
"node_modules/@esbuild/openharmony-arm64": {
"version": "0.25.9",
"resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.9.tgz",
"integrity": "sha512-4Xd0xNiMVXKh6Fa7HEJQbrpP3m3DDn43jKxMjxLLRjWnRsfxjORYJlXPO4JNcXtOyfajXorRKY9NkOpTHptErg==",
"version": "0.25.10",
"resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.10.tgz",
"integrity": "sha512-AVTSBhTX8Y/Fz6OmIVBip9tJzZEUcY8WLh7I59+upa5/GPhh2/aM6bvOMQySspnCCHvFi79kMtdJS1w0DXAeag==",
"cpu": [
"arm64"
],
@ -386,9 +386,9 @@
}
},
"node_modules/@esbuild/sunos-x64": {
"version": "0.25.9",
"resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.9.tgz",
"integrity": "sha512-WjH4s6hzo00nNezhp3wFIAfmGZ8U7KtrJNlFMRKxiI9mxEK1scOMAaa9i4crUtu+tBr+0IN6JCuAcSBJZfnphw==",
"version": "0.25.10",
"resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.10.tgz",
"integrity": "sha512-fswk3XT0Uf2pGJmOpDB7yknqhVkJQkAQOcW/ccVOtfx05LkbWOaRAtn5SaqXypeKQra1QaEa841PgrSL9ubSPQ==",
"cpu": [
"x64"
],
@ -403,9 +403,9 @@
}
},
"node_modules/@esbuild/win32-arm64": {
"version": "0.25.9",
"resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.9.tgz",
"integrity": "sha512-mGFrVJHmZiRqmP8xFOc6b84/7xa5y5YvR1x8djzXpJBSv/UsNK6aqec+6JDjConTgvvQefdGhFDAs2DLAds6gQ==",
"version": "0.25.10",
"resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.10.tgz",
"integrity": "sha512-ah+9b59KDTSfpaCg6VdJoOQvKjI33nTaQr4UluQwW7aEwZQsbMCfTmfEO4VyewOxx4RaDT/xCy9ra2GPWmO7Kw==",
"cpu": [
"arm64"
],
@ -420,9 +420,9 @@
}
},
"node_modules/@esbuild/win32-ia32": {
"version": "0.25.9",
"resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.9.tgz",
"integrity": "sha512-b33gLVU2k11nVx1OhX3C8QQP6UHQK4ZtN56oFWvVXvz2VkDoe6fbG8TOgHFxEvqeqohmRnIHe5A1+HADk4OQww==",
"version": "0.25.10",
"resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.10.tgz",
"integrity": "sha512-QHPDbKkrGO8/cz9LKVnJU22HOi4pxZnZhhA2HYHez5Pz4JeffhDjf85E57Oyco163GnzNCVkZK0b/n4Y0UHcSw==",
"cpu": [
"ia32"
],
@ -437,9 +437,9 @@
}
},
"node_modules/@esbuild/win32-x64": {
"version": "0.25.9",
"resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.9.tgz",
"integrity": "sha512-PPOl1mi6lpLNQxnGoyAfschAodRFYXJ+9fs6WHXz7CSWKbOqiMZsubC+BQsVKuul+3vKLuwTHsS2c2y9EoKwxQ==",
"version": "0.25.10",
"resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.10.tgz",
"integrity": "sha512-9KpxSVFCu0iK1owoez6aC/s/EdUQLDN3adTxGCqxMVhrPDj6bt5dbrHDXUuq+Bs2vATFBBrQS5vdQ/Ed2P+nbw==",
"cpu": [
"x64"
],
@ -454,9 +454,9 @@
}
},
"node_modules/@fortawesome/fontawesome-free": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-free/-/fontawesome-free-7.0.0.tgz",
"integrity": "sha512-X48nISrSOa89zu2VMljC4XaRf8NmgTwQBVHfS2Nu5G00ZwM31oOVrAtGxZF3b6wDYf9lJsf/Eq4cCSFKIkOWPQ==",
"version": "7.0.1",
"resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-free/-/fontawesome-free-7.0.1.tgz",
"integrity": "sha512-RLmb9U6H2rJDnGxEqXxzy7ANPrQz7WK2/eTjdZqyU9uRU5W+FkAec9uU5gTYzFBH7aoXIw2WTJSCJR4KPlReQw==",
"license": "(CC-BY-4.0 AND OFL-1.1 AND MIT)",
"engines": {
"node": ">=6"
@ -783,9 +783,9 @@
}
},
"node_modules/@rollup/rollup-android-arm-eabi": {
"version": "4.48.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.48.0.tgz",
"integrity": "sha512-aVzKH922ogVAWkKiyKXorjYymz2084zrhrZRXtLrA5eEx5SO8Dj0c/4FpCHZyn7MKzhW2pW4tK28vVr+5oQ2xw==",
"version": "4.50.2",
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.50.2.tgz",
"integrity": "sha512-uLN8NAiFVIRKX9ZQha8wy6UUs06UNSZ32xj6giK/rmMXAgKahwExvK6SsmgU5/brh4w/nSgj8e0k3c1HBQpa0A==",
"cpu": [
"arm"
],
@ -797,9 +797,9 @@
]
},
"node_modules/@rollup/rollup-android-arm64": {
"version": "4.48.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.48.0.tgz",
"integrity": "sha512-diOdQuw43xTa1RddAFbhIA8toirSzFMcnIg8kvlzRbK26xqEnKJ/vqQnghTAajy2Dcy42v+GMPMo6jq67od+Dw==",
"version": "4.50.2",
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.50.2.tgz",
"integrity": "sha512-oEouqQk2/zxxj22PNcGSskya+3kV0ZKH+nQxuCCOGJ4oTXBdNTbv+f/E3c74cNLeMO1S5wVWacSws10TTSB77g==",
"cpu": [
"arm64"
],
@ -811,9 +811,9 @@
]
},
"node_modules/@rollup/rollup-darwin-arm64": {
"version": "4.48.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.48.0.tgz",
"integrity": "sha512-QhR2KA18fPlJWFefySJPDYZELaVqIUVnYgAOdtJ+B/uH96CFg2l1TQpX19XpUMWUqMyIiyY45wje8K6F4w4/CA==",
"version": "4.50.2",
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.50.2.tgz",
"integrity": "sha512-OZuTVTpj3CDSIxmPgGH8en/XtirV5nfljHZ3wrNwvgkT5DQLhIKAeuFSiwtbMto6oVexV0k1F1zqURPKf5rI1Q==",
"cpu": [
"arm64"
],
@ -825,9 +825,9 @@
]
},
"node_modules/@rollup/rollup-darwin-x64": {
"version": "4.48.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.48.0.tgz",
"integrity": "sha512-Q9RMXnQVJ5S1SYpNSTwXDpoQLgJ/fbInWOyjbCnnqTElEyeNvLAB3QvG5xmMQMhFN74bB5ZZJYkKaFPcOG8sGg==",
"version": "4.50.2",
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.50.2.tgz",
"integrity": "sha512-Wa/Wn8RFkIkr1vy1k1PB//VYhLnlnn5eaJkfTQKivirOvzu5uVd2It01ukeQstMursuz7S1bU+8WW+1UPXpa8A==",
"cpu": [
"x64"
],
@ -839,9 +839,9 @@
]
},
"node_modules/@rollup/rollup-freebsd-arm64": {
"version": "4.48.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.48.0.tgz",
"integrity": "sha512-3jzOhHWM8O8PSfyft+ghXZfBkZawQA0PUGtadKYxFqpcYlOYjTi06WsnYBsbMHLawr+4uWirLlbhcYLHDXR16w==",
"version": "4.50.2",
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.50.2.tgz",
"integrity": "sha512-QkzxvH3kYN9J1w7D1A+yIMdI1pPekD+pWx7G5rXgnIlQ1TVYVC6hLl7SOV9pi5q9uIDF9AuIGkuzcbF7+fAhow==",
"cpu": [
"arm64"
],
@ -853,9 +853,9 @@
]
},
"node_modules/@rollup/rollup-freebsd-x64": {
"version": "4.48.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.48.0.tgz",
"integrity": "sha512-NcD5uVUmE73C/TPJqf78hInZmiSBsDpz3iD5MF/BuB+qzm4ooF2S1HfeTChj5K4AV3y19FFPgxonsxiEpy8v/A==",
"version": "4.50.2",
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.50.2.tgz",
"integrity": "sha512-dkYXB0c2XAS3a3jmyDkX4Jk0m7gWLFzq1C3qUnJJ38AyxIF5G/dyS4N9B30nvFseCfgtCEdbYFhk0ChoCGxPog==",
"cpu": [
"x64"
],
@ -867,9 +867,9 @@
]
},
"node_modules/@rollup/rollup-linux-arm-gnueabihf": {
"version": "4.48.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.48.0.tgz",
"integrity": "sha512-JWnrj8qZgLWRNHr7NbpdnrQ8kcg09EBBq8jVOjmtlB3c8C6IrynAJSMhMVGME4YfTJzIkJqvSUSVJRqkDnu/aA==",
"version": "4.50.2",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.50.2.tgz",
"integrity": "sha512-9VlPY/BN3AgbukfVHAB8zNFWB/lKEuvzRo1NKev0Po8sYFKx0i+AQlCYftgEjcL43F2h9Ui1ZSdVBc4En/sP2w==",
"cpu": [
"arm"
],
@ -881,9 +881,9 @@
]
},
"node_modules/@rollup/rollup-linux-arm-musleabihf": {
"version": "4.48.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.48.0.tgz",
"integrity": "sha512-9xu92F0TxuMH0tD6tG3+GtngwdgSf8Bnz+YcsPG91/r5Vgh5LNofO48jV55priA95p3c92FLmPM7CvsVlnSbGQ==",
"version": "4.50.2",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.50.2.tgz",
"integrity": "sha512-+GdKWOvsifaYNlIVf07QYan1J5F141+vGm5/Y8b9uCZnG/nxoGqgCmR24mv0koIWWuqvFYnbURRqw1lv7IBINw==",
"cpu": [
"arm"
],
@ -895,9 +895,9 @@
]
},
"node_modules/@rollup/rollup-linux-arm64-gnu": {
"version": "4.48.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.48.0.tgz",
"integrity": "sha512-NLtvJB5YpWn7jlp1rJiY0s+G1Z1IVmkDuiywiqUhh96MIraC0n7XQc2SZ1CZz14shqkM+XN2UrfIo7JB6UufOA==",
"version": "4.50.2",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.50.2.tgz",
"integrity": "sha512-df0Eou14ojtUdLQdPFnymEQteENwSJAdLf5KCDrmZNsy1c3YaCNaJvYsEUHnrg+/DLBH612/R0xd3dD03uz2dg==",
"cpu": [
"arm64"
],
@ -909,9 +909,9 @@
]
},
"node_modules/@rollup/rollup-linux-arm64-musl": {
"version": "4.48.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.48.0.tgz",
"integrity": "sha512-QJ4hCOnz2SXgCh+HmpvZkM+0NSGcZACyYS8DGbWn2PbmA0e5xUk4bIP8eqJyNXLtyB4gZ3/XyvKtQ1IFH671vQ==",
"version": "4.50.2",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.50.2.tgz",
"integrity": "sha512-iPeouV0UIDtz8j1YFR4OJ/zf7evjauqv7jQ/EFs0ClIyL+by++hiaDAfFipjOgyz6y6xbDvJuiU4HwpVMpRFDQ==",
"cpu": [
"arm64"
],
@ -922,10 +922,10 @@
"linux"
]
},
"node_modules/@rollup/rollup-linux-loongarch64-gnu": {
"version": "4.48.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.48.0.tgz",
"integrity": "sha512-Pk0qlGJnhILdIC5zSKQnprFjrGmjfDM7TPZ0FKJxRkoo+kgMRAg4ps1VlTZf8u2vohSicLg7NP+cA5qE96PaFg==",
"node_modules/@rollup/rollup-linux-loong64-gnu": {
"version": "4.50.2",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.50.2.tgz",
"integrity": "sha512-OL6KaNvBopLlj5fTa5D5bau4W82f+1TyTZRr2BdnfsrnQnmdxh4okMxR2DcDkJuh4KeoQZVuvHvzuD/lyLn2Kw==",
"cpu": [
"loong64"
],
@ -937,9 +937,9 @@
]
},
"node_modules/@rollup/rollup-linux-ppc64-gnu": {
"version": "4.48.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.48.0.tgz",
"integrity": "sha512-/dNFc6rTpoOzgp5GKoYjT6uLo8okR/Chi2ECOmCZiS4oqh3mc95pThWma7Bgyk6/WTEvjDINpiBCuecPLOgBLQ==",
"version": "4.50.2",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.50.2.tgz",
"integrity": "sha512-I21VJl1w6z/K5OTRl6aS9DDsqezEZ/yKpbqlvfHbW0CEF5IL8ATBMuUx6/mp683rKTK8thjs/0BaNrZLXetLag==",
"cpu": [
"ppc64"
],
@ -951,9 +951,9 @@
]
},
"node_modules/@rollup/rollup-linux-riscv64-gnu": {
"version": "4.48.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.48.0.tgz",
"integrity": "sha512-YBwXsvsFI8CVA4ej+bJF2d9uAeIiSkqKSPQNn0Wyh4eMDY4wxuSp71BauPjQNCKK2tD2/ksJ7uhJ8X/PVY9bHQ==",
"version": "4.50.2",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.50.2.tgz",
"integrity": "sha512-Hq6aQJT/qFFHrYMjS20nV+9SKrXL2lvFBENZoKfoTH2kKDOJqff5OSJr4x72ZaG/uUn+XmBnGhfr4lwMRrmqCQ==",
"cpu": [
"riscv64"
],
@ -965,9 +965,9 @@
]
},
"node_modules/@rollup/rollup-linux-riscv64-musl": {
"version": "4.48.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.48.0.tgz",
"integrity": "sha512-FI3Rr2aGAtl1aHzbkBIamsQyuauYtTF9SDUJ8n2wMXuuxwchC3QkumZa1TEXYIv/1AUp1a25Kwy6ONArvnyeVQ==",
"version": "4.50.2",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.50.2.tgz",
"integrity": "sha512-82rBSEXRv5qtKyr0xZ/YMF531oj2AIpLZkeNYxmKNN6I2sVE9PGegN99tYDLK2fYHJITL1P2Lgb4ZXnv0PjQvw==",
"cpu": [
"riscv64"
],
@ -979,9 +979,9 @@
]
},
"node_modules/@rollup/rollup-linux-s390x-gnu": {
"version": "4.48.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.48.0.tgz",
"integrity": "sha512-Dx7qH0/rvNNFmCcIRe1pyQ9/H0XO4v/f0SDoafwRYwc2J7bJZ5N4CHL/cdjamISZ5Cgnon6iazAVRFlxSoHQnQ==",
"version": "4.50.2",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.50.2.tgz",
"integrity": "sha512-4Q3S3Hy7pC6uaRo9gtXUTJ+EKo9AKs3BXKc2jYypEcMQ49gDPFU2P1ariX9SEtBzE5egIX6fSUmbmGazwBVF9w==",
"cpu": [
"s390x"
],
@ -993,9 +993,9 @@
]
},
"node_modules/@rollup/rollup-linux-x64-gnu": {
"version": "4.48.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.48.0.tgz",
"integrity": "sha512-GUdZKTeKBq9WmEBzvFYuC88yk26vT66lQV8D5+9TgkfbewhLaTHRNATyzpQwwbHIfJvDJ3N9WJ90wK/uR3cy3Q==",
"version": "4.50.2",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.50.2.tgz",
"integrity": "sha512-9Jie/At6qk70dNIcopcL4p+1UirusEtznpNtcq/u/C5cC4HBX7qSGsYIcG6bdxj15EYWhHiu02YvmdPzylIZlA==",
"cpu": [
"x64"
],
@ -1007,9 +1007,9 @@
]
},
"node_modules/@rollup/rollup-linux-x64-musl": {
"version": "4.48.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.48.0.tgz",
"integrity": "sha512-ao58Adz/v14MWpQgYAb4a4h3fdw73DrDGtaiF7Opds5wNyEQwtO6M9dBh89nke0yoZzzaegq6J/EXs7eBebG8A==",
"version": "4.50.2",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.50.2.tgz",
"integrity": "sha512-HPNJwxPL3EmhzeAnsWQCM3DcoqOz3/IC6de9rWfGR8ZCuEHETi9km66bH/wG3YH0V3nyzyFEGUZeL5PKyy4xvw==",
"cpu": [
"x64"
],
@ -1020,10 +1020,24 @@
"linux"
]
},
"node_modules/@rollup/rollup-openharmony-arm64": {
"version": "4.50.2",
"resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.50.2.tgz",
"integrity": "sha512-nMKvq6FRHSzYfKLHZ+cChowlEkR2lj/V0jYj9JnGUVPL2/mIeFGmVM2mLaFeNa5Jev7W7TovXqXIG2d39y1KYA==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"openharmony"
]
},
"node_modules/@rollup/rollup-win32-arm64-msvc": {
"version": "4.48.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.48.0.tgz",
"integrity": "sha512-kpFno46bHtjZVdRIOxqaGeiABiToo2J+st7Yce+aiAoo1H0xPi2keyQIP04n2JjDVuxBN6bSz9R6RdTK5hIppw==",
"version": "4.50.2",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.50.2.tgz",
"integrity": "sha512-eFUvvnTYEKeTyHEijQKz81bLrUQOXKZqECeiWH6tb8eXXbZk+CXSG2aFrig2BQ/pjiVRj36zysjgILkqarS2YA==",
"cpu": [
"arm64"
],
@ -1035,9 +1049,9 @@
]
},
"node_modules/@rollup/rollup-win32-ia32-msvc": {
"version": "4.48.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.48.0.tgz",
"integrity": "sha512-rFYrk4lLk9YUTIeihnQMiwMr6gDhGGSbWThPEDfBoU/HdAtOzPXeexKi7yU8jO+LWRKnmqPN9NviHQf6GDwBcQ==",
"version": "4.50.2",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.50.2.tgz",
"integrity": "sha512-cBaWmXqyfRhH8zmUxK3d3sAhEWLrtMjWBRwdMMHJIXSjvjLKvv49adxiEz+FJ8AP90apSDDBx2Tyd/WylV6ikA==",
"cpu": [
"ia32"
],
@ -1049,9 +1063,9 @@
]
},
"node_modules/@rollup/rollup-win32-x64-msvc": {
"version": "4.48.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.48.0.tgz",
"integrity": "sha512-sq0hHLTgdtwOPDB5SJOuaoHyiP1qSwg+71TQWk8iDS04bW1wIE0oQ6otPiRj2ZvLYNASLMaTp8QRGUVZ+5OL5A==",
"version": "4.50.2",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.50.2.tgz",
"integrity": "sha512-APwKy6YUhvZaEoHyM+9xqmTpviEI+9eL7LoCH+aLcvWYHJ663qG5zx7WzWZY+a9qkg5JtzcMyJ9z0WtQBMDmgA==",
"cpu": [
"x64"
],
@ -1085,9 +1099,9 @@
"license": "MIT"
},
"node_modules/alpinejs": {
"version": "3.14.9",
"resolved": "https://registry.npmjs.org/alpinejs/-/alpinejs-3.14.9.tgz",
"integrity": "sha512-gqSOhTEyryU9FhviNqiHBHzgjkvtukq9tevew29fTj+ofZtfsYriw4zPirHHOAy9bw8QoL3WGhyk7QqCh5AYlw==",
"version": "3.15.0",
"resolved": "https://registry.npmjs.org/alpinejs/-/alpinejs-3.15.0.tgz",
"integrity": "sha512-lpokA5okCF1BKh10LG8YjqhfpxyHBk4gE7boIgVHltJzYoM7O9nK3M7VlntLEJGsVmu7U/RzUWajmHREGT38Eg==",
"license": "MIT",
"dependencies": {
"@vue/reactivity": "~3.1.1"
@ -1101,9 +1115,9 @@
"license": "MIT"
},
"node_modules/axios": {
"version": "1.11.0",
"resolved": "https://registry.npmjs.org/axios/-/axios-1.11.0.tgz",
"integrity": "sha512-1Lx3WLFQWm3ooKDYZD1eXmoGO9fxYQjrycfHFC8P0sCfQVXyROp0p9PFWBehewBOdCwHc+f/b8I0fMto5eSfwA==",
"version": "1.12.2",
"resolved": "https://registry.npmjs.org/axios/-/axios-1.12.2.tgz",
"integrity": "sha512-vMJzPewAlRyOgxV2dU0Cuz2O8zzzx9VYtbJOaBgXFeLc4IV/Eg50n4LowmehOOR61S8ZMpc2K5Sa7g6A4jfkUw==",
"dev": true,
"license": "MIT",
"dependencies": {
@ -1113,9 +1127,9 @@
}
},
"node_modules/bootstrap": {
"version": "5.3.7",
"resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-5.3.7.tgz",
"integrity": "sha512-7KgiD8UHjfcPBHEpDNg+zGz8L3LqR3GVwqZiBRFX04a1BCArZOz1r2kjly2HQ0WokqTO0v1nF+QAt8dsW4lKlw==",
"version": "5.3.8",
"resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-5.3.8.tgz",
"integrity": "sha512-HP1SZDqaLDPwsNiqRqi5NcP0SSXciX2s9E+RyqJIIqGo+vJeN5AJVM98CXmW/Wux0nQ5L7jeWUdplCEf0Ee+tg==",
"funding": [
{
"type": "github",
@ -1277,9 +1291,9 @@
}
},
"node_modules/esbuild": {
"version": "0.25.9",
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.9.tgz",
"integrity": "sha512-CRbODhYyQx3qp7ZEwzxOk4JBqmD/seJrzPa/cGjY1VtIn5E09Oi9/dB4JwctnfZ8Q8iT7rioVv5k/FNT/uf54g==",
"version": "0.25.10",
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.10.tgz",
"integrity": "sha512-9RiGKvCwaqxO2owP61uQ4BgNborAQskMR6QusfWzQqv7AZOg5oGehdY2pRJMTKuwxd1IDBP4rSbI5lHzU7SMsQ==",
"dev": true,
"hasInstallScript": true,
"license": "MIT",
@ -1290,32 +1304,32 @@
"node": ">=18"
},
"optionalDependencies": {
"@esbuild/aix-ppc64": "0.25.9",
"@esbuild/android-arm": "0.25.9",
"@esbuild/android-arm64": "0.25.9",
"@esbuild/android-x64": "0.25.9",
"@esbuild/darwin-arm64": "0.25.9",
"@esbuild/darwin-x64": "0.25.9",
"@esbuild/freebsd-arm64": "0.25.9",
"@esbuild/freebsd-x64": "0.25.9",
"@esbuild/linux-arm": "0.25.9",
"@esbuild/linux-arm64": "0.25.9",
"@esbuild/linux-ia32": "0.25.9",
"@esbuild/linux-loong64": "0.25.9",
"@esbuild/linux-mips64el": "0.25.9",
"@esbuild/linux-ppc64": "0.25.9",
"@esbuild/linux-riscv64": "0.25.9",
"@esbuild/linux-s390x": "0.25.9",
"@esbuild/linux-x64": "0.25.9",
"@esbuild/netbsd-arm64": "0.25.9",
"@esbuild/netbsd-x64": "0.25.9",
"@esbuild/openbsd-arm64": "0.25.9",
"@esbuild/openbsd-x64": "0.25.9",
"@esbuild/openharmony-arm64": "0.25.9",
"@esbuild/sunos-x64": "0.25.9",
"@esbuild/win32-arm64": "0.25.9",
"@esbuild/win32-ia32": "0.25.9",
"@esbuild/win32-x64": "0.25.9"
"@esbuild/aix-ppc64": "0.25.10",
"@esbuild/android-arm": "0.25.10",
"@esbuild/android-arm64": "0.25.10",
"@esbuild/android-x64": "0.25.10",
"@esbuild/darwin-arm64": "0.25.10",
"@esbuild/darwin-x64": "0.25.10",
"@esbuild/freebsd-arm64": "0.25.10",
"@esbuild/freebsd-x64": "0.25.10",
"@esbuild/linux-arm": "0.25.10",
"@esbuild/linux-arm64": "0.25.10",
"@esbuild/linux-ia32": "0.25.10",
"@esbuild/linux-loong64": "0.25.10",
"@esbuild/linux-mips64el": "0.25.10",
"@esbuild/linux-ppc64": "0.25.10",
"@esbuild/linux-riscv64": "0.25.10",
"@esbuild/linux-s390x": "0.25.10",
"@esbuild/linux-x64": "0.25.10",
"@esbuild/netbsd-arm64": "0.25.10",
"@esbuild/netbsd-x64": "0.25.10",
"@esbuild/openbsd-arm64": "0.25.10",
"@esbuild/openbsd-x64": "0.25.10",
"@esbuild/openharmony-arm64": "0.25.10",
"@esbuild/sunos-x64": "0.25.10",
"@esbuild/win32-arm64": "0.25.10",
"@esbuild/win32-ia32": "0.25.10",
"@esbuild/win32-x64": "0.25.10"
}
},
"node_modules/fill-range": {
@ -1533,9 +1547,9 @@
}
},
"node_modules/laravel-vite-plugin": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/laravel-vite-plugin/-/laravel-vite-plugin-2.0.0.tgz",
"integrity": "sha512-pnaKHInJgiWpG/g+LmaISHl7D/1s5wnOXnrGiBdt4NOs+tYZRw0v/ZANELGX2/dGgHyEzO+iZ6x4idpoK04z/Q==",
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/laravel-vite-plugin/-/laravel-vite-plugin-2.0.1.tgz",
"integrity": "sha512-zQuvzWfUKQu9oNVi1o0RZAJCwhGsdhx4NEOyrVQwJHaWDseGP9tl7XUPLY2T8Cj6+IrZ6lmyxlR1KC8unf3RLA==",
"dev": true,
"license": "MIT",
"dependencies": {
@ -1698,9 +1712,9 @@
}
},
"node_modules/rollup": {
"version": "4.48.0",
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.48.0.tgz",
"integrity": "sha512-BXHRqK1vyt9XVSEHZ9y7xdYtuYbwVod2mLwOMFP7t/Eqoc1pHRlG/WdV2qNeNvZHRQdLedaFycljaYYM96RqJQ==",
"version": "4.50.2",
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.50.2.tgz",
"integrity": "sha512-BgLRGy7tNS9H66aIMASq1qSYbAAJV6Z6WR4QYTvj5FgF15rZ/ympT1uixHXwzbZUBDbkvqUI1KR0fH1FhMaQ9w==",
"dev": true,
"license": "MIT",
"dependencies": {
@ -1714,33 +1728,34 @@
"npm": ">=8.0.0"
},
"optionalDependencies": {
"@rollup/rollup-android-arm-eabi": "4.48.0",
"@rollup/rollup-android-arm64": "4.48.0",
"@rollup/rollup-darwin-arm64": "4.48.0",
"@rollup/rollup-darwin-x64": "4.48.0",
"@rollup/rollup-freebsd-arm64": "4.48.0",
"@rollup/rollup-freebsd-x64": "4.48.0",
"@rollup/rollup-linux-arm-gnueabihf": "4.48.0",
"@rollup/rollup-linux-arm-musleabihf": "4.48.0",
"@rollup/rollup-linux-arm64-gnu": "4.48.0",
"@rollup/rollup-linux-arm64-musl": "4.48.0",
"@rollup/rollup-linux-loongarch64-gnu": "4.48.0",
"@rollup/rollup-linux-ppc64-gnu": "4.48.0",
"@rollup/rollup-linux-riscv64-gnu": "4.48.0",
"@rollup/rollup-linux-riscv64-musl": "4.48.0",
"@rollup/rollup-linux-s390x-gnu": "4.48.0",
"@rollup/rollup-linux-x64-gnu": "4.48.0",
"@rollup/rollup-linux-x64-musl": "4.48.0",
"@rollup/rollup-win32-arm64-msvc": "4.48.0",
"@rollup/rollup-win32-ia32-msvc": "4.48.0",
"@rollup/rollup-win32-x64-msvc": "4.48.0",
"@rollup/rollup-android-arm-eabi": "4.50.2",
"@rollup/rollup-android-arm64": "4.50.2",
"@rollup/rollup-darwin-arm64": "4.50.2",
"@rollup/rollup-darwin-x64": "4.50.2",
"@rollup/rollup-freebsd-arm64": "4.50.2",
"@rollup/rollup-freebsd-x64": "4.50.2",
"@rollup/rollup-linux-arm-gnueabihf": "4.50.2",
"@rollup/rollup-linux-arm-musleabihf": "4.50.2",
"@rollup/rollup-linux-arm64-gnu": "4.50.2",
"@rollup/rollup-linux-arm64-musl": "4.50.2",
"@rollup/rollup-linux-loong64-gnu": "4.50.2",
"@rollup/rollup-linux-ppc64-gnu": "4.50.2",
"@rollup/rollup-linux-riscv64-gnu": "4.50.2",
"@rollup/rollup-linux-riscv64-musl": "4.50.2",
"@rollup/rollup-linux-s390x-gnu": "4.50.2",
"@rollup/rollup-linux-x64-gnu": "4.50.2",
"@rollup/rollup-linux-x64-musl": "4.50.2",
"@rollup/rollup-openharmony-arm64": "4.50.2",
"@rollup/rollup-win32-arm64-msvc": "4.50.2",
"@rollup/rollup-win32-ia32-msvc": "4.50.2",
"@rollup/rollup-win32-x64-msvc": "4.50.2",
"fsevents": "~2.3.2"
}
},
"node_modules/sass": {
"version": "1.90.0",
"resolved": "https://registry.npmjs.org/sass/-/sass-1.90.0.tgz",
"integrity": "sha512-9GUyuksjw70uNpb1MTYWsH9MQHOHY6kwfnkafC24+7aOMZn9+rVMBxRbLvw756mrBFbIsFg6Xw9IkR2Fnn3k+Q==",
"version": "1.92.1",
"resolved": "https://registry.npmjs.org/sass/-/sass-1.92.1.tgz",
"integrity": "sha512-ffmsdbwqb3XeyR8jJR6KelIXARM9bFQe8A6Q3W4Klmwy5Ckd5gz7jgUNHo4UOqutU5Sk1DtKLbpDP0nLCg1xqQ==",
"dev": true,
"license": "MIT",
"dependencies": {
@ -1835,9 +1850,9 @@
"link": true
},
"node_modules/vite": {
"version": "7.1.5",
"resolved": "https://registry.npmjs.org/vite/-/vite-7.1.5.tgz",
"integrity": "sha512-4cKBO9wR75r0BeIWWWId9XK9Lj6La5X846Zw9dFfzMRw38IlTk2iCcUt6hsyiDRcPidc55ZParFYDXi0nXOeLQ==",
"version": "7.1.6",
"resolved": "https://registry.npmjs.org/vite/-/vite-7.1.6.tgz",
"integrity": "sha512-SRYIB8t/isTwNn8vMB3MR6E+EQZM/WG1aKmmIUCfDXfVvKfc20ZpamngWHKzAmmu9ppsgxsg4b2I7c90JZudIQ==",
"dev": true,
"license": "MIT",
"dependencies": {

187
resources/schemas/v3.json

@ -0,0 +1,187 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"properties": {
"version": {
"description": "The version of the import configuration.",
"type": "integer",
"minimum": 1,
"maximum": 3,
"default": 3
},
"source": {
"type": "string",
"minLength": 1,
"maxLength": 255
},
"created_at": {
"type": "string",
"minLength": 1,
"maxLength": 255
},
"date": {
"type": "string",
"minLength": 0,
"maxLength": 255
},
"default_account": {
"type": "integer",
"minimum": 0
},
"delimiter": {
"type": "string",
"enum": [
"comma",
"semicolon",
"tab"
]
},
"headers": {
"type": "boolean"
},
"rules": {
"type": "boolean"
},
"skip_form": {
"type": "boolean"
},
"add_import_tag": {
"type": "boolean"
},
"roles": {
"type": "array",
"items": {
"type": "string"
}
},
"do_mapping": {
"anyOf": [
{
"type": "object"
},
{
"type": "array",
"items": {
"type": "boolean"
}
}
]
},
"mapping": {
"anyOf": [
{
"type": "object"
},
{
"type": "array"
}
]
},
"duplicate_detection_method": {
"type": "string",
"enum": [
"none",
"classic",
"cell"
]
},
"ignore_duplicate_lines": {
"type": "boolean"
},
"ignore_duplicate_transactions": {
"type": "boolean"
},
"unique_column_index": {
"type": "integer",
"minimum": 0
},
"unique_column_type": {
"type": "string"
},
"flow": {
"type": "string",
"enum": [
"nordigen",
"spectre",
"file",
"simplefin"
]
},
"identifier": {
"type": "string"
},
"connection": {
"type": "string"
},
"ignore_spectre_categories": {
"type": "boolean"
},
"map_all_data": {
"type": "boolean"
},
"accounts": {
"anyOf": [
{
"type": "object"
},
{
"type": "array"
}
]
},
"date_range": {
"type": "string"
},
"date_range_number": {
"type": "integer"
},
"date_range_unit": {
"type": "string"
},
"date_not_before": {
"type": "string"
},
"date_not_after": {
"type": "string"
},
"nordigen_country": {
"type": "string"
},
"nordigen_bank": {
"type": "string"
},
"nordigen_requisitions": {
"anyOf": [
{
"type": "object"
},
{
"type": "array"
}
]
},
"conversion": {
"type": "boolean"
}
},
"required": [
"version",
"default_account",
"delimiter",
"headers",
"rules",
"skip_form",
"add_import_tag",
"roles",
"do_mapping",
"mapping",
"duplicate_detection_method",
"ignore_duplicate_lines",
"ignore_duplicate_transactions",
"unique_column_index",
"unique_column_type",
"flow",
"conversion"
]
}

10
resources/views/v2/components/conversion-messages.blade.php

@ -7,13 +7,13 @@
Line #<span x-text="index"></span>:
<template x-if="messageList.length === 1">
<template x-for="message in messageList">
<span x-text="message"></span>
<span x-html="message"></span>
</template>
</template>
<template x-if="messageList.length > 1">
<ol>
<template x-for="message in messageList">
<li x-text="message"></li>
<li x-html="message"></li>
</template>
</ol>
</template>
@ -30,13 +30,13 @@
Line #<span x-text="index"></span>:
<template x-if="messageList.length === 1">
<template x-for="message in messageList">
<span x-text="message"></span>
<span x-html="message"></span>
</template>
</template>
<template x-if="messageList.length > 1">
<ol>
<template x-for="message in messageList">
<li x-text="message"></li>
<li x-html="message"></li>
</template>
</ol>
</template>
@ -60,7 +60,7 @@
<template x-if="messageList.length > 1">
<ol>
<template x-for="message in messageList">
<li x-text="message"></li>
<li x-html="message"></li>
</template>
</ol>
</template>

2
resources/views/v2/emails/import/report.blade.php

@ -1,5 +1,5 @@
@component('mail::message')
# Result of your import on {{ $time }}
# Result of your import on {{ $time }}@if('' !== $configFile), using configuration file `{{ $configFile }}`@endif
<hr>

Loading…
Cancel
Save