@ttt-productions/upload-ui 0.7.16 → 0.7.18
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/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -3
- package/dist/index.js.map +1 -1
- package/dist/react/guard/guarded-link.d.ts +11 -0
- package/dist/react/guard/guarded-link.d.ts.map +1 -0
- package/dist/react/guard/guarded-link.js.map +1 -0
- package/dist/react/guard/index.d.ts +3 -3
- package/dist/react/guard/index.d.ts.map +1 -1
- package/dist/react/guard/index.js +3 -3
- package/dist/react/guard/index.js.map +1 -1
- package/dist/react/guard/local-upload-guard-provider.d.ts +31 -0
- package/dist/react/guard/local-upload-guard-provider.d.ts.map +1 -0
- package/dist/react/{local-upload-guard-provider.js → guard/local-upload-guard-provider.js} +3 -60
- package/dist/react/guard/local-upload-guard-provider.js.map +1 -0
- package/dist/react/guard/use-guarded-navigation.d.ts +3 -0
- package/dist/react/guard/use-guarded-navigation.d.ts.map +1 -0
- package/dist/react/guard/use-guarded-navigation.js +12 -0
- package/dist/react/guard/use-guarded-navigation.js.map +1 -0
- package/dist/react/tray/in-flight-uploads-provider.d.ts +141 -0
- package/dist/react/tray/in-flight-uploads-provider.d.ts.map +1 -0
- package/dist/react/{in-flight-uploads-provider.js → tray/in-flight-uploads-provider.js} +16 -136
- package/dist/react/tray/in-flight-uploads-provider.js.map +1 -0
- package/dist/react/tray/index.d.ts +4 -4
- package/dist/react/tray/index.d.ts.map +1 -1
- package/dist/react/tray/index.js +4 -4
- package/dist/react/tray/index.js.map +1 -1
- package/dist/react/tray/use-clear-upload-activity.d.ts +8 -0
- package/dist/react/tray/use-clear-upload-activity.d.ts.map +1 -0
- package/dist/react/tray/use-clear-upload-activity.js +13 -0
- package/dist/react/tray/use-clear-upload-activity.js.map +1 -0
- package/dist/react/{use-mark-upload-activity-seen.d.ts → tray/use-mark-upload-activity-seen.d.ts} +0 -4
- package/dist/react/tray/use-mark-upload-activity-seen.d.ts.map +1 -0
- package/dist/react/{use-mark-upload-activity-seen.js → tray/use-mark-upload-activity-seen.js} +0 -21
- package/dist/react/tray/use-mark-upload-activity-seen.js.map +1 -0
- package/dist/react/{use-upload-processing.d.ts → tray/use-upload-processing.d.ts} +0 -10
- package/dist/react/tray/use-upload-processing.d.ts.map +1 -0
- package/dist/react/{use-upload-processing.js → tray/use-upload-processing.js} +10 -20
- package/dist/react/tray/use-upload-processing.js.map +1 -0
- package/dist/react/upload/deferred-upload-form-shell.d.ts +28 -0
- package/dist/react/upload/deferred-upload-form-shell.d.ts.map +1 -0
- package/dist/react/{deferred-upload-form-shell.js → upload/deferred-upload-form-shell.js} +5 -2
- package/dist/react/upload/deferred-upload-form-shell.js.map +1 -0
- package/dist/react/upload/index.d.ts +2 -2
- package/dist/react/upload/index.d.ts.map +1 -1
- package/dist/react/upload/index.js +2 -2
- package/dist/react/upload/index.js.map +1 -1
- package/dist/react/upload/use-guarded-upload.d.ts +16 -0
- package/dist/react/upload/use-guarded-upload.d.ts.map +1 -0
- package/dist/react/{use-guarded-upload.js → upload/use-guarded-upload.js} +2 -15
- package/dist/react/upload/use-guarded-upload.js.map +1 -0
- package/dist/upload-display.d.ts +0 -14
- package/dist/upload-display.d.ts.map +1 -1
- package/dist/upload-display.js +11 -12
- package/dist/upload-display.js.map +1 -1
- package/package.json +5 -5
- package/dist/react/deferred-upload-form-shell.d.ts +0 -46
- package/dist/react/deferred-upload-form-shell.d.ts.map +0 -1
- package/dist/react/deferred-upload-form-shell.js.map +0 -1
- package/dist/react/guarded-link.d.ts +0 -38
- package/dist/react/guarded-link.d.ts.map +0 -1
- package/dist/react/guarded-link.js.map +0 -1
- package/dist/react/in-flight-uploads-provider.d.ts +0 -266
- package/dist/react/in-flight-uploads-provider.d.ts.map +0 -1
- package/dist/react/in-flight-uploads-provider.js.map +0 -1
- package/dist/react/local-upload-guard-provider.d.ts +0 -112
- package/dist/react/local-upload-guard-provider.d.ts.map +0 -1
- package/dist/react/local-upload-guard-provider.js.map +0 -1
- package/dist/react/use-clear-upload-activity.d.ts +0 -33
- package/dist/react/use-clear-upload-activity.d.ts.map +0 -1
- package/dist/react/use-clear-upload-activity.js +0 -31
- package/dist/react/use-clear-upload-activity.js.map +0 -1
- package/dist/react/use-guarded-navigation.d.ts +0 -10
- package/dist/react/use-guarded-navigation.d.ts.map +0 -1
- package/dist/react/use-guarded-navigation.js +0 -40
- package/dist/react/use-guarded-navigation.js.map +0 -1
- package/dist/react/use-guarded-upload.d.ts +0 -45
- package/dist/react/use-guarded-upload.d.ts.map +0 -1
- package/dist/react/use-guarded-upload.js.map +0 -1
- package/dist/react/use-mark-upload-activity-seen.d.ts.map +0 -1
- package/dist/react/use-mark-upload-activity-seen.js.map +0 -1
- package/dist/react/use-upload-processing.d.ts.map +0 -1
- package/dist/react/use-upload-processing.js.map +0 -1
- /package/dist/react/{guarded-link.js → guard/guarded-link.js} +0 -0
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
-
//
|
|
4
|
-
//
|
|
5
|
-
// @ttt-productions/query-core" rule (see docs/packages/package-architecture.md →
|
|
6
|
-
// "Firestore access goes through query-core").
|
|
3
|
+
// SANCTIONED EXCEPTION to RULE-STD-ARCH-206 (packages read and write Firestore only
|
|
4
|
+
// through @ttt-productions/query-core).
|
|
7
5
|
//
|
|
8
6
|
// WHY this provider reads Firestore directly instead of via a query-core hook:
|
|
9
7
|
// 1. It needs snapshot *transition events* — onSnapshot's `docChanges()` with
|
|
@@ -18,41 +16,9 @@ import { jsx as _jsx } from "react/jsx-runtime";
|
|
|
18
16
|
// Turbopack module identity (see defaultFirestoreSubscribe's comment).
|
|
19
17
|
//
|
|
20
18
|
// Do NOT "migrate" this onto query-core without preserving docChanges() semantics.
|
|
21
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
22
19
|
import { collection, onSnapshot, query, where } from 'firebase/firestore';
|
|
23
|
-
/**
|
|
24
|
-
* Generic in-flight uploads provider.
|
|
25
|
-
*
|
|
26
|
-
* Provides a global Map of in-flight upload state by `pendingMediaId`, derived
|
|
27
|
-
* from a Firestore listener over the consumer-supplied collection. On terminal
|
|
28
|
-
* status transitions observed THIS SESSION, fires consumer-supplied success /
|
|
29
|
-
* failure / rejection callbacks. Records monitoring breadcrumbs and parse
|
|
30
|
-
* errors through the injected monitoring callback.
|
|
31
|
-
*
|
|
32
|
-
* EVERY app-specific value is supplied by the consumer:
|
|
33
|
-
* - userId resolution
|
|
34
|
-
* - Firestore `db` reference
|
|
35
|
-
* - collection path
|
|
36
|
-
* - listener time window (ms)
|
|
37
|
-
* - parser/schema for raw Firestore doc → typed PendingMedia
|
|
38
|
-
* - success copy per origin
|
|
39
|
-
* - notification callback (cache invalidation, etc.)
|
|
40
|
-
* - toast callback
|
|
41
|
-
* - rejection callback (for the media-rejection dialog or equivalent)
|
|
42
|
-
* - monitoring callback (breadcrumbs + captured errors)
|
|
43
|
-
*
|
|
44
|
-
* Read APIs:
|
|
45
|
-
* - `useInFlightUploadsState()` — full Map.
|
|
46
|
-
* - `useInFlightUpload(id)` — single doc, narrowable on status.
|
|
47
|
-
* - `useUploadActivityState()` — tray-visible items, sorted newest-first.
|
|
48
|
-
*
|
|
49
|
-
* The package owns the deduplication, initial-snapshot suppression, and
|
|
50
|
-
* non-terminal → terminal transition tracking. It does NOT own anything about
|
|
51
|
-
* what a file-origin is or what message text appears in toasts.
|
|
52
|
-
*/
|
|
53
20
|
import { createContext, useCallback, useContext, useEffect, useMemo, useRef, useState, } from 'react';
|
|
54
21
|
import { isPendingMediaNonTerminalStatus, isPendingMediaTerminalStatus, PendingMediaStatusSchema, } from '@ttt-productions/media-schemas';
|
|
55
|
-
// Status values derive from media-schemas' one declaration.
|
|
56
22
|
const STATUS = PendingMediaStatusSchema.enum;
|
|
57
23
|
const InFlightUploadsContext = createContext(undefined);
|
|
58
24
|
function fromParsed(parsed) {
|
|
@@ -92,7 +58,6 @@ function fromParsed(parsed) {
|
|
|
92
58
|
uploadTraySeenBy: parsed.uploadTraySeenBy,
|
|
93
59
|
};
|
|
94
60
|
}
|
|
95
|
-
// rejected
|
|
96
61
|
return {
|
|
97
62
|
...base,
|
|
98
63
|
status: STATUS.rejected,
|
|
@@ -102,10 +67,7 @@ function fromParsed(parsed) {
|
|
|
102
67
|
violationId: parsed.violationId,
|
|
103
68
|
uploadTrayClearedAt: parsed.uploadTrayClearedAt,
|
|
104
69
|
uploadTrayClearedBy: parsed.uploadTrayClearedBy,
|
|
105
|
-
//
|
|
106
|
-
// `rejected` branch — while `completed`/`failed` keep them — made a seen
|
|
107
|
-
// rejected upload relight the Files dot forever, because the tray's
|
|
108
|
-
// unseen-terminal check never saw `uploadTraySeenAt`.
|
|
70
|
+
// Without the seen fields a seen rejected upload relights the Files dot forever.
|
|
109
71
|
uploadTraySeenAt: parsed.uploadTraySeenAt,
|
|
110
72
|
uploadTraySeenBy: parsed.uploadTraySeenBy,
|
|
111
73
|
};
|
|
@@ -116,36 +78,19 @@ export function InFlightUploadsProvider(props) {
|
|
|
116
78
|
const [sourceState, setSourceState] = useState('connecting');
|
|
117
79
|
const [restarts, setRestarts] = useState(0);
|
|
118
80
|
const [retrying, setRetrying] = useState(false);
|
|
119
|
-
/** Set by `retry` for the subscription the restart opens; that run keeps the source state. */
|
|
120
81
|
const restartRequestedRef = useRef(false);
|
|
121
82
|
const seenTerminalIdsRef = useRef(new Set());
|
|
122
83
|
const statusByIdRef = useRef(new Map());
|
|
123
84
|
const hasProcessedInitialSnapshotRef = useRef(false);
|
|
124
|
-
/** The identity the dedup/tracking refs belong to — they outlive resubscribes
|
|
125
|
-
* for the SAME user (auth-settling flaps) and reset only on a real identity
|
|
126
|
-
* change. See the reset block in the subscription effect. */
|
|
127
85
|
const trackedUserIdRef = useRef(null);
|
|
128
|
-
// Stable refs for adapter callbacks — read from latest adapter inside effect.
|
|
129
86
|
const adapterRef = useRef(adapter);
|
|
130
87
|
useEffect(() => {
|
|
131
88
|
adapterRef.current = adapter;
|
|
132
89
|
});
|
|
133
90
|
const userId = adapter.getCurrentUserId();
|
|
134
91
|
useEffect(() => {
|
|
135
|
-
// The
|
|
136
|
-
//
|
|
137
|
-
// status-tracking refs are IDENTITY-scoped, not subscription-scoped: an
|
|
138
|
-
// auth-settling flap (uid → null → same uid re-subscribes) must neither
|
|
139
|
-
// re-fire terminals the previous subscription already fired (seen set
|
|
140
|
-
// persists) nor lose the observed non-terminal statuses that let the new
|
|
141
|
-
// subscription's initial listing detect a transition that completed during
|
|
142
|
-
// the gap. A real identity change — including UID-A → UID-B with no
|
|
143
|
-
// intermediate null user — starts clean; never rely on an intermediate
|
|
144
|
-
// sign-out to clear refs between two authenticated UIDs.
|
|
145
|
-
// A restart the person asked for keeps the source state it had (a failure stays a failure
|
|
146
|
-
// until the restarted listener answers); every other run starts over as `connecting`.
|
|
147
|
-
// A restart belongs to the identity it was asked for: one that lands with a sign-out or a switch
|
|
148
|
-
// of account is an ordinary new subscription, which starts over.
|
|
92
|
+
// The dedup and tracking refs are identity-scoped: they survive a same-user resubscribe and reset
|
|
93
|
+
// on any identity change, UID-A to UID-B with no sign-out between included.
|
|
149
94
|
let restarting = restartRequestedRef.current && userId !== null && userId === trackedUserIdRef.current;
|
|
150
95
|
restartRequestedRef.current = false;
|
|
151
96
|
setUploads(new Map());
|
|
@@ -195,12 +140,8 @@ export function InFlightUploadsProvider(props) {
|
|
|
195
140
|
const currentIsTerminal = isPendingMediaTerminalStatus(currentStatus);
|
|
196
141
|
const previousWasNonTerminal = isPendingMediaNonTerminalStatus(previousStatus);
|
|
197
142
|
if (isInitialSnapshot) {
|
|
198
|
-
// A
|
|
199
|
-
//
|
|
200
|
-
// refresh never re-toasts. ONE exception — this provider instance
|
|
201
|
-
// tracked the doc as non-terminal before (same-identity resubscribe
|
|
202
|
-
// gap; the tracking refs survive those), so the terminal listing IS
|
|
203
|
-
// the transition, observed across the gap, and must fire.
|
|
143
|
+
// A first snapshot re-lists current state: its terminal docs fire only when this instance tracked
|
|
144
|
+
// them as non-terminal before.
|
|
204
145
|
if (currentIsTerminal) {
|
|
205
146
|
if (previousWasNonTerminal && !seenTerminalIdsRef.current.has(parsed.id)) {
|
|
206
147
|
newlyTerminal.push(parsed);
|
|
@@ -209,25 +150,20 @@ export function InFlightUploadsProvider(props) {
|
|
|
209
150
|
}
|
|
210
151
|
}
|
|
211
152
|
else if (currentIsTerminal && !seenTerminalIdsRef.current.has(parsed.id)) {
|
|
212
|
-
//
|
|
213
|
-
// FIRST client-visible state is already terminal. A fast backend
|
|
214
|
-
// outcome (moderation rejection in ~2s) can coalesce created→terminal
|
|
215
|
-
// into one delivery, and the uploader is actively waiting on exactly
|
|
216
|
-
// this callback; swallowing it silently loses a rejection dialog.
|
|
153
|
+
// A fast outcome can coalesce created and terminal into one delivery, so any unseen terminal fires.
|
|
217
154
|
seenTerminalIdsRef.current.add(parsed.id);
|
|
218
155
|
newlyTerminal.push(parsed);
|
|
219
156
|
}
|
|
220
157
|
statusByIdRef.current.set(parsed.id, currentStatus);
|
|
221
158
|
}
|
|
222
159
|
hasProcessedInitialSnapshotRef.current = true;
|
|
223
|
-
// Metadata-derived source state: stay `connecting` until a server-confirmed
|
|
224
|
-
// snapshot, `offline` if only cached data arrives after being live.
|
|
225
160
|
const fromCache = snapshot.metadata?.fromCache ?? false;
|
|
226
|
-
// A restart ends on the server's answer: a cached snapshot during it keeps the failure on screen
|
|
227
|
-
// (the server may refuse again). Otherwise a snapshot after a failed listener comes from a new
|
|
228
|
-
// subscription: not yet live, never offline.
|
|
229
161
|
if (!(restarting && fromCache)) {
|
|
230
|
-
setSourceState((prev) => fromCache
|
|
162
|
+
setSourceState((prev) => fromCache
|
|
163
|
+
? prev === 'connecting' || prev === 'error'
|
|
164
|
+
? 'connecting'
|
|
165
|
+
: 'offline'
|
|
166
|
+
: 'live');
|
|
231
167
|
restarting = false;
|
|
232
168
|
setRetrying(false);
|
|
233
169
|
}
|
|
@@ -270,13 +206,6 @@ export function InFlightUploadsProvider(props) {
|
|
|
270
206
|
adapterRef.current.onUploadRejected(parsed);
|
|
271
207
|
}
|
|
272
208
|
}
|
|
273
|
-
// Bounded RESUBSCRIBE on listener error: a cold-session race (e.g. Firestore
|
|
274
|
-
// App Check enforcement rejecting the first attach before the token is
|
|
275
|
-
// minted) must not kill the listener for the whole session — observed live:
|
|
276
|
-
// one permission-denied at first login → sourceState 'error' forever, every
|
|
277
|
-
// tray file status dead until reload. Retry on a short ladder; a snapshot
|
|
278
|
-
// resets the ladder (healthy again); exhausting it goes terminal 'error'
|
|
279
|
-
// (a real rules denial stays denied — retries are cheap and bounded).
|
|
280
209
|
const RESUBSCRIBE_DELAYS_MS = [1_000, 3_000, 10_000, 30_000];
|
|
281
210
|
let attempt = 0;
|
|
282
211
|
let disposed = false;
|
|
@@ -289,7 +218,7 @@ export function InFlightUploadsProvider(props) {
|
|
|
289
218
|
userId,
|
|
290
219
|
windowStartMs,
|
|
291
220
|
onSnapshot: (snapshot) => {
|
|
292
|
-
attempt = 0;
|
|
221
|
+
attempt = 0;
|
|
293
222
|
handleSnapshot(snapshot);
|
|
294
223
|
},
|
|
295
224
|
onError: (error) => {
|
|
@@ -319,8 +248,6 @@ export function InFlightUploadsProvider(props) {
|
|
|
319
248
|
clearTimeout(retryTimer);
|
|
320
249
|
unsubscribe?.();
|
|
321
250
|
};
|
|
322
|
-
// adapter is intentionally NOT in the deps array — adapter is read via
|
|
323
|
-
// adapterRef on every snapshot, so identity changes don't re-subscribe.
|
|
324
251
|
}, [userId, subscribe, restarts]);
|
|
325
252
|
const retry = useCallback(() => {
|
|
326
253
|
restartRequestedRef.current = true;
|
|
@@ -330,9 +257,6 @@ export function InFlightUploadsProvider(props) {
|
|
|
330
257
|
const value = useMemo(() => ({ uploads, sourceState, retry, retrying }), [uploads, sourceState, retry, retrying]);
|
|
331
258
|
return (_jsx(InFlightUploadsContext.Provider, { value: value, children: children }));
|
|
332
259
|
}
|
|
333
|
-
// =============================================================================
|
|
334
|
-
// Read APIs
|
|
335
|
-
// =============================================================================
|
|
336
260
|
export function useInFlightUploadsState() {
|
|
337
261
|
const ctx = useContext(InFlightUploadsContext);
|
|
338
262
|
if (ctx === undefined) {
|
|
@@ -349,12 +273,6 @@ export function useInFlightUpload(id) {
|
|
|
349
273
|
return undefined;
|
|
350
274
|
return ctx.uploads.get(id);
|
|
351
275
|
}
|
|
352
|
-
/**
|
|
353
|
-
* Metadata-derived source state of the uploads listener
|
|
354
|
-
* (`connecting | live | offline | error`). The Files tray uses this to show a
|
|
355
|
-
* degraded indicator and never display "all caught up" while the source is
|
|
356
|
-
* `offline`/`error`/`connecting`.
|
|
357
|
-
*/
|
|
358
276
|
export function useUploadsSourceState() {
|
|
359
277
|
const ctx = useContext(InFlightUploadsContext);
|
|
360
278
|
if (ctx === undefined) {
|
|
@@ -362,10 +280,6 @@ export function useUploadsSourceState() {
|
|
|
362
280
|
}
|
|
363
281
|
return ctx.sourceState;
|
|
364
282
|
}
|
|
365
|
-
/**
|
|
366
|
-
* The uploads listener's restart — the Try again of a failure shown on `useUploadsSourceState` —
|
|
367
|
-
* and whether it is running.
|
|
368
|
-
*/
|
|
369
283
|
export function useUploadsSourceRetry() {
|
|
370
284
|
const ctx = useContext(InFlightUploadsContext);
|
|
371
285
|
if (ctx === undefined) {
|
|
@@ -373,24 +287,9 @@ export function useUploadsSourceRetry() {
|
|
|
373
287
|
}
|
|
374
288
|
return { retry: ctx.retry, retrying: ctx.retrying };
|
|
375
289
|
}
|
|
376
|
-
// =============================================================================
|
|
377
|
-
// Tray helpers
|
|
378
|
-
// =============================================================================
|
|
379
|
-
/**
|
|
380
|
-
* `true` for `completed` / `failed` / `rejected`. Used by tray UI to decide
|
|
381
|
-
* whether a Clear action is available for an item.
|
|
382
|
-
*/
|
|
383
290
|
export function isTerminalUpload(item) {
|
|
384
291
|
return isPendingMediaTerminalStatus(item.status);
|
|
385
292
|
}
|
|
386
|
-
/**
|
|
387
|
-
* Tray-visible items. Includes every pending/processing upload, plus terminal
|
|
388
|
-
* uploads that have NOT been cleared from the tray. Sorted newest-first by
|
|
389
|
-
* createdAt.
|
|
390
|
-
*
|
|
391
|
-
* The public selector name in upload-ui is `useUploadActivityState`. The
|
|
392
|
-
* mutation hook is `useClearUploadActivity` (in a separate file).
|
|
393
|
-
*/
|
|
394
293
|
export function useUploadActivityState() {
|
|
395
294
|
const uploads = useInFlightUploadsState();
|
|
396
295
|
return useMemo(() => {
|
|
@@ -403,29 +302,10 @@ export function useUploadActivityState() {
|
|
|
403
302
|
.sort((a, b) => b.createdAt - a.createdAt);
|
|
404
303
|
}, [uploads]);
|
|
405
304
|
}
|
|
406
|
-
//
|
|
407
|
-
//
|
|
408
|
-
// =============================================================================
|
|
409
|
-
/**
|
|
410
|
-
* Default Firestore subscription using the consumer's `firebase/firestore`
|
|
411
|
-
* module instance (via static ESM import at the top of this file).
|
|
412
|
-
*
|
|
413
|
-
* Using static ESM import — NOT `require()` — is load-bearing. CommonJS
|
|
414
|
-
* `require('firebase/firestore')` and ESM `import 'firebase/firestore'` resolve
|
|
415
|
-
* to different module instances under Next.js + Turbopack. If the consumer
|
|
416
|
-
* constructs `db` via ESM and we receive it here, but we then call
|
|
417
|
-
* `collection()` from a CJS-loaded copy of firebase, the firebase runtime
|
|
418
|
-
* does not recognize the db as a Firestore instance and throws
|
|
419
|
-
* "Expected first argument to collection() to be a CollectionReference,
|
|
420
|
-
* a DocumentReference or FirebaseFirestore".
|
|
421
|
-
*
|
|
422
|
-
* Consumers who want to skip the firebase code path entirely (tests, alt
|
|
423
|
-
* backends) supply their own `subscribe` prop to `InFlightUploadsProvider`.
|
|
424
|
-
*/
|
|
305
|
+
// A static ESM import, never require(): under Next.js + Turbopack a CJS-loaded firebase/firestore
|
|
306
|
+
// is another module instance and rejects a db built through ESM.
|
|
425
307
|
const defaultFirestoreSubscribe = (args) => {
|
|
426
308
|
const q = query(collection(args.db, args.collectionPath), where('userId', '==', args.userId), where('createdAt', '>=', args.windowStartMs));
|
|
427
|
-
// includeMetadataChanges so the provider can derive a `connecting|live|offline|error`
|
|
428
|
-
// source state from `snapshot.metadata.fromCache` (the Files tray degraded indicator).
|
|
429
309
|
return onSnapshot(q, { includeMetadataChanges: true }, args.onSnapshot, args.onError);
|
|
430
310
|
};
|
|
431
311
|
//# sourceMappingURL=in-flight-uploads-provider.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"in-flight-uploads-provider.js","sourceRoot":"","sources":["../../../src/react/tray/in-flight-uploads-provider.tsx"],"names":[],"mappings":"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","sourcesContent":["'use client';\n\n// SANCTIONED EXCEPTION to RULE-STD-ARCH-206 (packages read and write Firestore only\n// through @ttt-productions/query-core).\n//\n// WHY this provider reads Firestore directly instead of via a query-core hook:\n// 1. It needs snapshot *transition events* — onSnapshot's `docChanges()` with\n// added / modified / removed — to fire one-shot terminal callbacks and to\n// suppress the initial snapshot. query-core's hooks return \"the current\n// list\", not per-doc transitions, so they cannot express this state machine.\n// 2. The subscription is already abstracted behind an injectable\n// `FirestoreSubscribeFn` (the `subscribe` prop); the direct firebase code\n// path lives ONLY in `defaultFirestoreSubscribe` below and is fully\n// swappable (tests / alternate backends inject their own).\n// 3. The static ESM `firebase/firestore` import is load-bearing for Next.js +\n// Turbopack module identity (see defaultFirestoreSubscribe's comment).\n//\n// Do NOT \"migrate\" this onto query-core without preserving docChanges() semantics.\nimport { collection, onSnapshot, query, where } from 'firebase/firestore';\n\nimport {\n createContext,\n useCallback,\n useContext,\n useEffect,\n useMemo,\n useRef,\n useState,\n type ReactNode,\n} from 'react';\nimport {\n isPendingMediaNonTerminalStatus,\n isPendingMediaTerminalStatus,\n PendingMediaStatusSchema,\n type PendingMediaNonTerminalStatus,\n type PendingMediaStatus,\n} from '@ttt-productions/media-schemas';\n\nconst STATUS = PendingMediaStatusSchema.enum;\n\nexport type InFlightUploadStatus = PendingMediaStatus;\n\nexport type InFlightUploadBase<TFileOrigin extends string = string> = {\n id: string;\n fileOrigin: TFileOrigin;\n surface: string;\n createdAt: number;\n targetIds?: string[];\n originalContentType?: string;\n originalSize?: number;\n};\n\nexport type InFlightUploadActive<TFileOrigin extends string = string> =\n InFlightUploadBase<TFileOrigin> & {\n status: PendingMediaNonTerminalStatus;\n };\n\nexport type InFlightUploadCompleted<TFileOrigin extends string = string> =\n InFlightUploadBase<TFileOrigin> & {\n status: typeof PendingMediaStatusSchema.enum.completed;\n completedAt: number;\n uploadTrayClearedAt?: number;\n uploadTrayClearedBy?: string;\n uploadTraySeenAt?: number;\n uploadTraySeenBy?: string;\n };\n\nexport type InFlightUploadFailed<TFileOrigin extends string = string> =\n InFlightUploadBase<TFileOrigin> & {\n status: typeof PendingMediaStatusSchema.enum.failed;\n failedAt: number;\n errorCategory: string;\n errorMessage: string;\n uploadTrayClearedAt?: number;\n uploadTrayClearedBy?: string;\n uploadTraySeenAt?: number;\n uploadTraySeenBy?: string;\n };\n\nexport type InFlightUploadRejected<TFileOrigin extends string = string> =\n InFlightUploadBase<TFileOrigin> & {\n status: typeof PendingMediaStatusSchema.enum.rejected;\n rejectedAt: number;\n rejectionType: 'text' | 'media';\n errorMessage: string;\n violationId?: string;\n uploadTrayClearedAt?: number;\n uploadTrayClearedBy?: string;\n uploadTraySeenAt?: number;\n uploadTraySeenBy?: string;\n };\n\nexport type InFlightUpload<TFileOrigin extends string = string> =\n | InFlightUploadActive<TFileOrigin>\n | InFlightUploadCompleted<TFileOrigin>\n | InFlightUploadFailed<TFileOrigin>\n | InFlightUploadRejected<TFileOrigin>;\n\nexport type ParsedPendingMedia<TFileOrigin extends string = string> = {\n id: string;\n userId: string;\n fileOrigin: TFileOrigin;\n status: InFlightUploadStatus;\n createdAt: number;\n surface: string;\n targetIds?: string[];\n originalContentType?: string;\n originalSize?: number;\n completedAt?: number;\n failedAt?: number;\n rejectedAt?: number;\n errorCategory?: string;\n errorMessage?: string;\n rejectionType?: 'text' | 'media';\n violationId?: string;\n uploadTrayClearedAt?: number;\n uploadTrayClearedBy?: string;\n uploadTraySeenAt?: number;\n uploadTraySeenBy?: string;\n domainEvents?: unknown;\n};\n\nexport type InFlightUploadsAdapter<TFileOrigin extends string = string> = {\n getCurrentUserId: () => string | null;\n\n db: unknown;\n\n collectionPath: string;\n\n listenerWindowMs: number;\n\n parsePendingMedia: (raw: unknown) => ParsedPendingMedia<TFileOrigin>;\n\n onUploadCompleted: (parsed: ParsedPendingMedia<TFileOrigin>) => void;\n\n onUploadFailed: (parsed: ParsedPendingMedia<TFileOrigin>) => void;\n\n onUploadRejected: (parsed: ParsedPendingMedia<TFileOrigin>) => void;\n\n onMonitoringEvent: (event: InFlightUploadsMonitoringEvent<TFileOrigin>) => void;\n};\n\nexport type InFlightUploadsMonitoringEvent<TFileOrigin extends string = string> =\n | {\n type: 'breadcrumb';\n category: 'upload.terminal';\n level: 'info';\n message: string;\n data: {\n id: string;\n fileOrigin: TFileOrigin;\n status: InFlightUploadStatus;\n surface: string;\n };\n }\n | {\n type: 'parse-error';\n docId: string;\n error: unknown;\n data: unknown;\n }\n | {\n type: 'listener-error';\n error: unknown;\n };\n\nexport type FirestoreSubscribeFn = (args: {\n db: unknown;\n collectionPath: string;\n userId: string;\n windowStartMs: number;\n onSnapshot: (snapshot: FirestoreLikeSnapshot) => void;\n onError: (error: unknown) => void;\n}) => () => void;\n\nexport type FirestoreLikeSnapshot = {\n docChanges: () => FirestoreLikeDocChange[];\n metadata?: { fromCache: boolean };\n};\n\n/** Firestore serves cached snapshots offline without firing the error callback, so liveness comes from metadata. */\nexport type UploadsSourceState = 'connecting' | 'live' | 'offline' | 'error';\n\nexport type FirestoreLikeDocChange = {\n type: 'added' | 'modified' | 'removed';\n doc: {\n id: string;\n data: () => unknown;\n };\n};\n\ninterface InFlightUploadsContextValue<TFileOrigin extends string = string> {\n uploads: Map<string, InFlightUpload<TFileOrigin>>;\n sourceState: UploadsSourceState;\n retry: () => void;\n retrying: boolean;\n}\n\nexport interface UploadsSourceRetry {\n retry: () => void;\n retrying: boolean;\n}\n\nconst InFlightUploadsContext = createContext<InFlightUploadsContextValue | undefined>(undefined);\n\nexport interface InFlightUploadsProviderProps<TFileOrigin extends string = string> {\n adapter: InFlightUploadsAdapter<TFileOrigin>;\n subscribe?: FirestoreSubscribeFn;\n children: ReactNode;\n}\n\nfunction fromParsed<TFileOrigin extends string>(\n parsed: ParsedPendingMedia<TFileOrigin>,\n): InFlightUpload<TFileOrigin> {\n const base: InFlightUploadBase<TFileOrigin> = {\n id: parsed.id,\n fileOrigin: parsed.fileOrigin,\n surface: parsed.surface,\n createdAt: parsed.createdAt,\n targetIds: parsed.targetIds,\n originalContentType: parsed.originalContentType,\n originalSize: parsed.originalSize,\n };\n if (isPendingMediaNonTerminalStatus(parsed.status)) {\n return { ...base, status: parsed.status };\n }\n if (parsed.status === STATUS.completed) {\n return {\n ...base,\n status: STATUS.completed,\n completedAt: parsed.completedAt ?? parsed.createdAt,\n uploadTrayClearedAt: parsed.uploadTrayClearedAt,\n uploadTrayClearedBy: parsed.uploadTrayClearedBy,\n uploadTraySeenAt: parsed.uploadTraySeenAt,\n uploadTraySeenBy: parsed.uploadTraySeenBy,\n };\n }\n if (parsed.status === STATUS.failed) {\n return {\n ...base,\n status: STATUS.failed,\n failedAt: parsed.failedAt ?? parsed.createdAt,\n errorCategory: parsed.errorCategory ?? 'system',\n errorMessage: parsed.errorMessage ?? '',\n uploadTrayClearedAt: parsed.uploadTrayClearedAt,\n uploadTrayClearedBy: parsed.uploadTrayClearedBy,\n uploadTraySeenAt: parsed.uploadTraySeenAt,\n uploadTraySeenBy: parsed.uploadTraySeenBy,\n };\n }\n return {\n ...base,\n status: STATUS.rejected,\n rejectedAt: parsed.rejectedAt ?? parsed.createdAt,\n rejectionType: parsed.rejectionType ?? 'media',\n errorMessage: parsed.errorMessage ?? '',\n violationId: parsed.violationId,\n uploadTrayClearedAt: parsed.uploadTrayClearedAt,\n uploadTrayClearedBy: parsed.uploadTrayClearedBy,\n // Without the seen fields a seen rejected upload relights the Files dot forever.\n uploadTraySeenAt: parsed.uploadTraySeenAt,\n uploadTraySeenBy: parsed.uploadTraySeenBy,\n };\n}\n\nexport function InFlightUploadsProvider<TFileOrigin extends string = string>(\n props: InFlightUploadsProviderProps<TFileOrigin>,\n) {\n const { adapter, subscribe = defaultFirestoreSubscribe, children } = props;\n\n const [uploads, setUploads] = useState<Map<string, InFlightUpload<TFileOrigin>>>(new Map());\n const [sourceState, setSourceState] = useState<UploadsSourceState>('connecting');\n const [restarts, setRestarts] = useState(0);\n const [retrying, setRetrying] = useState(false);\n const restartRequestedRef = useRef(false);\n const seenTerminalIdsRef = useRef<Set<string>>(new Set());\n const statusByIdRef = useRef<Map<string, InFlightUploadStatus>>(new Map());\n const hasProcessedInitialSnapshotRef = useRef(false);\n const trackedUserIdRef = useRef<string | null>(null);\n\n const adapterRef = useRef(adapter);\n useEffect(() => {\n adapterRef.current = adapter;\n });\n\n const userId = adapter.getCurrentUserId();\n\n useEffect(() => {\n // The dedup and tracking refs are identity-scoped: they survive a same-user resubscribe and reset\n // on any identity change, UID-A to UID-B with no sign-out between included.\n let restarting =\n restartRequestedRef.current && userId !== null && userId === trackedUserIdRef.current;\n restartRequestedRef.current = false;\n setUploads(new Map());\n if (!restarting) {\n setSourceState('connecting');\n setRetrying(false);\n }\n if (userId !== null && userId !== trackedUserIdRef.current) {\n seenTerminalIdsRef.current = new Set();\n statusByIdRef.current = new Map();\n trackedUserIdRef.current = userId;\n }\n hasProcessedInitialSnapshotRef.current = false;\n\n if (!userId) {\n return;\n }\n\n const a = adapterRef.current;\n const windowStartMs = Date.now() - a.listenerWindowMs;\n\n const handleSnapshot = (snapshot: FirestoreLikeSnapshot) => {\n const updates: Array<{ id: string; upload: InFlightUpload<TFileOrigin> | null }> = [];\n const newlyTerminal: Array<ParsedPendingMedia<TFileOrigin>> = [];\n const isInitialSnapshot = !hasProcessedInitialSnapshotRef.current;\n\n for (const change of snapshot.docChanges()) {\n if (change.type === 'removed') {\n updates.push({ id: change.doc.id, upload: null });\n statusByIdRef.current.delete(change.doc.id);\n seenTerminalIdsRef.current.delete(change.doc.id);\n continue;\n }\n\n let parsed: ParsedPendingMedia<TFileOrigin>;\n try {\n parsed = adapterRef.current.parsePendingMedia(change.doc.data());\n } catch (error) {\n adapterRef.current.onMonitoringEvent({\n type: 'parse-error',\n docId: change.doc.id,\n error,\n data: change.doc.data(),\n });\n continue;\n }\n\n const upload = fromParsed(parsed);\n updates.push({ id: parsed.id, upload });\n\n const previousStatus = statusByIdRef.current.get(parsed.id);\n const currentStatus = parsed.status;\n const currentIsTerminal = isPendingMediaTerminalStatus(currentStatus);\n const previousWasNonTerminal = isPendingMediaNonTerminalStatus(previousStatus);\n\n if (isInitialSnapshot) {\n // A first snapshot re-lists current state: its terminal docs fire only when this instance tracked\n // them as non-terminal before.\n if (currentIsTerminal) {\n if (previousWasNonTerminal && !seenTerminalIdsRef.current.has(parsed.id)) {\n newlyTerminal.push(parsed);\n }\n seenTerminalIdsRef.current.add(parsed.id);\n }\n } else if (currentIsTerminal && !seenTerminalIdsRef.current.has(parsed.id)) {\n // A fast outcome can coalesce created and terminal into one delivery, so any unseen terminal fires.\n seenTerminalIdsRef.current.add(parsed.id);\n newlyTerminal.push(parsed);\n }\n\n statusByIdRef.current.set(parsed.id, currentStatus);\n }\n\n hasProcessedInitialSnapshotRef.current = true;\n\n const fromCache = snapshot.metadata?.fromCache ?? false;\n if (!(restarting && fromCache)) {\n setSourceState((prev) =>\n fromCache\n ? prev === 'connecting' || prev === 'error'\n ? 'connecting'\n : 'offline'\n : 'live',\n );\n restarting = false;\n setRetrying(false);\n }\n\n if (updates.length > 0) {\n setUploads((prev) => {\n const next = new Map(prev);\n for (const { id, upload } of updates) {\n if (upload === null) next.delete(id);\n else next.set(id, upload);\n }\n return next;\n });\n }\n\n for (const parsed of newlyTerminal) {\n handleTerminal(parsed);\n }\n };\n\n function handleTerminal(parsed: ParsedPendingMedia<TFileOrigin>) {\n adapterRef.current.onMonitoringEvent({\n type: 'breadcrumb',\n category: 'upload.terminal',\n level: 'info',\n message: `${parsed.fileOrigin}:${parsed.status}`,\n data: {\n id: parsed.id,\n fileOrigin: parsed.fileOrigin,\n status: parsed.status,\n surface: parsed.surface,\n },\n });\n\n if (parsed.status === STATUS.completed) {\n adapterRef.current.onUploadCompleted(parsed);\n } else if (parsed.status === STATUS.failed) {\n adapterRef.current.onUploadFailed(parsed);\n } else if (parsed.status === STATUS.rejected) {\n adapterRef.current.onUploadRejected(parsed);\n }\n }\n\n const RESUBSCRIBE_DELAYS_MS = [1_000, 3_000, 10_000, 30_000];\n let attempt = 0;\n let disposed = false;\n let retryTimer: ReturnType<typeof setTimeout> | undefined;\n let unsubscribe: (() => void) | undefined;\n\n const start = () => {\n unsubscribe = subscribe({\n db: a.db,\n collectionPath: a.collectionPath,\n userId,\n windowStartMs,\n onSnapshot: (snapshot) => {\n attempt = 0;\n handleSnapshot(snapshot);\n },\n onError: (error) => {\n adapterRef.current.onMonitoringEvent({ type: 'listener-error', error });\n unsubscribe?.();\n unsubscribe = undefined;\n if (disposed || attempt >= RESUBSCRIBE_DELAYS_MS.length) {\n setSourceState('error');\n setRetrying(false);\n return;\n }\n if (!restarting) setSourceState('connecting');\n retryTimer = setTimeout(() => {\n if (disposed) return;\n attempt += 1;\n start();\n }, RESUBSCRIBE_DELAYS_MS[attempt]);\n },\n });\n };\n start();\n\n return () => {\n disposed = true;\n if (retryTimer) clearTimeout(retryTimer);\n unsubscribe?.();\n };\n }, [userId, subscribe, restarts]);\n\n const retry = useCallback(() => {\n restartRequestedRef.current = true;\n setRetrying(true);\n setRestarts((count) => count + 1);\n }, []);\n\n const value = useMemo<InFlightUploadsContextValue<TFileOrigin>>(\n () => ({ uploads, sourceState, retry, retrying }),\n [uploads, sourceState, retry, retrying],\n );\n\n return (\n <InFlightUploadsContext.Provider value={value as InFlightUploadsContextValue}>\n {children}\n </InFlightUploadsContext.Provider>\n );\n}\n\nexport function useInFlightUploadsState<TFileOrigin extends string = string>(): Map<\n string,\n InFlightUpload<TFileOrigin>\n> {\n const ctx = useContext(InFlightUploadsContext);\n if (ctx === undefined) {\n throw new Error('useInFlightUploadsState must be used within InFlightUploadsProvider');\n }\n return ctx.uploads as Map<string, InFlightUpload<TFileOrigin>>;\n}\n\nexport function useInFlightUpload<TFileOrigin extends string = string>(\n id: string | null | undefined,\n): InFlightUpload<TFileOrigin> | undefined {\n const ctx = useContext(InFlightUploadsContext);\n if (ctx === undefined) {\n throw new Error('useInFlightUpload must be used within InFlightUploadsProvider');\n }\n if (!id) return undefined;\n return ctx.uploads.get(id) as InFlightUpload<TFileOrigin> | undefined;\n}\n\nexport function useUploadsSourceState(): UploadsSourceState {\n const ctx = useContext(InFlightUploadsContext);\n if (ctx === undefined) {\n throw new Error('useUploadsSourceState must be used within InFlightUploadsProvider');\n }\n return ctx.sourceState;\n}\n\nexport function useUploadsSourceRetry(): UploadsSourceRetry {\n const ctx = useContext(InFlightUploadsContext);\n if (ctx === undefined) {\n throw new Error('useUploadsSourceRetry must be used within InFlightUploadsProvider');\n }\n return { retry: ctx.retry, retrying: ctx.retrying };\n}\n\nexport function isTerminalUpload<TFileOrigin extends string = string>(\n item: InFlightUpload<TFileOrigin>,\n): item is Exclude<InFlightUpload<TFileOrigin>, { status: PendingMediaNonTerminalStatus }> {\n return isPendingMediaTerminalStatus(item.status);\n}\n\nexport function useUploadActivityState<\n TFileOrigin extends string = string,\n>(): InFlightUpload<TFileOrigin>[] {\n const uploads = useInFlightUploadsState<TFileOrigin>();\n return useMemo(() => {\n return Array.from(uploads.values())\n .filter((item) => {\n if (!isTerminalUpload(item)) return true;\n return item.uploadTrayClearedAt === undefined;\n })\n .sort((a, b) => b.createdAt - a.createdAt);\n }, [uploads]);\n}\n\n// A static ESM import, never require(): under Next.js + Turbopack a CJS-loaded firebase/firestore\n// is another module instance and rejects a db built through ESM.\nconst defaultFirestoreSubscribe: FirestoreSubscribeFn = (args) => {\n const q = query(\n collection(args.db as any, args.collectionPath),\n where('userId', '==', args.userId),\n where('createdAt', '>=', args.windowStartMs),\n );\n return onSnapshot(\n q,\n { includeMetadataChanges: true },\n args.onSnapshot as never,\n args.onError as never,\n );\n};\n"]}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
export { InFlightUploadsProvider, useInFlightUploadsState, useInFlightUpload, useUploadActivityState, useUploadsSourceState, useUploadsSourceRetry, isTerminalUpload, type UploadsSourceState, type UploadsSourceRetry, type InFlightUpload, type InFlightUploadActive, type InFlightUploadCompleted, type InFlightUploadFailed, type InFlightUploadRejected, type InFlightUploadBase, type InFlightUploadStatus, type InFlightUploadsAdapter, type InFlightUploadsMonitoringEvent, type InFlightUploadsProviderProps, type ParsedPendingMedia, type FirestoreSubscribeFn, type FirestoreLikeSnapshot, type FirestoreLikeDocChange, } from '
|
|
2
|
-
export { useClearUploadActivity, type ClearUploadActivityOptions, } from '
|
|
3
|
-
export { useMarkUploadActivitySeen, MarkUploadActivitySeenError, type MarkUploadActivitySeenOptions, } from '
|
|
4
|
-
export { useUploadProcessing, type UploadProcessingState, type UseUploadProcessingOptions, } from '
|
|
1
|
+
export { InFlightUploadsProvider, useInFlightUploadsState, useInFlightUpload, useUploadActivityState, useUploadsSourceState, useUploadsSourceRetry, isTerminalUpload, type UploadsSourceState, type UploadsSourceRetry, type InFlightUpload, type InFlightUploadActive, type InFlightUploadCompleted, type InFlightUploadFailed, type InFlightUploadRejected, type InFlightUploadBase, type InFlightUploadStatus, type InFlightUploadsAdapter, type InFlightUploadsMonitoringEvent, type InFlightUploadsProviderProps, type ParsedPendingMedia, type FirestoreSubscribeFn, type FirestoreLikeSnapshot, type FirestoreLikeDocChange, } from './in-flight-uploads-provider.js';
|
|
2
|
+
export { useClearUploadActivity, type ClearUploadActivityOptions, } from './use-clear-upload-activity.js';
|
|
3
|
+
export { useMarkUploadActivitySeen, MarkUploadActivitySeenError, type MarkUploadActivitySeenOptions, } from './use-mark-upload-activity-seen.js';
|
|
4
|
+
export { useUploadProcessing, type UploadProcessingState, type UseUploadProcessingOptions, } from './use-upload-processing.js';
|
|
5
5
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/react/tray/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,uBAAuB,EACvB,uBAAuB,EACvB,iBAAiB,EACjB,sBAAsB,EACtB,qBAAqB,EACrB,qBAAqB,EACrB,gBAAgB,EAChB,KAAK,kBAAkB,EACvB,KAAK,kBAAkB,EACvB,KAAK,cAAc,EACnB,KAAK,oBAAoB,EACzB,KAAK,uBAAuB,EAC5B,KAAK,oBAAoB,EACzB,KAAK,sBAAsB,EAC3B,KAAK,kBAAkB,EACvB,KAAK,oBAAoB,EACzB,KAAK,sBAAsB,EAC3B,KAAK,8BAA8B,EACnC,KAAK,4BAA4B,EACjC,KAAK,kBAAkB,EACvB,KAAK,oBAAoB,EACzB,KAAK,qBAAqB,EAC1B,KAAK,sBAAsB,GAC5B,MAAM,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/react/tray/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,uBAAuB,EACvB,uBAAuB,EACvB,iBAAiB,EACjB,sBAAsB,EACtB,qBAAqB,EACrB,qBAAqB,EACrB,gBAAgB,EAChB,KAAK,kBAAkB,EACvB,KAAK,kBAAkB,EACvB,KAAK,cAAc,EACnB,KAAK,oBAAoB,EACzB,KAAK,uBAAuB,EAC5B,KAAK,oBAAoB,EACzB,KAAK,sBAAsB,EAC3B,KAAK,kBAAkB,EACvB,KAAK,oBAAoB,EACzB,KAAK,sBAAsB,EAC3B,KAAK,8BAA8B,EACnC,KAAK,4BAA4B,EACjC,KAAK,kBAAkB,EACvB,KAAK,oBAAoB,EACzB,KAAK,qBAAqB,EAC1B,KAAK,sBAAsB,GAC5B,MAAM,iCAAiC,CAAC;AACzC,OAAO,EACL,sBAAsB,EACtB,KAAK,0BAA0B,GAChC,MAAM,gCAAgC,CAAC;AACxC,OAAO,EACL,yBAAyB,EACzB,2BAA2B,EAC3B,KAAK,6BAA6B,GACnC,MAAM,oCAAoC,CAAC;AAC5C,OAAO,EACL,mBAAmB,EACnB,KAAK,qBAAqB,EAC1B,KAAK,0BAA0B,GAChC,MAAM,4BAA4B,CAAC"}
|
package/dist/react/tray/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
export { InFlightUploadsProvider, useInFlightUploadsState, useInFlightUpload, useUploadActivityState, useUploadsSourceState, useUploadsSourceRetry, isTerminalUpload, } from '
|
|
2
|
-
export { useClearUploadActivity, } from '
|
|
3
|
-
export { useMarkUploadActivitySeen, MarkUploadActivitySeenError, } from '
|
|
4
|
-
export { useUploadProcessing, } from '
|
|
1
|
+
export { InFlightUploadsProvider, useInFlightUploadsState, useInFlightUpload, useUploadActivityState, useUploadsSourceState, useUploadsSourceRetry, isTerminalUpload, } from './in-flight-uploads-provider.js';
|
|
2
|
+
export { useClearUploadActivity, } from './use-clear-upload-activity.js';
|
|
3
|
+
export { useMarkUploadActivitySeen, MarkUploadActivitySeenError, } from './use-mark-upload-activity-seen.js';
|
|
4
|
+
export { useUploadProcessing, } from './use-upload-processing.js';
|
|
5
5
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/react/tray/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,uBAAuB,EACvB,uBAAuB,EACvB,iBAAiB,EACjB,sBAAsB,EACtB,qBAAqB,EACrB,qBAAqB,EACrB,gBAAgB,GAiBjB,MAAM,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/react/tray/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,uBAAuB,EACvB,uBAAuB,EACvB,iBAAiB,EACjB,sBAAsB,EACtB,qBAAqB,EACrB,qBAAqB,EACrB,gBAAgB,GAiBjB,MAAM,iCAAiC,CAAC;AACzC,OAAO,EACL,sBAAsB,GAEvB,MAAM,gCAAgC,CAAC;AACxC,OAAO,EACL,yBAAyB,EACzB,2BAA2B,GAE5B,MAAM,oCAAoC,CAAC;AAC5C,OAAO,EACL,mBAAmB,GAGpB,MAAM,4BAA4B,CAAC","sourcesContent":["export {\n InFlightUploadsProvider,\n useInFlightUploadsState,\n useInFlightUpload,\n useUploadActivityState,\n useUploadsSourceState,\n useUploadsSourceRetry,\n isTerminalUpload,\n type UploadsSourceState,\n type UploadsSourceRetry,\n type InFlightUpload,\n type InFlightUploadActive,\n type InFlightUploadCompleted,\n type InFlightUploadFailed,\n type InFlightUploadRejected,\n type InFlightUploadBase,\n type InFlightUploadStatus,\n type InFlightUploadsAdapter,\n type InFlightUploadsMonitoringEvent,\n type InFlightUploadsProviderProps,\n type ParsedPendingMedia,\n type FirestoreSubscribeFn,\n type FirestoreLikeSnapshot,\n type FirestoreLikeDocChange,\n} from './in-flight-uploads-provider.js';\nexport {\n useClearUploadActivity,\n type ClearUploadActivityOptions,\n} from './use-clear-upload-activity.js';\nexport {\n useMarkUploadActivitySeen,\n MarkUploadActivitySeenError,\n type MarkUploadActivitySeenOptions,\n} from './use-mark-upload-activity-seen.js';\nexport {\n useUploadProcessing,\n type UploadProcessingState,\n type UseUploadProcessingOptions,\n} from './use-upload-processing.js';\n"]}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { type MutationKey } from '@tanstack/react-query';
|
|
2
|
+
export interface ClearUploadActivityOptions {
|
|
3
|
+
clearFn: (pendingMediaId: string) => Promise<void>;
|
|
4
|
+
onError?: (error: Error, pendingMediaId: string) => void;
|
|
5
|
+
mutationKey?: MutationKey;
|
|
6
|
+
}
|
|
7
|
+
export declare function useClearUploadActivity(options: ClearUploadActivityOptions): import("@tanstack/react-query").UseMutationResult<void, Error, string, unknown>;
|
|
8
|
+
//# sourceMappingURL=use-clear-upload-activity.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-clear-upload-activity.d.ts","sourceRoot":"","sources":["../../../src/react/tray/use-clear-upload-activity.ts"],"names":[],"mappings":"AAEA,OAAO,EAAe,KAAK,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAEtE,MAAM,WAAW,0BAA0B;IACzC,OAAO,EAAE,CAAC,cAAc,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACnD,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,cAAc,EAAE,MAAM,KAAK,IAAI,CAAC;IACzD,WAAW,CAAC,EAAE,WAAW,CAAC;CAC3B;AAED,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,0BAA0B,mFASzE"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { useMutation } from '@tanstack/react-query';
|
|
3
|
+
export function useClearUploadActivity(options) {
|
|
4
|
+
const { clearFn, onError, mutationKey } = options;
|
|
5
|
+
return useMutation({
|
|
6
|
+
mutationKey,
|
|
7
|
+
mutationFn: clearFn,
|
|
8
|
+
onError: (error, pendingMediaId) => {
|
|
9
|
+
onError?.(error, pendingMediaId);
|
|
10
|
+
},
|
|
11
|
+
});
|
|
12
|
+
}
|
|
13
|
+
//# sourceMappingURL=use-clear-upload-activity.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-clear-upload-activity.js","sourceRoot":"","sources":["../../../src/react/tray/use-clear-upload-activity.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAEb,OAAO,EAAE,WAAW,EAAoB,MAAM,uBAAuB,CAAC;AAQtE,MAAM,UAAU,sBAAsB,CAAC,OAAmC;IACxE,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,WAAW,EAAE,GAAG,OAAO,CAAC;IAClD,OAAO,WAAW,CAAsB;QACtC,WAAW;QACX,UAAU,EAAE,OAAO;QACnB,OAAO,EAAE,CAAC,KAAK,EAAE,cAAc,EAAE,EAAE;YACjC,OAAO,EAAE,CAAC,KAAK,EAAE,cAAc,CAAC,CAAC;QACnC,CAAC;KACF,CAAC,CAAC;AACL,CAAC","sourcesContent":["'use client';\n\nimport { useMutation, type MutationKey } from '@tanstack/react-query';\n\nexport interface ClearUploadActivityOptions {\n clearFn: (pendingMediaId: string) => Promise<void>;\n onError?: (error: Error, pendingMediaId: string) => void;\n mutationKey?: MutationKey;\n}\n\nexport function useClearUploadActivity(options: ClearUploadActivityOptions) {\n const { clearFn, onError, mutationKey } = options;\n return useMutation<void, Error, string>({\n mutationKey,\n mutationFn: clearFn,\n onError: (error, pendingMediaId) => {\n onError?.(error, pendingMediaId);\n },\n });\n}\n"]}
|
package/dist/react/{use-mark-upload-activity-seen.d.ts → tray/use-mark-upload-activity-seen.d.ts}
RENAMED
|
@@ -1,12 +1,8 @@
|
|
|
1
1
|
export interface MarkUploadActivitySeenOptions {
|
|
2
|
-
/** Network call performing the mark-seen for at most `maxIdsPerCall` pendingMediaIds. */
|
|
3
2
|
markFn: (pendingMediaIds: string[]) => Promise<void>;
|
|
4
|
-
/** The most ids one `markFn` call accepts — the app's own per-call cap. */
|
|
5
3
|
maxIdsPerCall: number;
|
|
6
|
-
/** Optional error callback. Receives the first failure and every id that was not marked. */
|
|
7
4
|
onError?: (error: Error, pendingMediaIds: string[]) => void;
|
|
8
5
|
}
|
|
9
|
-
/** The mutation's failure when one or more calls failed: the first failure, and the ids left unmarked. */
|
|
10
6
|
export declare class MarkUploadActivitySeenError extends Error {
|
|
11
7
|
readonly failure: Error;
|
|
12
8
|
readonly unmarkedIds: string[];
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-mark-upload-activity-seen.d.ts","sourceRoot":"","sources":["../../../src/react/tray/use-mark-upload-activity-seen.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,6BAA6B;IAC5C,MAAM,EAAE,CAAC,eAAe,EAAE,MAAM,EAAE,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACrD,aAAa,EAAE,MAAM,CAAC;IACtB,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,eAAe,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;CAC7D;AAED,qBAAa,2BAA4B,SAAQ,KAAK;IACpD,QAAQ,CAAC,OAAO,EAAE,KAAK,CAAC;IACxB,QAAQ,CAAC,WAAW,EAAE,MAAM,EAAE,CAAC;gBAEnB,OAAO,EAAE,KAAK,EAAE,WAAW,EAAE,MAAM,EAAE;CAMlD;AAwBD,wBAAgB,yBAAyB,CAAC,OAAO,EAAE,6BAA6B,qFAS/E"}
|
package/dist/react/{use-mark-upload-activity-seen.js → tray/use-mark-upload-activity-seen.js}
RENAMED
|
@@ -1,26 +1,5 @@
|
|
|
1
1
|
'use client';
|
|
2
|
-
/**
|
|
3
|
-
* Generic mutation hook to mark terminal pendingMedia items as seen in the tray.
|
|
4
|
-
*
|
|
5
|
-
* Pure adapter: the consumer supplies `markFn` (typically a wrapped Firebase
|
|
6
|
-
* callable in the consuming app that writes `uploadTraySeenAt`/`uploadTraySeenBy` on the
|
|
7
|
-
* caller's own terminal pendingMedia docs). The package owns the useMutation
|
|
8
|
-
* wiring and the optional `onError` hook; the consumer owns the network call.
|
|
9
|
-
*
|
|
10
|
-
* The provider's Firestore listener observes the `uploadTraySeenAt` write and
|
|
11
|
-
* updates the in-flight upload records automatically — no optimistic update is
|
|
12
|
-
* needed in this hook. Marking seen is tray UX state, not a sensitive action,
|
|
13
|
-
* so it mirrors `useClearUploadActivity` exactly (no audit event).
|
|
14
|
-
*
|
|
15
|
-
* The mutation takes every id to mark (typically every currently-unseen terminal
|
|
16
|
-
* item when the File-status tab opens) and sends them to `markFn` in sequential
|
|
17
|
-
* calls of at most `maxIdsPerCall` — the app's own per-call cap, so no call is
|
|
18
|
-
* refused for its size. A failed call does not stop the rest: its ids simply stay
|
|
19
|
-
* unseen. When any call failed, the mutation fails, and `onError` receives the first
|
|
20
|
-
* failure and every id left unmarked. An empty array makes no call.
|
|
21
|
-
*/
|
|
22
2
|
import { useMutation } from '@tanstack/react-query';
|
|
23
|
-
/** The mutation's failure when one or more calls failed: the first failure, and the ids left unmarked. */
|
|
24
3
|
export class MarkUploadActivitySeenError extends Error {
|
|
25
4
|
failure;
|
|
26
5
|
unmarkedIds;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-mark-upload-activity-seen.js","sourceRoot":"","sources":["../../../src/react/tray/use-mark-upload-activity-seen.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAEb,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAQpD,MAAM,OAAO,2BAA4B,SAAQ,KAAK;IAC3C,OAAO,CAAQ;IACf,WAAW,CAAW;IAE/B,YAAY,OAAc,EAAE,WAAqB;QAC/C,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;QACvB,IAAI,CAAC,IAAI,GAAG,6BAA6B,CAAC;QAC1C,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;QACvB,IAAI,CAAC,WAAW,GAAG,WAAW,CAAC;IACjC,CAAC;CACF;AAED,KAAK,UAAU,aAAa,CAC1B,MAAoD,EACpD,aAAqB,EACrB,eAAyB;IAEzB,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,aAAa,CAAC,IAAI,aAAa,GAAG,CAAC,EAAE,CAAC;QAC1D,MAAM,IAAI,KAAK,CAAC,sDAAsD,aAAa,GAAG,CAAC,CAAC;IAC1F,CAAC;IACD,IAAI,YAAY,GAAiB,IAAI,CAAC;IACtC,MAAM,WAAW,GAAa,EAAE,CAAC;IACjC,KAAK,IAAI,KAAK,GAAG,CAAC,EAAE,KAAK,GAAG,eAAe,CAAC,MAAM,EAAE,KAAK,IAAI,aAAa,EAAE,CAAC;QAC3E,MAAM,KAAK,GAAG,eAAe,CAAC,KAAK,CAAC,KAAK,EAAE,KAAK,GAAG,aAAa,CAAC,CAAC;QAClE,IAAI,CAAC;YACH,MAAM,MAAM,CAAC,KAAK,CAAC,CAAC;QACtB,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,YAAY,KAAK,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;YACrE,WAAW,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC,CAAC;QAC7B,CAAC;IACH,CAAC;IACD,IAAI,YAAY;QAAE,MAAM,IAAI,2BAA2B,CAAC,YAAY,EAAE,WAAW,CAAC,CAAC;AACrF,CAAC;AAED,MAAM,UAAU,yBAAyB,CAAC,OAAsC;IAC9E,MAAM,EAAE,MAAM,EAAE,aAAa,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC;IACnD,OAAO,WAAW,CAAwB;QACxC,UAAU,EAAE,CAAC,eAAe,EAAE,EAAE,CAAC,aAAa,CAAC,MAAM,EAAE,aAAa,EAAE,eAAe,CAAC;QACtF,OAAO,EAAE,CAAC,KAAK,EAAE,eAAe,EAAE,EAAE;YAClC,IAAI,KAAK,YAAY,2BAA2B;gBAAE,OAAO,EAAE,CAAC,KAAK,CAAC,OAAO,EAAE,KAAK,CAAC,WAAW,CAAC,CAAC;;gBACzF,OAAO,EAAE,CAAC,KAAK,EAAE,eAAe,CAAC,CAAC;QACzC,CAAC;KACF,CAAC,CAAC;AACL,CAAC","sourcesContent":["'use client';\n\nimport { useMutation } from '@tanstack/react-query';\n\nexport interface MarkUploadActivitySeenOptions {\n markFn: (pendingMediaIds: string[]) => Promise<void>;\n maxIdsPerCall: number;\n onError?: (error: Error, pendingMediaIds: string[]) => void;\n}\n\nexport class MarkUploadActivitySeenError extends Error {\n readonly failure: Error;\n readonly unmarkedIds: string[];\n\n constructor(failure: Error, unmarkedIds: string[]) {\n super(failure.message);\n this.name = 'MarkUploadActivitySeenError';\n this.failure = failure;\n this.unmarkedIds = unmarkedIds;\n }\n}\n\nasync function markInBatches(\n markFn: (pendingMediaIds: string[]) => Promise<void>,\n maxIdsPerCall: number,\n pendingMediaIds: string[],\n): Promise<void> {\n if (!Number.isInteger(maxIdsPerCall) || maxIdsPerCall < 1) {\n throw new Error(`maxIdsPerCall must be a positive whole number, got ${maxIdsPerCall}.`);\n }\n let firstFailure: Error | null = null;\n const unmarkedIds: string[] = [];\n for (let start = 0; start < pendingMediaIds.length; start += maxIdsPerCall) {\n const batch = pendingMediaIds.slice(start, start + maxIdsPerCall);\n try {\n await markFn(batch);\n } catch (err) {\n firstFailure ??= err instanceof Error ? err : new Error(String(err));\n unmarkedIds.push(...batch);\n }\n }\n if (firstFailure) throw new MarkUploadActivitySeenError(firstFailure, unmarkedIds);\n}\n\nexport function useMarkUploadActivitySeen(options: MarkUploadActivitySeenOptions) {\n const { markFn, maxIdsPerCall, onError } = options;\n return useMutation<void, Error, string[]>({\n mutationFn: (pendingMediaIds) => markInBatches(markFn, maxIdsPerCall, pendingMediaIds),\n onError: (error, pendingMediaIds) => {\n if (error instanceof MarkUploadActivitySeenError) onError?.(error.failure, error.unmarkedIds);\n else onError?.(error, pendingMediaIds);\n },\n });\n}\n"]}
|
|
@@ -8,20 +8,10 @@ export interface UploadProcessingState {
|
|
|
8
8
|
isRejected: boolean;
|
|
9
9
|
}
|
|
10
10
|
export interface UseUploadProcessingOptions {
|
|
11
|
-
/** Override the processing-phase message. */
|
|
12
11
|
processingMessage?: string;
|
|
13
|
-
/** Override the success-phase message. */
|
|
14
12
|
successMessage?: string;
|
|
15
|
-
/** Override the failed-phase message. */
|
|
16
13
|
failedMessage?: string;
|
|
17
|
-
/** Override the rejected-phase message. */
|
|
18
14
|
rejectedMessage?: string;
|
|
19
15
|
}
|
|
20
|
-
/**
|
|
21
|
-
* Returns local UI processing state for the given pendingMediaId. If the
|
|
22
|
-
* `onTerminal` callback is provided, it fires once when the doc reaches a
|
|
23
|
-
* terminal status (completed / failed / rejected). Use `onTerminal` for
|
|
24
|
-
* local UI cleanup — global toast/dialog routing belongs in the provider.
|
|
25
|
-
*/
|
|
26
16
|
export declare function useUploadProcessing<TFileOrigin extends string = string>(pendingMediaId: string | null | undefined, onTerminal?: (state: UploadProcessingState) => void, options?: UseUploadProcessingOptions): UploadProcessingState;
|
|
27
17
|
//# sourceMappingURL=use-upload-processing.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-upload-processing.d.ts","sourceRoot":"","sources":["../../../src/react/tray/use-upload-processing.ts"],"names":[],"mappings":"AAWA,MAAM,WAAW,qBAAqB;IACpC,MAAM,EACJ,MAAM,GAAG,SAAS,GAAG,YAAY,GAAG,SAAS,GAAG,QAAQ,GAAG,eAAe,GAAG,gBAAgB,CAAC;IAChG,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,YAAY,EAAE,OAAO,CAAC;IACtB,UAAU,EAAE,OAAO,CAAC;IACpB,QAAQ,EAAE,OAAO,CAAC;IAClB,UAAU,EAAE,OAAO,CAAC;CACrB;AAOD,MAAM,WAAW,0BAA0B;IACzC,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAyED,wBAAgB,mBAAmB,CAAC,WAAW,SAAS,MAAM,GAAG,MAAM,EACrE,cAAc,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EACzC,UAAU,CAAC,EAAE,CAAC,KAAK,EAAE,qBAAqB,KAAK,IAAI,EACnD,OAAO,GAAE,0BAA+B,GACvC,qBAAqB,CA6BvB"}
|
|
@@ -1,19 +1,7 @@
|
|
|
1
1
|
'use client';
|
|
2
|
-
/**
|
|
3
|
-
* Adapter that maps `useInFlightUpload` state to the legacy
|
|
4
|
-
* `{ isProcessing, message, isComplete, isRejected, isFailed }` shape used
|
|
5
|
-
* by per-component spinners and overlays.
|
|
6
|
-
*
|
|
7
|
-
* Routing of toasts and rejection dialogs lives in `InFlightUploadsProvider`
|
|
8
|
-
* via the consumer-supplied callbacks — `useUploadProcessing` only surfaces
|
|
9
|
-
* local UI state. The `onTerminal` callback fires once per terminal status
|
|
10
|
-
* (completed / failed / rejected) and is intended for local UI cleanup
|
|
11
|
-
* (clearing form state, closing modals, etc.).
|
|
12
|
-
*/
|
|
13
2
|
import { useEffect, useRef } from 'react';
|
|
14
|
-
import { isPendingMediaNonTerminalStatus, PendingMediaStatusSchema } from '@ttt-productions/media-schemas';
|
|
3
|
+
import { isPendingMediaNonTerminalStatus, PendingMediaStatusSchema, } from '@ttt-productions/media-schemas';
|
|
15
4
|
import { useInFlightUpload } from './in-flight-uploads-provider.js';
|
|
16
|
-
// Pending-media status values derive from media-schemas' one declaration.
|
|
17
5
|
const STATUS = PendingMediaStatusSchema.enum;
|
|
18
6
|
const DEFAULT_PROCESSING_MESSAGE = 'Processing your content...';
|
|
19
7
|
const DEFAULT_SUCCESS_MESSAGE = 'Complete!';
|
|
@@ -85,12 +73,6 @@ function buildState(upload, opts) {
|
|
|
85
73
|
isRejected: false,
|
|
86
74
|
};
|
|
87
75
|
}
|
|
88
|
-
/**
|
|
89
|
-
* Returns local UI processing state for the given pendingMediaId. If the
|
|
90
|
-
* `onTerminal` callback is provided, it fires once when the doc reaches a
|
|
91
|
-
* terminal status (completed / failed / rejected). Use `onTerminal` for
|
|
92
|
-
* local UI cleanup — global toast/dialog routing belongs in the provider.
|
|
93
|
-
*/
|
|
94
76
|
export function useUploadProcessing(pendingMediaId, onTerminal, options = {}) {
|
|
95
77
|
const upload = useInFlightUpload(pendingMediaId);
|
|
96
78
|
const state = buildState(upload, options);
|
|
@@ -109,7 +91,15 @@ export function useUploadProcessing(pendingMediaId, onTerminal, options = {}) {
|
|
|
109
91
|
onTerminal(state);
|
|
110
92
|
}
|
|
111
93
|
}
|
|
112
|
-
}, [
|
|
94
|
+
}, [
|
|
95
|
+
pendingMediaId,
|
|
96
|
+
state.status,
|
|
97
|
+
state.isComplete,
|
|
98
|
+
state.isFailed,
|
|
99
|
+
state.isRejected,
|
|
100
|
+
state,
|
|
101
|
+
onTerminal,
|
|
102
|
+
]);
|
|
113
103
|
return state;
|
|
114
104
|
}
|
|
115
105
|
//# sourceMappingURL=use-upload-processing.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-upload-processing.js","sourceRoot":"","sources":["../../../src/react/tray/use-upload-processing.ts"],"names":[],"mappings":"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","sourcesContent":["'use client';\n\nimport { useEffect, useRef } from 'react';\nimport {\n isPendingMediaNonTerminalStatus,\n PendingMediaStatusSchema,\n} from '@ttt-productions/media-schemas';\nimport { useInFlightUpload, type InFlightUpload } from './in-flight-uploads-provider.js';\n\nconst STATUS = PendingMediaStatusSchema.enum;\n\nexport interface UploadProcessingState {\n status:\n 'idle' | 'pending' | 'processing' | 'success' | 'failed' | 'rejected-text' | 'rejected-media';\n message: string;\n errorMessage?: string;\n isProcessing: boolean;\n isComplete: boolean;\n isFailed: boolean;\n isRejected: boolean;\n}\n\nconst DEFAULT_PROCESSING_MESSAGE = 'Processing your content...';\nconst DEFAULT_SUCCESS_MESSAGE = 'Complete!';\nconst DEFAULT_FAILED_MESSAGE = 'Processing failed';\nconst DEFAULT_REJECTED_MESSAGE = 'Content rejected';\n\nexport interface UseUploadProcessingOptions {\n processingMessage?: string;\n successMessage?: string;\n failedMessage?: string;\n rejectedMessage?: string;\n}\n\nfunction buildState<TFileOrigin extends string>(\n upload: InFlightUpload<TFileOrigin> | undefined,\n opts: UseUploadProcessingOptions,\n): UploadProcessingState {\n const processingMessage = opts.processingMessage ?? DEFAULT_PROCESSING_MESSAGE;\n const successMessage = opts.successMessage ?? DEFAULT_SUCCESS_MESSAGE;\n const failedMessage = opts.failedMessage ?? DEFAULT_FAILED_MESSAGE;\n const rejectedMessage = opts.rejectedMessage ?? DEFAULT_REJECTED_MESSAGE;\n\n if (!upload) {\n return {\n status: 'idle',\n message: '',\n isProcessing: false,\n isComplete: false,\n isFailed: false,\n isRejected: false,\n };\n }\n if (isPendingMediaNonTerminalStatus(upload.status)) {\n return {\n status: upload.status,\n message: processingMessage,\n isProcessing: true,\n isComplete: false,\n isFailed: false,\n isRejected: false,\n };\n }\n if (upload.status === STATUS.completed) {\n return {\n status: 'success',\n message: successMessage,\n isProcessing: false,\n isComplete: true,\n isFailed: false,\n isRejected: false,\n };\n }\n if (upload.status === STATUS.failed) {\n return {\n status: 'failed',\n message: failedMessage,\n errorMessage: upload.errorMessage,\n isProcessing: false,\n isComplete: false,\n isFailed: true,\n isRejected: false,\n };\n }\n if (upload.status === STATUS.rejected) {\n return {\n status: upload.rejectionType === 'text' ? 'rejected-text' : 'rejected-media',\n message: rejectedMessage,\n errorMessage: upload.errorMessage,\n isProcessing: false,\n isComplete: false,\n isFailed: false,\n isRejected: true,\n };\n }\n return {\n status: 'processing',\n message: processingMessage,\n isProcessing: true,\n isComplete: false,\n isFailed: false,\n isRejected: false,\n };\n}\n\nexport function useUploadProcessing<TFileOrigin extends string = string>(\n pendingMediaId: string | null | undefined,\n onTerminal?: (state: UploadProcessingState) => void,\n options: UseUploadProcessingOptions = {},\n): UploadProcessingState {\n const upload = useInFlightUpload<TFileOrigin>(pendingMediaId);\n const state = buildState(upload, options);\n const lastFiredRef = useRef<string | null>(null);\n\n useEffect(() => {\n if (!onTerminal) return;\n if (!pendingMediaId) {\n lastFiredRef.current = null;\n return;\n }\n if (state.isComplete || state.isFailed || state.isRejected) {\n const sig = `${pendingMediaId}:${state.status}`;\n if (lastFiredRef.current !== sig) {\n lastFiredRef.current = sig;\n onTerminal(state);\n }\n }\n }, [\n pendingMediaId,\n state.status,\n state.isComplete,\n state.isFailed,\n state.isRejected,\n state,\n onTerminal,\n ]);\n\n return state;\n}\n"]}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import React, { type ReactNode, type Ref } from 'react';
|
|
2
|
+
import type { ClientMediaClaim, MediaOriginSpec, UploadState } from '@ttt-productions/media-schemas';
|
|
3
|
+
export interface DeferredUploadFormShellHandle {
|
|
4
|
+
submit: () => void;
|
|
5
|
+
}
|
|
6
|
+
export interface DeferredUploadFormShellProps<TVariables extends {
|
|
7
|
+
onProgress?: (s: UploadState | null) => void;
|
|
8
|
+
signal?: AbortSignal;
|
|
9
|
+
}, TResult = unknown> {
|
|
10
|
+
spec: MediaOriginSpec;
|
|
11
|
+
mutation: {
|
|
12
|
+
mutateAsync: (vars: TVariables) => Promise<TResult>;
|
|
13
|
+
isPending: boolean;
|
|
14
|
+
};
|
|
15
|
+
buildVariables: (file: File | null, onProgress: (s: UploadState | null) => void, signal: AbortSignal, claim?: ClientMediaClaim) => TVariables;
|
|
16
|
+
onSuccess?: (result: TResult) => void;
|
|
17
|
+
onError?: (err: unknown) => void;
|
|
18
|
+
onFileChange?: (file: File | null) => void;
|
|
19
|
+
onBeforeSelect?: () => boolean | Promise<boolean>;
|
|
20
|
+
children?: ReactNode;
|
|
21
|
+
}
|
|
22
|
+
export declare const DeferredUploadFormShell: <TVariables extends {
|
|
23
|
+
onProgress?: (s: UploadState | null) => void;
|
|
24
|
+
signal?: AbortSignal;
|
|
25
|
+
}, TResult = unknown>(props: DeferredUploadFormShellProps<TVariables, TResult> & {
|
|
26
|
+
ref?: Ref<DeferredUploadFormShellHandle>;
|
|
27
|
+
}) => React.ReactElement;
|
|
28
|
+
//# sourceMappingURL=deferred-upload-form-shell.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"deferred-upload-form-shell.d.ts","sourceRoot":"","sources":["../../../src/react/upload/deferred-upload-form-shell.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,EAMZ,KAAK,SAAS,EACd,KAAK,GAAG,EACT,MAAM,OAAO,CAAC;AAGf,OAAO,KAAK,EACV,gBAAgB,EAChB,eAAe,EACf,WAAW,EACZ,MAAM,gCAAgC,CAAC;AAExC,MAAM,WAAW,6BAA6B;IAC5C,MAAM,EAAE,MAAM,IAAI,CAAC;CACpB;AAED,MAAM,WAAW,4BAA4B,CAC3C,UAAU,SAAS;IACjB,UAAU,CAAC,EAAE,CAAC,CAAC,EAAE,WAAW,GAAG,IAAI,KAAK,IAAI,CAAC;IAC7C,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB,EACD,OAAO,GAAG,OAAO;IAEjB,IAAI,EAAE,eAAe,CAAC;IACtB,QAAQ,EAAE;QACR,WAAW,EAAE,CAAC,IAAI,EAAE,UAAU,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;QACpD,SAAS,EAAE,OAAO,CAAC;KACpB,CAAC;IACF,cAAc,EAAE,CACd,IAAI,EAAE,IAAI,GAAG,IAAI,EACjB,UAAU,EAAE,CAAC,CAAC,EAAE,WAAW,GAAG,IAAI,KAAK,IAAI,EAC3C,MAAM,EAAE,WAAW,EACnB,KAAK,CAAC,EAAE,gBAAgB,KACrB,UAAU,CAAC;IAChB,SAAS,CAAC,EAAE,CAAC,MAAM,EAAE,OAAO,KAAK,IAAI,CAAC;IACtC,OAAO,CAAC,EAAE,CAAC,GAAG,EAAE,OAAO,KAAK,IAAI,CAAC;IACjC,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,IAAI,GAAG,IAAI,KAAK,IAAI,CAAC;IAC3C,cAAc,CAAC,EAAE,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAClD,QAAQ,CAAC,EAAE,SAAS,CAAC;CACtB;AA8GD,eAAO,MAAM,uBAAuB,EAA+C,CACjF,UAAU,SAAS;IACjB,UAAU,CAAC,EAAE,CAAC,CAAC,EAAE,WAAW,GAAG,IAAI,KAAK,IAAI,CAAC;IAC7C,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB,EACD,OAAO,GAAG,OAAO,EAEjB,KAAK,EAAE,4BAA4B,CAAC,UAAU,EAAE,OAAO,CAAC,GAAG;IACzD,GAAG,CAAC,EAAE,GAAG,CAAC,6BAA6B,CAAC,CAAC;CAC1C,KACE,KAAK,CAAC,YAAY,CAAC"}
|