@ttt-productions/upload-ui 0.7.7 → 0.7.8

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.
@@ -1 +1 @@
1
- {"version":3,"file":"in-flight-uploads-provider.d.ts","sourceRoot":"","sources":["../../src/react/in-flight-uploads-provider.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"in-flight-uploads-provider.d.ts","sourceRoot":"","sources":["../../src/react/in-flight-uploads-provider.tsx"],"names":[],"mappings":"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"}
@@ -114,6 +114,10 @@ export function InFlightUploadsProvider(props) {
114
114
  const seenTerminalIdsRef = useRef(new Set());
115
115
  const statusByIdRef = useRef(new Map());
116
116
  const hasProcessedInitialSnapshotRef = useRef(false);
117
+ /** The identity the dedup/tracking refs belong to — they outlive resubscribes
118
+ * for the SAME user (auth-settling flaps) and reset only on a real identity
119
+ * change. See the reset block in the subscription effect. */
120
+ const trackedUserIdRef = useRef(null);
117
121
  // Stable refs for adapter callbacks — read from latest adapter inside effect.
118
122
  const adapterRef = useRef(adapter);
119
123
  useEffect(() => {
@@ -121,14 +125,23 @@ export function InFlightUploadsProvider(props) {
121
125
  });
122
126
  const userId = adapter.getCurrentUserId();
123
127
  useEffect(() => {
124
- // Reset all in-memory state for the new identity. Runs on every userId
125
- // change — including UID-A → UID-B with no intermediate null user.
126
- // Do not rely on an intermediate sign-out to clear refs between two
127
- // authenticated UIDs.
128
+ // The uploads map and source state rebuild from every subscription's initial
129
+ // snapshot, so they reset on every effect run. The terminal-dedup and
130
+ // status-tracking refs are IDENTITY-scoped, not subscription-scoped: an
131
+ // auth-settling flap (uid → null → same uid re-subscribes) must neither
132
+ // re-fire terminals the previous subscription already fired (seen set
133
+ // persists) nor lose the observed non-terminal statuses that let the new
134
+ // subscription's initial listing detect a transition that completed during
135
+ // the gap. A real identity change — including UID-A → UID-B with no
136
+ // intermediate null user — starts clean; never rely on an intermediate
137
+ // sign-out to clear refs between two authenticated UIDs.
128
138
  setUploads(new Map());
129
139
  setSourceState('connecting');
130
- seenTerminalIdsRef.current = new Set();
131
- statusByIdRef.current = new Map();
140
+ if (userId !== null && userId !== trackedUserIdRef.current) {
141
+ seenTerminalIdsRef.current = new Set();
142
+ statusByIdRef.current = new Map();
143
+ trackedUserIdRef.current = userId;
144
+ }
132
145
  hasProcessedInitialSnapshotRef.current = false;
133
146
  if (!userId) {
134
147
  return;
@@ -168,23 +181,28 @@ export function InFlightUploadsProvider(props) {
168
181
  currentStatus === 'rejected';
169
182
  const previousWasNonTerminal = previousStatus === 'pending' || previousStatus === 'processing';
170
183
  if (isInitialSnapshot) {
171
- // First snapshot after mount: mark already-terminal docs as seen,
172
- // but DO NOT fire callbacks. Prevents duplicate toasts on refresh.
184
+ // A subscription's first snapshot is a (re-)listing of current state,
185
+ // not a live event: already-terminal docs stay suppressed so a page
186
+ // refresh never re-toasts. ONE exception — this provider instance
187
+ // tracked the doc as non-terminal before (same-identity resubscribe
188
+ // gap; the tracking refs survive those), so the terminal listing IS
189
+ // the transition, observed across the gap, and must fire.
173
190
  if (currentIsTerminal) {
191
+ if (previousWasNonTerminal && !seenTerminalIdsRef.current.has(parsed.id)) {
192
+ newlyTerminal.push(parsed);
193
+ }
174
194
  seenTerminalIdsRef.current.add(parsed.id);
175
195
  }
176
196
  }
177
- else if (currentIsTerminal &&
178
- previousWasNonTerminal &&
179
- !seenTerminalIdsRef.current.has(parsed.id)) {
197
+ else if (currentIsTerminal && !seenTerminalIdsRef.current.has(parsed.id)) {
198
+ // Any unseen terminal in a LIVE snapshot fires — including a doc whose
199
+ // FIRST client-visible state is already terminal. A fast backend
200
+ // outcome (moderation rejection in ~2s) can coalesce created→terminal
201
+ // into one delivery, and the uploader is actively waiting on exactly
202
+ // this callback; swallowing it silently loses a rejection dialog.
180
203
  seenTerminalIdsRef.current.add(parsed.id);
181
204
  newlyTerminal.push(parsed);
182
205
  }
183
- else if (currentIsTerminal) {
184
- // Terminal doc appeared without an observed non-terminal predecessor
185
- // (race in a non-initial snapshot). Mark as seen, no callback fire.
186
- seenTerminalIdsRef.current.add(parsed.id);
187
- }
188
206
  statusByIdRef.current.set(parsed.id, currentStatus);
189
207
  }
190
208
  hasProcessedInitialSnapshotRef.current = true;
@@ -1 +1 @@
1
- {"version":3,"file":"in-flight-uploads-provider.js","sourceRoot":"","sources":["../../src/react/in-flight-uploads-provider.tsx"],"names":[],"mappings":"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","sourcesContent":["'use client';\n\n// ─────────────────────────────────────────────────────────────────────────────\n// SANCTIONED EXCEPTION to the \"packages read/write Firestore only through\n// @ttt-productions/query-core\" rule (see docs/packages/package-architecture.md →\n// \"Firestore access goes through 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.\n// ─────────────────────────────────────────────────────────────────────────────\nimport { collection, onSnapshot, query, where } from 'firebase/firestore';\n\n/**\n * Generic in-flight uploads provider.\n *\n * Provides a global Map of in-flight upload state by `pendingMediaId`, derived\n * from a Firestore listener over the consumer-supplied collection. On terminal\n * status transitions observed THIS SESSION, fires consumer-supplied success /\n * failure / rejection callbacks. Records monitoring breadcrumbs and parse\n * errors through the injected monitoring callback.\n *\n * EVERY app-specific value is supplied by the consumer:\n * - userId resolution\n * - Firestore `db` reference\n * - collection path\n * - listener time window (ms)\n * - parser/schema for raw Firestore doc → typed PendingMedia\n * - success copy per origin\n * - notification callback (cache invalidation, etc.)\n * - toast callback\n * - rejection callback (for the media-rejection dialog or equivalent)\n * - monitoring callback (breadcrumbs + captured errors)\n *\n * Read APIs:\n * - `useInFlightUploadsState()` — full Map.\n * - `useInFlightUpload(id)` — single doc, narrowable on status.\n * - `useUploadActivityState()` — tray-visible items, sorted newest-first.\n *\n * The package owns the deduplication, initial-snapshot suppression, and\n * non-terminal → terminal transition tracking. It does NOT own anything about\n * what a file-origin is or what message text appears in toasts.\n */\n\nimport {\n createContext,\n useContext,\n useEffect,\n useMemo,\n useRef,\n useState,\n type ReactNode,\n} from 'react';\n\n// =============================================================================\n// Generic shape of the data the provider tracks\n// =============================================================================\n\n/**\n * Generic pending-media status. Defined here so upload-ui has no dependency\n * on any app-specific package.\n */\nexport type InFlightUploadStatus =\n | 'pending'\n | 'processing'\n | 'completed'\n | 'failed'\n | 'rejected';\n\n/**\n * Generic in-flight upload record. The provider keeps a Map<id, InFlightUpload>\n * built from each parsed PendingMedia. Consumers parameterize the `fileOrigin`\n * type via the parser's return type (the provider treats it as opaque).\n *\n * `TFileOrigin` defaults to `string` so unannotated consumers get a permissive\n * shape; consuming apps bind it to their own `FileOrigin` union at the call site.\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: 'pending' | 'processing';\n };\n\nexport type InFlightUploadCompleted<TFileOrigin extends string = string> =\n InFlightUploadBase<TFileOrigin> & {\n status: '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: '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: '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\n// =============================================================================\n// Adapter contract — every app-specific behavior is injected here\n// =============================================================================\n\n/**\n * Result of the consumer-supplied parser. The provider keeps the raw parsed\n * record for callbacks (so consumers can read domain events, target IDs, etc.)\n * AND derives the generic InFlightUpload from it for the public Map.\n *\n * The parser MUST throw if validation fails; the provider catches and routes\n * the error to the monitoring callback.\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 // Terminal-status fields (only meaningful for the matching status)\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 /**\n * Opaque consumer-controlled domain-event payload, surfaced to the\n * `onUploadCompleted` and `onUploadRejected` callbacks for cache\n * invalidation. The provider does not interpret it.\n */\n domainEvents?: unknown;\n};\n\nexport type InFlightUploadsAdapter<TFileOrigin extends string = string> = {\n /** Returns the current user's uid, or null if not signed in. */\n getCurrentUserId: () => string | null;\n\n /** Firestore database adapter (loose typing — `unknown` keeps zero firebase coupling at the type level). */\n db: unknown;\n\n /** Collection path holding pending-media docs (e.g. \"pendingMedia\"). */\n collectionPath: string;\n\n /** Listener window in milliseconds — only docs with `createdAt >= now - window` are tracked. */\n listenerWindowMs: number;\n\n /**\n * Parse a raw Firestore doc snapshot's `.data()` into the generic shape the\n * provider tracks. Throws on validation failure; the provider routes thrown\n * errors to `onMonitoringEvent`.\n */\n parsePendingMedia: (raw: unknown) => ParsedPendingMedia<TFileOrigin>;\n\n /** Called once per observed non-terminal → terminal completed transition. */\n onUploadCompleted: (parsed: ParsedPendingMedia<TFileOrigin>) => void;\n\n /** Called once per observed non-terminal → terminal failed transition. */\n onUploadFailed: (parsed: ParsedPendingMedia<TFileOrigin>) => void;\n\n /** Called once per observed non-terminal → terminal rejected transition. */\n onUploadRejected: (parsed: ParsedPendingMedia<TFileOrigin>) => void;\n\n /**\n * Monitoring callback. Receives:\n * - `breadcrumb`: informational, fired on every observed terminal transition.\n * - `parse-error`: when `parsePendingMedia` throws.\n * - `listener-error`: when the Firestore listener's error callback fires.\n *\n * Consumers wire this to Sentry, OpenTelemetry, or any other observability\n * provider. The provider does NOT import any monitoring SDK directly.\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\n// =============================================================================\n// Firestore subscription contract — abstracted to avoid firebase coupling\n// =============================================================================\n\n/**\n * Minimal subscription contract used by the provider. The default\n * implementation lives in `firestore-subscribe.ts` and uses the standard\n * `firebase/firestore` `onSnapshot` + `query` + `where` builders.\n *\n * Tests inject a fake to drive the listener without spinning up Firestore.\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 /**\n * Snapshot metadata. Present when the subscription is opened with\n * `{ includeMetadataChanges: true }` (the default firebase implementation does).\n * `fromCache === false` means a server-confirmed snapshot. Optional so injected\n * test fakes need not supply it (absent ⇒ treated as server-confirmed).\n */\n metadata?: { fromCache: boolean };\n};\n\n/**\n * Metadata-derived liveness of the uploads listener, mirroring query-core's\n * `FirestoreSourceState`. Firestore serves cached snapshots offline WITHOUT\n * firing the error callback, so the Files tray source needs this to show a\n * degraded indicator instead of a false \"all caught up\":\n * - `connecting` — no server-confirmed snapshot yet.\n * - `live` — at least one server-confirmed snapshot (`fromCache === false`).\n * - `offline` — only cached data after having been live.\n * - `error` — the listener error callback fired.\n */\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\n// =============================================================================\n// Provider\n// =============================================================================\n\ninterface InFlightUploadsContextValue<TFileOrigin extends string = string> {\n uploads: Map<string, InFlightUpload<TFileOrigin>>;\n sourceState: UploadsSourceState;\n}\n\nconst InFlightUploadsContext = createContext<InFlightUploadsContextValue | undefined>(undefined);\n\nexport interface InFlightUploadsProviderProps<TFileOrigin extends string = string> {\n adapter: InFlightUploadsAdapter<TFileOrigin>;\n /** Firestore subscription function. Defaults to the firebase/firestore implementation. */\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 (parsed.status === 'pending' || parsed.status === 'processing') {\n return { ...base, status: parsed.status };\n }\n if (parsed.status === 'completed') {\n return {\n ...base,\n 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 === 'failed') {\n return {\n ...base,\n 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 // rejected\n return {\n ...base,\n 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 // Carry the seen fields through (round-9 finding 9): dropping them on the\n // `rejected` branch — while `completed`/`failed` keep them — made a seen\n // rejected upload relight the Files dot forever, because the tray's\n // unseen-terminal check never saw `uploadTraySeenAt`.\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 seenTerminalIdsRef = useRef<Set<string>>(new Set());\n const statusByIdRef = useRef<Map<string, InFlightUploadStatus>>(new Map());\n const hasProcessedInitialSnapshotRef = useRef(false);\n\n // Stable refs for adapter callbacks — read from latest adapter inside effect.\n const adapterRef = useRef(adapter);\n useEffect(() => {\n adapterRef.current = adapter;\n });\n\n const userId = adapter.getCurrentUserId();\n\n useEffect(() => {\n // Reset all in-memory state for the new identity. Runs on every userId\n // change — including UID-A → UID-B with no intermediate null user.\n // Do not rely on an intermediate sign-out to clear refs between two\n // authenticated UIDs.\n setUploads(new Map());\n setSourceState('connecting');\n seenTerminalIdsRef.current = new Set();\n statusByIdRef.current = new Map();\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 =\n currentStatus === 'completed' ||\n currentStatus === 'failed' ||\n currentStatus === 'rejected';\n const previousWasNonTerminal =\n previousStatus === 'pending' || previousStatus === 'processing';\n\n if (isInitialSnapshot) {\n // First snapshot after mount: mark already-terminal docs as seen,\n // but DO NOT fire callbacks. Prevents duplicate toasts on refresh.\n if (currentIsTerminal) {\n seenTerminalIdsRef.current.add(parsed.id);\n }\n } else if (\n currentIsTerminal &&\n previousWasNonTerminal &&\n !seenTerminalIdsRef.current.has(parsed.id)\n ) {\n seenTerminalIdsRef.current.add(parsed.id);\n newlyTerminal.push(parsed);\n } else if (currentIsTerminal) {\n // Terminal doc appeared without an observed non-terminal predecessor\n // (race in a non-initial snapshot). Mark as seen, no callback fire.\n seenTerminalIdsRef.current.add(parsed.id);\n }\n\n statusByIdRef.current.set(parsed.id, currentStatus);\n }\n\n hasProcessedInitialSnapshotRef.current = true;\n\n // Metadata-derived source state: stay `connecting` until a server-confirmed\n // snapshot, `offline` if only cached data arrives after being live.\n const fromCache = snapshot.metadata?.fromCache ?? false;\n setSourceState((prev) => (fromCache ? (prev === 'connecting' ? 'connecting' : 'offline') : 'live'));\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 === 'completed') {\n adapterRef.current.onUploadCompleted(parsed);\n } else if (parsed.status === 'failed') {\n adapterRef.current.onUploadFailed(parsed);\n } else if (parsed.status === 'rejected') {\n adapterRef.current.onUploadRejected(parsed);\n }\n }\n\n // Bounded RESUBSCRIBE on listener error: a cold-session race (e.g. Firestore\n // App Check enforcement rejecting the first attach before the token is\n // minted) must not kill the listener for the whole session — observed live:\n // one permission-denied at first login → sourceState 'error' forever, every\n // tray file status dead until reload. Retry on a short ladder; a snapshot\n // resets the ladder (healthy again); exhausting it goes terminal 'error'\n // (a real rules denial stays denied — retries are cheap and bounded).\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; // healthy — future errors get a fresh ladder\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 return;\n }\n 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 // adapter is intentionally NOT in the deps array — adapter is read via\n // adapterRef on every snapshot, so identity changes don't re-subscribe.\n\n }, [userId, subscribe]);\n\n const value = useMemo<InFlightUploadsContextValue<TFileOrigin>>(\n () => ({ uploads, sourceState }),\n [uploads, sourceState],\n );\n\n return (\n <InFlightUploadsContext.Provider value={value as InFlightUploadsContextValue}>\n {children}\n </InFlightUploadsContext.Provider>\n );\n}\n\n// =============================================================================\n// Read APIs\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\n/**\n * Metadata-derived source state of the uploads listener\n * (`connecting | live | offline | error`). The Files tray uses this to show a\n * degraded indicator and never display \"all caught up\" while the source is\n * `offline`/`error`/`connecting`.\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\n// =============================================================================\n// Tray helpers\n// =============================================================================\n\n/**\n * `true` for `completed` / `failed` / `rejected`. Used by tray UI to decide\n * whether a Clear action is available for an item.\n */\nexport function isTerminalUpload<TFileOrigin extends string = string>(\n item: InFlightUpload<TFileOrigin>,\n): item is Exclude<InFlightUpload<TFileOrigin>, { status: 'pending' | 'processing' }> {\n return (\n item.status === 'completed' ||\n item.status === 'failed' ||\n item.status === 'rejected'\n );\n}\n\n/**\n * Tray-visible items. Includes every pending/processing upload, plus terminal\n * uploads that have NOT been cleared from the tray. Sorted newest-first by\n * createdAt.\n *\n * The public selector name in upload-ui is `useUploadActivityState`. The\n * mutation hook is `useClearUploadActivity` (in a separate file).\n */\nexport function useUploadActivityState<TFileOrigin extends string = string>(): 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// =============================================================================\n// Default Firestore subscription implementation\n// =============================================================================\n\n/**\n * Default Firestore subscription using the consumer's `firebase/firestore`\n * module instance (via static ESM import at the top of this file).\n *\n * Using static ESM import — NOT `require()` — is load-bearing. CommonJS\n * `require('firebase/firestore')` and ESM `import 'firebase/firestore'` resolve\n * to different module instances under Next.js + Turbopack. If the consumer\n * constructs `db` via ESM and we receive it here, but we then call\n * `collection()` from a CJS-loaded copy of firebase, the firebase runtime\n * does not recognize the db as a Firestore instance and throws\n * \"Expected first argument to collection() to be a CollectionReference,\n * a DocumentReference or FirebaseFirestore\".\n *\n * Consumers who want to skip the firebase code path entirely (tests, alt\n * backends) supply their own `subscribe` prop to `InFlightUploadsProvider`.\n */\nconst defaultFirestoreSubscribe: FirestoreSubscribeFn = (args) => {\n const q = query(\n\n collection(args.db as any, args.collectionPath),\n where('userId', '==', args.userId),\n where('createdAt', '>=', args.windowStartMs),\n );\n // includeMetadataChanges so the provider can derive a `connecting|live|offline|error`\n // source state from `snapshot.metadata.fromCache` (the Files tray degraded indicator).\n return onSnapshot(q, { includeMetadataChanges: true }, args.onSnapshot as never, args.onError as never);\n};\n"]}
1
+ {"version":3,"file":"in-flight-uploads-provider.js","sourceRoot":"","sources":["../../src/react/in-flight-uploads-provider.tsx"],"names":[],"mappings":"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","sourcesContent":["'use client';\n\n// ─────────────────────────────────────────────────────────────────────────────\n// SANCTIONED EXCEPTION to the \"packages read/write Firestore only through\n// @ttt-productions/query-core\" rule (see docs/packages/package-architecture.md →\n// \"Firestore access goes through 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.\n// ─────────────────────────────────────────────────────────────────────────────\nimport { collection, onSnapshot, query, where } from 'firebase/firestore';\n\n/**\n * Generic in-flight uploads provider.\n *\n * Provides a global Map of in-flight upload state by `pendingMediaId`, derived\n * from a Firestore listener over the consumer-supplied collection. On terminal\n * status transitions observed THIS SESSION, fires consumer-supplied success /\n * failure / rejection callbacks. Records monitoring breadcrumbs and parse\n * errors through the injected monitoring callback.\n *\n * EVERY app-specific value is supplied by the consumer:\n * - userId resolution\n * - Firestore `db` reference\n * - collection path\n * - listener time window (ms)\n * - parser/schema for raw Firestore doc → typed PendingMedia\n * - success copy per origin\n * - notification callback (cache invalidation, etc.)\n * - toast callback\n * - rejection callback (for the media-rejection dialog or equivalent)\n * - monitoring callback (breadcrumbs + captured errors)\n *\n * Read APIs:\n * - `useInFlightUploadsState()` — full Map.\n * - `useInFlightUpload(id)` — single doc, narrowable on status.\n * - `useUploadActivityState()` — tray-visible items, sorted newest-first.\n *\n * The package owns the deduplication, initial-snapshot suppression, and\n * non-terminal → terminal transition tracking. It does NOT own anything about\n * what a file-origin is or what message text appears in toasts.\n */\n\nimport {\n createContext,\n useContext,\n useEffect,\n useMemo,\n useRef,\n useState,\n type ReactNode,\n} from 'react';\n\n// =============================================================================\n// Generic shape of the data the provider tracks\n// =============================================================================\n\n/**\n * Generic pending-media status. Defined here so upload-ui has no dependency\n * on any app-specific package.\n */\nexport type InFlightUploadStatus =\n | 'pending'\n | 'processing'\n | 'completed'\n | 'failed'\n | 'rejected';\n\n/**\n * Generic in-flight upload record. The provider keeps a Map<id, InFlightUpload>\n * built from each parsed PendingMedia. Consumers parameterize the `fileOrigin`\n * type via the parser's return type (the provider treats it as opaque).\n *\n * `TFileOrigin` defaults to `string` so unannotated consumers get a permissive\n * shape; consuming apps bind it to their own `FileOrigin` union at the call site.\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: 'pending' | 'processing';\n };\n\nexport type InFlightUploadCompleted<TFileOrigin extends string = string> =\n InFlightUploadBase<TFileOrigin> & {\n status: '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: '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: '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\n// =============================================================================\n// Adapter contract — every app-specific behavior is injected here\n// =============================================================================\n\n/**\n * Result of the consumer-supplied parser. The provider keeps the raw parsed\n * record for callbacks (so consumers can read domain events, target IDs, etc.)\n * AND derives the generic InFlightUpload from it for the public Map.\n *\n * The parser MUST throw if validation fails; the provider catches and routes\n * the error to the monitoring callback.\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 // Terminal-status fields (only meaningful for the matching status)\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 /**\n * Opaque consumer-controlled domain-event payload, surfaced to the\n * `onUploadCompleted` and `onUploadRejected` callbacks for cache\n * invalidation. The provider does not interpret it.\n */\n domainEvents?: unknown;\n};\n\nexport type InFlightUploadsAdapter<TFileOrigin extends string = string> = {\n /** Returns the current user's uid, or null if not signed in. */\n getCurrentUserId: () => string | null;\n\n /** Firestore database adapter (loose typing — `unknown` keeps zero firebase coupling at the type level). */\n db: unknown;\n\n /** Collection path holding pending-media docs (e.g. \"pendingMedia\"). */\n collectionPath: string;\n\n /** Listener window in milliseconds — only docs with `createdAt >= now - window` are tracked. */\n listenerWindowMs: number;\n\n /**\n * Parse a raw Firestore doc snapshot's `.data()` into the generic shape the\n * provider tracks. Throws on validation failure; the provider routes thrown\n * errors to `onMonitoringEvent`.\n */\n parsePendingMedia: (raw: unknown) => ParsedPendingMedia<TFileOrigin>;\n\n /** Called once per observed non-terminal → terminal completed transition. */\n onUploadCompleted: (parsed: ParsedPendingMedia<TFileOrigin>) => void;\n\n /** Called once per observed non-terminal → terminal failed transition. */\n onUploadFailed: (parsed: ParsedPendingMedia<TFileOrigin>) => void;\n\n /** Called once per observed non-terminal → terminal rejected transition. */\n onUploadRejected: (parsed: ParsedPendingMedia<TFileOrigin>) => void;\n\n /**\n * Monitoring callback. Receives:\n * - `breadcrumb`: informational, fired on every observed terminal transition.\n * - `parse-error`: when `parsePendingMedia` throws.\n * - `listener-error`: when the Firestore listener's error callback fires.\n *\n * Consumers wire this to Sentry, OpenTelemetry, or any other observability\n * provider. The provider does NOT import any monitoring SDK directly.\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\n// =============================================================================\n// Firestore subscription contract — abstracted to avoid firebase coupling\n// =============================================================================\n\n/**\n * Minimal subscription contract used by the provider. The default\n * implementation lives in `firestore-subscribe.ts` and uses the standard\n * `firebase/firestore` `onSnapshot` + `query` + `where` builders.\n *\n * Tests inject a fake to drive the listener without spinning up Firestore.\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 /**\n * Snapshot metadata. Present when the subscription is opened with\n * `{ includeMetadataChanges: true }` (the default firebase implementation does).\n * `fromCache === false` means a server-confirmed snapshot. Optional so injected\n * test fakes need not supply it (absent ⇒ treated as server-confirmed).\n */\n metadata?: { fromCache: boolean };\n};\n\n/**\n * Metadata-derived liveness of the uploads listener, mirroring query-core's\n * `FirestoreSourceState`. Firestore serves cached snapshots offline WITHOUT\n * firing the error callback, so the Files tray source needs this to show a\n * degraded indicator instead of a false \"all caught up\":\n * - `connecting` — no server-confirmed snapshot yet.\n * - `live` — at least one server-confirmed snapshot (`fromCache === false`).\n * - `offline` — only cached data after having been live.\n * - `error` — the listener error callback fired.\n */\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\n// =============================================================================\n// Provider\n// =============================================================================\n\ninterface InFlightUploadsContextValue<TFileOrigin extends string = string> {\n uploads: Map<string, InFlightUpload<TFileOrigin>>;\n sourceState: UploadsSourceState;\n}\n\nconst InFlightUploadsContext = createContext<InFlightUploadsContextValue | undefined>(undefined);\n\nexport interface InFlightUploadsProviderProps<TFileOrigin extends string = string> {\n adapter: InFlightUploadsAdapter<TFileOrigin>;\n /** Firestore subscription function. Defaults to the firebase/firestore implementation. */\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 (parsed.status === 'pending' || parsed.status === 'processing') {\n return { ...base, status: parsed.status };\n }\n if (parsed.status === 'completed') {\n return {\n ...base,\n 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 === 'failed') {\n return {\n ...base,\n 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 // rejected\n return {\n ...base,\n 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 // Carry the seen fields through (round-9 finding 9): dropping them on the\n // `rejected` branch — while `completed`/`failed` keep them — made a seen\n // rejected upload relight the Files dot forever, because the tray's\n // unseen-terminal check never saw `uploadTraySeenAt`.\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 seenTerminalIdsRef = useRef<Set<string>>(new Set());\n const statusByIdRef = useRef<Map<string, InFlightUploadStatus>>(new Map());\n const hasProcessedInitialSnapshotRef = useRef(false);\n /** The identity the dedup/tracking refs belong to — they outlive resubscribes\n * for the SAME user (auth-settling flaps) and reset only on a real identity\n * change. See the reset block in the subscription effect. */\n const trackedUserIdRef = useRef<string | null>(null);\n\n // Stable refs for adapter callbacks — read from latest adapter inside effect.\n const adapterRef = useRef(adapter);\n useEffect(() => {\n adapterRef.current = adapter;\n });\n\n const userId = adapter.getCurrentUserId();\n\n useEffect(() => {\n // The uploads map and source state rebuild from every subscription's initial\n // snapshot, so they reset on every effect run. The terminal-dedup and\n // status-tracking refs are IDENTITY-scoped, not subscription-scoped: an\n // auth-settling flap (uid → null → same uid re-subscribes) must neither\n // re-fire terminals the previous subscription already fired (seen set\n // persists) nor lose the observed non-terminal statuses that let the new\n // subscription's initial listing detect a transition that completed during\n // the gap. A real identity change — including UID-A → UID-B with no\n // intermediate null user — starts clean; never rely on an intermediate\n // sign-out to clear refs between two authenticated UIDs.\n setUploads(new Map());\n setSourceState('connecting');\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 =\n currentStatus === 'completed' ||\n currentStatus === 'failed' ||\n currentStatus === 'rejected';\n const previousWasNonTerminal =\n previousStatus === 'pending' || previousStatus === 'processing';\n\n if (isInitialSnapshot) {\n // A subscription's first snapshot is a (re-)listing of current state,\n // not a live event: already-terminal docs stay suppressed so a page\n // refresh never re-toasts. ONE exception — this provider instance\n // tracked the doc as non-terminal before (same-identity resubscribe\n // gap; the tracking refs survive those), so the terminal listing IS\n // the transition, observed across the gap, and must fire.\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 // Any unseen terminal in a LIVE snapshot fires — including a doc whose\n // FIRST client-visible state is already terminal. A fast backend\n // outcome (moderation rejection in ~2s) can coalesce created→terminal\n // into one delivery, and the uploader is actively waiting on exactly\n // this callback; swallowing it silently loses a rejection dialog.\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 // Metadata-derived source state: stay `connecting` until a server-confirmed\n // snapshot, `offline` if only cached data arrives after being live.\n const fromCache = snapshot.metadata?.fromCache ?? false;\n setSourceState((prev) => (fromCache ? (prev === 'connecting' ? 'connecting' : 'offline') : 'live'));\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 === 'completed') {\n adapterRef.current.onUploadCompleted(parsed);\n } else if (parsed.status === 'failed') {\n adapterRef.current.onUploadFailed(parsed);\n } else if (parsed.status === 'rejected') {\n adapterRef.current.onUploadRejected(parsed);\n }\n }\n\n // Bounded RESUBSCRIBE on listener error: a cold-session race (e.g. Firestore\n // App Check enforcement rejecting the first attach before the token is\n // minted) must not kill the listener for the whole session — observed live:\n // one permission-denied at first login → sourceState 'error' forever, every\n // tray file status dead until reload. Retry on a short ladder; a snapshot\n // resets the ladder (healthy again); exhausting it goes terminal 'error'\n // (a real rules denial stays denied — retries are cheap and bounded).\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; // healthy — future errors get a fresh ladder\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 return;\n }\n 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 // adapter is intentionally NOT in the deps array — adapter is read via\n // adapterRef on every snapshot, so identity changes don't re-subscribe.\n\n }, [userId, subscribe]);\n\n const value = useMemo<InFlightUploadsContextValue<TFileOrigin>>(\n () => ({ uploads, sourceState }),\n [uploads, sourceState],\n );\n\n return (\n <InFlightUploadsContext.Provider value={value as InFlightUploadsContextValue}>\n {children}\n </InFlightUploadsContext.Provider>\n );\n}\n\n// =============================================================================\n// Read APIs\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\n/**\n * Metadata-derived source state of the uploads listener\n * (`connecting | live | offline | error`). The Files tray uses this to show a\n * degraded indicator and never display \"all caught up\" while the source is\n * `offline`/`error`/`connecting`.\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\n// =============================================================================\n// Tray helpers\n// =============================================================================\n\n/**\n * `true` for `completed` / `failed` / `rejected`. Used by tray UI to decide\n * whether a Clear action is available for an item.\n */\nexport function isTerminalUpload<TFileOrigin extends string = string>(\n item: InFlightUpload<TFileOrigin>,\n): item is Exclude<InFlightUpload<TFileOrigin>, { status: 'pending' | 'processing' }> {\n return (\n item.status === 'completed' ||\n item.status === 'failed' ||\n item.status === 'rejected'\n );\n}\n\n/**\n * Tray-visible items. Includes every pending/processing upload, plus terminal\n * uploads that have NOT been cleared from the tray. Sorted newest-first by\n * createdAt.\n *\n * The public selector name in upload-ui is `useUploadActivityState`. The\n * mutation hook is `useClearUploadActivity` (in a separate file).\n */\nexport function useUploadActivityState<TFileOrigin extends string = string>(): 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// =============================================================================\n// Default Firestore subscription implementation\n// =============================================================================\n\n/**\n * Default Firestore subscription using the consumer's `firebase/firestore`\n * module instance (via static ESM import at the top of this file).\n *\n * Using static ESM import — NOT `require()` — is load-bearing. CommonJS\n * `require('firebase/firestore')` and ESM `import 'firebase/firestore'` resolve\n * to different module instances under Next.js + Turbopack. If the consumer\n * constructs `db` via ESM and we receive it here, but we then call\n * `collection()` from a CJS-loaded copy of firebase, the firebase runtime\n * does not recognize the db as a Firestore instance and throws\n * \"Expected first argument to collection() to be a CollectionReference,\n * a DocumentReference or FirebaseFirestore\".\n *\n * Consumers who want to skip the firebase code path entirely (tests, alt\n * backends) supply their own `subscribe` prop to `InFlightUploadsProvider`.\n */\nconst defaultFirestoreSubscribe: FirestoreSubscribeFn = (args) => {\n const q = query(\n\n collection(args.db as any, args.collectionPath),\n where('userId', '==', args.userId),\n where('createdAt', '>=', args.windowStartMs),\n );\n // includeMetadataChanges so the provider can derive a `connecting|live|offline|error`\n // source state from `snapshot.metadata.fromCache` (the Files tray degraded indicator).\n return onSnapshot(q, { includeMetadataChanges: true }, args.onSnapshot as never, args.onError as never);\n};\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ttt-productions/upload-ui",
3
- "version": "0.7.7",
3
+ "version": "0.7.8",
4
4
  "description": "Upload UI primitives: local upload guard provider, useGuardedUpload helper, DeferredUploadFormShell for forms that defer Firebase Storage upload until form submit.",
5
5
  "repository": {
6
6
  "type": "git",