handlemyfile 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE CHANGED
@@ -1,21 +1,21 @@
1
- MIT License
2
-
3
- Copyright (c) 2026 HandleMyFile Contributors
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining a copy
6
- of this software and associated documentation files (the "Software"), to deal
7
- in the Software without restriction, including without limitation the rights
8
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- copies of the Software, and to permit persons to whom the Software is
10
- furnished to do so, subject to the following conditions:
11
-
12
- The above copyright notice and this permission notice shall be included in all
13
- copies or substantial portions of the Software.
14
-
15
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
- SOFTWARE.
1
+ MIT License
2
+
3
+ Copyright (c) 2026 HandleMyFile Contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -101,17 +101,24 @@ pip install handlemyfile
101
101
  ```python
102
102
  import handlemyfile
103
103
 
104
- # Option 1: File-to-file conversion
105
- handlemyfile.convert_file("input.pdf", "output.docx")
104
+ # Option 1: File-to-file conversion (with optional progress callback)
105
+ def on_progress(current, total, stage):
106
+ print(f"Page {current}/{total} [{stage}]")
106
107
 
107
- # Option 2: In-memory byte conversion
108
+ handlemyfile.convert_file("input.pdf", "output.docx", on_progress=on_progress)
109
+
110
+ # Option 2: In-memory byte conversion with typed errors
108
111
  with open("document.pdf", "rb") as f:
109
112
  pdf_bytes = f.read()
110
113
 
111
- docx_bytes = handlemyfile.convert(pdf_bytes)
112
-
113
- with open("converted.docx", "wb") as f:
114
- f.write(docx_bytes)
114
+ try:
115
+ docx_bytes = handlemyfile.convert(pdf_bytes)
116
+ with open("converted.docx", "wb") as f:
117
+ f.write(docx_bytes)
118
+ except handlemyfile.PasswordProtectedError:
119
+ print("This PDF requires a password to open!")
120
+ except handlemyfile.InvalidPdfError:
121
+ print("Invalid PDF file header.")
115
122
  ```
116
123
 
117
124
  ### Python CLI
@@ -134,48 +141,71 @@ The package compiles to WebAssembly with zero external dependencies, making it i
134
141
  npm install handlemyfile
135
142
  ```
136
143
 
137
- ### Browser (ES Modules)
144
+ ### 1-Line Universal Usage (Browser, Vite, Next.js, Node.js)
138
145
 
139
- ```javascript
140
- import init, { convert_pdf_to_docx } from 'handlemyfile';
146
+ `handlemyfile` v0.2.0 introduces **zero-config auto-initialization**. You don't need to manually configure wasm asset URLs or call `init()`:
141
147
 
142
- async function convertFile(file) {
143
- // Initialize WebAssembly runtime
144
- await init();
148
+ ```typescript
149
+ import { convert } from 'handlemyfile';
145
150
 
146
- const arrayBuffer = await file.arrayBuffer();
147
- const pdfBytes = new Uint8Array(arrayBuffer);
151
+ // Auto-initializes WASM seamlessly in Browser or Node.js!
152
+ const docxBytes = await convert(pdfBytes);
153
+ ```
148
154
 
149
- // Convert PDF to Word DOCX
150
- const docxBytes = convert_pdf_to_docx(pdfBytes);
155
+ ### Real-Time Progress Callback
151
156
 
152
- // Create a download link for user
153
- const blob = new Blob([docxBytes], {
154
- type: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'
155
- });
156
- const url = URL.createObjectURL(blob);
157
- const a = document.createElement('a');
158
- a.href = url;
159
- a.download = 'converted.docx';
160
- a.click();
161
- }
157
+ For rich interactive progress bars (0% - 100%):
158
+
159
+ ```typescript
160
+ import { convert } from 'handlemyfile';
161
+
162
+ const docxBytes = await convert(pdfBytes, {
163
+ onProgress: ({ current, total, stage }) => {
164
+ console.log(`Page ${current}/${total} [${stage}]`);
165
+ }
166
+ });
162
167
  ```
