@ai-matrx/data 0.19.2 → 0.21.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +24 -0
- package/dist/files/tus.cjs +245 -0
- package/dist/files/tus.cjs.map +1 -0
- package/dist/files/tus.d.cts +106 -0
- package/dist/files/tus.d.ts +106 -0
- package/dist/files/tus.js +214 -0
- package/dist/files/tus.js.map +1 -0
- package/dist/files.cjs +47 -5
- package/dist/files.cjs.map +1 -1
- package/dist/files.d.cts +70 -3
- package/dist/files.d.ts +70 -3
- package/dist/files.js +47 -5
- package/dist/files.js.map +1 -1
- package/package.json +12 -1
package/dist/files.d.cts
CHANGED
|
@@ -381,7 +381,14 @@ interface FileUrls {
|
|
|
381
381
|
* `?inline=1` matches the exact spelling the backend emits on
|
|
382
382
|
* `FileRecord.url`, keeping cache keys identical either way.
|
|
383
383
|
*/
|
|
384
|
-
declare function
|
|
384
|
+
declare function buildFileUrls(filesBaseUrl: string, fileId: string): FileUrls;
|
|
385
|
+
/**
|
|
386
|
+
* @deprecated Renamed {@link buildFileUrls} (architecture step 14): `fileUrls(fileId)`
|
|
387
|
+
* is the ONE caller-facing signature — the host-bound builder in
|
|
388
|
+
* `@ai-matrx/media/files/engine/handler/utils/python-base`. This alias keeps a
|
|
389
|
+
* `latest` media build working for one release and is then removed.
|
|
390
|
+
*/
|
|
391
|
+
declare const fileUrls: typeof buildFileUrls;
|
|
385
392
|
/**
|
|
386
393
|
* The clean public byte-streaming share endpoint (`GET /share/{token}`,
|
|
387
394
|
* inline disposition) — the canonical embeddable URL for a minted link.
|
|
@@ -563,7 +570,7 @@ declare function createMatrxFilesClient<TSrc extends string = DurableSrc>(config
|
|
|
563
570
|
* panels — this module never logs.
|
|
564
571
|
*/
|
|
565
572
|
|
|
566
|
-
type FileErrorCode = "access_denied" | "not_found" | "deleted" | "share_link_invalid" | "external_fetch_failed" | "upload_failed" | "internal";
|
|
573
|
+
type FileErrorCode = "access_denied" | "not_found" | "deleted" | "share_link_invalid" | "external_fetch_failed" | "cors_blocked" | "mime_unknown" | "upload_failed" | "upload_cancelled" | "quota_exceeded" | "in_flight" | "internal";
|
|
567
574
|
declare class FileError extends Error {
|
|
568
575
|
readonly code: FileErrorCode;
|
|
569
576
|
readonly fileId?: string | undefined;
|
|
@@ -615,6 +622,66 @@ declare function fileErrorFromStatus(status: number, fileId?: string): FileError
|
|
|
615
622
|
*/
|
|
616
623
|
declare function classifyUnavailable(err: unknown): MediaUnavailableReason;
|
|
617
624
|
|
|
625
|
+
/**
|
|
626
|
+
* Upload dedup guard — one in-flight/just-landed claim per (folder, name, size).
|
|
627
|
+
* Origin: @ai-matrx/media files/engine/upload/uploadDedupGuard.ts (architecture step 14).
|
|
628
|
+
*
|
|
629
|
+
* Root cause (`common-docs/projects/acquisition-frontier/own-files/VERIFICATION.md`
|
|
630
|
+
* §12, 2026-09-18): in a 7-file pile, both zero-byte files were uploaded
|
|
631
|
+
* TWICE, 18s apart, the second auto-renamed "(1)" by `uniqueName()` in
|
|
632
|
+
* `features/files/redux/thunks.ts` — right after the dev server had refused
|
|
633
|
+
* connections. A client-side retry of the whole `uploadFiles()` dispatch
|
|
634
|
+
* after a transient failure re-sends a file whose first attempt may already
|
|
635
|
+
* have landed server-side (the client only knows its OWN request failed —
|
|
636
|
+
* a connection reset gives no proof the server never received the bytes).
|
|
637
|
+
*
|
|
638
|
+
* The obvious fix is the backend's OWN `X-Idempotency-Key` mechanism
|
|
639
|
+
* (`lib/python-client.ts` already sends it, `aidream` already stores it in
|
|
640
|
+
* `metadata._idempotency_key`) — but it is not the full answer here: the
|
|
641
|
+
* key is only reused *within* a single `uploadFiles()` dispatch
|
|
642
|
+
* (`newRequestId()` mints a fresh one per worker() call in thunks.ts), and
|
|
643
|
+
* server-side `_replayable_412` in `aidream/aidream/api/routers/files/__init__.py`
|
|
644
|
+
* only replays a 412 (precondition-failed) response under the key — a
|
|
645
|
+
* SUCCESSFUL upload is never deduped by the server on replay. So a second,
|
|
646
|
+
* independent `uploadFiles()` dispatch for the same intended file — the
|
|
647
|
+
* shape a caller-level retry takes — is indistinguishable from a genuinely
|
|
648
|
+
* new upload to both client and server.
|
|
649
|
+
*
|
|
650
|
+
* This guard closes the gap client-side, per (folder, name, size): the
|
|
651
|
+
* FIRST claim for a signature performs the real network request; any
|
|
652
|
+
* SECOND claim for the same signature while that request is still in
|
|
653
|
+
* flight, or shortly after it landed, reuses the first attempt's outcome
|
|
654
|
+
* instead of sending the bytes again. A claim that ends in failure is
|
|
655
|
+
* cleared immediately, so a genuine "it never landed, please retry" case is
|
|
656
|
+
* never blocked — only a request whose outcome is still pending, or already
|
|
657
|
+
* known-good, is deduped.
|
|
658
|
+
*/
|
|
659
|
+
interface DedupedUploadOutcome {
|
|
660
|
+
fileId: string;
|
|
661
|
+
filePath: string;
|
|
662
|
+
}
|
|
663
|
+
/** The dedup key: same folder, same original name, same byte count. */
|
|
664
|
+
declare function uploadDedupKey(folderPath: string, fileName: string, fileSize: number): string;
|
|
665
|
+
type UploadClaim = {
|
|
666
|
+
shared: true;
|
|
667
|
+
promise: Promise<DedupedUploadOutcome>;
|
|
668
|
+
} | {
|
|
669
|
+
shared: false;
|
|
670
|
+
/**
|
|
671
|
+
* The caller that owns this claim MUST call `settle` exactly once
|
|
672
|
+
* with the real upload's outcome (or a rejected promise on failure).
|
|
673
|
+
*/
|
|
674
|
+
settle: (outcome: Promise<DedupedUploadOutcome>) => void;
|
|
675
|
+
};
|
|
676
|
+
/**
|
|
677
|
+
* Claim a signature before starting an upload. See module doc for the
|
|
678
|
+
* contract: a `shared: true` result means someone else already owns this
|
|
679
|
+
* signature — await its `promise` instead of sending the file again.
|
|
680
|
+
*/
|
|
681
|
+
declare function claimUpload(key: string): UploadClaim;
|
|
682
|
+
/** Test-only: clears every claim so suites don't leak state between tests. */
|
|
683
|
+
declare function __resetUploadDedupGuardForTests(): void;
|
|
684
|
+
|
|
618
685
|
/**
|
|
619
686
|
* @ai-matrx/data/files — the `mx_files_session` cookie bootstrap.
|
|
620
687
|
*
|
|
@@ -683,4 +750,4 @@ interface FilesSession {
|
|
|
683
750
|
}
|
|
684
751
|
declare function createFilesSession(options: FilesSessionOptions): FilesSession;
|
|
685
752
|
|
|
686
|
-
export { type BlobCacheEntry, type BlobCachePort, type DurableSrc, ExternalFetchError, FileAccessDeniedError, FileDeletedError, FileError, type FileErrorCode, type FileMetadata, type FileMetadataPort, FileNotFoundError, type FileOrigins, type FileRecordWire, type FileSessionResponseWire, type FileShownTo, FileUploadError, type FileUploadResponseWire, type FileUrlRecognizer, type FileUrls, type FilesBlobHandle, type FilesDiagnosticsEvent, type FilesDiagnosticsSink, type FilesRecoveryReport, type FilesRecoveryVerdict, type FilesResolution, type FilesSession, type FilesSessionOptions, type FilesSessionSnapshot, type MatrxFilesClient, type MatrxFilesClientConfig, type MediaKind, type MediaMultiUploadResult, type MediaRef, type MediaRefLike, type MediaUnavailableReason, type MediaUploadOptions, type MediaUploadResult, type MediaUrlKind, SIGNED_URL_RE, ShareLinkInvalidError, type ShareLinkRecordWire, TUS_TRANSPORT_THRESHOLD_BYTES, type UploadTransport, classifyMediaUrl, classifyUnavailable, createFileUrlRecognizer, createFilesSession, createMatrxFilesClient, createMemoryBlobCache, fileErrorFromStatus, fileNameFromUrl, fileUrls, isDurableMediaUrl, isSignedUrl, mimeFromUrl, resolveUploadTransport, shareUrl, shareableMediaUrl, uploadAccessFields };
|
|
753
|
+
export { type BlobCacheEntry, type BlobCachePort, type DedupedUploadOutcome, type DurableSrc, ExternalFetchError, FileAccessDeniedError, FileDeletedError, FileError, type FileErrorCode, type FileMetadata, type FileMetadataPort, FileNotFoundError, type FileOrigins, type FileRecordWire, type FileSessionResponseWire, type FileShownTo, FileUploadError, type FileUploadResponseWire, type FileUrlRecognizer, type FileUrls, type FilesBlobHandle, type FilesDiagnosticsEvent, type FilesDiagnosticsSink, type FilesRecoveryReport, type FilesRecoveryVerdict, type FilesResolution, type FilesSession, type FilesSessionOptions, type FilesSessionSnapshot, type MatrxFilesClient, type MatrxFilesClientConfig, type MediaKind, type MediaMultiUploadResult, type MediaRef, type MediaRefLike, type MediaUnavailableReason, type MediaUploadOptions, type MediaUploadResult, type MediaUrlKind, SIGNED_URL_RE, ShareLinkInvalidError, type ShareLinkRecordWire, TUS_TRANSPORT_THRESHOLD_BYTES, type UploadClaim, type UploadTransport, __resetUploadDedupGuardForTests, buildFileUrls, claimUpload, classifyMediaUrl, classifyUnavailable, createFileUrlRecognizer, createFilesSession, createMatrxFilesClient, createMemoryBlobCache, fileErrorFromStatus, fileNameFromUrl, fileUrls, isDurableMediaUrl, isSignedUrl, mimeFromUrl, resolveUploadTransport, shareUrl, shareableMediaUrl, uploadAccessFields, uploadDedupKey };
|
package/dist/files.d.ts
CHANGED
|
@@ -381,7 +381,14 @@ interface FileUrls {
|
|
|
381
381
|
* `?inline=1` matches the exact spelling the backend emits on
|
|
382
382
|
* `FileRecord.url`, keeping cache keys identical either way.
|
|
383
383
|
*/
|
|
384
|
-
declare function
|
|
384
|
+
declare function buildFileUrls(filesBaseUrl: string, fileId: string): FileUrls;
|
|
385
|
+
/**
|
|
386
|
+
* @deprecated Renamed {@link buildFileUrls} (architecture step 14): `fileUrls(fileId)`
|
|
387
|
+
* is the ONE caller-facing signature — the host-bound builder in
|
|
388
|
+
* `@ai-matrx/media/files/engine/handler/utils/python-base`. This alias keeps a
|
|
389
|
+
* `latest` media build working for one release and is then removed.
|
|
390
|
+
*/
|
|
391
|
+
declare const fileUrls: typeof buildFileUrls;
|
|
385
392
|
/**
|
|
386
393
|
* The clean public byte-streaming share endpoint (`GET /share/{token}`,
|
|
387
394
|
* inline disposition) — the canonical embeddable URL for a minted link.
|
|
@@ -563,7 +570,7 @@ declare function createMatrxFilesClient<TSrc extends string = DurableSrc>(config
|
|
|
563
570
|
* panels — this module never logs.
|
|
564
571
|
*/
|
|
565
572
|
|
|
566
|
-
type FileErrorCode = "access_denied" | "not_found" | "deleted" | "share_link_invalid" | "external_fetch_failed" | "upload_failed" | "internal";
|
|
573
|
+
type FileErrorCode = "access_denied" | "not_found" | "deleted" | "share_link_invalid" | "external_fetch_failed" | "cors_blocked" | "mime_unknown" | "upload_failed" | "upload_cancelled" | "quota_exceeded" | "in_flight" | "internal";
|
|
567
574
|
declare class FileError extends Error {
|
|
568
575
|
readonly code: FileErrorCode;
|
|
569
576
|
readonly fileId?: string | undefined;
|
|
@@ -615,6 +622,66 @@ declare function fileErrorFromStatus(status: number, fileId?: string): FileError
|
|
|
615
622
|
*/
|
|
616
623
|
declare function classifyUnavailable(err: unknown): MediaUnavailableReason;
|
|
617
624
|
|
|
625
|
+
/**
|
|
626
|
+
* Upload dedup guard — one in-flight/just-landed claim per (folder, name, size).
|
|
627
|
+
* Origin: @ai-matrx/media files/engine/upload/uploadDedupGuard.ts (architecture step 14).
|
|
628
|
+
*
|
|
629
|
+
* Root cause (`common-docs/projects/acquisition-frontier/own-files/VERIFICATION.md`
|
|
630
|
+
* §12, 2026-09-18): in a 7-file pile, both zero-byte files were uploaded
|
|
631
|
+
* TWICE, 18s apart, the second auto-renamed "(1)" by `uniqueName()` in
|
|
632
|
+
* `features/files/redux/thunks.ts` — right after the dev server had refused
|
|
633
|
+
* connections. A client-side retry of the whole `uploadFiles()` dispatch
|
|
634
|
+
* after a transient failure re-sends a file whose first attempt may already
|
|
635
|
+
* have landed server-side (the client only knows its OWN request failed —
|
|
636
|
+
* a connection reset gives no proof the server never received the bytes).
|
|
637
|
+
*
|
|
638
|
+
* The obvious fix is the backend's OWN `X-Idempotency-Key` mechanism
|
|
639
|
+
* (`lib/python-client.ts` already sends it, `aidream` already stores it in
|
|
640
|
+
* `metadata._idempotency_key`) — but it is not the full answer here: the
|
|
641
|
+
* key is only reused *within* a single `uploadFiles()` dispatch
|
|
642
|
+
* (`newRequestId()` mints a fresh one per worker() call in thunks.ts), and
|
|
643
|
+
* server-side `_replayable_412` in `aidream/aidream/api/routers/files/__init__.py`
|
|
644
|
+
* only replays a 412 (precondition-failed) response under the key — a
|
|
645
|
+
* SUCCESSFUL upload is never deduped by the server on replay. So a second,
|
|
646
|
+
* independent `uploadFiles()` dispatch for the same intended file — the
|
|
647
|
+
* shape a caller-level retry takes — is indistinguishable from a genuinely
|
|
648
|
+
* new upload to both client and server.
|
|
649
|
+
*
|
|
650
|
+
* This guard closes the gap client-side, per (folder, name, size): the
|
|
651
|
+
* FIRST claim for a signature performs the real network request; any
|
|
652
|
+
* SECOND claim for the same signature while that request is still in
|
|
653
|
+
* flight, or shortly after it landed, reuses the first attempt's outcome
|
|
654
|
+
* instead of sending the bytes again. A claim that ends in failure is
|
|
655
|
+
* cleared immediately, so a genuine "it never landed, please retry" case is
|
|
656
|
+
* never blocked — only a request whose outcome is still pending, or already
|
|
657
|
+
* known-good, is deduped.
|
|
658
|
+
*/
|
|
659
|
+
interface DedupedUploadOutcome {
|
|
660
|
+
fileId: string;
|
|
661
|
+
filePath: string;
|
|
662
|
+
}
|
|
663
|
+
/** The dedup key: same folder, same original name, same byte count. */
|
|
664
|
+
declare function uploadDedupKey(folderPath: string, fileName: string, fileSize: number): string;
|
|
665
|
+
type UploadClaim = {
|
|
666
|
+
shared: true;
|
|
667
|
+
promise: Promise<DedupedUploadOutcome>;
|
|
668
|
+
} | {
|
|
669
|
+
shared: false;
|
|
670
|
+
/**
|
|
671
|
+
* The caller that owns this claim MUST call `settle` exactly once
|
|
672
|
+
* with the real upload's outcome (or a rejected promise on failure).
|
|
673
|
+
*/
|
|
674
|
+
settle: (outcome: Promise<DedupedUploadOutcome>) => void;
|
|
675
|
+
};
|
|
676
|
+
/**
|
|
677
|
+
* Claim a signature before starting an upload. See module doc for the
|
|
678
|
+
* contract: a `shared: true` result means someone else already owns this
|
|
679
|
+
* signature — await its `promise` instead of sending the file again.
|
|
680
|
+
*/
|
|
681
|
+
declare function claimUpload(key: string): UploadClaim;
|
|
682
|
+
/** Test-only: clears every claim so suites don't leak state between tests. */
|
|
683
|
+
declare function __resetUploadDedupGuardForTests(): void;
|
|
684
|
+
|
|
618
685
|
/**
|
|
619
686
|
* @ai-matrx/data/files — the `mx_files_session` cookie bootstrap.
|
|
620
687
|
*
|
|
@@ -683,4 +750,4 @@ interface FilesSession {
|
|
|
683
750
|
}
|
|
684
751
|
declare function createFilesSession(options: FilesSessionOptions): FilesSession;
|
|
685
752
|
|
|
686
|
-
export { type BlobCacheEntry, type BlobCachePort, type DurableSrc, ExternalFetchError, FileAccessDeniedError, FileDeletedError, FileError, type FileErrorCode, type FileMetadata, type FileMetadataPort, FileNotFoundError, type FileOrigins, type FileRecordWire, type FileSessionResponseWire, type FileShownTo, FileUploadError, type FileUploadResponseWire, type FileUrlRecognizer, type FileUrls, type FilesBlobHandle, type FilesDiagnosticsEvent, type FilesDiagnosticsSink, type FilesRecoveryReport, type FilesRecoveryVerdict, type FilesResolution, type FilesSession, type FilesSessionOptions, type FilesSessionSnapshot, type MatrxFilesClient, type MatrxFilesClientConfig, type MediaKind, type MediaMultiUploadResult, type MediaRef, type MediaRefLike, type MediaUnavailableReason, type MediaUploadOptions, type MediaUploadResult, type MediaUrlKind, SIGNED_URL_RE, ShareLinkInvalidError, type ShareLinkRecordWire, TUS_TRANSPORT_THRESHOLD_BYTES, type UploadTransport, classifyMediaUrl, classifyUnavailable, createFileUrlRecognizer, createFilesSession, createMatrxFilesClient, createMemoryBlobCache, fileErrorFromStatus, fileNameFromUrl, fileUrls, isDurableMediaUrl, isSignedUrl, mimeFromUrl, resolveUploadTransport, shareUrl, shareableMediaUrl, uploadAccessFields };
|
|
753
|
+
export { type BlobCacheEntry, type BlobCachePort, type DedupedUploadOutcome, type DurableSrc, ExternalFetchError, FileAccessDeniedError, FileDeletedError, FileError, type FileErrorCode, type FileMetadata, type FileMetadataPort, FileNotFoundError, type FileOrigins, type FileRecordWire, type FileSessionResponseWire, type FileShownTo, FileUploadError, type FileUploadResponseWire, type FileUrlRecognizer, type FileUrls, type FilesBlobHandle, type FilesDiagnosticsEvent, type FilesDiagnosticsSink, type FilesRecoveryReport, type FilesRecoveryVerdict, type FilesResolution, type FilesSession, type FilesSessionOptions, type FilesSessionSnapshot, type MatrxFilesClient, type MatrxFilesClientConfig, type MediaKind, type MediaMultiUploadResult, type MediaRef, type MediaRefLike, type MediaUnavailableReason, type MediaUploadOptions, type MediaUploadResult, type MediaUrlKind, SIGNED_URL_RE, ShareLinkInvalidError, type ShareLinkRecordWire, TUS_TRANSPORT_THRESHOLD_BYTES, type UploadClaim, type UploadTransport, __resetUploadDedupGuardForTests, buildFileUrls, claimUpload, classifyMediaUrl, classifyUnavailable, createFileUrlRecognizer, createFilesSession, createMatrxFilesClient, createMemoryBlobCache, fileErrorFromStatus, fileNameFromUrl, fileUrls, isDurableMediaUrl, isSignedUrl, mimeFromUrl, resolveUploadTransport, shareUrl, shareableMediaUrl, uploadAccessFields, uploadDedupKey };
|
package/dist/files.js
CHANGED
|
@@ -197,11 +197,12 @@ function fileNameFromUrl(url) {
|
|
|
197
197
|
if (!last || !/\.[a-z0-9]{1,5}$/i.test(last)) return null;
|
|
198
198
|
return decodeURIComponent(last);
|
|
199
199
|
}
|
|
200
|
-
function
|
|
200
|
+
function buildFileUrls(filesBaseUrl, fileId) {
|
|
201
201
|
const id = encodeURIComponent(fileId);
|
|
202
202
|
const base = `${filesBaseUrl.replace(/\/$/, "")}/files/${id}/download`;
|
|
203
203
|
return { download: base, inline: `${base}?inline=1` };
|
|
204
204
|
}
|
|
205
|
+
var fileUrls = buildFileUrls;
|
|
205
206
|
function shareUrl(filesBaseUrl, token) {
|
|
206
207
|
return `${filesBaseUrl.replace(/\/$/, "")}/share/${encodeURIComponent(token)}`;
|
|
207
208
|
}
|
|
@@ -699,7 +700,7 @@ function createMatrxFilesClient(config) {
|
|
|
699
700
|
const inflightDownloads = /* @__PURE__ */ new Map();
|
|
700
701
|
async function fetchFileBytes(fileId) {
|
|
701
702
|
const headers = await authHeaders();
|
|
702
|
-
const response = await fetchImpl(
|
|
703
|
+
const response = await fetchImpl(buildFileUrls(filesBase(), fileId).download, {
|
|
703
704
|
headers
|
|
704
705
|
});
|
|
705
706
|
if (!response.ok) {
|
|
@@ -961,7 +962,7 @@ function createMatrxFilesClient(config) {
|
|
|
961
962
|
}
|
|
962
963
|
const transport = kind === "video" || kind === "audio" ? "element" : "blob";
|
|
963
964
|
const resolution = {
|
|
964
|
-
src: mint(
|
|
965
|
+
src: mint(buildFileUrls(filesBase(), fileId).inline),
|
|
965
966
|
kind,
|
|
966
967
|
transport,
|
|
967
968
|
recoverable: true
|
|
@@ -1027,7 +1028,7 @@ function createMatrxFilesClient(config) {
|
|
|
1027
1028
|
mintStatus: session.snapshot().status,
|
|
1028
1029
|
fetchBytes: async (base, id) => {
|
|
1029
1030
|
const headers = await authHeaders();
|
|
1030
|
-
return fetchImpl(
|
|
1031
|
+
return fetchImpl(buildFileUrls(base, id).download, { headers });
|
|
1031
1032
|
},
|
|
1032
1033
|
cacheBlob: (id, blob) => {
|
|
1033
1034
|
const already = blobCache.get(id);
|
|
@@ -1079,6 +1080,43 @@ function createMatrxFilesClient(config) {
|
|
|
1079
1080
|
};
|
|
1080
1081
|
return client;
|
|
1081
1082
|
}
|
|
1083
|
+
|
|
1084
|
+
// src/files/dedup.ts
|
|
1085
|
+
var CLAIM_WINDOW_MS = 3 * 60 * 1e3;
|
|
1086
|
+
var claims = /* @__PURE__ */ new Map();
|
|
1087
|
+
function uploadDedupKey(folderPath, fileName, fileSize) {
|
|
1088
|
+
return [folderPath, fileName, String(fileSize)].join("\\0");
|
|
1089
|
+
}
|
|
1090
|
+
function claimUpload(key) {
|
|
1091
|
+
const now = Date.now();
|
|
1092
|
+
const existing = claims.get(key);
|
|
1093
|
+
if (existing && existing.expiresAt > now) {
|
|
1094
|
+
return { shared: true, promise: existing.promise };
|
|
1095
|
+
}
|
|
1096
|
+
let settleFn;
|
|
1097
|
+
const publicPromise = new Promise(
|
|
1098
|
+
(resolve, reject) => {
|
|
1099
|
+
settleFn = (outcome) => {
|
|
1100
|
+
outcome.then(
|
|
1101
|
+
(value) => {
|
|
1102
|
+
resolve(value);
|
|
1103
|
+
},
|
|
1104
|
+
(err) => {
|
|
1105
|
+
claims.delete(key);
|
|
1106
|
+
reject(err instanceof Error ? err : new Error(String(err)));
|
|
1107
|
+
}
|
|
1108
|
+
);
|
|
1109
|
+
};
|
|
1110
|
+
}
|
|
1111
|
+
);
|
|
1112
|
+
publicPromise.catch(() => {
|
|
1113
|
+
});
|
|
1114
|
+
claims.set(key, { promise: publicPromise, expiresAt: now + CLAIM_WINDOW_MS });
|
|
1115
|
+
return { shared: false, settle: settleFn };
|
|
1116
|
+
}
|
|
1117
|
+
function __resetUploadDedupGuardForTests() {
|
|
1118
|
+
claims.clear();
|
|
1119
|
+
}
|
|
1082
1120
|
export {
|
|
1083
1121
|
ExternalFetchError,
|
|
1084
1122
|
FileAccessDeniedError,
|
|
@@ -1089,6 +1127,9 @@ export {
|
|
|
1089
1127
|
SIGNED_URL_RE,
|
|
1090
1128
|
ShareLinkInvalidError,
|
|
1091
1129
|
TUS_TRANSPORT_THRESHOLD_BYTES,
|
|
1130
|
+
__resetUploadDedupGuardForTests,
|
|
1131
|
+
buildFileUrls,
|
|
1132
|
+
claimUpload,
|
|
1092
1133
|
classifyMediaUrl,
|
|
1093
1134
|
classifyUnavailable,
|
|
1094
1135
|
createFileUrlRecognizer,
|
|
@@ -1104,6 +1145,7 @@ export {
|
|
|
1104
1145
|
resolveUploadTransport,
|
|
1105
1146
|
shareUrl,
|
|
1106
1147
|
shareableMediaUrl,
|
|
1107
|
-
uploadAccessFields
|
|
1148
|
+
uploadAccessFields,
|
|
1149
|
+
uploadDedupKey
|
|
1108
1150
|
};
|
|
1109
1151
|
//# sourceMappingURL=files.js.map
|