@noy-db/as-zip 0.1.0-pre.3

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 ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 vLannaAi
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 ADDED
@@ -0,0 +1,170 @@
1
+ # @noy-db/as-zip
2
+
3
+ Composite record + blob archive for noy-db. Bundles a collection's
4
+ records and every record's attached blobs into one `.zip` — the
5
+ "download this audit trail" / "migrate this case folder" primitive.
6
+
7
+ Zero dependencies: ships a store-only ZIP writer (~150 lines,
8
+ RFC-compliant, no deflate). Most consumed blobs are already
9
+ compressed (PDF, PNG, JPEG, encrypted `.noydb` bundles) — re-
10
+ deflating would cost CPU without saving bytes.
11
+
12
+ ## Optional WinZip-AES-256 password (#304)
13
+
14
+ Pass `password` to encrypt every entry with WinZip-AES-256
15
+ (vendor version AE-2):
16
+
17
+ ```ts
18
+ const archive = await asZip.toBytes(vault, {
19
+ records: { collection: 'invoices' },
20
+ password: 'shared-with-recipient-2026',
21
+ })
22
+ ```
23
+
24
+ The output is still a valid single-disk ZIP that archive tools
25
+ recognising WinZip-AES (7-Zip, Archive Utility, WinRAR, modern
26
+ unzip builds) prompt for the password on extract. Read back via:
27
+
28
+ ```ts
29
+ const decoded = await asZip.fromBytes(vault, archive, {
30
+ collection: 'invoices',
31
+ password: 'shared-with-recipient-2026',
32
+ })
33
+ await decoded.apply()
34
+ ```
35
+
36
+ > AES-256 only. ZipCrypto and AES-128/192 are refused at both write
37
+ > and read time.
38
+ >
39
+ > Validated against 7-Zip 26.x (Linux/macOS/Windows) and Archive
40
+ > Utility (macOS 15) — see [`docs/interop-matrix.md`](../../docs/interop-matrix.md).
41
+ >
42
+ > **This is the interop layer**, not the encryption layer. For
43
+ > multi-recipient + revocable + audited noy-db egress, use
44
+ > `@noy-db/as-noydb` (#301).
45
+
46
+ Part of the `@noy-db/as-*` portable-artefact family, plaintext
47
+ tier, document sub-family. See
48
+ [`docs/packages-exports.md#authorization-model`](https://github.com/vLannaAi/noy-db/blob/main/docs/packages-exports.md#authorization-model).
49
+
50
+ ## Install
51
+
52
+ ```bash
53
+ pnpm add @noy-db/as-zip
54
+ ```
55
+
56
+ Requires `@noy-db/hub` as a peer.
57
+
58
+ ## Authorisation (RFC #249)
59
+
60
+ One capability check: `assertCanExport('plaintext', 'zip')`. A
61
+ composite archive is semantically the `'zip'` format from the auth
62
+ model's POV — requiring separate `'json'`, `'csv'`, `'blob'`
63
+ grants per call would fragment the grant surface without adding
64
+ isolation (the archive concatenates them anyway).
65
+
66
+ ```ts
67
+ await db.grant('firm', {
68
+ userId: 'auditor',
69
+ role: 'viewer',
70
+ passphrase: '…',
71
+ exportCapability: { plaintext: ['zip'] },
72
+ })
73
+ ```
74
+
75
+ ## API
76
+
77
+ ### `toBytes(vault, options)` — raw archive bytes
78
+
79
+ ```ts
80
+ import { toBytes } from '@noy-db/as-zip'
81
+
82
+ const bytes = await toBytes(vault, {
83
+ records: {
84
+ collection: 'invoices',
85
+ filter: (r) => r.status === 'paid', // optional
86
+ },
87
+ attachments: {
88
+ slots: ['raw', 'thumb'], // optional; default '*' = every slot
89
+ },
90
+ })
91
+ // → Uint8Array ready for `fs.writeFile` or `new Blob([bytes])`
92
+ ```
93
+
94
+ ### `download(vault, options)` — browser
95
+
96
+ ```ts
97
+ import { download } from '@noy-db/as-zip'
98
+
99
+ await download(vault, {
100
+ records: { collection: 'invoices' },
101
+ filename: 'invoices-2026-03.zip',
102
+ })
103
+ ```
104
+
105
+ ### `write(vault, path, options)` — Node file
106
+
107
+ ```ts
108
+ import { write } from '@noy-db/as-zip'
109
+
110
+ await write(vault, '/tmp/invoices.zip', {
111
+ records: { collection: 'invoices' },
112
+ acknowledgeRisks: true,
113
+ })
114
+ ```
115
+
116
+ ## Archive layout
117
+
118
+ ```
119
+ invoices.zip
120
+ ├── manifest.json # index + provenance
121
+ ├── records.json # decrypted records as JSON array
122
+ └── attachments/
123
+ ├── <recordId>/<slot> # raw blob bytes, MIME-native
124
+ └── ...
125
+ ```
126
+
127
+ The folder-per-record layout makes composite entities (invoice +
128
+ scan + receipt, email + body + attachments) browsable in
129
+ Finder/Explorer without tooling.
130
+
131
+ ### `manifest.json` shape
132
+
133
+ ```ts
134
+ {
135
+ _noydb_archive: 1,
136
+ collection: 'invoices',
137
+ exportedAt: '2026-04-22T...',
138
+ recordCount: 42,
139
+ attachmentCount: 17,
140
+ records: [
141
+ { id: 'inv-1', attachments: [
142
+ { slot: 'raw', path: 'attachments/inv-1/raw', size: 2341, mimeType: 'application/pdf' }
143
+ ]},
144
+ ...
145
+ ]
146
+ }
147
+ ```
148
+
149
+ ## Low-level encoder
150
+
151
+ The same zip writer is exposed for consumers who want to build
152
+ archives from non-noy-db payloads:
153
+
154
+ ```ts
155
+ import { writeZip, type ZipEntry } from '@noy-db/as-zip'
156
+
157
+ const bytes = writeZip([
158
+ { path: 'hello.txt', bytes: new TextEncoder().encode('hi') },
159
+ { path: 'blob.bin', bytes: someUint8Array },
160
+ ])
161
+ ```
162
+
163
+ STORE method (no compression). Single-disk, no Zip64. Files > 4 GiB
164
+ are not supported.
165
+
166
+ ## Related
167
+
168
+ - `@noy-db/as-blob` — single attachment
169
+ - `@noy-db/as-csv` — structured records as CSV
170
+ - `@noy-db/as-noydb` — encrypted bundle (bundle tier)