hazo_files 1.4.7 → 1.5.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.
@@ -0,0 +1,271 @@
1
+ // src/background_upload/core/event-emitter.ts
2
+ var TypedEventEmitter = class {
3
+ constructor() {
4
+ this.listeners = /* @__PURE__ */ new Map();
5
+ }
6
+ on(event, listener) {
7
+ let set = this.listeners.get(event);
8
+ if (!set) {
9
+ set = /* @__PURE__ */ new Set();
10
+ this.listeners.set(event, set);
11
+ }
12
+ set.add(listener);
13
+ return () => this.off(event, listener);
14
+ }
15
+ emit(event, data) {
16
+ const set = this.listeners.get(event);
17
+ if (!set) return;
18
+ for (const listener of set) {
19
+ listener(data);
20
+ }
21
+ }
22
+ off(event, listener) {
23
+ this.listeners.get(event)?.delete(listener);
24
+ }
25
+ removeAllListeners() {
26
+ this.listeners.clear();
27
+ }
28
+ };
29
+
30
+ // src/background_upload/core/job.ts
31
+ var Job = class {
32
+ constructor(init) {
33
+ this.status = "queued";
34
+ this.progress = null;
35
+ this.error = null;
36
+ this.confirmation_payload = null;
37
+ this.confirmation_resolve = null;
38
+ this.job_id = crypto.randomUUID();
39
+ this.batch_id = init.batch_id;
40
+ this.created_at = Date.now();
41
+ this.updated_at = this.created_at;
42
+ this.pipeline_steps = init.pipeline_steps;
43
+ this.context = {
44
+ files: init.files.map((f) => ({
45
+ file: f,
46
+ file_name: f.name,
47
+ mime_type: f.type
48
+ })),
49
+ group_id: init.group_id,
50
+ group_label: init.group_label,
51
+ extracted_data: {},
52
+ metadata: { ...init.metadata ?? {} }
53
+ };
54
+ }
55
+ get_snapshot() {
56
+ return {
57
+ job_id: this.job_id,
58
+ batch_id: this.batch_id,
59
+ status: this.status,
60
+ group_id: this.context.group_id,
61
+ group_label: this.context.group_label,
62
+ files: [...this.context.files],
63
+ progress: this.progress ? { ...this.progress } : null,
64
+ extracted_data: { ...this.context.extracted_data },
65
+ error: this.error,
66
+ metadata: { ...this.context.metadata },
67
+ confirmation_payload: this.confirmation_payload,
68
+ created_at: this.created_at,
69
+ updated_at: this.updated_at
70
+ };
71
+ }
72
+ set_status(status) {
73
+ this.status = status;
74
+ this.updated_at = Date.now();
75
+ }
76
+ set_progress(current, total) {
77
+ this.progress = { current, total };
78
+ this.updated_at = Date.now();
79
+ }
80
+ set_error(message) {
81
+ this.error = message;
82
+ this.updated_at = Date.now();
83
+ }
84
+ request_confirmation(payload) {
85
+ this.confirmation_payload = payload;
86
+ this.set_status("awaiting_confirmation");
87
+ return new Promise((resolve) => {
88
+ this.confirmation_resolve = resolve;
89
+ });
90
+ }
91
+ resolve_confirmation(result) {
92
+ if (this.confirmation_resolve) {
93
+ this.confirmation_resolve(result);
94
+ this.confirmation_resolve = null;
95
+ this.confirmation_payload = null;
96
+ this.updated_at = Date.now();
97
+ }
98
+ }
99
+ get_context() {
100
+ return this.context;
101
+ }
102
+ get_pipeline_steps() {
103
+ return this.pipeline_steps;
104
+ }
105
+ };
106
+
107
+ // src/background_upload/core/pipeline-executor.ts
108
+ var PipelineExecutor = class {
109
+ async execute(job, emitter) {
110
+ const steps = job.get_pipeline_steps();
111
+ const context = job.get_context();
112
+ const handle = {
113
+ job_id: job.job_id,
114
+ set_status: (status) => {
115
+ const previous_status = job.get_snapshot().status;
116
+ job.set_status(status);
117
+ emitter.emit("job:status_changed", { job: job.get_snapshot(), previous_status });
118
+ },
119
+ set_progress: (current, total) => {
120
+ job.set_progress(current, total);
121
+ emitter.emit("job:progress", { job: job.get_snapshot() });
122
+ },
123
+ request_confirmation: async (payload) => {
124
+ const previous_status = job.get_snapshot().status;
125
+ const result_promise = job.request_confirmation(payload);
126
+ emitter.emit("job:confirmation_needed", { job: job.get_snapshot(), payload });
127
+ emitter.emit("job:status_changed", { job: job.get_snapshot(), previous_status });
128
+ const result = await result_promise;
129
+ emitter.emit("job:confirmation_resolved", { job: job.get_snapshot(), result });
130
+ return result;
131
+ },
132
+ is_cancelled: () => job.get_snapshot().status === "error"
133
+ };
134
+ try {
135
+ for (const step of steps) {
136
+ if (handle.is_cancelled()) break;
137
+ await step.execute(context, handle);
138
+ }
139
+ if (!handle.is_cancelled()) {
140
+ const previous_status = job.get_snapshot().status;
141
+ job.set_status("done");
142
+ emitter.emit("job:status_changed", { job: job.get_snapshot(), previous_status });
143
+ emitter.emit("job:completed", { job: job.get_snapshot() });
144
+ }
145
+ } catch (err) {
146
+ const message = err instanceof Error ? err.message : String(err);
147
+ const previous_status = job.get_snapshot().status;
148
+ job.set_error(message);
149
+ job.set_status("error");
150
+ emitter.emit("job:status_changed", { job: job.get_snapshot(), previous_status });
151
+ emitter.emit("job:error", { job: job.get_snapshot(), error: message });
152
+ }
153
+ }
154
+ };
155
+
156
+ // src/background_upload/core/upload-manager.ts
157
+ var UploadManager = class {
158
+ constructor(config) {
159
+ this.jobs = /* @__PURE__ */ new Map();
160
+ this.batches = /* @__PURE__ */ new Map();
161
+ this.executor = new PipelineExecutor();
162
+ this.emitter = new TypedEventEmitter();
163
+ this.queue = [];
164
+ this.running = 0;
165
+ this.destroyed = false;
166
+ this.config = {
167
+ max_concurrent: config?.max_concurrent ?? 1,
168
+ default_pipeline_steps: config?.default_pipeline_steps ?? []
169
+ };
170
+ this.emitter.on("job:completed", ({ job }) => this.on_job_settled(job));
171
+ this.emitter.on("job:error", ({ job }) => this.on_job_settled(job));
172
+ }
173
+ on(event, listener) {
174
+ return this.emitter.on(event, listener);
175
+ }
176
+ submit_batch(options) {
177
+ if (this.destroyed) throw new Error("UploadManager is destroyed");
178
+ const batch_id = crypto.randomUUID();
179
+ const job_ids = [];
180
+ const pipeline_steps = options.pipeline_steps ?? this.config.default_pipeline_steps;
181
+ for (const file of options.files) {
182
+ const job = new Job({
183
+ batch_id,
184
+ files: [file],
185
+ group_id: options.group_id,
186
+ group_label: options.group_label,
187
+ pipeline_steps,
188
+ metadata: options.metadata
189
+ });
190
+ this.jobs.set(job.job_id, job);
191
+ job_ids.push(job.job_id);
192
+ this.emitter.emit("job:created", { job: job.get_snapshot() });
193
+ this.queue.push(job.job_id);
194
+ }
195
+ this.batches.set(batch_id, {
196
+ batch_id,
197
+ job_ids,
198
+ total: options.files.length,
199
+ completed: 0,
200
+ failed: 0,
201
+ emitted_complete: false
202
+ });
203
+ this.process_queue();
204
+ return batch_id;
205
+ }
206
+ get_jobs_for_group(group_id) {
207
+ const out = [];
208
+ for (const job of this.jobs.values()) {
209
+ const snap = job.get_snapshot();
210
+ if (snap.group_id === group_id) out.push(snap);
211
+ }
212
+ return out;
213
+ }
214
+ get_job(job_id) {
215
+ return this.jobs.get(job_id)?.get_snapshot() ?? null;
216
+ }
217
+ get_active_jobs() {
218
+ const out = [];
219
+ for (const job of this.jobs.values()) {
220
+ const snap = job.get_snapshot();
221
+ if (snap.status !== "done" && snap.status !== "error") out.push(snap);
222
+ }
223
+ return out;
224
+ }
225
+ resolve_confirmation(job_id, result) {
226
+ const job = this.jobs.get(job_id);
227
+ if (job) job.resolve_confirmation(result);
228
+ }
229
+ destroy() {
230
+ this.destroyed = true;
231
+ this.emitter.removeAllListeners();
232
+ this.jobs.clear();
233
+ this.batches.clear();
234
+ this.queue = [];
235
+ }
236
+ process_queue() {
237
+ while (!this.destroyed && this.queue.length > 0 && this.running < this.config.max_concurrent) {
238
+ const job_id = this.queue.shift();
239
+ const job = this.jobs.get(job_id);
240
+ if (!job) continue;
241
+ this.running++;
242
+ void this.executor.execute(job, this.emitter).finally(() => {
243
+ this.running--;
244
+ this.process_queue();
245
+ });
246
+ }
247
+ }
248
+ on_job_settled(job) {
249
+ const batch = this.batches.get(job.batch_id);
250
+ if (!batch) return;
251
+ let completed = 0, failed = 0;
252
+ for (const jid of batch.job_ids) {
253
+ const s = this.jobs.get(jid)?.get_snapshot().status;
254
+ if (s === "done") completed++;
255
+ else if (s === "error") failed++;
256
+ }
257
+ batch.completed = completed;
258
+ batch.failed = failed;
259
+ this.emitter.emit("batch:progress", { batch: { ...batch } });
260
+ if (!batch.emitted_complete && completed + failed === batch.total) {
261
+ batch.emitted_complete = true;
262
+ this.emitter.emit("batch:completed", { batch: { ...batch } });
263
+ }
264
+ }
265
+ };
266
+ export {
267
+ Job,
268
+ PipelineExecutor,
269
+ TypedEventEmitter,
270
+ UploadManager
271
+ };
@@ -0,0 +1,149 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ import * as React from 'react';
3
+ import React__default from 'react';
4
+
5
+ type JobStatus = 'queued' | 'uploading' | 'processing' | 'awaiting_confirmation' | 'completing' | 'done' | 'error';
6
+ interface UploadFile {
7
+ file: File;
8
+ file_id?: string;
9
+ file_name: string;
10
+ mime_type: string;
11
+ download_url?: string;
12
+ }
13
+ interface PipelineContext {
14
+ files: UploadFile[];
15
+ group_id: string;
16
+ group_label?: string;
17
+ extracted_data: Record<string, unknown>;
18
+ metadata: Record<string, unknown>;
19
+ }
20
+ interface ConfirmationResult {
21
+ confirmed: boolean;
22
+ data?: unknown;
23
+ }
24
+ interface JobHandle {
25
+ job_id: string;
26
+ set_status: (status: JobStatus) => void;
27
+ set_progress: (current: number, total: number) => void;
28
+ request_confirmation: <T = unknown>(payload: T) => Promise<ConfirmationResult>;
29
+ is_cancelled: () => boolean;
30
+ }
31
+ interface PipelineStep {
32
+ name: string;
33
+ execute: (context: PipelineContext, handle: JobHandle) => Promise<void>;
34
+ }
35
+ interface CreateBatchOptions {
36
+ files: File[];
37
+ group_id: string;
38
+ group_label?: string;
39
+ metadata?: Record<string, unknown>;
40
+ pipeline_steps?: PipelineStep[];
41
+ }
42
+ interface JobSnapshot {
43
+ job_id: string;
44
+ batch_id: string;
45
+ status: JobStatus;
46
+ group_id: string;
47
+ group_label?: string;
48
+ files: UploadFile[];
49
+ progress: {
50
+ current: number;
51
+ total: number;
52
+ } | null;
53
+ extracted_data: Record<string, unknown>;
54
+ error: string | null;
55
+ metadata: Record<string, unknown>;
56
+ confirmation_payload: unknown | null;
57
+ created_at: number;
58
+ updated_at: number;
59
+ }
60
+ interface BatchInfo {
61
+ batch_id: string;
62
+ job_ids: string[];
63
+ total: number;
64
+ completed: number;
65
+ failed: number;
66
+ }
67
+ interface UploadManagerEvents {
68
+ 'job:created': {
69
+ job: JobSnapshot;
70
+ };
71
+ 'job:status_changed': {
72
+ job: JobSnapshot;
73
+ previous_status: JobStatus;
74
+ };
75
+ 'job:progress': {
76
+ job: JobSnapshot;
77
+ };
78
+ 'job:completed': {
79
+ job: JobSnapshot;
80
+ };
81
+ 'job:error': {
82
+ job: JobSnapshot;
83
+ error: string;
84
+ };
85
+ 'job:confirmation_needed': {
86
+ job: JobSnapshot;
87
+ payload: unknown;
88
+ };
89
+ 'job:confirmation_resolved': {
90
+ job: JobSnapshot;
91
+ result: ConfirmationResult;
92
+ };
93
+ 'batch:progress': {
94
+ batch: BatchInfo;
95
+ };
96
+ 'batch:completed': {
97
+ batch: BatchInfo;
98
+ };
99
+ }
100
+ interface UploadManagerConfig {
101
+ max_concurrent?: number;
102
+ default_pipeline_steps?: PipelineStep[];
103
+ }
104
+
105
+ interface HazoFileUploadProviderProps {
106
+ children: React__default.ReactNode;
107
+ config?: UploadManagerConfig;
108
+ enable_toasts?: boolean;
109
+ }
110
+ declare function HazoFileUploadProvider({ children, config, enable_toasts, }: HazoFileUploadProviderProps): react_jsx_runtime.JSX.Element;
111
+
112
+ declare class UploadManager {
113
+ private jobs;
114
+ private batches;
115
+ private executor;
116
+ private emitter;
117
+ private queue;
118
+ private running;
119
+ private destroyed;
120
+ private readonly config;
121
+ constructor(config?: UploadManagerConfig);
122
+ on<K extends keyof UploadManagerEvents>(event: K, listener: (data: UploadManagerEvents[K]) => void): () => void;
123
+ submit_batch(options: CreateBatchOptions): string;
124
+ get_jobs_for_group(group_id: string): JobSnapshot[];
125
+ get_job(job_id: string): JobSnapshot | null;
126
+ get_active_jobs(): JobSnapshot[];
127
+ resolve_confirmation(job_id: string, result: ConfirmationResult): void;
128
+ destroy(): void;
129
+ private process_queue;
130
+ private on_job_settled;
131
+ }
132
+
133
+ interface UseFileUploadResult {
134
+ manager: UploadManager;
135
+ active_jobs: JobSnapshot[];
136
+ submit_batch: (options: CreateBatchOptions) => string;
137
+ get_job: (job_id: string) => JobSnapshot | null;
138
+ get_jobs_for_group: (group_id: string) => JobSnapshot[];
139
+ resolve_confirmation: (job_id: string, result: ConfirmationResult) => void;
140
+ }
141
+ declare function useFileUpload(): UseFileUploadResult;
142
+
143
+ declare function useJobStatus(job_id: string | null): JobSnapshot | null;
144
+
145
+ declare function useFileUploadToasts(manager: UploadManager): void;
146
+
147
+ declare const FileUploadContext: React.Context<UploadManager | null>;
148
+
149
+ export { FileUploadContext, HazoFileUploadProvider, type HazoFileUploadProviderProps, type UseFileUploadResult, useFileUpload, useFileUploadToasts, useJobStatus };
@@ -0,0 +1,149 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ import * as React from 'react';
3
+ import React__default from 'react';
4
+
5
+ type JobStatus = 'queued' | 'uploading' | 'processing' | 'awaiting_confirmation' | 'completing' | 'done' | 'error';
6
+ interface UploadFile {
7
+ file: File;
8
+ file_id?: string;
9
+ file_name: string;
10
+ mime_type: string;
11
+ download_url?: string;
12
+ }
13
+ interface PipelineContext {
14
+ files: UploadFile[];
15
+ group_id: string;
16
+ group_label?: string;
17
+ extracted_data: Record<string, unknown>;
18
+ metadata: Record<string, unknown>;
19
+ }
20
+ interface ConfirmationResult {
21
+ confirmed: boolean;
22
+ data?: unknown;
23
+ }
24
+ interface JobHandle {
25
+ job_id: string;
26
+ set_status: (status: JobStatus) => void;
27
+ set_progress: (current: number, total: number) => void;
28
+ request_confirmation: <T = unknown>(payload: T) => Promise<ConfirmationResult>;
29
+ is_cancelled: () => boolean;
30
+ }
31
+ interface PipelineStep {
32
+ name: string;
33
+ execute: (context: PipelineContext, handle: JobHandle) => Promise<void>;
34
+ }
35
+ interface CreateBatchOptions {
36
+ files: File[];
37
+ group_id: string;
38
+ group_label?: string;
39
+ metadata?: Record<string, unknown>;
40
+ pipeline_steps?: PipelineStep[];
41
+ }
42
+ interface JobSnapshot {
43
+ job_id: string;
44
+ batch_id: string;
45
+ status: JobStatus;
46
+ group_id: string;
47
+ group_label?: string;
48
+ files: UploadFile[];
49
+ progress: {
50
+ current: number;
51
+ total: number;
52
+ } | null;
53
+ extracted_data: Record<string, unknown>;
54
+ error: string | null;
55
+ metadata: Record<string, unknown>;
56
+ confirmation_payload: unknown | null;
57
+ created_at: number;
58
+ updated_at: number;
59
+ }
60
+ interface BatchInfo {
61
+ batch_id: string;
62
+ job_ids: string[];
63
+ total: number;
64
+ completed: number;
65
+ failed: number;
66
+ }
67
+ interface UploadManagerEvents {
68
+ 'job:created': {
69
+ job: JobSnapshot;
70
+ };
71
+ 'job:status_changed': {
72
+ job: JobSnapshot;
73
+ previous_status: JobStatus;
74
+ };
75
+ 'job:progress': {
76
+ job: JobSnapshot;
77
+ };
78
+ 'job:completed': {
79
+ job: JobSnapshot;
80
+ };
81
+ 'job:error': {
82
+ job: JobSnapshot;
83
+ error: string;
84
+ };
85
+ 'job:confirmation_needed': {
86
+ job: JobSnapshot;
87
+ payload: unknown;
88
+ };
89
+ 'job:confirmation_resolved': {
90
+ job: JobSnapshot;
91
+ result: ConfirmationResult;
92
+ };
93
+ 'batch:progress': {
94
+ batch: BatchInfo;
95
+ };
96
+ 'batch:completed': {
97
+ batch: BatchInfo;
98
+ };
99
+ }
100
+ interface UploadManagerConfig {
101
+ max_concurrent?: number;
102
+ default_pipeline_steps?: PipelineStep[];
103
+ }
104
+
105
+ interface HazoFileUploadProviderProps {
106
+ children: React__default.ReactNode;
107
+ config?: UploadManagerConfig;
108
+ enable_toasts?: boolean;
109
+ }
110
+ declare function HazoFileUploadProvider({ children, config, enable_toasts, }: HazoFileUploadProviderProps): react_jsx_runtime.JSX.Element;
111
+
112
+ declare class UploadManager {
113
+ private jobs;
114
+ private batches;
115
+ private executor;
116
+ private emitter;
117
+ private queue;
118
+ private running;
119
+ private destroyed;
120
+ private readonly config;
121
+ constructor(config?: UploadManagerConfig);
122
+ on<K extends keyof UploadManagerEvents>(event: K, listener: (data: UploadManagerEvents[K]) => void): () => void;
123
+ submit_batch(options: CreateBatchOptions): string;
124
+ get_jobs_for_group(group_id: string): JobSnapshot[];
125
+ get_job(job_id: string): JobSnapshot | null;
126
+ get_active_jobs(): JobSnapshot[];
127
+ resolve_confirmation(job_id: string, result: ConfirmationResult): void;
128
+ destroy(): void;
129
+ private process_queue;
130
+ private on_job_settled;
131
+ }
132
+
133
+ interface UseFileUploadResult {
134
+ manager: UploadManager;
135
+ active_jobs: JobSnapshot[];
136
+ submit_batch: (options: CreateBatchOptions) => string;
137
+ get_job: (job_id: string) => JobSnapshot | null;
138
+ get_jobs_for_group: (group_id: string) => JobSnapshot[];
139
+ resolve_confirmation: (job_id: string, result: ConfirmationResult) => void;
140
+ }
141
+ declare function useFileUpload(): UseFileUploadResult;
142
+
143
+ declare function useJobStatus(job_id: string | null): JobSnapshot | null;
144
+
145
+ declare function useFileUploadToasts(manager: UploadManager): void;
146
+
147
+ declare const FileUploadContext: React.Context<UploadManager | null>;
148
+
149
+ export { FileUploadContext, HazoFileUploadProvider, type HazoFileUploadProviderProps, type UseFileUploadResult, useFileUpload, useFileUploadToasts, useJobStatus };