163
168
 
164
- ### Node.js Usage
169
+ ### Non-Blocking Web Worker (Silky 60fps UI)
165
170
 
166
- ```javascript
167
- import fs from 'fs';
168
- import init, { convert_pdf_to_docx } from 'handlemyfile';
171
+ To convert large (100+ page) PDFs without freezing the browser's main thread:
169
172
 
170
- // Read wasm binary and initialize
171
- const wasmBuffer = fs.readFileSync('./node_modules/handlemyfile/handlemyfile_bg.wasm');
172
- await init(wasmBuffer);
173
+ ```typescript
174
+ import { convert } from 'handlemyfile';
173
175
 
174
- const pdfData = fs.readFileSync('input.pdf');
175
- const docxData = convert_pdf_to_docx(new Uint8Array(pdfData));
176
+ // Automatically offloads computation to a background Web Worker!
177
+ const docxBytes = await convert(pdfBytes, {
178
+ worker: true,
179
+ onProgress: ({ current, total }) => {
180
+ updateProgressBar(current / total);
181
+ }
182
+ });
183
+ ```
176
184
 
177
- fs.writeFileSync('output.docx', Buffer.from(docxData));
178
- console.log('Successfully generated output.docx');
185
+ ### Granular Error Handling
186
+
187
+ ```typescript
188
+ import { convert, HandleMyFileError } from 'handlemyfile';
189
+
190
+ try {
191
+ const docxBytes = await convert(pdfBytes);
192
+ } catch (err) {
193
+ if (err instanceof HandleMyFileError) {
194
+ switch (err.code) {
195
+ case 'ERR_PASSWORD_PROTECTED':
196
+ alert('This PDF is password-protected.');
197
+ break;
198
+ case 'ERR_INVALID_HEADER':
199
+ alert('Invalid PDF format.');
200
+ break;
201
+ case 'ERR_CORRUPT_PDF':
202
+ alert('The PDF file is corrupted.');
203
+ break;
204
+ default:
205
+ console.error('Conversion failed:', err.message);
206
+ }
207
+ }
208
+ }
179
209
  ```
180
210
 
181
211
  ---
package/handlemyfile.d.ts CHANGED
@@ -6,6 +6,11 @@
6
6
  */
7
7
  export function convert_pdf_to_docx(pdf_data: Uint8Array | number[]): Uint8Array;
8
8
 
9
+ /**
10
+ * WebAssembly entrypoint to convert PDF to DOCX with real-time page progress callback
11
+ */
12
+ export function convert_pdf_to_docx_with_progress(pdf_data: Uint8Array | number[], progress_callback: Function): Uint8Array;
13
+
9
14
  /**
10
15
  * WebAssembly entrypoint to inspect parsed spatial elements & structured layout
11
16
  */
@@ -21,11 +26,14 @@ export type InitInput = RequestInfo | URL | Response | BufferSource | WebAssembl
21
26
  export interface InitOutput {
22
27
  readonly memory: WebAssembly.Memory;
23
28
  readonly convert_pdf_to_docx: (a: number, b: number) => [number, number, number, number];
29
+ readonly convert_pdf_to_docx_with_progress: (a: number, b: number, c: any) => [number, number, number, number];
24
30
  readonly inspect_pdf_elements: (a: number, b: number) => [number, number, number];
25
31
  readonly inspect_pdf_structure: (a: number, b: number) => [number, number, number];
26
32
  readonly __wbindgen_malloc: (a: number, b: number) => number;
27
33
  readonly __wbindgen_realloc: (a: number, b: number, c: number, d: number) => number;
28
34
  readonly __wbindgen_free: (a: number, b: number, c: number) => void;
35
+ readonly __wbindgen_exn_store: (a: number) => void;
36
+ readonly __externref_table_alloc: () => number;
29
37
  readonly __wbindgen_externrefs: WebAssembly.Table;
30
38
  readonly __externref_table_dealloc: (a: number) => void;
31
39
  readonly __wbindgen_start: () => void;
package/handlemyfile.js CHANGED
@@ -17,6 +17,24 @@ export function convert_pdf_to_docx(pdf_data) {
17
17
  return v2;
18
18
  }
19
19
 
20
+ /**
21
+ * WebAssembly entrypoint to convert PDF to DOCX with real-time page progress callback
22
+ * @param {Uint8Array | number[]} pdf_data
23
+ * @param {Function} progress_callback
24
+ * @returns {Uint8Array}
25
+ */
26
+ export function convert_pdf_to_docx_with_progress(pdf_data, progress_callback) {
27
+ const ptr0 = passArray8ToWasm0(pdf_data, wasm.__wbindgen_malloc);
28
+ const len0 = WASM_VECTOR_LEN;
29
+ const ret = wasm.convert_pdf_to_docx_with_progress(ptr0, len0, progress_callback);
30
+ if (ret[3]) {
31
+ throw takeFromExternrefTable0(ret[2]);
32
+ }
33
+ var v2 = getArrayU8FromWasm0(ret[0], ret[1]).slice();
34
+ wasm.__wbindgen_free(ret[0], ret[1] * 1, 1);
35
+ return v2;
36
+ }
37
+
20
38
  /**
21
39
  * WebAssembly entrypoint to inspect parsed spatial elements & structured layout
22
40
  * @param {Uint8Array | number[]} pdf_data
@@ -67,6 +85,10 @@ function __wbg_get_imports() {
67
85
  __wbg___wbindgen_throw_4c88d8bf264fd984: function(arg0, arg1) {
68
86
  throw new Error(getStringFromWasm0(arg0, arg1));
69
87
  },
88
+ __wbg_call_275b78b3b6520b92: function() { return handleError(function (arg0, arg1, arg2, arg3, arg4) {
89
+ const ret = arg0.call(arg1, arg2, arg3, arg4);
90
+ return ret;
91
+ }, arguments); },
70
92
  __wbg_new_37eb45aaf5eeb820: function() {
71
93
  const ret = new Array();
72
94
  return ret;
@@ -119,6 +141,12 @@ function __wbg_get_imports() {
119
141
  };
120
142
  }
121
143
 
144
+ function addToExternrefTable0(obj) {
145
+ const idx = wasm.__externref_table_alloc();
146
+ wasm.__wbindgen_externrefs.set(idx, obj);
147
+ return idx;
148
+ }
149
+
122
150
  function getArrayU8FromWasm0(ptr, len) {
123
151
  ptr = ptr >>> 0;
124
152
  return getUint8ArrayMemory0().subarray(ptr / 1, ptr / 1 + len);
@@ -145,6 +173,15 @@ function getUint8ArrayMemory0() {
145
173
  return cachedUint8ArrayMemory0;
146
174
  }
147
175
 
176
+ function handleError(f, args) {
177
+ try {
178
+ return f.apply(this, args);
179
+ } catch (e) {
180
+ const idx = addToExternrefTable0(e);
181
+ wasm.__wbindgen_exn_store(idx);
182
+ }
183
+ }
184
+
148
185
  function passArray8ToWasm0(arg, malloc) {
149
186
  const ptr = malloc(arg.length * 1, 1) >>> 0;
150
187
  getUint8ArrayMemory0().set(arg, ptr / 1);
Binary file
@@ -0,0 +1,15 @@
1
+ /* tslint:disable */
2
+ /* eslint-disable */
3
+ export const memory: WebAssembly.Memory;
4
+ export const convert_pdf_to_docx: (a: number, b: number) => [number, number, number, number];
5
+ export const convert_pdf_to_docx_with_progress: (a: number, b: number, c: any) => [number, number, number, number];
6
+ export const inspect_pdf_elements: (a: number, b: number) => [number, number, number];
7
+ export const inspect_pdf_structure: (a: number, b: number) => [number, number, number];
8
+ export const __wbindgen_malloc: (a: number, b: number) => number;
9
+ export const __wbindgen_realloc: (a: number, b: number, c: number, d: number) => number;
10
+ export const __wbindgen_free: (a: number, b: number, c: number) => void;
11
+ export const __wbindgen_exn_store: (a: number) => void;
12
+ export const __externref_table_alloc: () => number;
13
+ export const __wbindgen_externrefs: WebAssembly.Table;
14
+ export const __externref_table_dealloc: (a: number) => void;
15
+ export const __wbindgen_start: () => void;
package/index.d.ts ADDED
@@ -0,0 +1,86 @@
1
+ export interface ProgressEvent {
2
+ current: number;
3
+ total: number;
4
+ stage: 'parsing' | 'analyzing_layout' | 'generating_docx' | 'done' | string;
5
+ }
6
+
7
+ export interface ConvertOptions {
8
+ /**
9
+ * Real-time progress callback with current page, total pages, and stage.
10
+ */
11
+ onProgress?: (progress: ProgressEvent) => void;
12
+
13
+ /**
14
+ * Optional custom URL or BufferSource for handlemyfile_bg.wasm.
15
+ * If omitted, it will automatically resolve via import.meta.url or Node.js fs.
16
+ */
17
+ wasmUrl?: string | URL | BufferSource;
18
+
19
+ /**
20
+ * When true in a browser environment, automatically spawns a background Web Worker
21
+ * to keep the main thread and UI completely non-blocking (60fps).
22
+ * @default false
23
+ */
24
+ worker?: boolean;
25
+ }
26
+
27
+ export type ErrorCode =
28
+ | 'ERR_PASSWORD_PROTECTED'
29
+ | 'ERR_INVALID_HEADER'
30
+ | 'ERR_CORRUPT_PDF'
31
+ | 'ERR_EMPTY_DOCUMENT'
32
+ | 'ERR_CONVERSION_FAILED'
33
+ | 'ERR_WORKER';
34
+
35
+ export class HandleMyFileError extends Error {
36
+ code: ErrorCode;
37
+ constructor(message: string, code?: ErrorCode);
38
+ }
39
+
40
+ /**
41
+ * Universal auto-initializer for WASM runtime.
42
+ * Optional: Calling convert() automatically initializes if not already done.
43
+ */
44
+ export function ensureInitialized(wasmUrlOrPath?: string | URL | BufferSource): Promise<void>;
45
+
46
+ /**
47
+ * High-Level, Zero-Config PDF to DOCX converter.
48
+ * Automatically initializes WebAssembly if not already loaded.
49
+ *
50
+ * @example
51
+ * ```typescript
52
+ * import { convert } from 'handlemyfile';
53
+ *
54
+ * // 1-line conversion!
55
+ * const docxBytes = await convert(pdfBytes);
56
+ *
57
+ * // With real-time progress:
58
+ * const docxBytes = await convert(pdfBytes, {
59
+ * onProgress: ({ current, total, stage }) => {
60
+ * console.log(`Page ${current}/${total} [${stage}]`);
61
+ * }
62
+ * });
63
+ *
64
+ * // Off-main-thread in Web Worker:
65
+ * const docxBytes = await convert(pdfBytes, { worker: true });
66
+ * ```
67
+ */
68
+ export function convert(pdfData: Uint8Array | ArrayBuffer, options?: ConvertOptions): Promise<Uint8Array>;
69
+
70
+ /**
71
+ * Synchronous converter for performance-critical environments where wasm is already initialized.
72
+ */
73
+ export function convertSync(pdfData: Uint8Array | ArrayBuffer): Uint8Array;
74
+
75
+ /**
76
+ * Run PDF conversion inside an isolated Web Worker to keep the browser UI completely responsive.
77
+ */
78
+ export function convertInWorker(pdfBytes: Uint8Array | ArrayBuffer, options?: ConvertOptions): Promise<Uint8Array>;
79
+
80
+ export function init(moduleOrPath?: any): Promise<any>;
81
+ export function convert_pdf_to_docx(pdf_data: Uint8Array | number[]): Uint8Array;
82
+ export function convert_pdf_to_docx_with_progress(pdf_data: Uint8Array | number[], progress_callback: Function): Uint8Array;
83
+ export function inspect_pdf_elements(pdf_data: Uint8Array | number[]): any;
84
+ export function inspect_pdf_structure(pdf_data: Uint8Array | number[]): any;
85
+
86
+ export default convert;
package/index.js ADDED
@@ -0,0 +1,207 @@
1
+ import initWasm, {
2
+ convert_pdf_to_docx,
3
+ convert_pdf_to_docx_with_progress,
4
+ inspect_pdf_elements,
5
+ inspect_pdf_structure
6
+ } from './handlemyfile.js';
7
+
8
+ export {
9
+ initWasm as init,
10
+ convert_pdf_to_docx,
11
+ convert_pdf_to_docx_with_progress,
12
+ inspect_pdf_elements,
13
+ inspect_pdf_structure
14
+ };
15
+
16
+ export class HandleMyFileError extends Error {
17
+ constructor(message, code = 'ERR_CONVERSION_FAILED') {
18
+ super(message);
19
+ this.name = 'HandleMyFileError';
20
+ this.code = code;
21
+ }
22
+ }
23
+
24
+ let isInitialized = false;
25
+ let initPromise = null;
26
+
27
+ function parseErrorCode(rawMessage) {
28
+ const msg = String(rawMessage || '');
29
+ if (msg.includes('ERR_PASSWORD_PROTECTED')) {
30
+ return { code: 'ERR_PASSWORD_PROTECTED', message: 'The PDF document is encrypted or password-protected.' };
31
+ }
32
+ if (msg.includes('ERR_INVALID_HEADER')) {
33
+ return { code: 'ERR_INVALID_HEADER', message: 'The provided file is not a valid PDF document (missing %PDF- header).' };
34
+ }
35
+ if (msg.includes('ERR_EMPTY_DOCUMENT')) {
36
+ return { code: 'ERR_EMPTY_DOCUMENT', message: 'The PDF document contains zero readable pages.' };
37
+ }
38
+ if (msg.includes('ERR_CORRUPT_PDF')) {
39
+ return { code: 'ERR_CORRUPT_PDF', message: 'Failed to parse PDF binary or cross-reference streams (file may be corrupted).' };
40
+ }
41
+ return { code: 'ERR_CONVERSION_FAILED', message: msg || 'Document conversion failed.' };
42
+ }
43
+
44
+ /**
45
+ * Universal auto-initializer that seamlessly detects Node.js vs Browser environments.
46
+ */
47
+ export async function ensureInitialized(wasmUrlOrPath) {
48
+ if (isInitialized) return;
49
+ if (initPromise) return initPromise;
50
+
51
+ initPromise = (async () => {
52
+ // 1. If explicit path or bytes provided
53
+ if (wasmUrlOrPath) {
54
+ await initWasm({ module_or_path: wasmUrlOrPath });
55
+ isInitialized = true;
56
+ return;
57
+ }
58
+
59
+ // 2. Node.js environment detection
60
+ const isNode = typeof process !== 'undefined' && process.versions && !!process.versions.node;
61
+ if (isNode) {
62
+ try {
63
+ const fs = await import('fs');
64
+ const path = await import('path');
65
+ const url = await import('url');
66
+ const dir = path.dirname(url.fileURLToPath(import.meta.url));
67
+ const wasmPath = path.join(dir, 'handlemyfile_bg.wasm');
68
+ const wasmBuffer = fs.readFileSync(wasmPath);
69
+ await initWasm({ module_or_path: wasmBuffer });
70
+ isInitialized = true;
71
+ return;
72
+ } catch (err) {
73
+ // Fallback to default if dynamic import fails
74
+ }
75
+ }
76
+
77
+ // 3. Browser / Bundler environment (Vite, Webpack, Rollup)
78
+ const defaultWasmUrl = new URL('./handlemyfile_bg.wasm', import.meta.url);
79
+ await initWasm({ module_or_path: defaultWasmUrl });
80
+ isInitialized = true;
81
+ })();
82
+
83
+ return initPromise;
84
+ }
85
+
86
+ /**
87
+ * High-Level, Zero-Config PDF to DOCX converter.
88
+ * Auto-initializes WASM if not already loaded.
89
+ *
90
+ * @param {Uint8Array | ArrayBuffer} pdfData - Input PDF bytes.
91
+ * @param {Object} [options] - Conversion options.
92
+ * @param {Function} [options.onProgress] - Progress callback: ({ current, total, stage }).
93
+ * @param {string | URL | BufferSource} [options.wasmUrl] - Custom URL or BufferSource for .wasm file.
94
+ * @param {boolean} [options.worker] - Run conversion off the main thread in a Web Worker.
95
+ * @returns {Promise<Uint8Array>} Generated DOCX bytes.
96
+ */
97
+ export async function convert(pdfData, options = {}) {
98
+ const inputBytes = pdfData instanceof Uint8Array ? pdfData : new Uint8Array(pdfData);
99
+
100
+ if (options.worker) {
101
+ return convertInWorker(inputBytes, options);
102
+ }
103
+
104
+ await ensureInitialized(options.wasmUrl);
105
+
106
+ try {
107
+ if (typeof options.onProgress === 'function') {
108
+ return convert_pdf_to_docx_with_progress(inputBytes, (current, total, stage) => {
109
+ options.onProgress({ current, total, stage });
110
+ });
111
+ }
112
+ return convert_pdf_to_docx(inputBytes);
113
+ } catch (err) {
114
+ const { code, message } = parseErrorCode(err);
115
+ throw new HandleMyFileError(message, code);
116
+ }
117
+ }
118
+
119
+ /**
120
+ * Synchronous converter for performance-critical environments where wasm is already initialized.
121
+ *
122
+ * @param {Uint8Array | ArrayBuffer} pdfData
123
+ * @returns {Uint8Array}
124
+ */
125
+ export function convertSync(pdfData) {
126
+ const inputBytes = pdfData instanceof Uint8Array ? pdfData : new Uint8Array(pdfData);
127
+ try {
128
+ return convert_pdf_to_docx(inputBytes);
129
+ } catch (err) {
130
+ const { code, message } = parseErrorCode(err);
131
+ throw new HandleMyFileError(message, code);
132
+ }
133
+ }
134
+
135
+ /**
136
+ * Run PDF conversion inside an isolated Web Worker to keep the browser UI 60fps responsive.
137
+ *
138
+ * @param {Uint8Array} pdfBytes
139
+ * @param {Object} [options]
140
+ * @returns {Promise<Uint8Array>}
141
+ */
142
+ export async function convertInWorker(pdfBytes, options = {}) {
143
+ if (typeof Worker === 'undefined') {
144
+ // Fallback to main thread if Web Workers are not supported (e.g. Node.js without worker_threads)
145
+ return convert(pdfBytes, { ...options, worker: false });
146
+ }
147
+
148
+ const wasmUrl = options.wasmUrl
149
+ ? String(options.wasmUrl)
150
+ : new URL('./handlemyfile_bg.wasm', import.meta.url).href;
151
+
152
+ // Inline worker script that imports this module
153
+ const workerCode = `
154
+ import { convert } from ${JSON.stringify(import.meta.url)};
155
+
156
+ self.onmessage = async (e) => {
157
+ const { id, pdfBytes, wasmUrl } = e.data;
158
+ try {
159
+ const docx = await convert(pdfBytes, {
160
+ wasmUrl,
161
+ onProgress: (p) => self.postMessage({ id, type: 'progress', progress: p })
162
+ });
163
+ self.postMessage({ id, type: 'success', docx }, [docx.buffer]);
164
+ } catch (err) {
165
+ self.postMessage({ id, type: 'error', error: err.message, code: err.code || 'ERR_CONVERSION_FAILED' });
166
+ }
167
+ };
168
+ `;
169
+
170
+ const blob = new Blob([workerCode], { type: 'application/javascript' });
171
+ const blobUrl = URL.createObjectURL(blob);
172
+ const worker = new Worker(blobUrl, { type: 'module' });
173
+
174
+ return new Promise((resolve, reject) => {
175
+ const id = Math.random().toString(36).substring(2);
176
+
177
+ worker.onmessage = (e) => {
178
+ if (e.data.id !== id) return;
179
+ if (e.data.type === 'progress') {
180
+ if (typeof options.onProgress === 'function') {
181
+ options.onProgress(e.data.progress);
182
+ }
183
+ } else if (e.data.type === 'success') {
184
+ cleanup();
185
+ resolve(e.data.docx);
186
+ } else if (e.data.type === 'error') {
187
+ cleanup();
188
+ reject(new HandleMyFileError(e.data.error, e.data.code));
189
+ }
190
+ };
191
+
192
+ worker.onerror = (err) => {
193
+ cleanup();
194
+ reject(new HandleMyFileError(err.message || 'Worker failure', 'ERR_WORKER'));
195
+ };
196
+
197
+ function cleanup() {
198
+ worker.terminate();
199
+ URL.revokeObjectURL(blobUrl);
200
+ }
201
+
202
+ // Send binary copy to worker
203
+ worker.postMessage({ id, pdfBytes, wasmUrl });
204
+ });
205
+ }
206
+
207
+ export default convert;
package/package.json CHANGED
@@ -1,31 +1,50 @@
1
1
  {
2
2
  "name": "handlemyfile",
3
3
  "type": "module",
4
- "collaborators": [
5
- "HandleMyFile Contributors"
6
- ],
4
+ "version": "0.2.0",
7
5
  "description": "High-precision PDF to DOCX converter engine in Pure Rust, WebAssembly, and Python",
8
- "version": "0.1.0",
9
6
  "license": "MIT",
7
+ "author": "HandleMyFile Contributors",
10
8
  "repository": {
11
9
  "type": "git",
12
10
  "url": "https://github.com/handlemyfile/handlemyfile"
13
11
  },
14
12
  "files": [
15
13
  "handlemyfile_bg.wasm",
14
+ "handlemyfile_bg.wasm.d.ts",
16
15
  "handlemyfile.js",
17
- "handlemyfile.d.ts"
16
+ "handlemyfile.d.ts",
17
+ "index.js",
18
+ "index.d.ts",
19
+ "README.md",
20
+ "LICENSE"
18
21
  ],
19
- "main": "handlemyfile.js",
20
- "types": "handlemyfile.d.ts",
22
+ "main": "index.js",
23
+ "module": "index.js",
24
+ "types": "index.d.ts",
25
+ "exports": {
26
+ ".": {
27
+ "types": "./index.d.ts",
28
+ "import": "./index.js",
29
+ "default": "./index.js"
30
+ },
31
+ "./wasm": {
32
+ "types": "./handlemyfile.d.ts",
33
+ "import": "./handlemyfile.js",
34
+ "default": "./handlemyfile.js"
35
+ },
36
+ "./package.json": "./package.json"
37
+ },
21
38
  "sideEffects": [
22
- "./snippets/*"
39
+ "./handlemyfile_bg.wasm"
23
40
  ],
24
41
  "keywords": [
25
42
  "pdf",
26
43
  "docx",
27
44
  "converter",
28
45
  "word",
29
- "layout-analysis"
46
+ "wasm",
47
+ "webassembly",
48
+ "rust"
30
49
  ]
31
- }
50
+ }