1 Commits

Author SHA1 Message Date
bc2ca3b31a chore(deps): update dependency vue to v3.5.34
Some checks failed
JS Unit Tests / test (pull_request) Failing after 34s
Build Test / test (pull_request) Successful in 37s
PHP Unit Tests / test (pull_request) Successful in 1m23s
2026-05-21 03:42:31 +00:00
9 changed files with 88 additions and 800 deletions

18
composer.lock generated
View File

@@ -592,16 +592,16 @@
},
{
"name": "phpunit/phpunit",
"version": "11.5.55",
"version": "11.5.53",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/phpunit.git",
"reference": "adc7262fccc12de2b30f12a8aa0b33775d814f00"
"reference": "a997a653a82845f1240d73ee73a8a4e97e4b0607"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/adc7262fccc12de2b30f12a8aa0b33775d814f00",
"reference": "adc7262fccc12de2b30f12a8aa0b33775d814f00",
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/a997a653a82845f1240d73ee73a8a4e97e4b0607",
"reference": "a997a653a82845f1240d73ee73a8a4e97e4b0607",
"shasum": ""
},
"require": {
@@ -674,7 +674,7 @@
"support": {
"issues": "https://github.com/sebastianbergmann/phpunit/issues",
"security": "https://github.com/sebastianbergmann/phpunit/security/policy",
"source": "https://github.com/sebastianbergmann/phpunit/tree/11.5.55"
"source": "https://github.com/sebastianbergmann/phpunit/tree/11.5.53"
},
"funding": [
{
@@ -698,7 +698,7 @@
"type": "tidelift"
}
],
"time": "2026-02-18T12:37:06+00:00"
"time": "2026-02-10T12:28:25+00:00"
},
{
"name": "sebastian/cli-parser",
@@ -1791,15 +1791,15 @@
],
"aliases": [],
"minimum-stability": "stable",
"stability-flags": {},
"stability-flags": [],
"prefer-stable": false,
"prefer-lowest": false,
"platform": {
"php": ">=8.2 <=8.5"
},
"platform-dev": {},
"platform-dev": [],
"platform-overrides": {
"php": "8.2"
},
"plugin-api-version": "2.9.0"
"plugin-api-version": "2.3.0"
}

View File

