@dynamic-entity/server 1.14.0 → 2.0.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/README.md +39 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -129,6 +129,16 @@ console.log(`imported ${result.imported}, skipped ${result.skipped}`);
|
|
|
129
129
|
**awaits** `onBatch`, and drops the batch. Peak memory is a function of `batchSize`, not of the
|
|
130
130
|
file's size — which is the entire reason this package exists.
|
|
131
131
|
|
|
132
|
+
**One qualification, for xlsx.** That statement is exact for CSV, which is read as a byte
|
|
133
|
+
stream from first row to last. An `.xlsx` file is a zip archive, and exceljs cannot be handed
|
|
134
|
+
a stream of one: `guardZip` validates the archive and rebuilds it in memory before exceljs is
|
|
135
|
+
constructed, so the *compressed* file is resident for the length of the import. It is bounded
|
|
136
|
+
by `maxBytes` rather than by `batchSize`, and it is the compressed size — a fifty-megabyte
|
|
137
|
+
workbook is fifty megabytes here, not the several hundred its rows would occupy expanded. The
|
|
138
|
+
row-by-row half above still holds: what scales with `batchSize` is everything downstream of
|
|
139
|
+
the reader. `xlsx-source.ts` has always said this in its own header; it belongs where a
|
|
140
|
+
reader meets the claim first.
|
|
141
|
+
|
|
132
142
|
---
|
|
133
143
|
|
|
134
144
|
## Four things to know before you deploy this
|
|
@@ -203,7 +213,35 @@ catastrophic backtrack. See [SECURITY.md](../../SECURITY.md).
|
|
|
203
213
|
|
|
204
214
|
## What it holds in memory
|
|
205
215
|
|
|
206
|
-
|
|
216
|
+
```mermaid
|
|
217
|
+
flowchart LR
|
|
218
|
+
U["the browser<br>uploads a file"]
|
|
219
|
+
R["readSheet()<br>streamed, limits enforced"]
|
|
220
|
+
M["applyMapping()<br>one batch of 500"]
|
|
221
|
+
Y["your onImport<br>awaited"]
|
|
222
|
+
C["imported: 50000<br>records: empty"]
|
|
223
|
+
|
|
224
|
+
U -->|"multipart POST"| R
|
|
225
|
+
R --> M
|
|
226
|
+
M -->|"records"| Y
|
|
227
|
+
Y -.->|"resolves: drop the batch, pull the next 500"| R
|
|
228
|
+
R -.->|"when the file ends"| C
|
|
229
|
+
|
|
230
|
+
classDef yours stroke-width:3px,stroke-dasharray:5 3
|
|
231
|
+
class Y yours
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
The dashed edge back to `readSheet` is the whole package. A batch is mapped, handed to your
|
|
235
|
+
writer, **awaited**, and dropped before the next is pulled — so peak memory downstream of the
|
|
236
|
+
reader is a function of `batchSize` and not of the file. Not awaiting would turn bounded memory
|
|
237
|
+
into an unbounded queue of pending writes, which is the same failure arrived at from the other
|
|
238
|
+
side. For xlsx, add the rebuilt archive `guardZip` holds — see the qualification above.
|
|
239
|
+
|
|
240
|
+
Measured on a fifty-thousand-row, thirty-five-column sheet: **2.7 MB** of collected heap, against
|
|
241
|
+
163 MB with the per-batch flush removed. `stress.spec.ts` asserts it at 16 MB, chosen to
|
|
242
|
+
discriminate rather than to be comfortable.
|
|
243
|
+
|
|
244
|
+
The rest, stated rather than left to be discovered:
|
|
207
245
|
|
|
208
246
|
- **CSV streams properly.** Rows are read incrementally and never accumulated.
|
|
209
247
|
- **Exactly one worksheet is read** — the lowest-numbered `sheetN.xml`, not whichever the
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dynamic-entity/server",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.1",
|
|
4
4
|
"description": "Streaming spreadsheet import for @dynamic-entity/core, with an Express adapter.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"dynamic-entity",
|
|
@@ -47,7 +47,7 @@
|
|
|
47
47
|
"exceljs": "4.4.0"
|
|
48
48
|
},
|
|
49
49
|
"peerDependencies": {
|
|
50
|
-
"@dynamic-entity/core": "^
|
|
50
|
+
"@dynamic-entity/core": "^2.0.1",
|
|
51
51
|
"express": "^4.18.0 || ^5.0.0"
|
|
52
52
|
},
|
|
53
53
|
"peerDependenciesMeta": {
|