@ttt-productions/upload-core 0.0.2

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.
Files changed (61) hide show
  1. package/dist/index.d.ts +9 -0
  2. package/dist/index.d.ts.map +1 -0
  3. package/dist/index.js +9 -0
  4. package/dist/index.js.map +1 -0
  5. package/dist/persistence/localstorage.d.ts +6 -0
  6. package/dist/persistence/localstorage.d.ts.map +1 -0
  7. package/dist/persistence/localstorage.js +54 -0
  8. package/dist/persistence/localstorage.js.map +1 -0
  9. package/dist/queue/upload-queue.d.ts +16 -0
  10. package/dist/queue/upload-queue.d.ts.map +1 -0
  11. package/dist/queue/upload-queue.js +115 -0
  12. package/dist/queue/upload-queue.js.map +1 -0
  13. package/dist/react/index.d.ts +4 -0
  14. package/dist/react/index.d.ts.map +1 -0
  15. package/dist/react/index.js +4 -0
  16. package/dist/react/index.js.map +1 -0
  17. package/dist/react/use-upload-controller.d.ts +10 -0
  18. package/dist/react/use-upload-controller.d.ts.map +1 -0
  19. package/dist/react/use-upload-controller.js +32 -0
  20. package/dist/react/use-upload-controller.js.map +1 -0
  21. package/dist/react/use-upload-file.d.ts +8 -0
  22. package/dist/react/use-upload-file.d.ts.map +1 -0
  23. package/dist/react/use-upload-file.js +44 -0
  24. package/dist/react/use-upload-file.js.map +1 -0
  25. package/dist/react/use-upload-sessions.d.ts +5 -0
  26. package/dist/react/use-upload-sessions.d.ts.map +1 -0
  27. package/dist/react/use-upload-sessions.js +14 -0
  28. package/dist/react/use-upload-sessions.js.map +1 -0
  29. package/dist/storage/delete.d.ts +3 -0
  30. package/dist/storage/delete.d.ts.map +1 -0
  31. package/dist/storage/delete.js +6 -0
  32. package/dist/storage/delete.js.map +1 -0
  33. package/dist/storage/upload.d.ts +15 -0
  34. package/dist/storage/upload.d.ts.map +1 -0
  35. package/dist/storage/upload.js +157 -0
  36. package/dist/storage/upload.js.map +1 -0
  37. package/dist/types.d.ts +87 -0
  38. package/dist/types.d.ts.map +1 -0
  39. package/dist/types.js +2 -0
  40. package/dist/types.js.map +1 -0
  41. package/dist/utils/file-size.d.ts +2 -0
  42. package/dist/utils/file-size.d.ts.map +1 -0
  43. package/dist/utils/file-size.js +6 -0
  44. package/dist/utils/file-size.js.map +1 -0
  45. package/dist/utils/filename.d.ts +2 -0
  46. package/dist/utils/filename.d.ts.map +1 -0
  47. package/dist/utils/filename.js +17 -0
  48. package/dist/utils/filename.js.map +1 -0
  49. package/dist/utils/path.d.ts +7 -0
  50. package/dist/utils/path.d.ts.map +1 -0
  51. package/dist/utils/path.js +22 -0
  52. package/dist/utils/path.js.map +1 -0
  53. package/dist/utils/retry.d.ts +3 -0
  54. package/dist/utils/retry.d.ts.map +1 -0
  55. package/dist/utils/retry.js +31 -0
  56. package/dist/utils/retry.js.map +1 -0
  57. package/dist/utils/upload-store.d.ts +19 -0
  58. package/dist/utils/upload-store.d.ts.map +1 -0
  59. package/dist/utils/upload-store.js +162 -0
  60. package/dist/utils/upload-store.js.map +1 -0
  61. package/package.json +45 -0