@@ -13,7 +13,6 @@ use InvalidArgumentException;
use KTXC\Http\Response\JsonResponse;
use KTXC\Http\Response\Response;
use KTXC\Http\Response\StreamedNdJsonResponse;
use KTXC\Http\Response\StreamedResponse;
use KTXC\SessionIdentity;
use KTXC\SessionTenant;
use KTXF\Controller\ControllerAbstract;
@@ -32,6 +31,12 @@ use KTXM\MailManager\Manager;
use Psr\Log\LoggerInterface;
use Throwable;
/**
* Default Controller - Unified Mail API
*
* Handles all mail operations in JMAP-style API pattern.
* Supports both single operations and batches with result references.
*/
class DefaultController extends ControllerAbstract {
private const ERR_MISSING_PROVIDER = 'Missing parameter: provider';
@@ -163,7 +168,6 @@ class DefaultController extends ControllerAbstract {
'entity.move' => $this->entityMove($tenantId, $userId, $data),
'entity.copy' => throw new InvalidArgumentException('Operation not implemented: ' . $operation),
'entity.transmit' => $this->entityTransmit($tenantId, $userId, $data),
'entity.download' => $this->entityDownload($tenantId, $userId, $data),
default => throw new InvalidArgumentException(self::ERR_INVALID_OPERATION . $operation)
};
@@ -554,14 +558,14 @@ class DefaultController extends ControllerAbstract {
if (is_bool($result)) {
return [
'disposition' => 'deleted'
'outcome' => 'deleted'
];
}
if ($result instanceof JsonSerializable) {
return [
'disposition' => 'moved',
'mutation' => $result
'outcome' => 'moved',
'data' => $result
];
}
@@ -769,21 +773,21 @@ class DefaultController extends ControllerAbstract {
}
private function entityDelete(string $tenantId, string $userId, array $data): mixed {
if (!isset($data['targets'])) {
throw new InvalidArgumentException(self::ERR_MISSING_TARGETS);
if (!isset($data['sources'])) {
throw new InvalidArgumentException(self::ERR_MISSING_SOURCES);
}
if (!is_array($data['targets'])) {
throw new InvalidArgumentException(self::ERR_INVALID_TARGETS);
if (!is_array($data['sources'])) {
throw new InvalidArgumentException(self::ERR_INVALID_SOURCES);
}
$targets = ResourceIdentifiers::fromArray($data['targets']);
foreach ($targets as $target) {
if (!$target instanceof EntityIdentifier) {
throw new InvalidArgumentException('Invalid parameter: targets must contain provider:service:collection:entity identifiers');
$sources = ResourceIdentifiers::fromArray($data['sources']);
foreach ($sources as $source) {
if (!$source instanceof EntityIdentifier) {
throw new InvalidArgumentException('Invalid parameter: sources must contain provider:service:collection:entity identifiers');
}
}
return $this->mailManager->entityDelete($tenantId, $userId, ...$targets->all());
return $this->mailManager->entityDelete($tenantId, $userId, ...$sources->all());
}
private function entityPatch(string $tenantId, string $userId, array $data): mixed {
@@ -864,46 +868,4 @@ class DefaultController extends ControllerAbstract {
return ['jobId' => $jobId];
}
private function entityDownload(string $tenantId, string $userId, array $data): mixed {
if (!isset($data['target'])) {
throw new InvalidArgumentException(self::ERR_MISSING_TARGET);
}
if (!is_string($data['target'])) {
throw new InvalidArgumentException(self::ERR_INVALID_IDENTIFIER);
}
// 'part' is optional — null means full RFC 822 message download
$part = isset($data['part']) && is_array($data['part']) ? $data['part'] : null;
$target = ResourceIdentifier::fromString($data['target']);
$logger = $this->logger;
$result = $this->mailManager->entityDownload($tenantId, $userId, $target, $part);
$filename = $result->filename();
$asciiFilename = preg_replace('/[^\x20-\x7E]|[\\\\"]/', '_', $filename);
$encodedFilename = rawurlencode($filename);
$disposition = sprintf(
'attachment; filename="%s"; filename*=UTF-8\'\'%s',
$asciiFilename,
$encodedFilename,
);
$responseGenerator = (static function () use ($result, $logger): \Generator {
try {
yield from $result->stream();
} catch (\Throwable $t) {
$logger->error('Error streaming entity download', ['exception' => $t]);
// Headers already sent — cannot change status code; stop output cleanly
}
})();
return new StreamedResponse($responseGenerator, 200, [
'Content-Disposition' => $disposition,
'Content-Type' => $result->mimeType(),
'Content-Transfer-Encoding' => 'binary',
'Cache-Control' => 'no-store',
]);
}
}

View File

@@ -20,7 +20,6 @@ use KTXF\Mail\Service\ServiceCollectionMutableInterface;
use KTXF\Mail\Service\ServiceConfigurableInterface;
use KTXF\Mail\Service\ServiceEntityMutableInterface;
use KTXF\Mail\Service\ServiceMutableInterface;
use KTXF\Resource\BinaryResource;
use KTXF\Resource\Filter\IFilter;
use KTXF\Resource\Identifier\CollectionIdentifier;
use KTXF\Resource\Identifier\EntityIdentifier;
@@ -952,13 +951,6 @@ class Manager {
}
}
public function entityDownload(string $tenantId, string $userId, EntityIdentifier $targetEntity, array|null $targetPart): BinaryResource {
// retrieve service
$service = $this->serviceFetch($tenantId, $userId, $targetEntity->provider(), $targetEntity->service());
// download entity
return $service->entityDownload($targetEntity, $targetPart);
}
/**
* Check if messages exist
*
@@ -1302,4 +1294,5 @@ class Manager {
return $operationOutcome;
}
}

612
package-lock.json generated
View File

@@ -9,9 +9,9 @@
"version": "1.0.0",
"license": "AGPL-3.0-or-later",
"dependencies": {
"pinia": "^3.0.0",
"pinia": "^2.3.1",
"vue": "^3.5.18",
"vue-router": "^5.0.0",
"vue-router": "^4.5.1",
"vuetify": "^4.0.0"
},
"devDependencies": {
@@ -24,69 +24,6 @@
"vue-tsc": "^3.0.5"
}
},
"node_modules/@babel/generator": {
"version": "8.0.0-rc.5",
"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-8.0.0-rc.5.tgz",
"integrity": "sha512-nFZPWz3FHIS7y6rMIVoa/WBwjdutfIaRJIBQjzn+t3RnecZoRNlGmGcyR2wb0T/IgSd50Kz/6dG8/LvMCRunjg==",
"license": "MIT",
"dependencies": {
"@babel/parser": "^8.0.0-rc.5",
"@babel/types": "^8.0.0-rc.5",
"@jridgewell/gen-mapping": "^0.3.12",
"@jridgewell/trace-mapping": "^0.3.28",
"@types/jsesc": "^2.5.0",
"jsesc": "^3.0.2"
},
"engines": {
"node": "^22.18.0 || >=24.11.0"
}
},
"node_modules/@babel/generator/node_modules/@babel/helper-string-parser": {
"version": "8.0.0-rc.5",
"resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-8.0.0-rc.5.tgz",
"integrity": "sha512-sN7R8rBvDurfaziNfDEIjIntlazmlkCDGO4SNl2RJ3wRCn+QxspLV7hzYAE8WWVd2joVuT8sUxeePdLp2idI1A==",
"license": "MIT",
"engines": {
"node": "^22.18.0 || >=24.11.0"
}
},
"node_modules/@babel/generator/node_modules/@babel/helper-validator-identifier": {
"version": "8.0.0-rc.5",
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-8.0.0-rc.5.tgz",
"integrity": "sha512-ehJDxHvtbZ85RtX/L2fi0h9AGsBNqB5Euv1EB8RMAvGYvD+2X+QbpzzOpbklnNXO+WSZJNOaetw2BBj27xsWVg==",
"license": "MIT",
"engines": {
"node": "^22.18.0 || >=24.11.0"
}
},
"node_modules/@babel/generator/node_modules/@babel/parser": {
"version": "8.0.0-rc.5",
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-8.0.0-rc.5.tgz",
"integrity": "sha512-/Mfg83rK3+jsRbl4Vbd0jqxc6M1A1/WNFtgrowRM1unEsD3XcNnrBdMM0JWakd0/RN9lseQKwPduW1TiEwKOlQ==",
"license": "MIT",
"dependencies": {
"@babel/types": "^8.0.0-rc.5"
},
"bin": {
"parser": "bin/babel-parser.js"
},
"engines": {
"node": "^22.18.0 || >=24.11.0"
}
},
"node_modules/@babel/generator/node_modules/@babel/types": {
"version": "8.0.0-rc.5",
"resolved": "https://registry.npmjs.org/@babel/types/-/types-8.0.0-rc.5.tgz",
"integrity": "sha512-JeSVu/m8x/zpp4CLjYHVNXuhEyOkhPXuxM8YOXjh6L4LlvQNKuUNOTo5KdBuKAcTDHw8DquToTaEkhsBqPXOaA==",
"license": "MIT",
"dependencies": {
"@babel/helper-string-parser": "^8.0.0-rc.5",
"@babel/helper-validator-identifier": "^8.0.0-rc.5"
},
"engines": {
"node": "^22.18.0 || >=24.11.0"
}
},
"node_modules/@babel/helper-string-parser": {
"version": "7.27.1",
"resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz",
@@ -177,30 +114,11 @@
"tslib": "^2.4.0"
}
},
"node_modules/@jridgewell/gen-mapping": {
"version": "0.3.13",
"resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz",
"integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==",
"license": "MIT",
"dependencies": {
"@jridgewell/sourcemap-codec": "^1.5.0",
"@jridgewell/trace-mapping": "^0.3.24"
}
},
"node_modules/@jridgewell/remapping": {
"version": "2.3.5",
"resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz",
"integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==",
"license": "MIT",
"dependencies": {
"@jridgewell/gen-mapping": "^0.3.5",
"@jridgewell/trace-mapping": "^0.3.24"
}
},
"node_modules/@jridgewell/resolve-uri": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz",
"integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=6.0.0"
@@ -216,6 +134,7 @@
"version": "0.3.31",
"resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz",
"integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==",
"dev": true,
"license": "MIT",
"dependencies": {
"@jridgewell/resolve-uri": "^3.1.0",
@@ -568,12 +487,6 @@
"dev": true,
"license": "MIT"
},
"node_modules/@types/jsesc": {
"version": "2.5.1",
"resolved": "https://registry.npmjs.org/@types/jsesc/-/jsesc-2.5.1.tgz",
"integrity": "sha512-9VN+6yxLOPLOav+7PwjZbxiID2bVaeq0ED4qSQmdQTdjnXJSaCVKTR58t15oqH1H5t8Ng2ZX1SabJVoN9Q34bw==",
"license": "MIT"
},
"node_modules/@vitejs/plugin-vue": {
"version": "6.0.7",
"resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-6.0.7.tgz",
@@ -802,33 +715,6 @@
"vscode-uri": "^3.0.8"
}
},
"node_modules/@vue-macros/common": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/@vue-macros/common/-/common-3.1.2.tgz",
"integrity": "sha512-h9t4ArDdniO9ekYHAD95t9AZcAbb19lEGK+26iAjUODOIJKmObDNBSe4+6ELQAA3vtYiFPPBtHh7+cQCKi3Dng==",
"license": "MIT",
"dependencies": {
"@vue/compiler-sfc": "^3.5.22",
"ast-kit": "^2.1.2",
"local-pkg": "^1.1.2",
"magic-string-ast": "^1.0.2",
"unplugin-utils": "^0.3.0"
},
"engines": {
"node": ">=20.19.0"
},
"funding": {
"url": "https://github.com/sponsors/vue-macros"
},
"peerDependencies": {
"vue": "^2.7.0 || ^3.2.25"
},
"peerDependenciesMeta": {
"vue": {
"optional": true
}
}
},
"node_modules/@vue/compiler-core": {
"version": "3.5.34",
"resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.34.tgz",
@@ -880,62 +766,11 @@
}
},
"node_modules/@vue/devtools-api": {
"version": "8.1.2",
"resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-8.1.2.tgz",
"integrity": "sha512-vA0O112YqyDuNA1s7Yb2gCgToQ/OxOWiFDO5ThLCcDy0ldHnSd1dUTaSYhOldbqoNgumE4dxtGAoAaSUKUD1Zg==",
"license": "MIT",
"dependencies": {
"@vue/devtools-kit": "^8.1.2"
}
},
"node_modules/@vue/devtools-api/node_modules/@vue/devtools-kit": {
"version": "8.1.2",
"resolved": "https://registry.npmjs.org/@vue/devtools-kit/-/devtools-kit-8.1.2.tgz",
"integrity": "sha512-f75/upc+GCyjXErpgPGz4582ujS0L/adAltGy+tqXMGUJpgAcfGr6CxnnhpZY8BHuMYt6KpbF8uaFrrQG66rGQ==",
"license": "MIT",
"dependencies": {
"@vue/devtools-shared": "^8.1.2",
"birpc": "^2.6.1",
"hookable": "^5.5.3",
"perfect-debounce": "^2.0.0"
}
},
"node_modules/@vue/devtools-api/node_modules/@vue/devtools-shared": {
"version": "8.1.2",
"resolved": "https://registry.npmjs.org/@vue/devtools-shared/-/devtools-shared-8.1.2.tgz",
"integrity": "sha512-X9RyVFYAdkBe4IUf5v48TxBF/6QPmF8CmWrDAjXzfUHrgQ/HGfTC1A6TqgXqZ03ye66l3AD51BAGD69IvKM9sw==",
"version": "6.6.4",
"resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-6.6.4.tgz",
"integrity": "sha512-sGhTPMuXqZ1rVOk32RylztWkfXTRhuS7vgAKv0zjqk8gbsHkJ7xfFf+jbySxt7tWObEJwyKaHMikV/WGDiQm8g==",
"license": "MIT"
},
"node_modules/@vue/devtools-api/node_modules/perfect-debounce": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/perfect-debounce/-/perfect-debounce-2.1.0.tgz",
"integrity": "sha512-LjgdTytVFXeUgtHZr9WYViYSM/g8MkcTPYDlPa3cDqMirHjKiSZPYd6DoL7pK8AJQr+uWkQvCjHNdiMqsrJs+g==",
"license": "MIT"
},
"node_modules/@vue/devtools-kit": {
"version": "7.7.9",
"resolved": "https://registry.npmjs.org/@vue/devtools-kit/-/devtools-kit-7.7.9.tgz",
"integrity": "sha512-PyQ6odHSgiDVd4hnTP+aDk2X4gl2HmLDfiyEnn3/oV+ckFDuswRs4IbBT7vacMuGdwY/XemxBoh302ctbsptuA==",
"license": "MIT",
"dependencies": {
"@vue/devtools-shared": "^7.7.9",
"birpc": "^2.3.0",
"hookable": "^5.5.3",
"mitt": "^3.0.1",
"perfect-debounce": "^1.0.0",
"speakingurl": "^14.0.1",
"superjson": "^2.2.2"
}
},
"node_modules/@vue/devtools-shared": {
"version": "7.7.9",
"resolved": "https://registry.npmjs.org/@vue/devtools-shared/-/devtools-shared-7.7.9.tgz",
"integrity": "sha512-iWAb0v2WYf0QWmxCGy0seZNDPdO3Sp5+u78ORnyeonS6MT4PC7VPrryX2BpMJrwlDeaZ6BD4vP4XKjK0SZqaeA==",
"license": "MIT",
"dependencies": {
"rfdc": "^1.4.1"
}
},
"node_modules/@vue/language-core": {
"version": "3.3.1",
"resolved": "https://registry.npmjs.org/@vue/language-core/-/language-core-3.3.1.tgz",
@@ -1021,18 +856,6 @@
}
}
},
"node_modules/acorn": {
"version": "8.16.0",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz",
"integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==",
"license": "MIT",
"bin": {
"acorn": "bin/acorn"
},
"engines": {
"node": ">=0.4.0"
}
},
"node_modules/alien-signals": {
"version": "3.2.1",
"resolved": "https://registry.npmjs.org/alien-signals/-/alien-signals-3.2.1.tgz",
@@ -1051,22 +874,6 @@
"node": ">=12"
}
},
"node_modules/ast-kit": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/ast-kit/-/ast-kit-2.2.0.tgz",
"integrity": "sha512-m1Q/RaVOnTp9JxPX+F+Zn7IcLYMzM8kZofDImfsKZd8MbR+ikdOzTeztStWqfrqIxZnYWryyI9ePm3NGjnZgGw==",
"license": "MIT",
"dependencies": {
"@babel/parser": "^7.28.5",
"pathe": "^2.0.3"
},
"engines": {
"node": ">=20.19.0"
},
"funding": {
"url": "https://github.com/sponsors/sxzz"
}
},
"node_modules/ast-v8-to-istanbul": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/ast-v8-to-istanbul/-/ast-v8-to-istanbul-1.0.0.tgz",
@@ -1089,31 +896,6 @@
"@types/estree": "^1.0.0"
}
},
"node_modules/ast-walker-scope": {
"version": "0.8.3",
"resolved": "https://registry.npmjs.org/ast-walker-scope/-/ast-walker-scope-0.8.3.tgz",
"integrity": "sha512-cbdCP0PGOBq0ASG+sjnKIoYkWMKhhz+F/h9pRexUdX2Hd38+WOlBkRKlqkGOSm0YQpcFMQBJeK4WspUAkwsEdg==",
"license": "MIT",
"dependencies": {
"@babel/parser": "^7.28.4",
"ast-kit": "^2.1.3"
},
"engines": {
"node": ">=20.19.0"
},
"funding": {
"url": "https://github.com/sponsors/sxzz"
}
},
"node_modules/birpc": {
"version": "2.9.0",
"resolved": "https://registry.npmjs.org/birpc/-/birpc-2.9.0.tgz",
"integrity": "sha512-KrayHS5pBi69Xi9JmvoqrIgYGDkD6mcSe/i6YKi3w5kekCLzrX4+nawcXqrj2tIp50Kw/mT/s3p+GVK0A0sKxw==",
"license": "MIT",
"funding": {
"url": "https://github.com/sponsors/antfu"
}
},
"node_modules/chai": {
"version": "6.2.2",
"resolved": "https://registry.npmjs.org/chai/-/chai-6.2.2.tgz",
@@ -1125,27 +907,6 @@
"node": ">=18"
}
},
"node_modules/chokidar": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-5.0.0.tgz",
"integrity": "sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==",
"license": "MIT",
"dependencies": {
"readdirp": "^5.0.0"
},
"engines": {
"node": ">= 20.19.0"
},
"funding": {
"url": "https://paulmillr.com/funding/"
}
},
"node_modules/confbox": {
"version": "0.2.4",
"resolved": "https://registry.npmjs.org/confbox/-/confbox-0.2.4.tgz",
"integrity": "sha512-ysOGlgTFbN2/Y6Cg3Iye8YKulHw+R2fNXHrgSmXISQdMnomY6eNDprVdW9R5xBguEqI954+S6709UyiO7B+6OQ==",
"license": "MIT"
},
"node_modules/convert-source-map": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz",
@@ -1153,21 +914,6 @@
"dev": true,
"license": "MIT"
},
"node_modules/copy-anything": {
"version": "4.0.5",
"resolved": "https://registry.npmjs.org/copy-anything/-/copy-anything-4.0.5.tgz",
"integrity": "sha512-7Vv6asjS4gMOuILabD3l739tsaxFQmC+a7pLZm02zyvs8p977bL3zEgq3yDk5rn9B0PbYgIv++jmHcuUab4RhA==",
"license": "MIT",
"dependencies": {
"is-what": "^5.2.0"
},
"engines": {
"node": ">=18"
},
"funding": {
"url": "https://github.com/sponsors/mesqueeb"
}
},
"node_modules/csstype": {
"version": "3.2.3",
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz",
@@ -1221,16 +967,11 @@
"node": ">=12.0.0"
}
},
"node_modules/exsolve": {
"version": "1.0.8",
"resolved": "https://registry.npmjs.org/exsolve/-/exsolve-1.0.8.tgz",
"integrity": "sha512-LmDxfWXwcTArk8fUEnOfSZpHOJ6zOMUJKOtFLFqJLoKJetuQG874Uc7/Kki7zFLzYybmZhp1M7+98pfMqeX8yA==",
"license": "MIT"
},
"node_modules/fdir": {
"version": "6.5.0",
"resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz",
"integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=12.0.0"
@@ -1283,12 +1024,6 @@
"node": ">=8"
}
},
"node_modules/hookable": {
"version": "5.5.3",
"resolved": "https://registry.npmjs.org/hookable/-/hookable-5.5.3.tgz",
"integrity": "sha512-Yc+BQe8SvoXH1643Qez1zqLRmbA5rCL+sSmk6TVos0LWVfNIB7PGncdlId77WzLGSIB5KaWgTaNTs2lNVEI6VQ==",
"license": "MIT"
},
"node_modules/html-escaper": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz",
@@ -1296,18 +1031,6 @@
"dev": true,
"license": "MIT"
},
"node_modules/is-what": {
"version": "5.5.0",
"resolved": "https://registry.npmjs.org/is-what/-/is-what-5.5.0.tgz",
"integrity": "sha512-oG7cgbmg5kLYae2N5IVd3jm2s+vldjxJzK1pcu9LfpGuQ93MQSzo0okvRna+7y5ifrD+20FE8FvjusyGaz14fw==",
"license": "MIT",
"engines": {
"node": ">=18"
},
"funding": {
"url": "https://github.com/sponsors/mesqueeb"
}
},
"node_modules/istanbul-lib-coverage": {
"version": "3.2.2",
"resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz",
@@ -1354,30 +1077,6 @@
"dev": true,
"license": "MIT"
},
"node_modules/jsesc": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz",
"integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==",
"license": "MIT",
"bin": {
"jsesc": "bin/jsesc"
},
"engines": {
"node": ">=6"
}
},
"node_modules/json5": {
"version": "2.2.3",
"resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz",
"integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==",
"license": "MIT",
"bin": {
"json5": "lib/cli.js"
},
"engines": {
"node": ">=6"
}
},
"node_modules/lightningcss": {
"version": "1.32.0",
"resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.32.0.tgz",
@@ -1639,23 +1338,6 @@
"url": "https://opencollective.com/parcel"
}
},
"node_modules/local-pkg": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/local-pkg/-/local-pkg-1.2.1.tgz",
"integrity": "sha512-++gUqRDEvcnN6Zhqrr+y/CkVEHhlrR96vZn3nZZPYzMcBUyBtTKzB9NadClFIsIVSsu+3i9tfk/erqy9kAmt7Q==",
"license": "MIT",
"dependencies": {
"mlly": "^1.7.4",
"pkg-types": "^2.3.0",
"quansync": "^0.2.11"
},
"engines": {
"node": ">=14"
},
"funding": {
"url": "https://github.com/sponsors/antfu"
}
},
"node_modules/magic-string": {
"version": "0.30.21",
"resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz",
@@ -1665,21 +1347,6 @@
"@jridgewell/sourcemap-codec": "^1.5.5"
}
},
"node_modules/magic-string-ast": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/magic-string-ast/-/magic-string-ast-1.0.3.tgz",
"integrity": "sha512-CvkkH1i81zl7mmb94DsRiFeG9V2fR2JeuK8yDgS8oiZSFa++wWLEgZ5ufEOyLHbvSbD1gTRKv9NdX69Rnvr9JA==",
"license": "MIT",
"dependencies": {
"magic-string": "^0.30.19"
},
"engines": {
"node": ">=20.19.0"
},
"funding": {
"url": "https://github.com/sponsors/sxzz"
}
},
"node_modules/magicast": {
"version": "0.5.2",
"resolved": "https://registry.npmjs.org/magicast/-/magicast-0.5.2.tgz",
@@ -1708,41 +1375,6 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/mitt": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/mitt/-/mitt-3.0.1.tgz",
"integrity": "sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==",
"license": "MIT"
},
"node_modules/mlly": {
"version": "1.8.2",
"resolved": "https://registry.npmjs.org/mlly/-/mlly-1.8.2.tgz",
"integrity": "sha512-d+ObxMQFmbt10sretNDytwt85VrbkhhUA/JBGm1MPaWJ65Cl4wOgLaB1NYvJSZ0Ef03MMEU/0xpPMXUIQ29UfA==",
"license": "MIT",
"dependencies": {
"acorn": "^8.16.0",
"pathe": "^2.0.3",
"pkg-types": "^1.3.1",
"ufo": "^1.6.3"
}
},
"node_modules/mlly/node_modules/confbox": {
"version": "0.1.8",
"resolved": "https://registry.npmjs.org/confbox/-/confbox-0.1.8.tgz",
"integrity": "sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==",
"license": "MIT"
},
"node_modules/mlly/node_modules/pkg-types": {
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-1.3.1.tgz",
"integrity": "sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==",
"license": "MIT",
"dependencies": {
"confbox": "^0.1.8",
"mlly": "^1.7.4",
"pathe": "^2.0.1"
}
},
"node_modules/mrmime": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/mrmime/-/mrmime-2.0.1.tgz",
@@ -1757,6 +1389,7 @@
"version": "0.4.1",
"resolved": "https://registry.npmjs.org/muggle-string/-/muggle-string-0.4.1.tgz",
"integrity": "sha512-VNTrAak/KhO2i8dqqnqnAHOa3cYBwXEZe9h+D5h/1ZqFSTEFHdM65lR7RoIqq3tBBYavsOXV84NoHXZ0AkPyqQ==",
"dev": true,
"license": "MIT"
},
"node_modules/nanoid": {
@@ -1799,12 +1432,7 @@
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz",
"integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==",
"license": "MIT"
},
"node_modules/perfect-debounce": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/perfect-debounce/-/perfect-debounce-1.0.0.tgz",
"integrity": "sha512-xCy9V055GLEqoFaHoC1SoLIaLmWctgCUaBaWxDZ7/Zx4CTyX7cJQLJOok/orfjZAh9kEYpjJa4d0KcJmCbctZA==",
"dev": true,
"license": "MIT"
},
"node_modules/picocolors": {
@@ -1817,6 +1445,7 @@
"version": "4.0.4",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz",
"integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=12"
@@ -1826,19 +1455,20 @@
}
},
"node_modules/pinia": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/pinia/-/pinia-3.0.4.tgz",
"integrity": "sha512-l7pqLUFTI/+ESXn6k3nu30ZIzW5E2WZF/LaHJEpoq6ElcLD+wduZoB2kBN19du6K/4FDpPMazY2wJr+IndBtQw==",
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/pinia/-/pinia-2.3.1.tgz",
"integrity": "sha512-khUlZSwt9xXCaTbbxFYBKDc/bWAGWJjOgvxETwkTN7KRm66EeT1ZdZj6i2ceh9sP2Pzqsbc704r2yngBrxBVug==",
"license": "MIT",
"dependencies": {
"@vue/devtools-api": "^7.7.7"
"@vue/devtools-api": "^6.6.3",
"vue-demi": "^0.14.10"
},
"funding": {
"url": "https://github.com/sponsors/posva"
},
"peerDependencies": {
"typescript": ">=4.5.0",
"vue": "^3.5.11"
"typescript": ">=4.4.4",
"vue": "^2.7.0 || ^3.5.11"
},
"peerDependenciesMeta": {
"typescript": {
@@ -1846,26 +1476,6 @@
}
}
},
"node_modules/pinia/node_modules/@vue/devtools-api": {
"version": "7.7.9",
"resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-7.7.9.tgz",
"integrity": "sha512-kIE8wvwlcZ6TJTbNeU2HQNtaxLx3a84aotTITUuL/4bzfPxzajGBOoqjMhwZJ8L9qFYDU/lAYMEEm11dnZOD6g==",
"license": "MIT",
"dependencies": {
"@vue/devtools-kit": "^7.7.9"
}
},
"node_modules/pkg-types": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-2.3.1.tgz",
"integrity": "sha512-y+ichcgc2LrADuhLNAx8DFjVfgz91pRxfZdI3UDhxHvcVEZsenLO+7XaU5vOp0u/7V/wZ+plyuQxtrDlZJ+yeg==",
"license": "MIT",
"dependencies": {
"confbox": "^0.2.4",
"exsolve": "^1.0.8",
"pathe": "^2.0.3"
}
},
"node_modules/postcss": {
"version": "8.5.15",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.15.tgz",
@@ -1894,41 +1504,6 @@
"node": "^10 || ^12 || >=14"
}
},
"node_modules/quansync": {
"version": "0.2.11",
"resolved": "https://registry.npmjs.org/quansync/-/quansync-0.2.11.tgz",
"integrity": "sha512-AifT7QEbW9Nri4tAwR5M/uzpBuqfZf+zwaEM/QkzEjj7NBuFD2rBuy0K3dE+8wltbezDV7JMA0WfnCPYRSYbXA==",
"funding": [
{
"type": "individual",
"url": "https://github.com/sponsors/antfu"
},
{
"type": "individual",
"url": "https://github.com/sponsors/sxzz"
}
],
"license": "MIT"
},
"node_modules/readdirp": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-5.0.0.tgz",
"integrity": "sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ==",
"license": "MIT",
"engines": {
"node": ">= 20.19.0"
},
"funding": {
"type": "individual",
"url": "https://paulmillr.com/funding/"
}
},
"node_modules/rfdc": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.4.1.tgz",
"integrity": "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==",
"license": "MIT"
},
"node_modules/rolldown": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.0.1.tgz",
@@ -1963,12 +1538,6 @@
"@rolldown/binding-win32-x64-msvc": "1.0.1"
}
},
"node_modules/scule": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/scule/-/scule-1.3.0.tgz",
"integrity": "sha512-6FtHJEvt+pVMIB9IBY+IcCJ6Z5f1iQnytgyfKMhDKgmzYG+TeH/wx1y3l27rshSbLiSanrR9ffZDrEsmjlQF2g==",
"license": "MIT"
},
"node_modules/semver": {
"version": "7.7.4",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz",
@@ -2014,15 +1583,6 @@
"node": ">=0.10.0"
}
},
"node_modules/speakingurl": {
"version": "14.0.1",
"resolved": "https://registry.npmjs.org/speakingurl/-/speakingurl-14.0.1.tgz",
"integrity": "sha512-1POYv7uv2gXoyGFpBCmpDVSNV74IfsWlDW216UPjbWufNf+bSU6GdbDsxdcxtfwb4xlI3yxzOTKClUosxARYrQ==",
"license": "BSD-3-Clause",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/stackback": {
"version": "0.0.2",
"resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz",
@@ -2038,18 +1598,6 @@
"dev": true,
"license": "MIT"
},
"node_modules/superjson": {
"version": "2.2.6",
"resolved": "https://registry.npmjs.org/superjson/-/superjson-2.2.6.tgz",
"integrity": "sha512-H+ue8Zo4vJmV2nRjpx86P35lzwDT3nItnIsocgumgr0hHMQ+ZGq5vrERg9kJBo5AWGmxZDhzDo+WVIJqkB0cGA==",
"license": "MIT",
"dependencies": {
"copy-anything": "^4"
},
"engines": {
"node": ">=16"
}
},
"node_modules/supports-color": {
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
@@ -2086,6 +1634,7 @@
"version": "0.2.16",
"resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.16.tgz",
"integrity": "sha512-pn99VhoACYR8nFHhxqix+uvsbXineAasWm5ojXoN8xEwK5Kd3/TrhNn1wByuD52UxWRLy8pu+kRMniEi6Eq9Zg==",
"dev": true,
"license": "MIT",
"dependencies": {
"fdir": "^6.5.0",
@@ -2140,42 +1689,6 @@
"node": ">=14.17"
}
},
"node_modules/ufo": {
"version": "1.6.4",
"resolved": "https://registry.npmjs.org/ufo/-/ufo-1.6.4.tgz",
"integrity": "sha512-JFNbkD1Svwe0KvGi8GOeLcP4kAWQ609twvCdcHxq1oSL8svv39ZuSvajcD8B+5D0eL4+s1Is2D/O6KN3qcTeRA==",
"license": "MIT"
},
"node_modules/unplugin": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/unplugin/-/unplugin-3.0.0.tgz",
"integrity": "sha512-0Mqk3AT2TZCXWKdcoaufeXNukv2mTrEZExeXlHIOZXdqYoHHr4n51pymnwV8x2BOVxwXbK2HLlI7usrqMpycdg==",
"license": "MIT",
"dependencies": {
"@jridgewell/remapping": "^2.3.5",
"picomatch": "^4.0.3",
"webpack-virtual-modules": "^0.6.2"
},
"engines": {
"node": "^20.19.0 || >=22.12.0"
}
},
"node_modules/unplugin-utils": {
"version": "0.3.1",
"resolved": "https://registry.npmjs.org/unplugin-utils/-/unplugin-utils-0.3.1.tgz",
"integrity": "sha512-5lWVjgi6vuHhJ526bI4nlCOmkCIF3nnfXkCMDeMJrtdvxTs6ZFCM8oNufGTsDbKv/tJ/xj8RpvXjRuPBZJuJog==",
"license": "MIT",
"dependencies": {
"pathe": "^2.0.3",
"picomatch": "^4.0.3"
},
"engines": {
"node": ">=20.19.0"
},
"funding": {
"url": "https://github.com/sponsors/sxzz"
}
},
"node_modules/vite": {
"version": "8.0.13",
"resolved": "https://registry.npmjs.org/vite/-/vite-8.0.13.tgz",
@@ -2373,49 +1886,45 @@
}
}
},
"node_modules/vue-demi": {
"version": "0.14.10",
"resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.14.10.tgz",
"integrity": "sha512-nMZBOwuzabUO0nLgIcc6rycZEebF6eeUfaiQx9+WSk8e29IbLvPU9feI6tqW4kTo3hvoYAJkMh8n8D0fuISphg==",
"hasInstallScript": true,
"license": "MIT",
"bin": {
"vue-demi-fix": "bin/vue-demi-fix.js",
"vue-demi-switch": "bin/vue-demi-switch.js"
},
"engines": {
"node": ">=12"
},
"funding": {
"url": "https://github.com/sponsors/antfu"
},
"peerDependencies": {
"@vue/composition-api": "^1.0.0-rc.1",
"vue": "^3.0.0-0 || ^2.6.0"
},
"peerDependenciesMeta": {
"@vue/composition-api": {
"optional": true
}
}
},
"node_modules/vue-router": {
"version": "5.0.7",
"resolved": "https://registry.npmjs.org/vue-router/-/vue-router-5.0.7.tgz",
"integrity": "sha512-dqfk8kvRbCutmCOCj/XLDqDEYxc1wBdAOGLuVy5M93ifYMsBd5fIjfaPN4tQAbxr5IprdBDIox1gr4wYyOx/SA==",
"version": "4.6.4",
"resolved": "https://registry.npmjs.org/vue-router/-/vue-router-4.6.4.tgz",
"integrity": "sha512-Hz9q5sa33Yhduglwz6g9skT8OBPii+4bFn88w6J+J4MfEo4KRRpmiNG/hHHkdbRFlLBOqxN8y8gf2Fb0MTUgVg==",
"license": "MIT",
"dependencies": {
"@babel/generator": "^8.0.0-rc.4",
"@vue-macros/common": "^3.1.1",
"@vue/devtools-api": "^8.1.1",
"ast-walker-scope": "^0.8.3",
"chokidar": "^5.0.0",
"json5": "^2.2.3",
"local-pkg": "^1.1.2",
"magic-string": "^0.30.21",
"mlly": "^1.8.0",
"muggle-string": "^0.4.1",
"pathe": "^2.0.3",
"picomatch": "^4.0.3",
"scule": "^1.3.0",
"tinyglobby": "^0.2.15",
"unplugin": "^3.0.0",
"unplugin-utils": "^0.3.1",
"yaml": "^2.8.2"
"@vue/devtools-api": "^6.6.4"
},
"funding": {
"url": "https://github.com/sponsors/posva"
},
"peerDependencies": {
"@pinia/colada": ">=0.21.2",
"@vue/compiler-sfc": "^3.5.34",
"pinia": "^3.0.4",
"vue": "^3.5.34"
},
"peerDependenciesMeta": {
"@pinia/colada": {
"optional": true
},
"@vue/compiler-sfc": {
"optional": true
},
"pinia": {
"optional": true
}
"vue": "^3.5.0"
}
},
"node_modules/vue-tsc": {
@@ -2462,12 +1971,6 @@
}
}
},
"node_modules/webpack-virtual-modules": {
"version": "0.6.2",
"resolved": "https://registry.npmjs.org/webpack-virtual-modules/-/webpack-virtual-modules-0.6.2.tgz",
"integrity": "sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ==",
"license": "MIT"
},
"node_modules/why-is-node-running": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.3.0.tgz",
@@ -2485,21 +1988,6 @@
"engines": {
"node": ">=8"
}
},
"node_modules/yaml": {
"version": "2.9.0",
"resolved": "https://registry.npmjs.org/yaml/-/yaml-2.9.0.tgz",
"integrity": "sha512-2AvhNX3mb8zd6Zy7INTtSpl1F15HW6Wnqj0srWlkKLcpYl/gMIMJiyuGq2KeI2YFxUPjdlB+3Lc10seMLtL4cA==",
"license": "ISC",
"bin": {
"yaml": "bin.mjs"
},
"engines": {
"node": ">= 14.6"
},
"funding": {
"url": "https://github.com/sponsors/eemeli"
}
}
}
}

View File

@@ -18,9 +18,9 @@
"test:coverage": "vitest run --coverage --config tests/js/vitest.config.ts"
},
"dependencies": {
"pinia": "^3.0.0",
"pinia": "^2.3.1",
"vue": "^3.5.18",
"vue-router": "^5.0.0",
"vue-router": "^4.5.1",
"vuetify": "^4.0.0"
},
"devDependencies": {

View File

@@ -2,7 +2,7 @@
* Entity management service
*/
import { transceivePost, transceiveStream, transceiveDownload } from './transceive';
import { transceivePost, transceiveStream } from './transceive';
import type {
EntityFetchRequest,
EntityFetchResponse,
@@ -27,7 +27,6 @@ import type {
EntityListBulkRequest,
EntityPatchResponse,
EntityPatchRequest,
EntityDownloadRequest,
} from '../types/entity';
import { useIntegrationStore } from '@KTXC/stores/integrationStore';
import { EntityObject } from '../models';
@@ -111,7 +110,7 @@ export const entityService = {
// Convert response to EntityObject instances
const list: Record<string, EntityObject> = {};
Object.entries(response).forEach(([, entity]) => {
Object.entries(response).forEach(([identifier, entity]) => {
list[entity.identifier] = createEntityObject(entity);
});
@@ -217,16 +216,6 @@ export const entityService = {
async transmit(request: EntityTransmitRequest): Promise<EntityTransmitResponse> {
return await transceivePost<EntityTransmitRequest, EntityTransmitResponse>('entity.transmit', request);
},
/**
* Submit a browser-native attachment download request.
*
* The backend download endpoint is expected to honor the supplied selector
* and respond with an attachment payload rather than JSON.
*/
download(request: EntityDownloadRequest): { transaction: string } {
return transceiveDownload<EntityDownloadRequest>('entity.download', request);
},
};
export default entityService;

View File

@@ -141,84 +141,3 @@ export async function transceiveStream<TRequest, TData>(
return { total };
}
/**
* Submit a browser-native file download request via a top-level form POST.
*
* This avoids buffering the response body in application-managed JavaScript
* memory. The backend is expected to accept form fields where `data` contains
* the serialized operation payload and to return an attachment response.
*/
export function transceiveDownload<TRequest>(
operation: string,
data: TRequest,
user?: string,
): { transaction: string } {
if (typeof document === 'undefined' || typeof window === 'undefined') {
throw new Error('Browser window is not available for download submission');
}
const request: ApiRequest<TRequest> = {
version: API_VERSION,
transaction: generateTransactionId(),
operation,
data,
user,
};
const form = document.createElement('form');
form.method = 'POST';
form.action = API_URL;
form.target = '_blank';
form.style.display = 'none';
appendHiddenField(form, 'version', String(request.version));
appendHiddenField(form, 'transaction', request.transaction);
appendHiddenField(form, 'operation', request.operation);
appendFormValue(form, 'data', request.data);
if (request.user) {
appendHiddenField(form, 'user', request.user);
}
document.body.appendChild(form);
form.submit();
form.remove();
return { transaction: request.transaction };
}
function appendHiddenField(form: HTMLFormElement, name: string, value: string): void {
const input = document.createElement('input');
input.type = 'hidden';
input.name = name;
input.value = value;
form.appendChild(input);
}
function appendFormValue(form: HTMLFormElement, name: string, value: unknown): void {
if (value === undefined) {
return;
}
if (value === null) {
appendHiddenField(form, name, '');
return;
}
if (Array.isArray(value)) {
value.forEach((item, index) => {
appendFormValue(form, `${name}[${index}]`, item);
});
return;
}
if (typeof value === 'object') {
Object.entries(value as Record<string, unknown>).forEach(([key, nestedValue]) => {
appendFormValue(form, `${name}[${key}]`, nestedValue);
});
return;
}
appendHiddenField(form, name, String(value));
}

View File

@@ -7,8 +7,7 @@ import { defineStore } from 'pinia'
import { entityService } from '../services'
import { EntityObject, MessageObject } from '../models'
import type {
EntityBlobSelector,
EntityDownloadRequest,
EntityListStreamRequest,
EntityTransmitRequest,
EntityTransmitResponse,
} from '../types/entity'
@@ -19,7 +18,7 @@ import type {
ListRange,
ListSort,
} from '../types/common'
import type { MessageInterface, MessagePartInterface } from '@/types/message'
import type { MessageInterface } from '@/types/message'
export const useEntitiesStore = defineStore('mailEntitiesStore', () => {
// State
@@ -185,15 +184,15 @@ export const useEntitiesStore = defineStore('mailEntitiesStore', () => {
const response = await entityService.delta({ sources })
// Process delta and update store
Object.entries(response).forEach(([, providerData]) => {
Object.entries(response).forEach(([provider, providerData]) => {
// Skip if no changes for provider
if (providerData === false) return
Object.entries(providerData).forEach(([, serviceData]) => {
Object.entries(providerData).forEach(([service, serviceData]) => {
// Skip if no changes for service
if (serviceData === false) return
Object.entries(serviceData).forEach(([, collectionData]) => {
Object.entries(serviceData).forEach(([collection, collectionData]) => {
// Skip if no changes for collection
if (collectionData === false) return
@@ -475,39 +474,6 @@ export const useEntitiesStore = defineStore('mailEntitiesStore', () => {
}
}
async function download(target: EntityIdentifier, part?: Partial<MessagePartInterface>) {
let targetPart: EntityBlobSelector | undefined = undefined
if (part && (part.blobId || part.partId || part.cid)) {
targetPart = {
blobId: part.blobId ?? undefined,
partId: part.partId ?? undefined,
cid: part.cid ?? undefined,
}
}
let filename: string
if (part && part.name && part.name.trim().length > 0) {
filename = part.name.trim()
} else if (part) {
filename = `attachment-${part.partId || part.blobId || part.cid || 'unknown'}`
} else {
filename = 'message.eml'
}
const request: EntityDownloadRequest = {
target,
part: targetPart,
filename,
}
try {
entityService.download(request)
} catch (error: any) {
console.error('[Mail Manager][Store] - Failed to submit attachment download:', error)
throw error
}
}
// Return public API
return {
// State (readonly)
@@ -529,6 +495,5 @@ export const useEntitiesStore = defineStore('mailEntitiesStore', () => {
delta,
move,
transmit,
download,
}
})

View File

@@ -205,32 +205,4 @@ export interface EntityTransmitRequest {
export interface EntityTransmitResponse {
id: string;
status: 'queued' | 'sent';
}
/**
* Entity Blob Fetch
*/
export interface EntityBlobSelector {
blobId?: string;
partId?: string;
cid?: string;
}
export interface EntityDownloadRequest {
target: EntityIdentifier;
part?: EntityBlobSelector;
filename?: string | null;
}
export interface EntityBlobsRequest {
target: EntityIdentifier;
parts: EntityBlobSelector[];
}
export interface EntityBlobsResult {
source: EntityIdentifier;
part: EntityBlobSelector;
blob: Blob;
}
export interface EntityBlobsResponse extends Array<EntityBlobsResult> {}
}