@vef-framework-react/core 2.1.11 → 2.2.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/dist/cjs/api/helpers.cjs +1 -1
- package/dist/cjs/dnd/index.cjs +1 -1
- package/dist/cjs/index.cjs +1 -1
- package/dist/cjs/storage/errors.cjs +1 -0
- package/dist/cjs/storage/index.cjs +1 -0
- package/dist/cjs/storage/protocol.cjs +1 -0
- package/dist/cjs/storage/resumable/fingerprint.cjs +1 -0
- package/dist/cjs/storage/resumable/index.cjs +1 -0
- package/dist/cjs/storage/resumable/persistence.cjs +1 -0
- package/dist/cjs/storage/resumable/plan.cjs +1 -0
- package/dist/cjs/storage/types.cjs +1 -0
- package/dist/cjs/storage/uploader.cjs +1 -0
- package/dist/es/api/client.js +1 -1
- package/dist/es/api/constants.js +1 -1
- package/dist/es/api/helpers.js +19 -3
- package/dist/es/api/index.js +1 -1
- package/dist/es/auth/helpers.js +1 -1
- package/dist/es/auth/index.js +1 -1
- package/dist/es/context/api-client.js +1 -1
- package/dist/es/context/app.js +1 -1
- package/dist/es/context/context-selector.js +1 -1
- package/dist/es/context/disabled.js +1 -1
- package/dist/es/context/index.js +1 -1
- package/dist/es/dnd/index.js +9 -7
- package/dist/es/http/client.js +1 -1
- package/dist/es/http/constants.js +1 -1
- package/dist/es/http/errors.js +1 -1
- package/dist/es/http/helpers.js +1 -1
- package/dist/es/http/index.js +1 -1
- package/dist/es/immer/index.js +1 -1
- package/dist/es/index.js +33 -27
- package/dist/es/motion/features.js +1 -1
- package/dist/es/motion/index.js +1 -1
- package/dist/es/motion/motion-provider.js +1 -1
- package/dist/es/query/constants.js +1 -1
- package/dist/es/query/helpers.js +1 -1
- package/dist/es/query/hooks.js +1 -1
- package/dist/es/query/index.js +1 -1
- package/dist/es/sse/client.js +1 -1
- package/dist/es/sse/helpers.js +1 -1
- package/dist/es/sse/index.js +1 -1
- package/dist/es/state/index.js +1 -1
- package/dist/es/state-machine/index.js +1 -1
- package/dist/es/storage/errors.js +24 -0
- package/dist/es/storage/index.js +8 -0
- package/dist/es/storage/protocol.js +55 -0
- package/dist/es/storage/resumable/fingerprint.js +25 -0
- package/dist/es/storage/resumable/index.js +4 -0
- package/dist/es/storage/resumable/persistence.js +46 -0
- package/dist/es/storage/resumable/plan.js +35 -0
- package/dist/es/storage/types.js +5 -0
- package/dist/es/storage/uploader.js +223 -0
- package/dist/es/store/bound.js +1 -1
- package/dist/es/store/index.js +1 -1
- package/dist/es/store/unbound.js +1 -1
- package/dist/es/store/use-deep.js +1 -1
- package/dist/types/api/helpers.d.ts +16 -1
- package/dist/types/api/index.d.ts +1 -1
- package/dist/types/api/types.d.ts +30 -0
- package/dist/types/dnd/index.d.ts +4 -0
- package/dist/types/index.d.ts +3 -3
- package/dist/types/storage/errors.d.ts +46 -0
- package/dist/types/storage/index.d.ts +5 -0
- package/dist/types/storage/protocol.d.ts +102 -0
- package/dist/types/storage/resumable/fingerprint.d.ts +52 -0
- package/dist/types/storage/resumable/index.d.ts +3 -0
- package/dist/types/storage/resumable/persistence.d.ts +98 -0
- package/dist/types/storage/resumable/plan.d.ts +105 -0
- package/dist/types/storage/types.d.ts +166 -0
- package/dist/types/storage/uploader.d.ts +58 -0
- package/package.json +10 -10
- package/dist/cjs/ai/index.cjs +0 -1
- package/dist/es/ai/index.js +0 -3
- package/dist/types/ai/index.d.ts +0 -6
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A persisted upload session that can be matched against a re-opened file
|
|
3
|
+
* to resume from where the previous attempt left off. The record carries
|
|
4
|
+
* only what the client needs to call `list_parts` and rebuild the
|
|
5
|
+
* Uploader's plan — the authoritative list of completed parts is always
|
|
6
|
+
* fetched from the backend, never trusted from disk.
|
|
7
|
+
*/
|
|
8
|
+
export interface ResumeRecord {
|
|
9
|
+
/**
|
|
10
|
+
* Stable identifier of the file the session belongs to. Used by the
|
|
11
|
+
* persistence layer as a lookup key. Computed by the `FileFingerprinter`.
|
|
12
|
+
*/
|
|
13
|
+
fingerprint: string;
|
|
14
|
+
/**
|
|
15
|
+
* Server-assigned claim ID. Replays into `list_parts` / `upload_part`
|
|
16
|
+
* — every framework RPC routes by claimId, never by the backend's
|
|
17
|
+
* internal multipart upload ID.
|
|
18
|
+
*/
|
|
19
|
+
claimId: string;
|
|
20
|
+
/**
|
|
21
|
+
* Object key the backend assigned for this upload. Recorded for
|
|
22
|
+
* diagnostic purposes and parity with `InitUploadResponse`.
|
|
23
|
+
*/
|
|
24
|
+
key: string;
|
|
25
|
+
/**
|
|
26
|
+
* Backend-authoritative part size. Persisted so the client can sanity-
|
|
27
|
+
* check the saved record against the file size before resuming
|
|
28
|
+
* (e.g. an out-of-date partSize indicates a configuration drift).
|
|
29
|
+
*/
|
|
30
|
+
partSize: number;
|
|
31
|
+
/**
|
|
32
|
+
* Total number of parts the original `init_upload` planned for.
|
|
33
|
+
*/
|
|
34
|
+
partCount: number;
|
|
35
|
+
/**
|
|
36
|
+
* Wall-clock expiry as an ISO-8601 string (mirrors
|
|
37
|
+
* `InitUploadResponse.expiresAt`). Reading code MUST compare this
|
|
38
|
+
* against `Date.now()` and discard expired records — the server-side
|
|
39
|
+
* sweeper may have deleted the underlying claim already.
|
|
40
|
+
*/
|
|
41
|
+
expiresAt: string;
|
|
42
|
+
/**
|
|
43
|
+
* Local timestamp (`Date.now()`) when the record was last written.
|
|
44
|
+
* Not used for control flow; useful for diagnostics and future
|
|
45
|
+
* cleanup policies.
|
|
46
|
+
*/
|
|
47
|
+
savedAt: number;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Pluggable persistence for `ResumeRecord` values. The default
|
|
51
|
+
* implementation (`LocalStoragePersistence`) targets `localStorage`,
|
|
52
|
+
* but the interface is intentionally async so callers can swap in
|
|
53
|
+
* IndexedDB, a server-side session store (for cross-device resume),
|
|
54
|
+
* or a multi-tenant namespaced backend.
|
|
55
|
+
*
|
|
56
|
+
* Implementations should be safe to call from any context (including
|
|
57
|
+
* SSR — see `LocalStoragePersistence` for the typical guard pattern).
|
|
58
|
+
* `load` MUST return `null` when no record exists; throwing is reserved
|
|
59
|
+
* for genuine I/O failures the caller would want to surface.
|
|
60
|
+
*/
|
|
61
|
+
export interface ResumablePersistence {
|
|
62
|
+
load: (fingerprint: string) => Promise<ResumeRecord | null>;
|
|
63
|
+
save: (record: ResumeRecord) => Promise<void>;
|
|
64
|
+
remove: (fingerprint: string) => Promise<void>;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Default `ResumablePersistence` implementation backed by
|
|
68
|
+
* `window.localStorage`. Keys are namespaced under `keyPrefix` (default
|
|
69
|
+
* `__VEF_UPLOAD_RESUME__`) so resume records cannot collide with the
|
|
70
|
+
* project's other localStorage consumers.
|
|
71
|
+
*
|
|
72
|
+
* The implementation is intentionally tolerant of structurally invalid
|
|
73
|
+
* stored payloads — if a record fails to parse it is dropped and `load`
|
|
74
|
+
* returns `null`, mirroring the "no record" case. This guards against
|
|
75
|
+
* format drift between releases (we'd rather start a fresh upload than
|
|
76
|
+
* crash on a stale row).
|
|
77
|
+
*/
|
|
78
|
+
export declare class LocalStoragePersistence implements ResumablePersistence {
|
|
79
|
+
#private;
|
|
80
|
+
constructor(keyPrefix?: string);
|
|
81
|
+
load(fingerprint: string): Promise<ResumeRecord | null>;
|
|
82
|
+
save(record: ResumeRecord): Promise<void>;
|
|
83
|
+
remove(fingerprint: string): Promise<void>;
|
|
84
|
+
/**
|
|
85
|
+
* Drop every record this persistence instance owns (matched by the
|
|
86
|
+
* configured key prefix). Call this on logout / account-switch so a
|
|
87
|
+
* subsequent user does not inherit the previous user's resume
|
|
88
|
+
* metadata — even though server-side ownership checks prevent
|
|
89
|
+
* cross-user claim theft, leaving the records around still leaks
|
|
90
|
+
* which keys the previous user had in flight (and, with the prefix
|
|
91
|
+
* fingerprint, whether they had ever uploaded any of a given set of
|
|
92
|
+
* candidate files).
|
|
93
|
+
*
|
|
94
|
+
* Foreign records (different prefix, unrelated localStorage entries)
|
|
95
|
+
* are left untouched.
|
|
96
|
+
*/
|
|
97
|
+
clearAll(): Promise<void>;
|
|
98
|
+
}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import { GenericAbortSignal } from 'axios';
|
|
2
|
+
import { ListedPart, ProtocolContext } from '../protocol';
|
|
3
|
+
import { ResumablePersistence, ResumeRecord } from './persistence';
|
|
4
|
+
/**
|
|
5
|
+
* Inputs collected for a potential resume; passed to the
|
|
6
|
+
* `onResumeDetected` callback so the UI layer can decide whether to
|
|
7
|
+
* continue the previous session or discard it.
|
|
8
|
+
*
|
|
9
|
+
* `completedParts` is the live result of `list_parts`, NOT a value
|
|
10
|
+
* retrieved from disk — the backend is the source of truth. The record
|
|
11
|
+
* is included so the UI can show context ("you uploaded N MiB of
|
|
12
|
+
* <filename> two hours ago, resume?").
|
|
13
|
+
*/
|
|
14
|
+
export interface ResumeCandidate {
|
|
15
|
+
record: ResumeRecord;
|
|
16
|
+
completedParts: ListedPart[];
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Caller decision on whether to honor a `ResumeCandidate`. A discriminated
|
|
20
|
+
* union so future intents (e.g. "resume but rename target", "fork into a
|
|
21
|
+
* new claim") can be added without changing the callback signature.
|
|
22
|
+
*/
|
|
23
|
+
export type ResumeDecision = {
|
|
24
|
+
kind: "resume";
|
|
25
|
+
} | {
|
|
26
|
+
kind: "discard";
|
|
27
|
+
};
|
|
28
|
+
/**
|
|
29
|
+
* Final resume plan handed to `Uploader.start(plan)`. The Uploader
|
|
30
|
+
* branches on `kind`:
|
|
31
|
+
*
|
|
32
|
+
* - `fresh`: behave as before — call `init_upload`, upload every part.
|
|
33
|
+
* - `resume`: skip `init_upload`, treat `completedParts` as the set of
|
|
34
|
+
* part numbers (with their server-recorded sizes) to bypass during
|
|
35
|
+
* the worker loop.
|
|
36
|
+
*
|
|
37
|
+
* `expiresAt` is carried through so consumers downstream of the
|
|
38
|
+
* Uploader (notably `useUpload`'s persistence layer) can refresh the
|
|
39
|
+
* stored record with the original authoritative expiry rather than
|
|
40
|
+
* re-deriving it.
|
|
41
|
+
*/
|
|
42
|
+
export type ResumePlan = {
|
|
43
|
+
kind: "fresh";
|
|
44
|
+
} | {
|
|
45
|
+
kind: "resume";
|
|
46
|
+
claimId: string;
|
|
47
|
+
key: string;
|
|
48
|
+
partSize: number;
|
|
49
|
+
partCount: number;
|
|
50
|
+
expiresAt: string;
|
|
51
|
+
completedParts: readonly ListedPart[];
|
|
52
|
+
};
|
|
53
|
+
/**
|
|
54
|
+
* Caller's decision handler. Receives the candidate (record + live
|
|
55
|
+
* completed parts) and returns the decision. The default — when the
|
|
56
|
+
* caller does not provide one — is `{ kind: "discard" }`, because a
|
|
57
|
+
* resume that picks the wrong file is far worse than a redundant
|
|
58
|
+
* fresh upload.
|
|
59
|
+
*/
|
|
60
|
+
export type ResumeDecisionHandler = (candidate: ResumeCandidate) => Promise<ResumeDecision>;
|
|
61
|
+
/**
|
|
62
|
+
* Inputs to `resolveResumePlan`. The caller is responsible for
|
|
63
|
+
* computing the fingerprint (so it can also use it elsewhere, e.g.
|
|
64
|
+
* to write the resume record after the upload starts) — the planner
|
|
65
|
+
* only consumes the resulting string.
|
|
66
|
+
*/
|
|
67
|
+
export interface ResolveResumeInputs {
|
|
68
|
+
fingerprint: string;
|
|
69
|
+
persistence: ResumablePersistence;
|
|
70
|
+
/**
|
|
71
|
+
* Protocol context carrying the HttpClient and RPC routing details.
|
|
72
|
+
* Same shape as the one passed to `initUpload` / `uploadPart` / etc.
|
|
73
|
+
*/
|
|
74
|
+
ctx: ProtocolContext;
|
|
75
|
+
/**
|
|
76
|
+
* Defaults to `() => ({ kind: "discard" })`. Callers MUST provide a
|
|
77
|
+
* handler if they want resume to actually happen.
|
|
78
|
+
*/
|
|
79
|
+
onResumeDetected?: ResumeDecisionHandler;
|
|
80
|
+
/**
|
|
81
|
+
* Optional cancellation signal for the in-flight `list_parts` / abort
|
|
82
|
+
* calls. Without it the planner blocks the caller until the network
|
|
83
|
+
* request settles — a slow server or hung connection makes
|
|
84
|
+
* `uploader.abort()` useless during the resume-detection phase.
|
|
85
|
+
*/
|
|
86
|
+
signal?: GenericAbortSignal;
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Compute the `ResumePlan` for a given fingerprint:
|
|
90
|
+
*
|
|
91
|
+
* 1. Look up the persisted record; on miss → `fresh`.
|
|
92
|
+
* 2. Validate the record's expiry against the wall clock; on expiry →
|
|
93
|
+
* remove + `fresh`.
|
|
94
|
+
* 3. Call `list_parts` to get the authoritative completed-parts list;
|
|
95
|
+
* on protocol error → remove + `fresh` (the claim is likely gone
|
|
96
|
+
* server-side).
|
|
97
|
+
* 4. Hand the candidate to `onResumeDetected`; honor the returned
|
|
98
|
+
* decision.
|
|
99
|
+
*
|
|
100
|
+
* A `discard` decision removes the local record first, then issues a
|
|
101
|
+
* best-effort `abort_upload`. Local-state cleanup is ordered first so
|
|
102
|
+
* a process crash between the two steps cannot leave a record that
|
|
103
|
+
* outlives its backend claim.
|
|
104
|
+
*/
|
|
105
|
+
export declare function resolveResumePlan(inputs: ResolveResumeInputs): Promise<ResumePlan>;
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Object key namespace prefixes used by the framework. Mirrors the constants
|
|
3
|
+
* declared on the Go side; clients embed them in object keys to communicate
|
|
4
|
+
* the intended visibility.
|
|
5
|
+
*
|
|
6
|
+
* - `PUBLIC_PREFIX`: anonymous-readable via the backend's direct URL.
|
|
7
|
+
* - `PRIVATE_PREFIX`: authenticated reads through `/storage/files/<key>`.
|
|
8
|
+
*/
|
|
9
|
+
export declare const PUBLIC_PREFIX = "pub/";
|
|
10
|
+
export declare const PRIVATE_PREFIX = "priv/";
|
|
11
|
+
/**
|
|
12
|
+
* The lifecycle status of an Uploader instance. Transitions are linear up to
|
|
13
|
+
* a terminal state (`succeeded`, `failed`, `aborted`).
|
|
14
|
+
*
|
|
15
|
+
* - `idle`: created but `start()` has not been called yet.
|
|
16
|
+
* - `initializing`: opening the multipart session against the backend.
|
|
17
|
+
* - `uploading`: streaming parts to the backend.
|
|
18
|
+
* - `completing`: assembling the multipart session on the backend.
|
|
19
|
+
* - `aborting`: caller requested cancellation and cleanup is in flight.
|
|
20
|
+
* - `succeeded`: terminal — final ObjectInfo is available on the result.
|
|
21
|
+
* - `failed`: terminal — the original error is stored on the instance.
|
|
22
|
+
* - `aborted`: terminal — `abort()` (or the external signal) completed.
|
|
23
|
+
*/
|
|
24
|
+
export type UploadStatus = "idle" | "initializing" | "uploading" | "completing" | "aborting" | "succeeded" | "failed" | "aborted";
|
|
25
|
+
/**
|
|
26
|
+
* Initialization parameters forwarded to the backend's `init_upload`. Either
|
|
27
|
+
* supply these explicitly via `UploaderOptions.init` or rely on the defaults
|
|
28
|
+
* derived from the `File`'s `name`, `type`, and `size`.
|
|
29
|
+
*/
|
|
30
|
+
export interface UploadInit {
|
|
31
|
+
/**
|
|
32
|
+
* Override the original filename. Defaults to `file.name`.
|
|
33
|
+
*/
|
|
34
|
+
filename?: string;
|
|
35
|
+
/**
|
|
36
|
+
* Override the declared MIME type. Defaults to `file.type`.
|
|
37
|
+
*/
|
|
38
|
+
contentType?: string;
|
|
39
|
+
/**
|
|
40
|
+
* Land the object under `pub/` (`true`) or `priv/` (`false`/omitted).
|
|
41
|
+
*/
|
|
42
|
+
public?: boolean;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Aggregated upload progress emitted by the Uploader.
|
|
46
|
+
*
|
|
47
|
+
* `loaded` aggregates bytes acknowledged across **completed** parts, plus the
|
|
48
|
+
* latest in-flight progress for each part that has not yet finished. The
|
|
49
|
+
* value is monotonically non-decreasing within a single upload session.
|
|
50
|
+
*/
|
|
51
|
+
export interface UploadProgress {
|
|
52
|
+
/**
|
|
53
|
+
* Bytes acknowledged so far. Never exceeds `total`.
|
|
54
|
+
*/
|
|
55
|
+
loaded: number;
|
|
56
|
+
/**
|
|
57
|
+
* Total file size in bytes (mirrors the declared `size`).
|
|
58
|
+
*/
|
|
59
|
+
total: number;
|
|
60
|
+
/**
|
|
61
|
+
* Number of parts that have been fully accepted by the backend.
|
|
62
|
+
*/
|
|
63
|
+
partsCompleted: number;
|
|
64
|
+
/**
|
|
65
|
+
* Total number of parts in the upload plan.
|
|
66
|
+
*/
|
|
67
|
+
partsTotal: number;
|
|
68
|
+
/**
|
|
69
|
+
* Convenience field: `loaded / total` rounded to an integer percentage.
|
|
70
|
+
*/
|
|
71
|
+
percent: number;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* The final result of a successful upload. Combines the backend `ObjectInfo`
|
|
75
|
+
* with the framework-tracked `originalFilename`.
|
|
76
|
+
*/
|
|
77
|
+
export interface UploadResult {
|
|
78
|
+
bucket: string;
|
|
79
|
+
key: string;
|
|
80
|
+
eTag: string;
|
|
81
|
+
size: number;
|
|
82
|
+
contentType: string;
|
|
83
|
+
lastModified: string;
|
|
84
|
+
originalFilename: string;
|
|
85
|
+
metadata?: Record<string, string>;
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Construction options for `Uploader`. Defaults match the server's documented
|
|
89
|
+
* conventions; override only when you have a concrete reason.
|
|
90
|
+
*/
|
|
91
|
+
export interface UploaderOptions {
|
|
92
|
+
/**
|
|
93
|
+
* RPC entrypoint URL. Defaults to `/api`.
|
|
94
|
+
*/
|
|
95
|
+
apiPath?: string;
|
|
96
|
+
/**
|
|
97
|
+
* RPC resource name. Defaults to `sys/storage`.
|
|
98
|
+
*/
|
|
99
|
+
resource?: string;
|
|
100
|
+
/**
|
|
101
|
+
* RPC version. Defaults to `v1`.
|
|
102
|
+
*/
|
|
103
|
+
version?: string;
|
|
104
|
+
/**
|
|
105
|
+
* Init-time overrides for the backend session.
|
|
106
|
+
*/
|
|
107
|
+
init?: UploadInit;
|
|
108
|
+
/**
|
|
109
|
+
* Maximum number of parts uploaded in parallel. The backend can already
|
|
110
|
+
* absorb high concurrency; the practical cap is the client's outbound
|
|
111
|
+
* bandwidth and the browser's per-origin connection budget. Defaults to 3.
|
|
112
|
+
*/
|
|
113
|
+
partConcurrency?: number;
|
|
114
|
+
/**
|
|
115
|
+
* Per-part retry budget for transient failures. The initial attempt counts
|
|
116
|
+
* as 1, so a value of 3 yields up to 2 retries before the part is treated
|
|
117
|
+
* as fatal. Defaults to 3.
|
|
118
|
+
*/
|
|
119
|
+
maxPartRetries?: number;
|
|
120
|
+
/**
|
|
121
|
+
* Base delay (ms) for exponential per-part retry backoff. Defaults to 500.
|
|
122
|
+
*/
|
|
123
|
+
retryBaseDelay?: number;
|
|
124
|
+
/**
|
|
125
|
+
* Maximum delay (ms) any single retry will wait. Defaults to 8000.
|
|
126
|
+
*/
|
|
127
|
+
retryMaxDelay?: number;
|
|
128
|
+
/**
|
|
129
|
+
* External abort signal. Combined with the internal controller so any of
|
|
130
|
+
* `signal.abort()`, `uploader.abort()`, or a fatal protocol error will
|
|
131
|
+
* tear down in-flight parts and trigger a best-effort `abort_upload`.
|
|
132
|
+
*/
|
|
133
|
+
signal?: AbortSignal;
|
|
134
|
+
/**
|
|
135
|
+
* Invoked after every part progress tick.
|
|
136
|
+
*/
|
|
137
|
+
onProgress?: (progress: UploadProgress) => void;
|
|
138
|
+
/**
|
|
139
|
+
* Invoked on every `UploadStatus` transition.
|
|
140
|
+
*/
|
|
141
|
+
onStatusChange?: (status: UploadStatus) => void;
|
|
142
|
+
/**
|
|
143
|
+
* Invoked once after the backend has confirmed an upload session.
|
|
144
|
+
* Carries the fields needed to persist a resumable record. Fires on
|
|
145
|
+
* the fresh path (after `init_upload` returns) and on the resume path
|
|
146
|
+
* (synthesized immediately from the supplied `ResumePlan`) so a
|
|
147
|
+
* consumer like `useUpload` can write the localStorage record at the
|
|
148
|
+
* earliest opportunity in either case.
|
|
149
|
+
*/
|
|
150
|
+
onSessionOpened?: (session: UploadSessionSnapshot) => void;
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Minimal session description handed to `onSessionOpened`. Mirrors the
|
|
154
|
+
* subset of `InitUploadResponse` that downstream resume-persistence
|
|
155
|
+
* code cares about. The Uploader carries the original `expiresAt`
|
|
156
|
+
* through both the fresh path (returned by `init_upload`) and the
|
|
157
|
+
* resume path (sourced from the persisted record) so consumers can
|
|
158
|
+
* always parse it directly.
|
|
159
|
+
*/
|
|
160
|
+
export interface UploadSessionSnapshot {
|
|
161
|
+
claimId: string;
|
|
162
|
+
key: string;
|
|
163
|
+
partSize: number;
|
|
164
|
+
partCount: number;
|
|
165
|
+
expiresAt: string;
|
|
166
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { HttpClient } from '../http';
|
|
2
|
+
import { ResumePlan } from './resumable/plan';
|
|
3
|
+
import { UploaderOptions, UploadProgress, UploadResult, UploadStatus } from './types';
|
|
4
|
+
/**
|
|
5
|
+
* Drives a single file through the four-step chunked upload protocol
|
|
6
|
+
* (`init_upload → upload_part* → complete_upload`) exposed by the framework's
|
|
7
|
+
* `sys/storage` resource. Errors trigger a best-effort `abort_upload` so the
|
|
8
|
+
* backend never retains a dangling multipart session.
|
|
9
|
+
*
|
|
10
|
+
* The instance is one-shot: a successful or failed run cannot be restarted.
|
|
11
|
+
* Create a fresh `Uploader` for each file.
|
|
12
|
+
*/
|
|
13
|
+
export declare class Uploader {
|
|
14
|
+
#private;
|
|
15
|
+
constructor(http: Readonly<HttpClient>, file: Blob, options?: UploaderOptions);
|
|
16
|
+
/**
|
|
17
|
+
* Current lifecycle status.
|
|
18
|
+
*/
|
|
19
|
+
get status(): UploadStatus;
|
|
20
|
+
/**
|
|
21
|
+
* Latest aggregated progress snapshot.
|
|
22
|
+
*/
|
|
23
|
+
get progress(): UploadProgress;
|
|
24
|
+
/**
|
|
25
|
+
* Start the upload. Returns the eventual `UploadResult` on success or
|
|
26
|
+
* rejects with an `UploadError` (use `instanceof UploadAbortedError` /
|
|
27
|
+
* `UploadProtocolError` / `UploadPartError` to discriminate). Calling
|
|
28
|
+
* `start()` more than once returns the original promise.
|
|
29
|
+
*
|
|
30
|
+
* When called with a `plan` of kind `"resume"`, the uploader skips
|
|
31
|
+
* `init_upload` and synthesises the session from the plan's
|
|
32
|
+
* `claimId`/`partSize`/`partCount`. Workers will skip every part
|
|
33
|
+
* number in `plan.completedParts`. The default behaviour
|
|
34
|
+
* (no plan, or `kind: "fresh"`) is unchanged.
|
|
35
|
+
*/
|
|
36
|
+
start(plan?: ResumePlan): Promise<UploadResult>;
|
|
37
|
+
/**
|
|
38
|
+
* Cancel an in-flight upload and best-effort abort the backend session.
|
|
39
|
+
* Safe to call from any state — terminal states are a no-op. Returns when
|
|
40
|
+
* the backend has been notified (or never reachable in the first place).
|
|
41
|
+
*/
|
|
42
|
+
abort(): Promise<void>;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Convenience wrapper that constructs an Uploader and immediately starts it.
|
|
46
|
+
* Use the class directly when you need to expose `abort()` to the UI or
|
|
47
|
+
* observe status transitions externally.
|
|
48
|
+
*/
|
|
49
|
+
export declare function uploadFile(http: Readonly<HttpClient>, file: Blob, options?: UploaderOptions): Promise<UploadResult>;
|
|
50
|
+
/**
|
|
51
|
+
* Exposed for test seams; not part of the stable public surface.
|
|
52
|
+
*/
|
|
53
|
+
export declare const _internals: {
|
|
54
|
+
DEFAULT_PART_CONCURRENCY: number;
|
|
55
|
+
DEFAULT_MAX_PART_RETRIES: number;
|
|
56
|
+
DEFAULT_RETRY_BASE_DELAY: number;
|
|
57
|
+
DEFAULT_RETRY_MAX_DELAY: number;
|
|
58
|
+
};
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vef-framework-react/core",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "2.
|
|
4
|
+
"version": "2.2.0",
|
|
5
5
|
"private": false,
|
|
6
6
|
"description": "Core features for VEF framework",
|
|
7
7
|
"author": {
|
|
@@ -49,27 +49,27 @@
|
|
|
49
49
|
},
|
|
50
50
|
"dependencies": {
|
|
51
51
|
"@dnd-kit/abstract": "^0.4.0",
|
|
52
|
+
"@dnd-kit/collision": "^0.4.0",
|
|
52
53
|
"@dnd-kit/dom": "^0.4.0",
|
|
53
54
|
"@dnd-kit/helpers": "^0.4.0",
|
|
54
55
|
"@dnd-kit/react": "^0.4.0",
|
|
55
56
|
"@emotion/react": "^11.14.0",
|
|
56
57
|
"@hello-pangea/dnd": "^18.0.1",
|
|
57
58
|
"@microsoft/fetch-event-source": "^2.0.1",
|
|
58
|
-
"@tanstack/react-query": "^5.100.
|
|
59
|
+
"@tanstack/react-query": "^5.100.9",
|
|
59
60
|
"@xstate/react": "^6.1.0",
|
|
60
|
-
"
|
|
61
|
-
"axios": "^1.15.2",
|
|
61
|
+
"axios": "^1.16.0",
|
|
62
62
|
"clsx": "^2.1.1",
|
|
63
|
-
"immer": "^11.1.
|
|
64
|
-
"jotai": "^2.
|
|
63
|
+
"immer": "^11.1.7",
|
|
64
|
+
"jotai": "^2.20.0",
|
|
65
65
|
"motion": "^12.38.0",
|
|
66
66
|
"use-immer": "^0.11.0",
|
|
67
|
-
"xstate": "^5.
|
|
68
|
-
"zustand": "^5.0.
|
|
69
|
-
"@vef-framework-react/shared": "2.
|
|
67
|
+
"xstate": "^5.31.0",
|
|
68
|
+
"zustand": "^5.0.13",
|
|
69
|
+
"@vef-framework-react/shared": "2.2.0"
|
|
70
70
|
},
|
|
71
71
|
"devDependencies": {
|
|
72
|
-
"react": "^19.2.
|
|
72
|
+
"react": "^19.2.6"
|
|
73
73
|
},
|
|
74
74
|
"scripts": {
|
|
75
75
|
"clean": "rimraf dist",
|
package/dist/cjs/ai/index.cjs
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
require(`../_internal/_rolldown/runtime.cjs`),require(`ai`);
|
package/dist/es/ai/index.js
DELETED
|
@@ -1,3 +0,0 @@
|
|
|
1
|
-
/*! @vef-framework-react/core v2.1.11 made by Venus | 2026-04-29T08:23:47.448Z */
|
|
2
|
-
import { DefaultChatTransport as e, TextStreamChatTransport as t, getToolName as n, getToolOrDynamicToolName as r, isDataUIPart as i, isDeepEqualData as a, isFileUIPart as o, isReasoningUIPart as s, isTextUIPart as c, isToolOrDynamicToolUIPart as l, isToolUIPart as u, parsePartialJson as d } from "ai";
|
|
3
|
-
export { e as DefaultChatTransport, t as TextStreamChatTransport, n as getToolName, r as getToolOrDynamicToolName, i as isDataUIPart, a as isDeepEqualData, o as isFileUIPart, s as isReasoningUIPart, c as isTextUIPart, l as isToolOrDynamicToolUIPart, u as isToolUIPart, d as parsePartialJson };
|
package/dist/types/ai/index.d.ts
DELETED
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
export { DefaultChatTransport, TextStreamChatTransport, type ChatTransport } from 'ai';
|
|
2
|
-
export type { DataUIPart, DynamicToolUIPart, FileUIPart, ReasoningUIPart, SourceDocumentUIPart, SourceUrlUIPart, StepStartUIPart, TextUIPart, ToolUIPart, UIMessage, UIMessageChunk, UIMessagePart } from 'ai';
|
|
3
|
-
export type { UIToolInvocation, UITools } from 'ai';
|
|
4
|
-
export { getToolName, getToolOrDynamicToolName } from 'ai';
|
|
5
|
-
export { isDataUIPart, isFileUIPart, isReasoningUIPart, isTextUIPart, isToolOrDynamicToolUIPart, isToolUIPart } from 'ai';
|
|
6
|
-
export { isDeepEqualData, parsePartialJson } from 'ai';
|