@@ -0,0 +1,9 @@
1
+ export * from "./types";
2
+ export * from "./storage/upload";
3
+ export * from "./storage/delete";
4
+ export * from "./utils/filename";
5
+ export * from "./utils/path";
6
+ export * from "./utils/upload-store";
7
+ export * from "./queue/upload-queue";
8
+ export * from "./persistence/localstorage";
9
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,SAAS,CAAC;AAExB,cAAc,kBAAkB,CAAC;AACjC,cAAc,kBAAkB,CAAC;AAEjC,cAAc,kBAAkB,CAAC;AACjC,cAAc,cAAc,CAAC;AAC7B,cAAc,sBAAsB,CAAC;AAErC,cAAc,sBAAsB,CAAC;AACrC,cAAc,4BAA4B,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,9 @@
1
+ export * from "./types";
2
+ export * from "./storage/upload";
3
+ export * from "./storage/delete";
4
+ export * from "./utils/filename";
5
+ export * from "./utils/path";
6
+ export * from "./utils/upload-store";
7
+ export * from "./queue/upload-queue";
8
+ export * from "./persistence/localstorage";
9
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,SAAS,CAAC;AAExB,cAAc,kBAAkB,CAAC;AACjC,cAAc,kBAAkB,CAAC;AAEjC,cAAc,kBAAkB,CAAC;AACjC,cAAc,cAAc,CAAC;AAC7B,cAAc,sBAAsB,CAAC;AAErC,cAAc,sBAAsB,CAAC;AACrC,cAAc,4BAA4B,CAAC"}
@@ -0,0 +1,6 @@
1
+ import type { UploadSessionPersistenceAdapter } from "../types";
2
+ export declare function createLocalStorageUploadSessionPersistence(opts?: {
3
+ /** Prefix for keys. Default: "ttt_upload_session:" */
4
+ prefix?: string;
5
+ }): UploadSessionPersistenceAdapter;
6
+ //# sourceMappingURL=localstorage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"localstorage.d.ts","sourceRoot":"","sources":["../../src/persistence/localstorage.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,+BAA+B,EAAsB,MAAM,UAAU,CAAC;AAUpF,wBAAgB,0CAA0C,CAAC,IAAI,CAAC,EAAE;IAChE,sDAAsD;IACtD,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB,GAAG,+BAA+B,CA0ClC"}
@@ -0,0 +1,54 @@
1
+ function hasLocalStorage() {
2
+ try {
3
+ return typeof window !== "undefined" && !!window.localStorage;
4
+ }
5
+ catch {
6
+ return false;
7
+ }
8
+ }
9
+ export function createLocalStorageUploadSessionPersistence(opts) {
10
+ const prefix = opts?.prefix ?? "ttt_upload_session:";
11
+ const k = (id) => `${prefix}${id}`;
12
+ const safeParse = (raw) => {
13
+ if (!raw)
14
+ return null;
15
+ try {
16
+ return JSON.parse(raw);
17
+ }
18
+ catch {
19
+ return null;
20
+ }
21
+ };
22
+ return {
23
+ listIds: () => {
24
+ if (!hasLocalStorage())
25
+ return [];
26
+ const ids = [];
27
+ for (let i = 0; i < window.localStorage.length; i += 1) {
28
+ const key = window.localStorage.key(i);
29
+ if (!key)
30
+ continue;
31
+ if (!key.startsWith(prefix))
32
+ continue;
33
+ ids.push(key.slice(prefix.length));
34
+ }
35
+ return ids;
36
+ },
37
+ get: (id) => {
38
+ if (!hasLocalStorage())
39
+ return null;
40
+ return safeParse(window.localStorage.getItem(k(id)));
41
+ },
42
+ set: (id, state) => {
43
+ if (!hasLocalStorage())
44
+ return;
45
+ window.localStorage.setItem(k(id), JSON.stringify(state));
46
+ },
47
+ remove: (id) => {
48
+ if (!hasLocalStorage())
49
+ return;
50
+ window.localStorage.removeItem(k(id));
51
+ },
52
+ };
53
+ }
54
+ //# sourceMappingURL=localstorage.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"localstorage.js","sourceRoot":"","sources":["../../src/persistence/localstorage.ts"],"names":[],"mappings":"AAEA,SAAS,eAAe;IACtB,IAAI,CAAC;QACH,OAAO,OAAO,MAAM,KAAK,WAAW,IAAI,CAAC,CAAC,MAAM,CAAC,YAAY,CAAC;IAChE,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED,MAAM,UAAU,0CAA0C,CAAC,IAG1D;IACC,MAAM,MAAM,GAAG,IAAI,EAAE,MAAM,IAAI,qBAAqB,CAAC;IAErD,MAAM,CAAC,GAAG,CAAC,EAAU,EAAE,EAAE,CAAC,GAAG,MAAM,GAAG,EAAE,EAAE,CAAC;IAE3C,MAAM,SAAS,GAAG,CAAC,GAAkB,EAA6B,EAAE;QAClE,IAAI,CAAC,GAAG;YAAE,OAAO,IAAI,CAAC;QACtB,IAAI,CAAC;YACH,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAuB,CAAC;QAC/C,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,IAAI,CAAC;QACd,CAAC;IACH,CAAC,CAAC;IAEF,OAAO;QACL,OAAO,EAAE,GAAG,EAAE;YACZ,IAAI,CAAC,eAAe,EAAE;gBAAE,OAAO,EAAE,CAAC;YAClC,MAAM,GAAG,GAAa,EAAE,CAAC;YACzB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,MAAM,CAAC,YAAY,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC;gBACvD,MAAM,GAAG,GAAG,MAAM,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;gBACvC,IAAI,CAAC,GAAG;oBAAE,SAAS;gBACnB,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,MAAM,CAAC;oBAAE,SAAS;gBACtC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC;YACrC,CAAC;YACD,OAAO,GAAG,CAAC;QACb,CAAC;QAED,GAAG,EAAE,CAAC,EAAU,EAAE,EAAE;YAClB,IAAI,CAAC,eAAe,EAAE;gBAAE,OAAO,IAAI,CAAC;YACpC,OAAO,SAAS,CAAC,MAAM,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;QACvD,CAAC;QAED,GAAG,EAAE,CAAC,EAAU,EAAE,KAAyB,EAAE,EAAE;YAC7C,IAAI,CAAC,eAAe,EAAE;gBAAE,OAAO;YAC/B,MAAM,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC;QAC5D,CAAC;QAED,MAAM,EAAE,CAAC,EAAU,EAAE,EAAE;YACrB,IAAI,CAAC,eAAe,EAAE;gBAAE,OAAO;YAC/B,MAAM,CAAC,YAAY,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;QACxC,CAAC;KACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,16 @@
1
+ import type { UploadController, UploadQueueOptions, StartUploadArgs } from "../types";
2
+ export declare class UploadQueue {
3
+ private concurrency;
4
+ private running;
5
+ private pending;
6
+ private seq;
7
+ constructor(opts?: UploadQueueOptions);
8
+ setConcurrency(n: number): void;
9
+ getPendingCount(): number;
10
+ getRunningCount(): number;
11
+ enqueue(args: StartUploadArgs & {
12
+ priority?: number;
13
+ }): UploadController;
14
+ private pump;
15
+ }
16
+ //# sourceMappingURL=upload-queue.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"upload-queue.d.ts","sourceRoot":"","sources":["../../src/queue/upload-queue.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAA6B,kBAAkB,EAAE,eAAe,EAAE,MAAM,UAAU,CAAC;AAqBjH,qBAAa,WAAW;IACtB,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,OAAO,CAAK;IACpB,OAAO,CAAC,OAAO,CAAa;IAC5B,OAAO,CAAC,GAAG,CAAK;gBAEJ,IAAI,CAAC,EAAE,kBAAkB;IAIrC,cAAc,CAAC,CAAC,EAAE,MAAM;IAKxB,eAAe;IAIf,eAAe;IAIf,OAAO,CAAC,IAAI,EAAE,eAAe,GAAG;QAAE,QAAQ,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,gBAAgB;IA+DxE,OAAO,CAAC,IAAI;CAoCb"}
@@ -0,0 +1,115 @@
1
+ import { getFileSize } from "../utils/file-size";
2
+ import { upsertUploadSession, removeUploadSession } from "../utils/upload-store";
3
+ import { startResumableUpload } from "../storage/upload";
4
+ function safeId() {
5
+ return Math.random().toString(36).slice(2) + Date.now().toString(36);
6
+ }
7
+ function noopBool() {
8
+ return false;
9
+ }
10
+ export class UploadQueue {
11
+ concurrency;
12
+ running = 0;
13
+ pending = [];
14
+ seq = 0;
15
+ constructor(opts) {
16
+ this.concurrency = Math.max(1, opts?.concurrency ?? 2);
17
+ }
18
+ setConcurrency(n) {
19
+ this.concurrency = Math.max(1, n);
20
+ this.pump();
21
+ }
22
+ getPendingCount() {
23
+ return this.pending.length;
24
+ }
25
+ getRunningCount() {
26
+ return this.running;
27
+ }
28
+ enqueue(args) {
29
+ const id = args.id ?? `upl_${safeId()}`;
30
+ const priority = args.priority ?? 0;
31
+ const startedAt = Date.now();
32
+ upsertUploadSession({
33
+ id,
34
+ status: "queued",
35
+ path: args.path,
36
+ transferred: 0,
37
+ total: getFileSize(args.file),
38
+ percent: 0,
39
+ startedAt,
40
+ updatedAt: startedAt,
41
+ });
42
+ let real = null;
43
+ let resolveDone;
44
+ let rejectDone;
45
+ const done = new Promise((res, rej) => {
46
+ resolveDone = res;
47
+ rejectDone = rej;
48
+ });
49
+ const controller = {
50
+ id,
51
+ task: null,
52
+ pause: () => (real ? real.pause() : noopBool()),
53
+ resume: () => (real ? real.resume() : noopBool()),
54
+ cancel: () => {
55
+ if (real)
56
+ return real.cancel();
57
+ this.pending = this.pending.filter((j) => j.id !== id);
58
+ removeUploadSession(id);
59
+ rejectDone(new DOMException("Aborted", "AbortError"));
60
+ return true;
61
+ },
62
+ done,
63
+ };
64
+ const job = {
65
+ id,
66
+ args: { ...args, id },
67
+ priority,
68
+ seq: this.seq++,
69
+ resolveController: (c) => {
70
+ real = c;
71
+ controller.task = c.task;
72
+ controller.pause = c.pause;
73
+ controller.resume = c.resume;
74
+ controller.cancel = c.cancel;
75
+ c.done.then(resolveDone, rejectDone);
76
+ },
77
+ rejectController: (e) => rejectDone(e),
78
+ };
79
+ this.pending.push(job);
80
+ this.pump();
81
+ return controller;
82
+ }
83
+ pump() {
84
+ while (this.running < this.concurrency && this.pending.length > 0) {
85
+ this.pending.sort((a, b) => (b.priority - a.priority) || (a.seq - b.seq));
86
+ const job = this.pending.shift();
87
+ this.running += 1;
88
+ try {
89
+ const { priority: _p, ...rest } = job.args;
90
+ const c = startResumableUpload({
91
+ ...rest,
92
+ id: job.id, // guarantee
93
+ });
94
+ job.resolveController(c);
95
+ c.done.finally(() => {
96
+ this.running -= 1;
97
+ this.pump();
98
+ });
99
+ }
100
+ catch (e) {
101
+ this.running -= 1;
102
+ upsertUploadSession({
103
+ id: job.id,
104
+ status: "error",
105
+ path: job.args.path,
106
+ error: e,
107
+ updatedAt: Date.now(),
108
+ });
109
+ job.rejectController(e);
110
+ this.pump();
111
+ }
112
+ }
113
+ }
114
+ }
115
+ //# sourceMappingURL=upload-queue.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"upload-queue.js","sourceRoot":"","sources":["../../src/queue/upload-queue.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ export * from "./use-upload-file";
2
+ export * from "./use-upload-controller";
3
+ export * from "./use-upload-sessions";
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/react/index.ts"],"names":[],"mappings":"AAAA,cAAc,mBAAmB,CAAC;AAClC,cAAc,yBAAyB,CAAC;AACxC,cAAc,uBAAuB,CAAC"}
@@ -0,0 +1,4 @@
1
+ export * from "./use-upload-file";
2
+ export * from "./use-upload-controller";
3
+ export * from "./use-upload-sessions";
4
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/react/index.ts"],"names":[],"mappings":"AAAA,cAAc,mBAAmB,CAAC;AAClC,cAAc,yBAAyB,CAAC;AACxC,cAAc,uBAAuB,CAAC"}
@@ -0,0 +1,10 @@
1
+ import type { StartUploadArgs, UploadController, UploadSessionState } from "../types";
2
+ export declare function useUploadController(): {
3
+ start: (args: StartUploadArgs) => UploadController;
4
+ controller: UploadController | null;
5
+ session: UploadSessionState | null;
6
+ pause: () => boolean;
7
+ resume: () => boolean;
8
+ cancel: () => boolean;
9
+ };
10
+ //# sourceMappingURL=use-upload-controller.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-upload-controller.d.ts","sourceRoot":"","sources":["../../src/react/use-upload-controller.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,eAAe,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,MAAM,UAAU,CAAC;AAItF,wBAAgB,mBAAmB;kBAWA,eAAe;;;;;;EAkBjD"}
@@ -0,0 +1,32 @@
1
+ "use client";
2
+ import { useCallback, useEffect, useMemo, useState } from "react";
3
+ import { startResumableUpload } from "../storage/upload";
4
+ import { getUploadSession, subscribeUploadSession } from "../utils/upload-store";
5
+ export function useUploadController() {
6
+ const [controller, setController] = useState(null);
7
+ const [session, setSession] = useState(null);
8
+ useEffect(() => {
9
+ if (!controller)
10
+ return;
11
+ const id = controller.id;
12
+ setSession(getUploadSession(id) ?? null);
13
+ return subscribeUploadSession(id, (s) => setSession(s));
14
+ }, [controller]);
15
+ const start = useCallback((args) => {
16
+ const c = startResumableUpload({ ...args, id: args.id ?? `upl_${Math.random().toString(36).slice(2)}${Date.now().toString(36)}` });
17
+ setController(c);
18
+ return c;
19
+ }, []);
20
+ const api = useMemo(() => {
21
+ return {
22
+ start,
23
+ controller,
24
+ session,
25
+ pause: () => controller?.pause() ?? false,
26
+ resume: () => controller?.resume() ?? false,
27
+ cancel: () => controller?.cancel() ?? false,
28
+ };
29
+ }, [start, controller, session]);
30
+ return api;
31
+ }
32
+ //# sourceMappingURL=use-upload-controller.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-upload-controller.js","sourceRoot":"","sources":["../../src/react/use-upload-controller.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAEb,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAElE,OAAO,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AACzD,OAAO,EAAE,gBAAgB,EAAE,sBAAsB,EAAE,MAAM,uBAAuB,CAAC;AAEjF,MAAM,UAAU,mBAAmB;IACjC,MAAM,CAAC,UAAU,EAAE,aAAa,CAAC,GAAG,QAAQ,CAA0B,IAAI,CAAC,CAAC;IAC5E,MAAM,CAAC,OAAO,EAAE,UAAU,CAAC,GAAG,QAAQ,CAA4B,IAAI,CAAC,CAAC;IAExE,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,CAAC,UAAU;YAAE,OAAO;QACxB,MAAM,EAAE,GAAG,UAAU,CAAC,EAAE,CAAC;QACzB,UAAU,CAAC,gBAAgB,CAAC,EAAE,CAAC,IAAI,IAAI,CAAC,CAAC;QACzC,OAAO,sBAAsB,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC;IAC1D,CAAC,EAAE,CAAC,UAAU,CAAC,CAAC,CAAC;IAEjB,MAAM,KAAK,GAAG,WAAW,CAAC,CAAC,IAAqB,EAAE,EAAE;QAClD,MAAM,CAAC,GAAG,oBAAoB,CAAC,EAAE,GAAG,IAAI,EAAE,EAAE,EAAE,IAAI,CAAC,EAAE,IAAI,OAAO,IAAI,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC;QACnI,aAAa,CAAC,CAAC,CAAC,CAAC;QACjB,OAAO,CAAC,CAAC;IACX,CAAC,EAAE,EAAE,CAAC,CAAC;IAEP,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,EAAE;QACvB,OAAO;YACL,KAAK;YACL,UAAU;YACV,OAAO;YACP,KAAK,EAAE,GAAG,EAAE,CAAC,UAAU,EAAE,KAAK,EAAE,IAAI,KAAK;YACzC,MAAM,EAAE,GAAG,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,IAAI,KAAK;YAC3C,MAAM,EAAE,GAAG,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,IAAI,KAAK;SAC5C,CAAC;IACJ,CAAC,EAAE,CAAC,KAAK,EAAE,UAAU,EAAE,OAAO,CAAC,CAAC,CAAC;IAEjC,OAAO,GAAG,CAAC;AACb,CAAC"}
@@ -0,0 +1,8 @@
1
+ import type { UploadFileResumableArgs, UploadFileResumableResult } from "../types";
2
+ export declare function useUploadFile(): {
3
+ upload: (args: Omit<UploadFileResumableArgs, "onProgress">) => Promise<UploadFileResumableResult>;
4
+ progress: number;
5
+ isUploading: boolean;
6
+ error: unknown;
7
+ };
8
+ //# sourceMappingURL=use-upload-file.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-upload-file.d.ts","sourceRoot":"","sources":["../../src/react/use-upload-file.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,uBAAuB,EAAE,yBAAyB,EAAE,MAAM,UAAU,CAAC;AAGnF,wBAAgB,aAAa;mBAeZ,IAAI,CAAC,uBAAuB,EAAE,YAAY,CAAC,KAAG,OAAO,CAAC,yBAAyB,CAAC;;;;EA+BhG"}
@@ -0,0 +1,44 @@
1
+ "use client";
2
+ import { useCallback, useEffect, useRef, useState } from "react";
3
+ import { uploadFileResumable } from "../storage/upload";
4
+ export function useUploadFile() {
5
+ const [progress, setProgress] = useState(0);
6
+ const [isUploading, setIsUploading] = useState(false);
7
+ const [error, setError] = useState(null);
8
+ const mountedRef = useRef(true);
9
+ useEffect(() => {
10
+ mountedRef.current = true;
11
+ return () => {
12
+ mountedRef.current = false;
13
+ };
14
+ }, []);
15
+ const upload = useCallback(async (args) => {
16
+ setIsUploading(true);
17
+ setError(null);
18
+ setProgress(0);
19
+ try {
20
+ const res = await uploadFileResumable({
21
+ ...args,
22
+ onProgress: ({ percent }) => {
23
+ if (!mountedRef.current)
24
+ return;
25
+ setProgress(percent);
26
+ },
27
+ });
28
+ if (!mountedRef.current)
29
+ return res;
30
+ setProgress(100);
31
+ setIsUploading(false);
32
+ return res;
33
+ }
34
+ catch (e) {
35
+ if (mountedRef.current) {
36
+ setError(e);
37
+ setIsUploading(false);
38
+ }
39
+ throw e;
40
+ }
41
+ }, []);
42
+ return { upload, progress, isUploading, error };
43
+ }
44
+ //# sourceMappingURL=use-upload-file.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-upload-file.js","sourceRoot":"","sources":["../../src/react/use-upload-file.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAEb,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAEjE,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AAExD,MAAM,UAAU,aAAa;IAC3B,MAAM,CAAC,QAAQ,EAAE,WAAW,CAAC,GAAG,QAAQ,CAAS,CAAC,CAAC,CAAC;IACpD,MAAM,CAAC,WAAW,EAAE,cAAc,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;IACtD,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAG,QAAQ,CAAU,IAAI,CAAC,CAAC;IAElD,MAAM,UAAU,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC;IAEhC,SAAS,CAAC,GAAG,EAAE;QACb,UAAU,CAAC,OAAO,GAAG,IAAI,CAAC;QAC1B,OAAO,GAAG,EAAE;YACV,UAAU,CAAC,OAAO,GAAG,KAAK,CAAC;QAC7B,CAAC,CAAC;IACJ,CAAC,EAAE,EAAE,CAAC,CAAC;IAEP,MAAM,MAAM,GAAG,WAAW,CACxB,KAAK,EAAE,IAAiD,EAAsC,EAAE;QAC9F,cAAc,CAAC,IAAI,CAAC,CAAC;QACrB,QAAQ,CAAC,IAAI,CAAC,CAAC;QACf,WAAW,CAAC,CAAC,CAAC,CAAC;QAEf,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,MAAM,mBAAmB,CAAC;gBACpC,GAAG,IAAI;gBACP,UAAU,EAAE,CAAC,EAAE,OAAO,EAAuB,EAAE,EAAE;oBAC/C,IAAI,CAAC,UAAU,CAAC,OAAO;wBAAE,OAAO;oBAChC,WAAW,CAAC,OAAO,CAAC,CAAC;gBACvB,CAAC;aACF,CAAC,CAAC;YAEH,IAAI,CAAC,UAAU,CAAC,OAAO;gBAAE,OAAO,GAAG,CAAC;YAEpC,WAAW,CAAC,GAAG,CAAC,CAAC;YACjB,cAAc,CAAC,KAAK,CAAC,CAAC;YACtB,OAAO,GAAG,CAAC;QACb,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACX,IAAI,UAAU,CAAC,OAAO,EAAE,CAAC;gBACvB,QAAQ,CAAC,CAAC,CAAC,CAAC;gBACZ,cAAc,CAAC,KAAK,CAAC,CAAC;YACxB,CAAC;YACD,MAAM,CAAC,CAAC;QACV,CAAC;IACH,CAAC,EACD,EAAE,CACH,CAAC;IAEF,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,WAAW,EAAE,KAAK,EAAE,CAAC;AAClD,CAAC"}
@@ -0,0 +1,5 @@
1
+ import type { UploadSessionState } from "../types";
2
+ export declare function useUploadSessions(): {
3
+ sessions: UploadSessionState[];
4
+ };
5
+ //# sourceMappingURL=use-upload-sessions.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-upload-sessions.d.ts","sourceRoot":"","sources":["../../src/react/use-upload-sessions.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,UAAU,CAAC;AAGnD,wBAAgB,iBAAiB;;EAYhC"}
@@ -0,0 +1,14 @@
1
+ "use client";
2
+ import { useEffect, useState } from "react";
3
+ import { listUploadSessions, subscribeUploadSessionsList } from "../utils/upload-store";
4
+ export function useUploadSessions() {
5
+ const [sessions, setSessions] = useState(() => listUploadSessions());
6
+ useEffect(() => {
7
+ const sync = () => setSessions(listUploadSessions());
8
+ sync();
9
+ const unsub = subscribeUploadSessionsList(sync);
10
+ return () => unsub();
11
+ }, []);
12
+ return { sessions };
13
+ }
14
+ //# sourceMappingURL=use-upload-sessions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-upload-sessions.js","sourceRoot":"","sources":["../../src/react/use-upload-sessions.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAEb,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAE5C,OAAO,EAAE,kBAAkB,EAAE,2BAA2B,EAAE,MAAM,uBAAuB,CAAC;AAExF,MAAM,UAAU,iBAAiB;IAC/B,MAAM,CAAC,QAAQ,EAAE,WAAW,CAAC,GAAG,QAAQ,CAAuB,GAAG,EAAE,CAAC,kBAAkB,EAAE,CAAC,CAAC;IAE3F,SAAS,CAAC,GAAG,EAAE;QACb,MAAM,IAAI,GAAG,GAAG,EAAE,CAAC,WAAW,CAAC,kBAAkB,EAAE,CAAC,CAAC;QACrD,IAAI,EAAE,CAAC;QAEP,MAAM,KAAK,GAAG,2BAA2B,CAAC,IAAI,CAAC,CAAC;QAChD,OAAO,GAAG,EAAE,CAAC,KAAK,EAAE,CAAC;IACvB,CAAC,EAAE,EAAE,CAAC,CAAC;IAEP,OAAO,EAAE,QAAQ,EAAE,CAAC;AACtB,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { DeleteFileArgs } from "../types";
2
+ export declare function deleteFile(args: DeleteFileArgs): Promise<void>;
3
+ //# sourceMappingURL=delete.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"delete.d.ts","sourceRoot":"","sources":["../../src/storage/delete.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAG/C,wBAAsB,UAAU,CAAC,IAAI,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,CAGpE"}
@@ -0,0 +1,6 @@
1
+ import { deleteObject, ref } from "firebase/storage";
2
+ export async function deleteFile(args) {
3
+ const { storage, path } = args;
4
+ await deleteObject(ref(storage, path));
5
+ }
6
+ //# sourceMappingURL=delete.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"delete.js","sourceRoot":"","sources":["../../src/storage/delete.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,GAAG,EAAE,MAAM,kBAAkB,CAAC;AAErD,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,IAAoB;IACnD,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,GAAG,IAAI,CAAC;IAC/B,MAAM,YAAY,CAAC,GAAG,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC,CAAC;AACzC,CAAC"}
@@ -0,0 +1,15 @@
1
+ import type { UploadFileResumableArgs, UploadController, UploadFileResumableResult } from "../types";
2
+ import { type FirebaseStorage, type UploadMetadata } from "firebase/storage";
3
+ export declare function startResumableUpload(args: {
4
+ id: string;
5
+ storage: FirebaseStorage;
6
+ path: string;
7
+ file: Blob;
8
+ metadata?: UploadMetadata;
9
+ onProgress?: UploadFileResumableArgs["onProgress"];
10
+ signal?: AbortSignal;
11
+ }): UploadController;
12
+ export declare function uploadFileResumable(args: Omit<Parameters<typeof startResumableUpload>[0], "id"> & {
13
+ id?: string;
14
+ }): Promise<UploadFileResumableResult>;
15
+ //# sourceMappingURL=upload.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"upload.d.ts","sourceRoot":"","sources":["../../src/storage/upload.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,uBAAuB,EAAE,gBAAgB,EAAE,yBAAyB,EAAE,MAAM,UAAU,CAAC;AAIrG,OAAO,EAIL,KAAK,eAAe,EACpB,KAAK,cAAc,EAEpB,MAAM,kBAAkB,CAAC;AAM1B,wBAAgB,oBAAoB,CAAC,IAAI,EAAE;IACzC,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,eAAe,CAAC;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,IAAI,CAAC;IACX,QAAQ,CAAC,EAAE,cAAc,CAAC;IAC1B,UAAU,CAAC,EAAE,uBAAuB,CAAC,YAAY,CAAC,CAAC;IACnD,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB,GAAG,gBAAgB,CA4JnB;AAED,wBAAsB,mBAAmB,CACvC,IAAI,EAAE,IAAI,CAAC,UAAU,CAAC,OAAO,oBAAoB,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG;IAAE,EAAE,CAAC,EAAE,MAAM,CAAA;CAAE,GAC7E,OAAO,CAAC,yBAAyB,CAAC,CAIpC"}
@@ -0,0 +1,157 @@
1
+ import { getFileSize } from "../utils/file-size";
2
+ import { upsertUploadSession } from "../utils/upload-store";
3
+ import { getDownloadURL, ref, uploadBytesResumable, } from "firebase/storage";
4
+ function isAbortError(e) {
5
+ return e instanceof DOMException && e.name === "AbortError";
6
+ }
7
+ export function startResumableUpload(args) {
8
+ const { id, storage, path, file, metadata, onProgress, signal } = args;
9
+ const r = ref(storage, path);
10
+ const task = uploadBytesResumable(r, file, metadata);
11
+ const startedAt = Date.now();
12
+ upsertUploadSession({
13
+ id,
14
+ status: "uploading",
15
+ path,
16
+ transferred: 0,
17
+ total: getFileSize(file),
18
+ percent: 0,
19
+ startedAt,
20
+ updatedAt: startedAt,
21
+ });
22
+ let unsub = null;
23
+ let resolveDone;
24
+ let rejectDone;
25
+ const done = new Promise((res, rej) => {
26
+ resolveDone = res;
27
+ rejectDone = rej;
28
+ });
29
+ const onAbort = () => {
30
+ try {
31
+ task.cancel();
32
+ }
33
+ catch { }
34
+ };
35
+ if (signal) {
36
+ if (signal.aborted)
37
+ onAbort();
38
+ signal.addEventListener("abort", onAbort, { once: true });
39
+ }
40
+ unsub = task.on("state_changed", (snap) => {
41
+ const transferred = snap.bytesTransferred ?? 0;
42
+ const total = snap.totalBytes ?? getFileSize(file);
43
+ const percent = total > 0 ? (transferred / total) * 100 : 0;
44
+ upsertUploadSession({
45
+ id,
46
+ status: snap.state === "paused"
47
+ ? "paused"
48
+ : snap.state === "running"
49
+ ? "uploading"
50
+ : "uploading",
51
+ path,
52
+ transferred,
53
+ total,
54
+ percent,
55
+ updatedAt: Date.now(),
56
+ });
57
+ onProgress?.({ transferred, total, percent, snapshot: snap });
58
+ }, async (err) => {
59
+ if (signal)
60
+ signal.removeEventListener("abort", onAbort);
61
+ if (unsub)
62
+ unsub();
63
+ // normalize aborts as "canceled" (not "error")
64
+ if (isAbortError(err)) {
65
+ upsertUploadSession({
66
+ id,
67
+ status: "canceled",
68
+ path,
69
+ updatedAt: Date.now(),
70
+ error: err,
71
+ });
72
+ return rejectDone(err);
73
+ }
74
+ upsertUploadSession({
75
+ id,
76
+ status: "error",
77
+ path,
78
+ updatedAt: Date.now(),
79
+ error: err,
80
+ });
81
+ rejectDone(err);
82
+ }, async () => {
83
+ try {
84
+ const downloadURL = await getDownloadURL(task.snapshot.ref);
85
+ const contentType = task.snapshot.metadata?.contentType ?? null;
86
+ const size = task.snapshot.totalBytes ?? getFileSize(file);
87
+ const result = {
88
+ downloadURL,
89
+ fullPath: task.snapshot.ref.fullPath,
90
+ contentType,
91
+ size,
92
+ };
93
+ upsertUploadSession({
94
+ id,
95
+ status: "success",
96
+ path,
97
+ transferred: size,
98
+ total: size,
99
+ percent: 100,
100
+ updatedAt: Date.now(),
101
+ result,
102
+ });
103
+ resolveDone(result);
104
+ }
105
+ catch (e) {
106
+ upsertUploadSession({
107
+ id,
108
+ status: "error",
109
+ path,
110
+ updatedAt: Date.now(),
111
+ error: e,
112
+ });
113
+ rejectDone(e);
114
+ }
115
+ finally {
116
+ if (signal)
117
+ signal.removeEventListener("abort", onAbort);
118
+ if (unsub)
119
+ unsub();
120
+ }
121
+ });
122
+ return {
123
+ id,
124
+ task,
125
+ pause: () => {
126
+ try {
127
+ return task.pause();
128
+ }
129
+ catch {
130
+ return false;
131
+ }
132
+ },
133
+ resume: () => {
134
+ try {
135
+ return task.resume();
136
+ }
137
+ catch {
138
+ return false;
139
+ }
140
+ },
141
+ cancel: () => {
142
+ try {
143
+ return task.cancel();
144
+ }
145
+ catch {
146
+ return false;
147
+ }
148
+ },
149
+ done,
150
+ };
151
+ }
152
+ export async function uploadFileResumable(args) {
153
+ const id = args.id ?? `upl_${Math.random().toString(36).slice(2)}${Date.now().toString(36)}`;
154
+ const c = startResumableUpload({ ...args, id });
155
+ return c.done;
156
+ }
157
+ //# sourceMappingURL=upload.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"upload.js","sourceRoot":"","sources":["../../src/storage/upload.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,87 @@
1
+ import type { FirebaseStorage, UploadMetadata, UploadTask, UploadTaskSnapshot } from "firebase/storage";
2
+ export type UploadProgressHandler = (p: {
3
+ transferred: number;
4
+ total: number;
5
+ percent: number;
6
+ snapshot?: UploadTaskSnapshot;
7
+ }) => void;
8
+ export interface UploadFileResumableArgs {
9
+ storage: FirebaseStorage;
10
+ path: string;
11
+ file: Blob | File;
12
+ metadata?: UploadMetadata;
13
+ onProgress?: UploadProgressHandler;
14
+ /** Optional retry policy for transient failures. */
15
+ retry?: {
16
+ maxRetries?: number;
17
+ baseDelayMs?: number;
18
+ maxDelayMs?: number;
19
+ };
20
+ /** Optional cancellation signal. */
21
+ signal?: AbortSignal;
22
+ }
23
+ export interface UploadFileResumableResult {
24
+ downloadURL: string;
25
+ fullPath: string;
26
+ contentType: string | null;
27
+ size: number;
28
+ }
29
+ export interface DeleteFileArgs {
30
+ storage: FirebaseStorage;
31
+ path: string;
32
+ }
33
+ export type UploadSessionStatus = "idle" | "queued" | "uploading" | "paused" | "success" | "error" | "canceled";
34
+ export interface UploadSessionPersistenceAdapter {
35
+ /** Return all session ids currently stored. */
36
+ listIds: () => Promise<string[]> | string[];
37
+ get: (id: string) => Promise<UploadSessionState | null> | UploadSessionState | null;
38
+ set: (id: string, state: UploadSessionState) => Promise<void> | void;
39
+ remove: (id: string) => Promise<void> | void;
40
+ }
41
+ export interface UploadQueueOptions {
42
+ /** Maximum concurrent uploads. Default: 3 */
43
+ concurrency?: number;
44
+ /** Optional persistence adapter for session state. */
45
+ persistence?: UploadSessionPersistenceAdapter;
46
+ }
47
+ export interface UploadSessionState {
48
+ id: string;
49
+ status: UploadSessionStatus;
50
+ path: string;
51
+ /** Monotonic version counter for state updates. */
52
+ version: number;
53
+ transferred: number;
54
+ total: number;
55
+ percent: number;
56
+ startedAt: number;
57
+ updatedAt: number;
58
+ error?: unknown;
59
+ result?: UploadFileResumableResult;
60
+ }
61
+ export interface DisposeUploadSessionArgs {
62
+ /** Session id to dispose. */
63
+ id: string;
64
+ /** If true, cancel any active upload task before disposal. Default true. */
65
+ cancel?: boolean;
66
+ /** If true, remove session state from the in-memory store. Default true. */
67
+ remove?: boolean;
68
+ }
69
+ export interface UploadController {
70
+ id: string;
71
+ task: UploadTask;
72
+ pause: () => boolean;
73
+ resume: () => boolean;
74
+ cancel: () => boolean;
75
+ /** Resolves on success, rejects on error/cancel. */
76
+ done: Promise<UploadFileResumableResult>;
77
+ }
78
+ export interface StartUploadArgs extends Omit<UploadFileResumableArgs, "onProgress"> {
79
+ /** Optional stable id for UI tracking. */
80
+ id?: string;
81
+ /**
82
+ * UploadQueue-only: higher numbers run sooner.
83
+ * Ignored by startResumableUpload/uploadFileResumable.
84
+ */
85
+ priority?: number;
86
+ }
87
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
package/dist/types.js ADDED
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
@@ -0,0 +1,2 @@
1
+ export declare function getFileSize(file: Blob | File): number;
2
+ //# sourceMappingURL=file-size.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"file-size.d.ts","sourceRoot":"","sources":["../../src/utils/file-size.ts"],"names":[],"mappings":"AAAA,wBAAgB,WAAW,CAAC,IAAI,EAAE,IAAI,GAAG,IAAI,GAAG,MAAM,CAIrD"}
@@ -0,0 +1,6 @@
1
+ export function getFileSize(file) {
2
+ const anyFile = file;
3
+ const size = anyFile?.size;
4
+ return typeof size === "number" && size >= 0 ? size : 0;
5
+ }
6
+ //# sourceMappingURL=file-size.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"file-size.js","sourceRoot":"","sources":["../../src/utils/file-size.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,WAAW,CAAC,IAAiB;IAC3C,MAAM,OAAO,GAAG,IAAW,CAAC;IAC5B,MAAM,IAAI,GAAG,OAAO,EAAE,IAAI,CAAC;IAC3B,OAAO,OAAO,IAAI,KAAK,QAAQ,IAAI,IAAI,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;AAC1D,CAAC"}
@@ -0,0 +1,2 @@
1
+ export declare function normalizeFilename(name: string): string;
2
+ //# sourceMappingURL=filename.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"filename.d.ts","sourceRoot":"","sources":["../../src/utils/filename.ts"],"names":[],"mappings":"AAAA,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAiBpD"}
@@ -0,0 +1,17 @@
1
+ export function normalizeFilename(name) {
2
+ const trimmed = (name || "").trim();
3
+ if (!trimmed)
4
+ return "file";
5
+ // keep extension if present
6
+ const lastDot = trimmed.lastIndexOf(".");
7
+ const base = lastDot > 0 ? trimmed.slice(0, lastDot) : trimmed;
8
+ const ext = lastDot > 0 ? trimmed.slice(lastDot).toLowerCase() : "";
9
+ const safeBase = base
10
+ .toLowerCase()
11
+ .replace(/[^a-z0-9-_ ]/g, "")
12
+ .replace(/\s+/g, "-")
13
+ .replace(/-+/g, "-")
14
+ .replace(/^-|-$/g, "");
15
+ return `${safeBase || "file"}${ext}`;
16
+ }
17
+ //# sourceMappingURL=filename.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"filename.js","sourceRoot":"","sources":["../../src/utils/filename.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,iBAAiB,CAAC,IAAY;IAC1C,MAAM,OAAO,GAAG,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;IACpC,IAAI,CAAC,OAAO;QAAE,OAAO,MAAM,CAAC;IAE5B,4BAA4B;IAC5B,MAAM,OAAO,GAAG,OAAO,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;IACzC,MAAM,IAAI,GAAG,OAAO,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC;IAC/D,MAAM,GAAG,GAAG,OAAO,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;IAEpE,MAAM,QAAQ,GAAG,IAAI;SAClB,WAAW,EAAE;SACb,OAAO,CAAC,eAAe,EAAE,EAAE,CAAC;SAC5B,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC;SACpB,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC;SACnB,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;IAEzB,OAAO,GAAG,QAAQ,IAAI,MAAM,GAAG,GAAG,EAAE,CAAC;AACvC,CAAC"}
@@ -0,0 +1,7 @@
1
+ export declare function buildUploadPath(args: {
2
+ basePath: string;
3
+ ownerId?: string;
4
+ contentId?: string;
5
+ filename?: string;
6
+ }): string;
7
+ //# sourceMappingURL=path.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"path.d.ts","sourceRoot":"","sources":["../../src/utils/path.ts"],"names":[],"mappings":"AAaA,wBAAgB,eAAe,CAAC,IAAI,EAAE;IACpC,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,UAYA"}
@@ -0,0 +1,22 @@
1
+ import { joinPath } from "@ttt-productions/firebase-helpers";
2
+ import { normalizeFilename } from "./filename";
3
+ function sanitizeSegment(seg) {
4
+ const s = String(seg ?? "").trim();
5
+ // Remove slashes and collapse dot-runs to avoid traversal.
6
+ const noSlashes = s.replace(/[\\/]+/g, "_");
7
+ const noDots = noSlashes.replace(/\.+/g, ".");
8
+ const cleaned = noDots.replace(/[^a-zA-Z0-9._-]/g, "_");
9
+ const trimmed = cleaned.replace(/^\.+/, "").replace(/\.+$/, "");
10
+ return trimmed.slice(0, 80) || "_";
11
+ }
12
+ export function buildUploadPath(args) {
13
+ const { basePath, ownerId, contentId, filename } = args;
14
+ // Sanitize segments for security (traversal prevention)
15
+ const segments = [basePath, ownerId, contentId]
16
+ .filter((p) => !!p)
17
+ .map(sanitizeSegment);
18
+ const filePart = filename ? normalizeFilename(filename) : "file";
19
+ // Use shared helper to robustly join them
20
+ return joinPath(...segments, filePart);
21
+ }
22
+ //# sourceMappingURL=path.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"path.js","sourceRoot":"","sources":["../../src/utils/path.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,mCAAmC,CAAC;AAC7D,OAAO,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAE/C,SAAS,eAAe,CAAC,GAAW;IAClC,MAAM,CAAC,GAAG,MAAM,CAAC,GAAG,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;IACnC,2DAA2D;IAC3D,MAAM,SAAS,GAAG,CAAC,CAAC,OAAO,CAAC,SAAS,EAAE,GAAG,CAAC,CAAC;IAC5C,MAAM,MAAM,GAAG,SAAS,CAAC,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAC9C,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC,kBAAkB,EAAE,GAAG,CAAC,CAAC;IACxD,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;IAChE,OAAO,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,GAAG,CAAC;AACrC,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,IAK/B;IACC,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,GAAG,IAAI,CAAC;IAExD,wDAAwD;IACxD,MAAM,QAAQ,GAAG,CAAC,QAAQ,EAAE,OAAO,EAAE,SAAS,CAAC;SAC5C,MAAM,CAAC,CAAC,CAAC,EAAe,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;SAC/B,GAAG,CAAC,eAAe,CAAC,CAAC;IAExB,MAAM,QAAQ,GAAG,QAAQ,CAAC,CAAC,CAAC,iBAAiB,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;IAEjE,0CAA0C;IAC1C,OAAO,QAAQ,CAAC,GAAG,QAAQ,EAAE,QAAQ,CAAC,CAAC;AACzC,CAAC"}
@@ -0,0 +1,3 @@
1
+ export declare function sleep(ms: number, signal?: AbortSignal): Promise<void>;
2
+ export declare function backoffDelayMs(attempt: number, baseDelayMs: number, maxDelayMs: number): number;
3
+ //# sourceMappingURL=retry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"retry.d.ts","sourceRoot":"","sources":["../../src/utils/retry.ts"],"names":[],"mappings":"AAAA,wBAAgB,KAAK,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAuBrE;AAED,wBAAgB,cAAc,CAC5B,OAAO,EAAE,MAAM,EACf,WAAW,EAAE,MAAM,EACnB,UAAU,EAAE,MAAM,GACjB,MAAM,CAKR"}
@@ -0,0 +1,31 @@
1
+ export function sleep(ms, signal) {
2
+ if (ms <= 0)
3
+ return Promise.resolve();
4
+ return new Promise((resolve, reject) => {
5
+ const t = setTimeout(() => {
6
+ cleanup();
7
+ resolve();
8
+ }, ms);
9
+ const onAbort = () => {
10
+ cleanup();
11
+ reject(new DOMException("Aborted", "AbortError"));
12
+ };
13
+ const cleanup = () => {
14
+ clearTimeout(t);
15
+ if (signal)
16
+ signal.removeEventListener("abort", onAbort);
17
+ };
18
+ if (signal) {
19
+ if (signal.aborted)
20
+ return onAbort();
21
+ signal.addEventListener("abort", onAbort, { once: true });
22
+ }
23
+ });
24
+ }
25
+ export function backoffDelayMs(attempt, baseDelayMs, maxDelayMs) {
26
+ const exp = Math.min(maxDelayMs, baseDelayMs * Math.pow(2, Math.max(0, attempt - 1)));
27
+ // jitter: 0.75x..1.25x
28
+ const jitter = exp * (0.75 + Math.random() * 0.5);
29
+ return Math.floor(Math.min(maxDelayMs, jitter));
30
+ }
31
+ //# sourceMappingURL=retry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"retry.js","sourceRoot":"","sources":["../../src/utils/retry.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,KAAK,CAAC,EAAU,EAAE,MAAoB;IACpD,IAAI,EAAE,IAAI,CAAC;QAAE,OAAO,OAAO,CAAC,OAAO,EAAE,CAAC;IACtC,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACrC,MAAM,CAAC,GAAG,UAAU,CAAC,GAAG,EAAE;YACxB,OAAO,EAAE,CAAC;YACV,OAAO,EAAE,CAAC;QACZ,CAAC,EAAE,EAAE,CAAC,CAAC;QAEP,MAAM,OAAO,GAAG,GAAG,EAAE;YACnB,OAAO,EAAE,CAAC;YACV,MAAM,CAAC,IAAI,YAAY,CAAC,SAAS,EAAE,YAAY,CAAC,CAAC,CAAC;QACpD,CAAC,CAAC;QAEF,MAAM,OAAO,GAAG,GAAG,EAAE;YACnB,YAAY,CAAC,CAAC,CAAC,CAAC;YAChB,IAAI,MAAM;gBAAE,MAAM,CAAC,mBAAmB,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QAC3D,CAAC,CAAC;QAEF,IAAI,MAAM,EAAE,CAAC;YACX,IAAI,MAAM,CAAC,OAAO;gBAAE,OAAO,OAAO,EAAE,CAAC;YACrC,MAAM,CAAC,gBAAgB,CAAC,OAAO,EAAE,OAAO,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;QAC5D,CAAC;IACH,CAAC,CAAC,CAAC;AACL,CAAC;AAED,MAAM,UAAU,cAAc,CAC5B,OAAe,EACf,WAAmB,EACnB,UAAkB;IAElB,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,UAAU,EAAE,WAAW,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,OAAO,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;IACtF,uBAAuB;IACvB,MAAM,MAAM,GAAG,GAAG,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC,MAAM,EAAE,GAAG,GAAG,CAAC,CAAC;IAClD,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC,CAAC;AAClD,CAAC"}
@@ -0,0 +1,19 @@
1
+ import type { UploadSessionState, UploadSessionPersistenceAdapter } from "../types";
2
+ type Listener = (s: UploadSessionState) => void;
3
+ type ListListener = () => void;
4
+ export declare function setUploadSessionPersistence(adapter: UploadSessionPersistenceAdapter | null): void;
5
+ export type PersistenceErrorHandler = (err: unknown, op: "set" | "remove" | "get", id: string) => void;
6
+ export declare function setUploadSessionPersistenceErrorHandler(handler: PersistenceErrorHandler | null): void;
7
+ export declare function pruneOldUploadSessions(): number;
8
+ /** Load persisted sessions into the in-memory store. */
9
+ export declare function rehydrateUploadSessions(): Promise<void>;
10
+ export declare function getUploadSession(id: string): UploadSessionState | undefined;
11
+ export declare function listUploadSessions(): UploadSessionState[];
12
+ export declare function upsertUploadSession(partial: Partial<UploadSessionState> & Pick<UploadSessionState, "id">): void;
13
+ export declare function removeUploadSession(id: string): void;
14
+ export declare function clearUploadSessionListeners(id: string): void;
15
+ export declare function subscribeUploadSession(id: string, fn: Listener): () => void;
16
+ /** Subscribe to changes in the *list* (new/removed sessions, rehydrate). */
17
+ export declare function subscribeUploadSessionsList(fn: ListListener): () => void;
18
+ export {};
19
+ //# sourceMappingURL=upload-store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"upload-store.d.ts","sourceRoot":"","sources":["../../src/utils/upload-store.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,kBAAkB,EAAE,+BAA+B,EAAE,MAAM,UAAU,CAAC;AAEpF,KAAK,QAAQ,GAAG,CAAC,CAAC,EAAE,kBAAkB,KAAK,IAAI,CAAC;AAChD,KAAK,YAAY,GAAG,MAAM,IAAI,CAAC;AAQ/B,wBAAgB,2BAA2B,CAAC,OAAO,EAAE,+BAA+B,GAAG,IAAI,QAE1F;AAGD,MAAM,MAAM,uBAAuB,GAAG,CAAC,GAAG,EAAE,OAAO,EAAE,EAAE,EAAE,KAAK,GAAG,QAAQ,GAAG,KAAK,EAAE,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;AAIvG,wBAAgB,uCAAuC,CAAC,OAAO,EAAE,uBAAuB,GAAG,IAAI,QAE9F;AA6BD,wBAAgB,sBAAsB,WAyBrC;AAED,wDAAwD;AACxD,wBAAsB,uBAAuB,kBAgB5C;AAED,wBAAgB,gBAAgB,CAAC,EAAE,EAAE,MAAM,GAAG,kBAAkB,GAAG,SAAS,CAE3E;AAED,wBAAgB,kBAAkB,IAAI,kBAAkB,EAAE,CAEzD;AAED,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,OAAO,CAAC,kBAAkB,CAAC,GAAG,IAAI,CAAC,kBAAkB,EAAE,IAAI,CAAC,QA8CxG;AAED,wBAAgB,mBAAmB,CAAC,EAAE,EAAE,MAAM,QAK7C;AAED,wBAAgB,2BAA2B,CAAC,EAAE,EAAE,MAAM,QAErD;AAED,wBAAgB,sBAAsB,CAAC,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,QAAQ,GAAG,MAAM,IAAI,CAiB3E;AAED,4EAA4E;AAC5E,wBAAgB,2BAA2B,CAAC,EAAE,EAAE,YAAY,GAAG,MAAM,IAAI,CAGxE"}
@@ -0,0 +1,162 @@
1
+ import { now } from "@ttt-productions/firebase-helpers";
2
+ const sessions = new Map();
3
+ const listeners = new Map();
4
+ const listListeners = new Set();
5
+ let persistence = null;
6
+ export function setUploadSessionPersistence(adapter) {
7
+ persistence = adapter;
8
+ }
9
+ let persistenceErrorHandler = null;
10
+ export function setUploadSessionPersistenceErrorHandler(handler) {
11
+ persistenceErrorHandler = handler;
12
+ }
13
+ async function persistUpsert(state) {
14
+ try {
15
+ await persistence?.set(state.id, state);
16
+ }
17
+ catch (err) {
18
+ console.error("[upload-store] Failed to persist session:", state.id, err);
19
+ persistenceErrorHandler?.(err, "set", state.id);
20
+ }
21
+ }
22
+ async function persistRemove(id) {
23
+ try {
24
+ await persistence?.remove(id);
25
+ }
26
+ catch (err) {
27
+ console.error("[upload-store] Failed to remove persisted session:", id, err);
28
+ persistenceErrorHandler?.(err, "remove", id);
29
+ }
30
+ }
31
+ function notifyList() {
32
+ for (const fn of listListeners)
33
+ fn();
34
+ }
35
+ // ---- Session pruning ----
36
+ const MAX_SESSIONS = 100;
37
+ const SUCCESS_TTL_MS = 24 * 60 * 60 * 1000; // 24h
38
+ const ERROR_TTL_MS = 7 * 24 * 60 * 60 * 1000; // 7d
39
+ export function pruneOldUploadSessions() {
40
+ const t = now();
41
+ const all = listUploadSessions();
42
+ let pruned = 0;
43
+ for (const s of all) {
44
+ if (s.status === "success" && t - s.updatedAt > SUCCESS_TTL_MS) {
45
+ removeUploadSession(s.id);
46
+ pruned++;
47
+ }
48
+ else if ((s.status === "error" || s.status === "canceled") && t - s.updatedAt > ERROR_TTL_MS) {
49
+ removeUploadSession(s.id);
50
+ pruned++;
51
+ }
52
+ }
53
+ const remaining = listUploadSessions();
54
+ if (remaining.length > MAX_SESSIONS) {
55
+ for (const s of remaining.slice(MAX_SESSIONS)) {
56
+ removeUploadSession(s.id);
57
+ pruned++;
58
+ }
59
+ }
60
+ return pruned;
61
+ }
62
+ /** Load persisted sessions into the in-memory store. */
63
+ export async function rehydrateUploadSessions() {
64
+ if (!persistence)
65
+ return;
66
+ const ids = await persistence.listIds();
67
+ for (const id of ids) {
68
+ try {
69
+ const s = await persistence.get(id);
70
+ if (s)
71
+ sessions.set(id, s);
72
+ }
73
+ catch (err) {
74
+ console.error("[upload-store] Failed to read persisted session:", id, err);
75
+ persistenceErrorHandler?.(err, "get", id);
76
+ }
77
+ }
78
+ pruneOldUploadSessions();
79
+ notifyList();
80
+ }
81
+ export function getUploadSession(id) {
82
+ return sessions.get(id);
83
+ }
84
+ export function listUploadSessions() {
85
+ return Array.from(sessions.values()).sort((a, b) => b.updatedAt - a.updatedAt);
86
+ }
87
+ export function upsertUploadSession(partial) {
88
+ const prev = sessions.get(partial.id);
89
+ // Guard against out-of-order async updates.
90
+ if (prev && partial.updatedAt != null && partial.updatedAt < prev.updatedAt)
91
+ return;
92
+ const prevStatus = prev?.status ?? "idle";
93
+ const nextStatus = partial.status ?? prevStatus;
94
+ const isTerminal = (s) => s === "success" || s === "error" || s === "canceled";
95
+ const prevIsTerminal = isTerminal(prevStatus);
96
+ const nextIsTerminal = isTerminal(nextStatus);
97
+ // Once terminal, stay terminal. If we receive a terminal nextStatus first, accept it.
98
+ const status = prevIsTerminal ? prevStatus : nextIsTerminal ? nextStatus : nextStatus;
99
+ // Progress values should never go backwards.
100
+ const transferred = Math.max(partial.transferred ?? 0, prev?.transferred ?? 0);
101
+ const total = Math.max(partial.total ?? 0, prev?.total ?? 0);
102
+ const percent = Math.max(partial.percent ?? 0, prev?.percent ?? 0);
103
+ const version = (prev?.version ?? 0) + 1;
104
+ const next = {
105
+ id: partial.id,
106
+ status,
107
+ path: partial.path ?? prev?.path ?? "",
108
+ version,
109
+ transferred,
110
+ total,
111
+ percent,
112
+ startedAt: partial.startedAt ?? prev?.startedAt ?? now(),
113
+ updatedAt: partial.updatedAt ?? now(),
114
+ error: partial.error ?? prev?.error,
115
+ result: partial.result ?? prev?.result,
116
+ };
117
+ const wasMissing = !sessions.has(partial.id);
118
+ sessions.set(partial.id, next);
119
+ void persistUpsert(next);
120
+ const ls = listeners.get(partial.id);
121
+ if (ls)
122
+ for (const fn of ls)
123
+ fn(next);
124
+ if (wasMissing)
125
+ notifyList();
126
+ }
127
+ export function removeUploadSession(id) {
128
+ const existed = sessions.delete(id);
129
+ clearUploadSessionListeners(id);
130
+ void persistRemove(id);
131
+ if (existed)
132
+ notifyList();
133
+ }
134
+ export function clearUploadSessionListeners(id) {
135
+ if (listeners.has(id))
136
+ listeners.delete(id);
137
+ }
138
+ export function subscribeUploadSession(id, fn) {
139
+ let set = listeners.get(id);
140
+ if (!set) {
141
+ set = new Set();
142
+ listeners.set(id, set);
143
+ }
144
+ set.add(fn);
145
+ const current = sessions.get(id);
146
+ if (current)
147
+ fn(current);
148
+ return () => {
149
+ const s = listeners.get(id);
150
+ if (!s)
151
+ return;
152
+ s.delete(fn);
153
+ if (s.size === 0)
154
+ listeners.delete(id);
155
+ };
156
+ }
157
+ /** Subscribe to changes in the *list* (new/removed sessions, rehydrate). */
158
+ export function subscribeUploadSessionsList(fn) {
159
+ listListeners.add(fn);
160
+ return () => listListeners.delete(fn);
161
+ }
162
+ //# sourceMappingURL=upload-store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"upload-store.js","sourceRoot":"","sources":["../../src/utils/upload-store.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,45 @@
1
+ {
2
+ "name": "@ttt-productions/upload-core",
3
+ "version": "0.0.2",
4
+ "repository": {
5
+ "type": "git",
6
+ "url": "git+https://github.com/ttt-productions/ttt-packages.git",
7
+ "directory": "packages/upload-core"
8
+ },
9
+ "type": "module",
10
+ "main": "dist/index.js",
11
+ "module": "dist/index.js",
12
+ "types": "dist/index.d.ts",
13
+ "sideEffects": false,
14
+ "files": [
15
+ "dist"
16
+ ],
17
+ "exports": {
18
+ ".": {
19
+ "types": "./dist/index.d.ts",
20
+ "default": "./dist/index.js"
21
+ },
22
+ "./react": {
23
+ "types": "./dist/react/index.d.ts",
24
+ "default": "./dist/react/index.js"
25
+ }
26
+ },
27
+ "scripts": {
28
+ "build": "tsc",
29
+ "clean": "rm -rf dist *.tsbuildinfo",
30
+ "typecheck": "tsc --noEmit",
31
+ "prepublishOnly": "npm run clean && npm run build"
32
+ },
33
+ "dependencies": {
34
+ "@ttt-productions/firebase-helpers": "^0.2.14"
35
+ },
36
+ "peerDependencies": {
37
+ "firebase": ">=10.0.0",
38
+ "react": ">=18.0.0"
39
+ },
40
+ "devDependencies": {
41
+ "typescript": "^5.8.3"
42
+ },
43
+ "author": "DJ (TTT Productions)",
44
+ "license": "MIT"
45
+ }