@particle-academy/holy-sheet 2.10.1 → 2.11.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/CHANGELOG.md +52 -0
- package/README.md +34 -0
- package/dist/chunk-OL6E7DE5.js +6828 -0
- package/dist/chunk-OL6E7DE5.js.map +1 -0
- package/dist/cli.cjs +6909 -0
- package/dist/cli.cjs.map +1 -0
- package/dist/cli.d.cts +1 -0
- package/dist/cli.d.ts +1 -0
- package/dist/cli.js +82 -0
- package/dist/cli.js.map +1 -0
- package/dist/index.cjs +845 -267
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +62 -5
- package/dist/index.d.ts +62 -5
- package/dist/index.js +9 -6255
- package/dist/index.js.map +1 -1
- package/package.json +5 -2
package/CHANGELOG.md
CHANGED
|
@@ -10,6 +10,58 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
10
10
|
|
|
11
11
|
## [Unreleased]
|
|
12
12
|
|
|
13
|
+
## [2.11.0] - 2026-10-27
|
|
14
|
+
|
|
15
|
+
### Added
|
|
16
|
+
|
|
17
|
+
- **Excel `.xltx` templates read, and `.ots` templates marked.** `read()` /
|
|
18
|
+
`describe()` read an `.xltx` exactly as its `.xlsx` twin and add
|
|
19
|
+
`sourceKind: "template"`; an `.ots` (already read, unmarked) now says so too.
|
|
20
|
+
`Workbook` gains a trailing optional `sourceKind` (default `"document"`).
|
|
21
|
+
Document reads are unchanged and carry no `sourceKind` key, so nothing to do
|
|
22
|
+
unless you want to tell the two apart. Mirrors PHP holy-sheet.
|
|
23
|
+
- **`Agent.convertTemplate(bytes, to?)`** (also on `HolySheet`) and the new
|
|
24
|
+
`holy-sheet` bin, `npx holy-sheet template:convert <in> <out>
|
|
25
|
+
[--to=document|template] [--force]`, turn a template into its workbook twin
|
|
26
|
+
and back. Only the declaration is rewritten: the workbook part's content-type
|
|
27
|
+
value (OOXML), or the `mimetype` entry plus the manifest root's `media-type`
|
|
28
|
+
(ODF 1.3 Part 2 section 3.3 requires them to agree). Every other zip member is
|
|
29
|
+
copied as its original record, byte for byte; `mimetype` stays first and
|
|
30
|
+
stored. The bin is Node-only and never imported by the isomorphic index.
|
|
31
|
+
- `OfficeTemplateRefused` with a constant `reason`.
|
|
32
|
+
|
|
33
|
+
### Changed
|
|
34
|
+
|
|
35
|
+
- **A macro-enabled template (`.xltm`) is now refused** with
|
|
36
|
+
`OfficeTemplateRefused("macro_enabled")`; it used to be read as a workbook with
|
|
37
|
+
its VBA silently ignored. So is an `.xltx` carrying a `vbaProject.bin`. An
|
|
38
|
+
`.xlsm` still reads as before but is never converted.
|
|
39
|
+
- A package that declares a template of another family is refused with
|
|
40
|
+
`family_mismatch` instead of being read as whatever its parts looked like.
|
|
41
|
+
|
|
42
|
+
## [2.10.2] - 2026-10-26
|
|
43
|
+
|
|
44
|
+
### Security
|
|
45
|
+
|
|
46
|
+
- Route XLSX/ODS and public `unzipSync` reads through bounded ZIP validation:
|
|
47
|
+
coherent local/central records, safe unique member names, CRC and exact sizes,
|
|
48
|
+
archive/part/total/ratio limits and bounded DEFLATE output. Reject truncated or
|
|
49
|
+
invalid codes and back-references with typed `ArchiveRefused`; Node file input
|
|
50
|
+
is bounded before allocation. Defaults: 64 MiB archive/part, 256 MiB expanded,
|
|
51
|
+
16,384 entries and 1000:1 ratio. `unzipSync(bytes, limits)` supports lower host
|
|
52
|
+
ceilings. Existing valid payload bytes and spreadsheet projections are retained.
|
|
53
|
+
|
|
54
|
+
- Update Vitest to 4.1.12 for security fixes; dev toolchain only, nothing to do.
|
|
55
|
+
|
|
56
|
+
- **Dev toolchain only — no runtime change, nothing for consumers to do.** The
|
|
57
|
+
lockfile now resolves `vite` 8.3.5 (was 8.2.2), whose bundled
|
|
58
|
+
`launch-editor` fixes GHSA-587h-7wmj-h5pm (HIGH, `fs.existsSync()` check
|
|
59
|
+
bypassable on Windows), GHSA-698v-4r3x-3vcv (`escapeCmdArgs()` omits `%`
|
|
60
|
+
escaping on Windows) and GHSA-r825-w8mm-5pxw (editor CLI flag
|
|
61
|
+
misinterpretation). `vite` is only reached through the test/dev toolchain
|
|
62
|
+
and the published package does not ship our lockfile, so the exposure was
|
|
63
|
+
this repo's own dev server.
|
|
64
|
+
|
|
13
65
|
## [2.10.1] — 2026-10-19
|
|
14
66
|
|
|
15
67
|
### Fixed
|
package/README.md
CHANGED
|
@@ -37,6 +37,13 @@ await Agent.write(schema, "sales.xlsx");
|
|
|
37
37
|
|
|
38
38
|
## API
|
|
39
39
|
|
|
40
|
+
Spreadsheet reads and `unzipSync` validate ZIP structure, CRC, unique safe names
|
|
41
|
+
and expansion before XML parsing. Unsafe ZIPs throw exported `ArchiveRefused`
|
|
42
|
+
with a bounded `reason`; ordinary non-spreadsheet formats retain
|
|
43
|
+
`UnsupportedFormatException`. Defaults are 64 MiB archive/part, 256 MiB expanded,
|
|
44
|
+
16,384 entries and 1000:1 ratio. `unzipSync(bytes, limits)` accepts lower host
|
|
45
|
+
ceilings via `ArchiveLimits`. This input layer does not add lossless editing.
|
|
46
|
+
|
|
40
47
|
`Agent` (static) mirrors the PHP surface:
|
|
41
48
|
|
|
42
49
|
- `validate(schema)` → structured errors `{path, expected, got, value, hint}[]`
|
|
@@ -69,6 +76,33 @@ when there is one). What maps and what does not is listed in the PHP package's
|
|
|
69
76
|
[`docs/ReadPath.md`](https://github.com/Particle-Academy/holy-sheet/blob/main/docs/ReadPath.md#opendocument-spreadsheets-ods);
|
|
70
77
|
this port reads the same fixtures and is diffed against it.
|
|
71
78
|
|
|
79
|
+
### Excel and LibreOffice templates (.xltx, .ots)
|
|
80
|
+
|
|
81
|
+
An `.xltx` is an `.xlsx` whose workbook part is declared a template; an `.ots`
|
|
82
|
+
is an `.ods` whose `mimetype` (and manifest root entry) says
|
|
83
|
+
`spreadsheet-template`. `read()` / `describe()` read both exactly as their twins
|
|
84
|
+
and add `sourceKind: "template"` (also `Workbook#sourceKind` from
|
|
85
|
+
`readWorkbook()`). A document read has no `sourceKind` key, as before.
|
|
86
|
+
|
|
87
|
+
```ts
|
|
88
|
+
Agent.read(xltxBytes); // { ..., sourceKind: "template" }
|
|
89
|
+
Agent.convertTemplate(xltxBytes); // .xlsx bytes ("document" | "template" | null = flip)
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
```
|
|
93
|
+
npx holy-sheet template:convert budget.xltx budget.xlsx
|
|
94
|
+
npx holy-sheet template:convert budget.ods budget.ots --to=template
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
Conversion rewrites only the declaration: the content-type value in
|
|
98
|
+
`[Content_Types].xml`, or the ODF `mimetype` entry plus the manifest's root
|
|
99
|
+
`media-type` (ODF 1.3 requires the two to match). Every other member is copied
|
|
100
|
+
as its original zip record, byte for byte; `mimetype` stays first and stored.
|
|
101
|
+
Refused with `OfficeTemplateRefused` (a constant `reason`): macro-enabled `.xltm`
|
|
102
|
+
(`macro_enabled`; an `.xlsm` is never converted either) and a package declaring
|
|
103
|
+
a template of another family (`family_mismatch`). The archive guards apply
|
|
104
|
+
first. Mirrors PHP `Agent::convertTemplate()`.
|
|
105
|
+
|
|
72
106
|
### Versions as diffs
|
|
73
107
|
|
|
74
108
|
`Agent.diff(a, b)` returns the ops that turn one schema into another, and
|