react-csv-autopilot 1.0.1 → 1.1.1-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -71,12 +71,7 @@ var _WorkerManager = class _WorkerManager {
71
71
  constructor() {
72
72
  __privateAdd(this, _WorkerManager_instances);
73
73
  __privateAdd(this, _worker);
74
- let workerUrl;
75
- try {
76
- workerUrl = new URL("./worker.js", import_meta.url);
77
- } catch {
78
- workerUrl = "/worker.js";
79
- }
74
+ const workerUrl = new URL("./worker.js", import_meta.url);
80
75
  __privateSet(this, _worker, new Worker(workerUrl, {
81
76
  name: WEB_WORKER_NAME,
82
77
  type: "module"
@@ -383,3 +378,4 @@ function useMessageExportCSV(cb) {
383
378
  }, [cb]);
384
379
  }
385
380
  var useMessageExportCSV_default = useMessageExportCSV;
381
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts","../src/hooks/useExportCSV.ts","../src/core/controllers/ExportController.ts","../src/core/contants/index.ts","../src/core/WorkerManager.ts","../src/core/strategy/BolbExportStrategy.ts","../src/core/strategy/FsAccessExportStrategy.ts","../src/core/createExportController.ts","../src/core/ExportControllerSingleton.ts","../src/hooks/useMessageExportCSV.ts"],"sourcesContent":["export type { ExportController } from \"./core/controllers/ExportController\";\nexport { Column, ExportParams } from \"./core/types\";\nexport { useExportCSV, useMessageExportCSV } from \"./hooks\";\n","import { useRef } from \"react\";\nimport { type ExportController, ExportControllerSingleton } from \"../core\";\n\nfunction useExportCSV() {\n const exportCallbackRef = useRef<ExportController>(ExportControllerSingleton.init());\n\n return {\n handler: exportCallbackRef?.current,\n };\n}\n\nexport default useExportCSV;\n","import type BolbExportStrategy from \"../strategy/BolbExportStrategy\";\nimport type FsAccessExportStrategy from \"../strategy/FsAccessExportStrategy\";\nimport type { ExportParams, ExportResponse, ExportStrategy } from \"../types\";\n\ntype ExportControllerDeps = {\n fsAccessStrategy: FsAccessExportStrategy;\n blobExportStrategy: BolbExportStrategy;\n};\n\nexport class ExportController {\n constructor(private readonly deps: ExportControllerDeps) {}\n\n public async start<T>(params: ExportParams<T>): Promise<ExportResponse> {\n const strategy = this.#resolveStrategy();\n\n return strategy.export(params);\n }\n\n #canUseFSAccess() {\n return typeof window.showSaveFilePicker === \"function\";\n }\n\n #resolveStrategy(): ExportStrategy {\n if (this.#canUseFSAccess()) {\n return this.deps.fsAccessStrategy;\n }\n\n return this.deps.blobExportStrategy;\n }\n}\n","export const WEB_WORKER_NAME = \"scv-worker\";\nexport const BROADCAST_CHANNEL_NAME = \"react-csv-exporter\";\n","import { WEB_WORKER_NAME } from \"./contants\";\nimport type { JobId, ToWorkerMessage } from \"./types\";\n\nconst pending = new Map<JobId, { resolve: (value: unknown) => void; reject: (reason?: ErrorEvent) => void }>();\n\nclass WorkerManager {\n #worker: Worker | null;\n\n constructor() {\n const workerUrl = new URL(\"./worker.js\", import.meta.url);\n\n this.#worker = new Worker(workerUrl, {\n name: WEB_WORKER_NAME,\n type: \"module\",\n });\n\n this.#listenerRegistry();\n }\n\n static initialise() {\n return new WorkerManager();\n }\n\n #listenerRegistry() {\n this.#worker?.addEventListener(\"message\", (event) => {\n const { id, result, error } = event.data;\n const entity = pending.get(id);\n\n if (!entity) {\n return;\n }\n\n pending.delete(id);\n\n if (error) {\n entity.reject(error);\n } else {\n entity.resolve(result);\n }\n });\n\n this.#worker?.addEventListener(\"error\", (event) => {\n for (const [, { reject }] of pending) {\n reject(event);\n }\n\n pending.clear();\n });\n }\n\n async triggerWorker(payload: ToWorkerMessage) {\n const id = payload.id ?? Math.random().toString(36).substr(2);\n\n const p = new Promise((resolve, reject) => {\n pending.set(id, { reject, resolve });\n });\n\n this.#worker?.postMessage(payload);\n\n return p;\n }\n\n terminate() {\n if (this.#worker) {\n this.#worker.terminate();\n this.#worker = null;\n }\n }\n}\n\nexport default WorkerManager;\n","import { BROADCAST_CHANNEL_NAME } from \"../contants\";\nimport type { ExportParams, ExportResponse, ExportStrategy, JobId } from \"../types\";\nimport WorkerManager from \"../WorkerManager\";\n\nclass BolbExportStrategy implements ExportStrategy {\n private workerManager: WorkerManager;\n\n constructor() {\n this.workerManager = WorkerManager.initialise();\n }\n\n async export<T>(params: ExportParams<T>): Promise<ExportResponse> {\n const suggestedName = params.fileName ?? \"export\";\n const filename = suggestedName.endsWith(\".csv\") ? suggestedName : `${suggestedName}.csv`;\n\n let iterator: JobId = 0 as JobId;\n let totalRowsLoaded = 0;\n\n const messaging = new BroadcastChannel(BROADCAST_CHANNEL_NAME);\n\n const csvParts: BlobPart[] = [];\n\n try {\n while (true) {\n const response = await params.getNextPage(iterator++);\n\n const safeRows = Array.isArray(response.rows) ? response.rows : [];\n const safeTotal = response.total ?? 0;\n\n const isRowsEmpty = safeRows.length === 0;\n\n const nextRowsLoaded = totalRowsLoaded + safeRows.length;\n totalRowsLoaded = isRowsEmpty ? safeTotal : nextRowsLoaded;\n\n const isFinished = safeTotal > 0 ? totalRowsLoaded >= safeTotal : isRowsEmpty;\n\n if (isRowsEmpty) {\n messaging.postMessage(\n JSON.stringify({\n loadedItemsCount: totalRowsLoaded,\n total: safeTotal,\n type: \"done\",\n }),\n );\n\n await this.workerManager.triggerWorker({\n id: iterator,\n type: \"completed\",\n });\n\n break;\n }\n\n const csvChunk = (await this.workerManager.triggerWorker({\n columns: params.columns,\n data: safeRows as Record<string, unknown>[],\n id: iterator,\n type: \"to_csv_chunk\",\n })) as string;\n\n csvParts.push(csvChunk);\n\n messaging.postMessage(\n JSON.stringify({\n loadedItemsCount: totalRowsLoaded,\n total: safeTotal,\n type: \"progress\",\n }),\n );\n\n if (isFinished) {\n messaging.postMessage(\n JSON.stringify({\n loadedItemsCount: totalRowsLoaded,\n total: safeTotal,\n type: \"done\",\n }),\n );\n\n await this.workerManager.triggerWorker({\n id: iterator,\n type: \"completed\",\n });\n\n break;\n }\n }\n\n const blob = new Blob([\"\\uFEFF\", ...csvParts], {\n type: \"text/csv;charset=utf-8\",\n });\n\n this.downloadBlob(blob, filename);\n\n return { finished: true, totalRowsLoaded };\n } catch (error) {\n messaging.postMessage(\n JSON.stringify({\n loadedItemsCount: totalRowsLoaded,\n total: 0,\n type: \"failed\",\n }),\n );\n throw error;\n } finally {\n messaging.close();\n this.workerManager.terminate();\n }\n }\n\n private downloadBlob(blob: Blob, filename: string) {\n const url = URL.createObjectURL(blob);\n\n const a = document.createElement(\"a\");\n a.href = url;\n a.download = filename;\n a.rel = \"noopener\";\n\n document.body.appendChild(a);\n a.click();\n a.remove();\n\n URL.revokeObjectURL(url);\n }\n}\n\nexport default BolbExportStrategy;\n","import { BROADCAST_CHANNEL_NAME } from \"../contants\";\nimport type { ExportParams, ExportResponse, ExportStrategy, JobId } from \"../types\";\nimport WorkerManager from \"../WorkerManager\";\n\nclass FsAccessExportStrategy implements ExportStrategy {\n private workerManager: WorkerManager;\n\n constructor() {\n this.workerManager = WorkerManager.initialise();\n }\n\n async export<T>(params: ExportParams<T>): Promise<ExportResponse> {\n const _suggestedName = params?.fileName || \"export\";\n\n const fileHandle = await window.showSaveFilePicker({\n suggestedName: _suggestedName,\n types: [{ accept: { \"text/csv\": [\".csv\"] }, description: \"CSV file\" }],\n });\n\n const writableFileStream = await fileHandle.createWritable();\n let iterator: JobId = 0 as JobId;\n let totalRowsLoaded = 0;\n\n const encoder = new TextEncoder();\n const messaging = new BroadcastChannel(BROADCAST_CHANNEL_NAME);\n\n const readable = new ReadableStream({\n pull: async (controller) => {\n try {\n const response = await params.getNextPage(iterator++);\n\n const safeRows = Array.isArray(response.rows) ? response?.rows : [];\n const safeTotal = response.total ?? 0;\n\n const isRowsEmpty = !safeRows || !safeRows.length;\n const nextRowsLoaded = totalRowsLoaded + safeRows.length;\n totalRowsLoaded = isRowsEmpty ? safeTotal : nextRowsLoaded;\n const isFinished = totalRowsLoaded >= safeTotal;\n\n if (isRowsEmpty) {\n messaging.postMessage(\n JSON.stringify({\n loadedItemsCount: totalRowsLoaded,\n total: safeTotal,\n type: \"done\",\n }),\n );\n\n await this.workerManager.triggerWorker({\n id: iterator,\n type: \"completed\",\n });\n\n messaging.close();\n controller.close();\n\n return;\n }\n\n const csvChunks = await this.workerManager.triggerWorker({\n columns: params.columns,\n data: safeRows as Record<string, unknown>[],\n id: iterator,\n type: \"to_csv_chunk\",\n });\n\n messaging.postMessage(\n JSON.stringify({\n loadedItemsCount: totalRowsLoaded,\n total: safeTotal,\n type: \"progress\",\n }),\n );\n\n controller.enqueue(encoder.encode(csvChunks as string));\n\n if (isFinished) {\n messaging.postMessage(\n JSON.stringify({\n loadedItemsCount: totalRowsLoaded,\n total: safeTotal,\n type: \"done\",\n }),\n );\n\n await this.workerManager.triggerWorker({\n id: iterator,\n type: \"completed\",\n });\n\n messaging.close();\n controller.close();\n\n return;\n }\n } catch (error) {\n controller.error(error);\n\n messaging.postMessage(\n JSON.stringify({\n loadedItemsCount: totalRowsLoaded,\n total: 0,\n type: \"failed\",\n }),\n );\n }\n },\n });\n\n try {\n await readable.pipeTo(writableFileStream);\n } catch (err) {\n console.error(\"Export failed:\", err);\n throw err;\n } finally {\n this.workerManager.terminate();\n }\n\n return {\n finished: true,\n totalRowsLoaded,\n };\n }\n}\n\nexport default FsAccessExportStrategy;\n","import { ExportController } from \"./controllers/ExportController\";\nimport BolbExportStrategy from \"./strategy/BolbExportStrategy\";\nimport FsAccessExportStrategy from \"./strategy/FsAccessExportStrategy\";\n\nfunction createExportController(): ExportController {\n return new ExportController({\n blobExportStrategy: new BolbExportStrategy(),\n fsAccessStrategy: new FsAccessExportStrategy(),\n });\n}\n\nexport default createExportController;\n","import type { ExportController } from \"./controllers/ExportController\";\nimport createExportController from \"./createExportController\";\n\n// biome-ignore lint/complexity/noStaticOnlyClass: Note(Pavlo) Prefer to keep as class\nclass ExportControllerSingleton {\n static instance: ExportController | null = null;\n static initialized: boolean = false;\n\n static init() {\n if (ExportControllerSingleton.instance) {\n return ExportControllerSingleton.instance;\n }\n\n ExportControllerSingleton.instance = createExportController();\n ExportControllerSingleton.initialized = true;\n\n return ExportControllerSingleton.instance;\n }\n\n static getInstance(): ExportController {\n if (!ExportControllerSingleton.instance) {\n return ExportControllerSingleton.init();\n }\n\n return ExportControllerSingleton.instance;\n }\n}\n\nexport default ExportControllerSingleton;\n","import { useEffect } from \"react\";\nimport { BROADCAST_CHANNEL_NAME } from \"../core/contants\";\n\ntype Payload = {\n total: number;\n loadedItemsCount: number;\n state: \"progress\" | \"failed\" | \"done\";\n};\n\nfunction useMessageExportCSV(cb: (payload: Payload) => void) {\n useEffect(() => {\n const channel = new BroadcastChannel(BROADCAST_CHANNEL_NAME);\n\n channel.addEventListener(\"message\", (params: MessageEvent) => {\n try {\n const json = JSON.parse(params.data) as Payload;\n\n cb(json);\n } catch (error) {\n console.error({ error });\n }\n });\n\n return () => {\n channel.close();\n };\n }, [cb]);\n}\n\nexport default useMessageExportCSV;\n"],"mappings":"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","names":["import_react"]}
package/dist/index.js CHANGED
@@ -44,12 +44,7 @@ var _WorkerManager = class _WorkerManager {
44
44
  constructor() {
45
45
  __privateAdd(this, _WorkerManager_instances);
46
46
  __privateAdd(this, _worker);
47
- let workerUrl;
48
- try {
49
- workerUrl = new URL("./worker.js", import.meta.url);
50
- } catch {
51
- workerUrl = "/worker.js";
52
- }
47
+ const workerUrl = new URL("./worker.js", import.meta.url);
53
48
  __privateSet(this, _worker, new Worker(workerUrl, {
54
49
  name: WEB_WORKER_NAME,
55
50
  type: "module"
@@ -360,3 +355,4 @@ export {
360
355
  useExportCSV_default as useExportCSV,
361
356
  useMessageExportCSV_default as useMessageExportCSV
362
357
  };
358
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/hooks/useExportCSV.ts","../src/core/controllers/ExportController.ts","../src/core/contants/index.ts","../src/core/WorkerManager.ts","../src/core/strategy/BolbExportStrategy.ts","../src/core/strategy/FsAccessExportStrategy.ts","../src/core/createExportController.ts","../src/core/ExportControllerSingleton.ts","../src/hooks/useMessageExportCSV.ts"],"sourcesContent":["import { useRef } from \"react\";\nimport { type ExportController, ExportControllerSingleton } from \"../core\";\n\nfunction useExportCSV() {\n const exportCallbackRef = useRef<ExportController>(ExportControllerSingleton.init());\n\n return {\n handler: exportCallbackRef?.current,\n };\n}\n\nexport default useExportCSV;\n","import type BolbExportStrategy from \"../strategy/BolbExportStrategy\";\nimport type FsAccessExportStrategy from \"../strategy/FsAccessExportStrategy\";\nimport type { ExportParams, ExportResponse, ExportStrategy } from \"../types\";\n\ntype ExportControllerDeps = {\n fsAccessStrategy: FsAccessExportStrategy;\n blobExportStrategy: BolbExportStrategy;\n};\n\nexport class ExportController {\n constructor(private readonly deps: ExportControllerDeps) {}\n\n public async start<T>(params: ExportParams<T>): Promise<ExportResponse> {\n const strategy = this.#resolveStrategy();\n\n return strategy.export(params);\n }\n\n #canUseFSAccess() {\n return typeof window.showSaveFilePicker === \"function\";\n }\n\n #resolveStrategy(): ExportStrategy {\n if (this.#canUseFSAccess()) {\n return this.deps.fsAccessStrategy;\n }\n\n return this.deps.blobExportStrategy;\n }\n}\n","export const WEB_WORKER_NAME = \"scv-worker\";\nexport const BROADCAST_CHANNEL_NAME = \"react-csv-exporter\";\n","import { WEB_WORKER_NAME } from \"./contants\";\nimport type { JobId, ToWorkerMessage } from \"./types\";\n\nconst pending = new Map<JobId, { resolve: (value: unknown) => void; reject: (reason?: ErrorEvent) => void }>();\n\nclass WorkerManager {\n #worker: Worker | null;\n\n constructor() {\n const workerUrl = new URL(\"./worker.js\", import.meta.url);\n\n this.#worker = new Worker(workerUrl, {\n name: WEB_WORKER_NAME,\n type: \"module\",\n });\n\n this.#listenerRegistry();\n }\n\n static initialise() {\n return new WorkerManager();\n }\n\n #listenerRegistry() {\n this.#worker?.addEventListener(\"message\", (event) => {\n const { id, result, error } = event.data;\n const entity = pending.get(id);\n\n if (!entity) {\n return;\n }\n\n pending.delete(id);\n\n if (error) {\n entity.reject(error);\n } else {\n entity.resolve(result);\n }\n });\n\n this.#worker?.addEventListener(\"error\", (event) => {\n for (const [, { reject }] of pending) {\n reject(event);\n }\n\n pending.clear();\n });\n }\n\n async triggerWorker(payload: ToWorkerMessage) {\n const id = payload.id ?? Math.random().toString(36).substr(2);\n\n const p = new Promise((resolve, reject) => {\n pending.set(id, { reject, resolve });\n });\n\n this.#worker?.postMessage(payload);\n\n return p;\n }\n\n terminate() {\n if (this.#worker) {\n this.#worker.terminate();\n this.#worker = null;\n }\n }\n}\n\nexport default WorkerManager;\n","import { BROADCAST_CHANNEL_NAME } from \"../contants\";\nimport type { ExportParams, ExportResponse, ExportStrategy, JobId } from \"../types\";\nimport WorkerManager from \"../WorkerManager\";\n\nclass BolbExportStrategy implements ExportStrategy {\n private workerManager: WorkerManager;\n\n constructor() {\n this.workerManager = WorkerManager.initialise();\n }\n\n async export<T>(params: ExportParams<T>): Promise<ExportResponse> {\n const suggestedName = params.fileName ?? \"export\";\n const filename = suggestedName.endsWith(\".csv\") ? suggestedName : `${suggestedName}.csv`;\n\n let iterator: JobId = 0 as JobId;\n let totalRowsLoaded = 0;\n\n const messaging = new BroadcastChannel(BROADCAST_CHANNEL_NAME);\n\n const csvParts: BlobPart[] = [];\n\n try {\n while (true) {\n const response = await params.getNextPage(iterator++);\n\n const safeRows = Array.isArray(response.rows) ? response.rows : [];\n const safeTotal = response.total ?? 0;\n\n const isRowsEmpty = safeRows.length === 0;\n\n const nextRowsLoaded = totalRowsLoaded + safeRows.length;\n totalRowsLoaded = isRowsEmpty ? safeTotal : nextRowsLoaded;\n\n const isFinished = safeTotal > 0 ? totalRowsLoaded >= safeTotal : isRowsEmpty;\n\n if (isRowsEmpty) {\n messaging.postMessage(\n JSON.stringify({\n loadedItemsCount: totalRowsLoaded,\n total: safeTotal,\n type: \"done\",\n }),\n );\n\n await this.workerManager.triggerWorker({\n id: iterator,\n type: \"completed\",\n });\n\n break;\n }\n\n const csvChunk = (await this.workerManager.triggerWorker({\n columns: params.columns,\n data: safeRows as Record<string, unknown>[],\n id: iterator,\n type: \"to_csv_chunk\",\n })) as string;\n\n csvParts.push(csvChunk);\n\n messaging.postMessage(\n JSON.stringify({\n loadedItemsCount: totalRowsLoaded,\n total: safeTotal,\n type: \"progress\",\n }),\n );\n\n if (isFinished) {\n messaging.postMessage(\n JSON.stringify({\n loadedItemsCount: totalRowsLoaded,\n total: safeTotal,\n type: \"done\",\n }),\n );\n\n await this.workerManager.triggerWorker({\n id: iterator,\n type: \"completed\",\n });\n\n break;\n }\n }\n\n const blob = new Blob([\"\\uFEFF\", ...csvParts], {\n type: \"text/csv;charset=utf-8\",\n });\n\n this.downloadBlob(blob, filename);\n\n return { finished: true, totalRowsLoaded };\n } catch (error) {\n messaging.postMessage(\n JSON.stringify({\n loadedItemsCount: totalRowsLoaded,\n total: 0,\n type: \"failed\",\n }),\n );\n throw error;\n } finally {\n messaging.close();\n this.workerManager.terminate();\n }\n }\n\n private downloadBlob(blob: Blob, filename: string) {\n const url = URL.createObjectURL(blob);\n\n const a = document.createElement(\"a\");\n a.href = url;\n a.download = filename;\n a.rel = \"noopener\";\n\n document.body.appendChild(a);\n a.click();\n a.remove();\n\n URL.revokeObjectURL(url);\n }\n}\n\nexport default BolbExportStrategy;\n","import { BROADCAST_CHANNEL_NAME } from \"../contants\";\nimport type { ExportParams, ExportResponse, ExportStrategy, JobId } from \"../types\";\nimport WorkerManager from \"../WorkerManager\";\n\nclass FsAccessExportStrategy implements ExportStrategy {\n private workerManager: WorkerManager;\n\n constructor() {\n this.workerManager = WorkerManager.initialise();\n }\n\n async export<T>(params: ExportParams<T>): Promise<ExportResponse> {\n const _suggestedName = params?.fileName || \"export\";\n\n const fileHandle = await window.showSaveFilePicker({\n suggestedName: _suggestedName,\n types: [{ accept: { \"text/csv\": [\".csv\"] }, description: \"CSV file\" }],\n });\n\n const writableFileStream = await fileHandle.createWritable();\n let iterator: JobId = 0 as JobId;\n let totalRowsLoaded = 0;\n\n const encoder = new TextEncoder();\n const messaging = new BroadcastChannel(BROADCAST_CHANNEL_NAME);\n\n const readable = new ReadableStream({\n pull: async (controller) => {\n try {\n const response = await params.getNextPage(iterator++);\n\n const safeRows = Array.isArray(response.rows) ? response?.rows : [];\n const safeTotal = response.total ?? 0;\n\n const isRowsEmpty = !safeRows || !safeRows.length;\n const nextRowsLoaded = totalRowsLoaded + safeRows.length;\n totalRowsLoaded = isRowsEmpty ? safeTotal : nextRowsLoaded;\n const isFinished = totalRowsLoaded >= safeTotal;\n\n if (isRowsEmpty) {\n messaging.postMessage(\n JSON.stringify({\n loadedItemsCount: totalRowsLoaded,\n total: safeTotal,\n type: \"done\",\n }),\n );\n\n await this.workerManager.triggerWorker({\n id: iterator,\n type: \"completed\",\n });\n\n messaging.close();\n controller.close();\n\n return;\n }\n\n const csvChunks = await this.workerManager.triggerWorker({\n columns: params.columns,\n data: safeRows as Record<string, unknown>[],\n id: iterator,\n type: \"to_csv_chunk\",\n });\n\n messaging.postMessage(\n JSON.stringify({\n loadedItemsCount: totalRowsLoaded,\n total: safeTotal,\n type: \"progress\",\n }),\n );\n\n controller.enqueue(encoder.encode(csvChunks as string));\n\n if (isFinished) {\n messaging.postMessage(\n JSON.stringify({\n loadedItemsCount: totalRowsLoaded,\n total: safeTotal,\n type: \"done\",\n }),\n );\n\n await this.workerManager.triggerWorker({\n id: iterator,\n type: \"completed\",\n });\n\n messaging.close();\n controller.close();\n\n return;\n }\n } catch (error) {\n controller.error(error);\n\n messaging.postMessage(\n JSON.stringify({\n loadedItemsCount: totalRowsLoaded,\n total: 0,\n type: \"failed\",\n }),\n );\n }\n },\n });\n\n try {\n await readable.pipeTo(writableFileStream);\n } catch (err) {\n console.error(\"Export failed:\", err);\n throw err;\n } finally {\n this.workerManager.terminate();\n }\n\n return {\n finished: true,\n totalRowsLoaded,\n };\n }\n}\n\nexport default FsAccessExportStrategy;\n","import { ExportController } from \"./controllers/ExportController\";\nimport BolbExportStrategy from \"./strategy/BolbExportStrategy\";\nimport FsAccessExportStrategy from \"./strategy/FsAccessExportStrategy\";\n\nfunction createExportController(): ExportController {\n return new ExportController({\n blobExportStrategy: new BolbExportStrategy(),\n fsAccessStrategy: new FsAccessExportStrategy(),\n });\n}\n\nexport default createExportController;\n","import type { ExportController } from \"./controllers/ExportController\";\nimport createExportController from \"./createExportController\";\n\n// biome-ignore lint/complexity/noStaticOnlyClass: Note(Pavlo) Prefer to keep as class\nclass ExportControllerSingleton {\n static instance: ExportController | null = null;\n static initialized: boolean = false;\n\n static init() {\n if (ExportControllerSingleton.instance) {\n return ExportControllerSingleton.instance;\n }\n\n ExportControllerSingleton.instance = createExportController();\n ExportControllerSingleton.initialized = true;\n\n return ExportControllerSingleton.instance;\n }\n\n static getInstance(): ExportController {\n if (!ExportControllerSingleton.instance) {\n return ExportControllerSingleton.init();\n }\n\n return ExportControllerSingleton.instance;\n }\n}\n\nexport default ExportControllerSingleton;\n","import { useEffect } from \"react\";\nimport { BROADCAST_CHANNEL_NAME } from \"../core/contants\";\n\ntype Payload = {\n total: number;\n loadedItemsCount: number;\n state: \"progress\" | \"failed\" | \"done\";\n};\n\nfunction useMessageExportCSV(cb: (payload: Payload) => void) {\n useEffect(() => {\n const channel = new BroadcastChannel(BROADCAST_CHANNEL_NAME);\n\n channel.addEventListener(\"message\", (params: MessageEvent) => {\n try {\n const json = JSON.parse(params.data) as Payload;\n\n cb(json);\n } catch (error) {\n console.error({ error });\n }\n });\n\n return () => {\n channel.close();\n };\n }, [cb]);\n}\n\nexport default useMessageExportCSV;\n"],"mappings":"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","names":[]}
package/dist/worker.js ADDED
@@ -0,0 +1,115 @@
1
+ // src/core/utils.ts
2
+ function objectsToCSV(jsonArray, columns, includeHeaders) {
3
+ if (!jsonArray.length || !columns.length) return "";
4
+ const rows = [];
5
+ if (includeHeaders) {
6
+ rows.push(columns.map((col) => col.label).join(","));
7
+ }
8
+ jsonArray.forEach((row) => {
9
+ rows.push(
10
+ columns.map((col) => {
11
+ const val = getNested(row, col.key);
12
+ const normalizedValue = normalisedValue(val);
13
+ const maybeFormattedValue = getFormatter(col, normalizedValue);
14
+ return maybeFormattedValue;
15
+ }).join(",")
16
+ );
17
+ });
18
+ return `${rows.join("\n")}
19
+ `;
20
+ }
21
+ function getNested(obj, keyPath) {
22
+ return keyPath.split(".").reduce((acc, key) => {
23
+ if (acc && typeof acc === "object") {
24
+ return acc[key];
25
+ }
26
+ return void 0;
27
+ }, obj);
28
+ }
29
+ function normalisedValue(value) {
30
+ let result = value;
31
+ if (typeof result === "string") {
32
+ result = `"${result.replace(/"/g, '""')}"`;
33
+ }
34
+ if (result === void 0 || result === null) {
35
+ result = "";
36
+ }
37
+ return result;
38
+ }
39
+ function makeFormatters(locale = "en-US", timeZone = "UTC", currency = "USD") {
40
+ return {
41
+ dateFull: new Intl.DateTimeFormat(locale, { dateStyle: "full", timeZone }),
42
+ dateMediumTime: new Intl.DateTimeFormat(locale, {
43
+ dateStyle: "medium",
44
+ timeStyle: "short",
45
+ timeZone
46
+ }),
47
+ numCompact: new Intl.NumberFormat(locale, {
48
+ maximumFractionDigits: 1,
49
+ notation: "compact"
50
+ }),
51
+ numCurrency: new Intl.NumberFormat(locale, {
52
+ currency,
53
+ maximumFractionDigits: 2,
54
+ style: "currency"
55
+ }),
56
+ numDecimal: new Intl.NumberFormat(locale, { maximumFractionDigits: 2 }),
57
+ numPercent: new Intl.NumberFormat(locale, {
58
+ maximumFractionDigits: 1,
59
+ style: "percent"
60
+ }),
61
+ timeShort: new Intl.DateTimeFormat(locale, {
62
+ timeStyle: "short",
63
+ timeZone
64
+ })
65
+ };
66
+ }
67
+ function getFormatter(col, value) {
68
+ const formatters = makeFormatters();
69
+ const availableFormatters = Object.keys(formatters);
70
+ if ("formatType" in col && availableFormatters.includes(col.formatType)) {
71
+ const enhance = formatters[col.formatType];
72
+ return enhance.format(Number(value));
73
+ } else {
74
+ return value;
75
+ }
76
+ }
77
+
78
+ // src/core/worker.ts
79
+ var headersWritten = /* @__PURE__ */ new Map();
80
+ self.onmessage = (event) => {
81
+ const msg = event.data;
82
+ try {
83
+ switch (msg.type) {
84
+ case "to_csv_chunk": {
85
+ const { columns, data, id } = msg;
86
+ const csvChunk = objectsToCSV(data, columns, !headersWritten.get(id));
87
+ const out = {
88
+ id,
89
+ result: csvChunk,
90
+ type: "csv_chunk"
91
+ };
92
+ headersWritten.set(id, true);
93
+ self.postMessage(out);
94
+ break;
95
+ }
96
+ case "completed": {
97
+ const out = { id: msg.id, type: "done" };
98
+ self.postMessage(out);
99
+ break;
100
+ }
101
+ default: {
102
+ console.warn(`Unsupported for worker message:: ${JSON.stringify(msg)}`);
103
+ break;
104
+ }
105
+ }
106
+ } catch (error) {
107
+ const _error = error instanceof Error ? error : new Error(String(error));
108
+ self.postMessage({
109
+ error: _error,
110
+ id: msg.id,
111
+ type: "error"
112
+ });
113
+ }
114
+ };
115
+ //# sourceMappingURL=worker.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/core/utils.ts","../src/core/worker.ts"],"sourcesContent":["import type { Column, ToCSVChunkMessage } from \"./types\";\n\nexport function objectsToCSV(\n jsonArray: ToCSVChunkMessage[\"data\"],\n columns: ToCSVChunkMessage[\"columns\"],\n includeHeaders: boolean,\n) {\n if (!jsonArray.length || !columns.length) return \"\";\n\n const rows = [];\n\n if (includeHeaders) {\n rows.push(columns.map((col) => col.label).join(\",\"));\n }\n\n jsonArray.forEach((row) => {\n rows.push(\n columns\n .map((col) => {\n const val: unknown = getNested(row, col.key);\n const normalizedValue = normalisedValue(val);\n const maybeFormattedValue = getFormatter(col, normalizedValue);\n\n return maybeFormattedValue;\n })\n .join(\",\"),\n );\n });\n\n return `${rows.join(\"\\n\")}\\n`;\n}\n\nfunction getNested(obj: Record<string, unknown>, keyPath: string): unknown {\n return keyPath.split(\".\").reduce<unknown>((acc, key) => {\n if (acc && typeof acc === \"object\") {\n return (acc as Record<string, unknown>)[key];\n }\n\n return undefined;\n }, obj);\n}\n\nfunction normalisedValue<T>(value: T): string | T {\n let result: string | T = value;\n\n if (typeof result === \"string\") {\n result = `\"${result.replace(/\"/g, '\"\"')}\"`;\n }\n\n if (result === undefined || result === null) {\n result = \"\";\n }\n\n return result;\n}\n\nfunction makeFormatters(locale = \"en-US\", timeZone = \"UTC\", currency = \"USD\") {\n return {\n dateFull: new Intl.DateTimeFormat(locale, { dateStyle: \"full\", timeZone }),\n dateMediumTime: new Intl.DateTimeFormat(locale, {\n dateStyle: \"medium\",\n timeStyle: \"short\",\n timeZone,\n }),\n numCompact: new Intl.NumberFormat(locale, {\n maximumFractionDigits: 1,\n notation: \"compact\",\n }),\n numCurrency: new Intl.NumberFormat(locale, {\n currency,\n maximumFractionDigits: 2,\n style: \"currency\",\n }),\n\n numDecimal: new Intl.NumberFormat(locale, { maximumFractionDigits: 2 }),\n numPercent: new Intl.NumberFormat(locale, {\n maximumFractionDigits: 1,\n style: \"percent\",\n }),\n timeShort: new Intl.DateTimeFormat(locale, {\n timeStyle: \"short\",\n timeZone,\n }),\n };\n}\n\nfunction getFormatter(col: Column, value: unknown) {\n const formatters = makeFormatters();\n const availableFormatters = Object.keys(formatters);\n\n if (\"formatType\" in col && availableFormatters.includes(col.formatType as string)) {\n const enhance = formatters[col.formatType as keyof typeof formatters];\n\n return enhance.format(Number(value));\n } else {\n return value;\n }\n}\n","import type { FromWorkerMessage, JobId, ToWorkerMessage } from \"./types\";\nimport { objectsToCSV } from \"./utils\";\n\nconst headersWritten = new Map<JobId, boolean>();\n\nself.onmessage = (event: MessageEvent<ToWorkerMessage>) => {\n const msg = event.data;\n\n try {\n switch (msg.type) {\n case \"to_csv_chunk\": {\n const { columns, data, id } = msg;\n const csvChunk = objectsToCSV(data, columns, !headersWritten.get(id));\n const out: FromWorkerMessage = {\n id,\n result: csvChunk,\n type: \"csv_chunk\",\n };\n\n headersWritten.set(id, true);\n\n self.postMessage(out);\n\n break;\n }\n\n case \"completed\": {\n const out: FromWorkerMessage = { id: msg.id, type: \"done\" };\n self.postMessage(out);\n\n break;\n }\n\n default: {\n console.warn(`Unsupported for worker message:: ${JSON.stringify(msg)}`);\n break;\n }\n }\n } catch (error) {\n const _error = error instanceof Error ? error : new Error(String(error));\n\n self.postMessage({\n error: _error,\n id: msg.id,\n type: \"error\",\n });\n }\n};\n"],"mappings":"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","names":[]}
package/package.json CHANGED
@@ -13,9 +13,9 @@
13
13
  },
14
14
  "exports": {
15
15
  ".": {
16
+ "types": "./dist/index.d.ts",
16
17
  "import": "./dist/index.js",
17
- "require": "./dist/index.cjs",
18
- "types": "./dist/index.d.ts"
18
+ "require": "./dist/index.cjs"
19
19
  }
20
20
  },
21
21
  "files": [
@@ -55,10 +55,11 @@
55
55
  },
56
56
  "scripts": {
57
57
  "build": "tsup",
58
+ "build:watch": "npm run build --watch",
58
59
  "dev": "tsup --watch"
59
60
  },
60
61
  "sideEffects": false,
61
62
  "type": "module",
62
63
  "types": "dist/index.d.ts",
63
- "version": "1.0.1"
64
+ "version": "1.1.1-beta.1"
64
65
  }
package/dist/index.d.cts DELETED
@@ -1,59 +0,0 @@
1
- type formatterTypes = "dateFull" | "dateMediumTime" | "timeShort" | "numDecimal" | "numCompact" | "numCurrency" | "numPercent";
2
- type Column = {
3
- key: string;
4
- label: string;
5
- timezone?: "UTC" | string;
6
- formatType?: formatterTypes;
7
- };
8
- type ExportParams<T> = {
9
- fileName: string;
10
- columns: Column[];
11
- getNextPage: (offset: number) => Promise<{
12
- rows: T[];
13
- total: number;
14
- }>;
15
- };
16
- type ExportResponse = {
17
- finished: boolean;
18
- totalRowsLoaded: number;
19
- };
20
- interface ExportStrategy {
21
- export<T>(params: ExportParams<T>): Promise<ExportResponse>;
22
- }
23
-
24
- declare class BolbExportStrategy implements ExportStrategy {
25
- private workerManager;
26
- constructor();
27
- export<T>(params: ExportParams<T>): Promise<ExportResponse>;
28
- private downloadBlob;
29
- }
30
-
31
- declare class FsAccessExportStrategy implements ExportStrategy {
32
- private workerManager;
33
- constructor();
34
- export<T>(params: ExportParams<T>): Promise<ExportResponse>;
35
- }
36
-
37
- type ExportControllerDeps = {
38
- fsAccessStrategy: FsAccessExportStrategy;
39
- blobExportStrategy: BolbExportStrategy;
40
- };
41
- declare class ExportController {
42
- #private;
43
- private readonly deps;
44
- constructor(deps: ExportControllerDeps);
45
- start<T>(params: ExportParams<T>): Promise<ExportResponse>;
46
- }
47
-
48
- declare function useExportCSV(): {
49
- handler: ExportController;
50
- };
51
-
52
- type Payload = {
53
- total: number;
54
- loadedItemsCount: number;
55
- state: "progress" | "failed" | "done";
56
- };
57
- declare function useMessageExportCSV(cb: (payload: Payload) => void): void;
58
-
59
- export { type Column, ExportController, type ExportParams, useExportCSV, useMessageExportCSV };
package/dist/index.d.ts DELETED
@@ -1,59 +0,0 @@
1
- type formatterTypes = "dateFull" | "dateMediumTime" | "timeShort" | "numDecimal" | "numCompact" | "numCurrency" | "numPercent";
2
- type Column = {
3
- key: string;
4
- label: string;
5
- timezone?: "UTC" | string;
6
- formatType?: formatterTypes;
7
- };
8
- type ExportParams<T> = {
9
- fileName: string;
10
- columns: Column[];
11
- getNextPage: (offset: number) => Promise<{
12
- rows: T[];
13
- total: number;
14
- }>;
15
- };
16
- type ExportResponse = {
17
- finished: boolean;
18
- totalRowsLoaded: number;
19
- };
20
- interface ExportStrategy {
21
- export<T>(params: ExportParams<T>): Promise<ExportResponse>;
22
- }
23
-
24
- declare class BolbExportStrategy implements ExportStrategy {
25
- private workerManager;
26
- constructor();
27
- export<T>(params: ExportParams<T>): Promise<ExportResponse>;
28
- private downloadBlob;
29
- }
30
-
31
- declare class FsAccessExportStrategy implements ExportStrategy {
32
- private workerManager;
33
- constructor();
34
- export<T>(params: ExportParams<T>): Promise<ExportResponse>;
35
- }
36
-
37
- type ExportControllerDeps = {
38
- fsAccessStrategy: FsAccessExportStrategy;
39
- blobExportStrategy: BolbExportStrategy;
40
- };
41
- declare class ExportController {
42
- #private;
43
- private readonly deps;
44
- constructor(deps: ExportControllerDeps);
45
- start<T>(params: ExportParams<T>): Promise<ExportResponse>;
46
- }
47
-
48
- declare function useExportCSV(): {
49
- handler: ExportController;
50
- };
51
-
52
- type Payload = {
53
- total: number;
54
- loadedItemsCount: number;
55
- state: "progress" | "failed" | "done";
56
- };
57
- declare function useMessageExportCSV(cb: (payload: Payload) => void): void;
58
-
59
- export { type Column, ExportController, type ExportParams, useExportCSV, useMessageExportCSV };