@noy-db/as-xlsx 0.2.0-pre.30 → 0.2.0-pre.31
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/package.json +9 -16
- package/dist/index.cjs +0 -1170
- package/dist/index.cjs.map +0 -1
- package/dist/index.d.cts +0 -538
package/dist/index.d.cts
DELETED
|
@@ -1,538 +0,0 @@
|
|
|
1
|
-
import { DictEntry, VaultDiff, Vault } from '@noy-db/hub';
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Minimal zero-dependency XLSX writer.
|
|
5
|
-
*
|
|
6
|
-
* An `.xlsx` file is a ZIP archive (Office Open XML / OOXML) with
|
|
7
|
-
* SpreadsheetML inside. This writer emits the six parts needed for
|
|
8
|
-
* a valid worksheet and hands them to `@noy-db/as-zip`'s
|
|
9
|
-
* `writeZip()` to assemble the final `.xlsx` bytes.
|
|
10
|
-
*
|
|
11
|
-
* ## Emitted parts
|
|
12
|
-
*
|
|
13
|
-
* ```
|
|
14
|
-
* [Content_Types].xml # MIME descriptors
|
|
15
|
-
* _rels/.rels # root → workbook pointer
|
|
16
|
-
* xl/workbook.xml # sheet list
|
|
17
|
-
* xl/_rels/workbook.xml.rels # sheet-part pointers
|
|
18
|
-
* xl/worksheets/sheet<N>.xml # cell data
|
|
19
|
-
* xl/sharedStrings.xml # string pool (Unicode-safe)
|
|
20
|
-
* ```
|
|
21
|
-
*
|
|
22
|
-
* Strings route through the shared-string table (`sharedStrings.xml`)
|
|
23
|
-
* rather than being inlined on cells, which is:
|
|
24
|
-
*
|
|
25
|
-
* 1. Slightly more compact when strings repeat (client names,
|
|
26
|
-
* status labels, locale codes).
|
|
27
|
-
* 2. Consistent with how Excel writes its own files — some
|
|
28
|
-
* strict-OOXML readers refuse inline strings.
|
|
29
|
-
*
|
|
30
|
-
* Numbers, booleans, and dates are written as typed cells; strings
|
|
31
|
-
* and everything else fall back to the shared-string path.
|
|
32
|
-
*
|
|
33
|
-
* ## Not supported
|
|
34
|
-
*
|
|
35
|
-
* - Cell styles (fonts, colours, borders, number formats).
|
|
36
|
-
* - Formulas, merged cells, frozen panes, auto-filter.
|
|
37
|
-
* - Charts, images, drawings.
|
|
38
|
-
* - Zip64 / archives > 4 GiB.
|
|
39
|
-
*
|
|
40
|
-
* @module
|
|
41
|
-
*/
|
|
42
|
-
/**
|
|
43
|
-
* A formula cell. Emits `<f>` so the spreadsheet recomputes live; `v` is an
|
|
44
|
-
* optional cached result (what the formula currently evaluates to) so the value
|
|
45
|
-
* shows immediately on open and survives a round-trip read. Build via
|
|
46
|
-
* {@link formula}. The formula string must NOT include a leading `=`.
|
|
47
|
-
*/
|
|
48
|
-
interface XlsxFormulaCell {
|
|
49
|
-
readonly __xlsxFormula: string;
|
|
50
|
-
readonly v?: string | number | boolean;
|
|
51
|
-
}
|
|
52
|
-
/** Build a {@link XlsxFormulaCell}. `f` is the formula body without a leading `=`. */
|
|
53
|
-
declare function formula(f: string, cachedValue?: string | number | boolean): XlsxFormulaCell;
|
|
54
|
-
/**
|
|
55
|
-
* A value cell carrying a number-format code (e.g. `'#,##0.00'` for currency,
|
|
56
|
-
* `'yyyy-mm-dd'` for dates). Build via {@link styled}. The format only renders
|
|
57
|
-
* meaningfully on numeric values.
|
|
58
|
-
*/
|
|
59
|
-
interface XlsxStyledCell {
|
|
60
|
-
readonly __xlsxStyle: string;
|
|
61
|
-
readonly v: string | number | boolean | null;
|
|
62
|
-
}
|
|
63
|
-
/** Build a {@link XlsxStyledCell} — a value plus an Excel number-format code. */
|
|
64
|
-
declare function styled(value: string | number | boolean | null, numberFormat: string): XlsxStyledCell;
|
|
65
|
-
/** A data-validation rule (dropdown) over a cell range. */
|
|
66
|
-
interface XlsxValidation {
|
|
67
|
-
/** Target range in A1 notation, e.g. `'B2:B100'`. */
|
|
68
|
-
readonly sqref: string;
|
|
69
|
-
/** Inline allowed values → a `"a,b,c"` list. Mutually exclusive with `formula1`. */
|
|
70
|
-
readonly values?: readonly string[];
|
|
71
|
-
/** Explicit `formula1` (e.g. a range ref `Clients!$A$2:$A$999`). */
|
|
72
|
-
readonly formula1?: string;
|
|
73
|
-
}
|
|
74
|
-
/** One row in a sheet. A cell is a primitive value or an {@link XlsxFormulaCell}. */
|
|
75
|
-
type XlsxRow = ReadonlyArray<unknown>;
|
|
76
|
-
/** One sheet in a workbook. */
|
|
77
|
-
interface XlsxSheet {
|
|
78
|
-
/** Sheet tab name — Excel caps at 31 chars; we truncate with `…`. */
|
|
79
|
-
readonly name: string;
|
|
80
|
-
/** Header row, rendered as row 1. Omit to skip the header. */
|
|
81
|
-
readonly header?: readonly string[];
|
|
82
|
-
/** Data rows — each is an array aligned with `header` if present. */
|
|
83
|
-
readonly rows: readonly XlsxRow[];
|
|
84
|
-
/**
|
|
85
|
-
* Optional per-column widths in Excel character units (same scale as
|
|
86
|
-
* SheetJS's `wch`). When set, emits a `<cols>` block so Excel opens
|
|
87
|
-
* the file with the columns sized as specified instead of the default
|
|
88
|
-
* 10-character width. Index aligned with `header` / row cells.
|
|
89
|
-
*
|
|
90
|
-
* Non-finite or non-positive entries are skipped (column falls back
|
|
91
|
-
* to Excel's default width). A consumer typically passes `undefined`
|
|
92
|
-
* for "auto" columns and a number for explicit widths.
|
|
93
|
-
*/
|
|
94
|
-
readonly widths?: ReadonlyArray<number | undefined>;
|
|
95
|
-
/** Data-validation dropdowns applied to ranges on this sheet. */
|
|
96
|
-
readonly validations?: readonly XlsxValidation[];
|
|
97
|
-
}
|
|
98
|
-
/**
|
|
99
|
-
* Build a complete `.xlsx` byte stream from the supplied sheet data.
|
|
100
|
-
* Pure — no I/O beyond the internal zip concatenation.
|
|
101
|
-
*/
|
|
102
|
-
declare function writeXlsx(sheets: readonly XlsxSheet[], options?: {
|
|
103
|
-
definedNames?: ReadonlyArray<{
|
|
104
|
-
readonly name: string;
|
|
105
|
-
readonly ref: string;
|
|
106
|
-
}>;
|
|
107
|
-
}): Promise<Uint8Array>;
|
|
108
|
-
/**
|
|
109
|
-
* Convert a 1-based column index to Excel A1 letter notation.
|
|
110
|
-
* 1 → A, 26 → Z, 27 → AA, 702 → ZZ, 703 → AAA.
|
|
111
|
-
*/
|
|
112
|
-
declare function colLetter(n: number): string;
|
|
113
|
-
|
|
114
|
-
/**
|
|
115
|
-
* Minimal OOXML reader. Inverse of `writeXlsx` in `xlsx.ts`.
|
|
116
|
-
*
|
|
117
|
-
* Walks the three parts the writer emits:
|
|
118
|
-
*
|
|
119
|
-
* - `xl/sharedStrings.xml` → string table (idx → string)
|
|
120
|
-
* - `xl/workbook.xml` → sheet name list (with sheetId)
|
|
121
|
-
* - `xl/_rels/workbook.xml.rels` → sheetId → sheet part path
|
|
122
|
-
* - `xl/worksheets/sheet<N>.xml` → cell data
|
|
123
|
-
*
|
|
124
|
-
* Cell types matched to the writer's emission rules:
|
|
125
|
-
* - no `t` attribute → number (`<v>` is parsed as Number)
|
|
126
|
-
* - `t="s"` → shared-string ref
|
|
127
|
-
* - `t="b"` → boolean (`1` ↔ true, `0` ↔ false)
|
|
128
|
-
* - empty `<c />` → undefined
|
|
129
|
-
*
|
|
130
|
-
* Excel date serials are NOT auto-converted — the writer outputs ISO-
|
|
131
|
-
* 8601 strings via the shared-string path, so dates round-trip as
|
|
132
|
-
* strings unless the consumer opts into `dateFields` coercion (handled
|
|
133
|
-
* one layer up in `index.ts:fromBytes`).
|
|
134
|
-
*
|
|
135
|
-
* @module
|
|
136
|
-
*/
|
|
137
|
-
/** A row of cell values keyed by column letter (`'A' → 'foo'`). */
|
|
138
|
-
type ReadXlsxRow = Record<string, unknown>;
|
|
139
|
-
interface ReadXlsxSheet {
|
|
140
|
-
/** Sheet tab name from `xl/workbook.xml`. */
|
|
141
|
-
readonly name: string;
|
|
142
|
-
/** All rows in declaration order. Columns indexed by Excel letter. */
|
|
143
|
-
readonly rows: readonly ReadXlsxRow[];
|
|
144
|
-
}
|
|
145
|
-
interface ReadXlsxResult {
|
|
146
|
-
readonly sheets: readonly ReadXlsxSheet[];
|
|
147
|
-
}
|
|
148
|
-
/**
|
|
149
|
-
* Decode an `.xlsx` (OOXML) byte stream into per-sheet row data. The
|
|
150
|
-
* caller decides what to do with the rows (header inference, type
|
|
151
|
-
* coercion, record building) — the reader stays format-only.
|
|
152
|
-
*
|
|
153
|
-
* Throws on malformed XML, missing parts, or sheet-id mismatches.
|
|
154
|
-
*/
|
|
155
|
-
declare function readXlsx(bytes: Uint8Array): Promise<ReadXlsxResult>;
|
|
156
|
-
|
|
157
|
-
type InferredType = 'string' | 'number' | 'boolean' | 'date';
|
|
158
|
-
interface InferredField {
|
|
159
|
-
readonly type: InferredType;
|
|
160
|
-
/** Target collection (sheet) name when this field looks like a foreign key. */
|
|
161
|
-
readonly references?: string;
|
|
162
|
-
}
|
|
163
|
-
interface InferredCollection {
|
|
164
|
-
readonly idField: string;
|
|
165
|
-
readonly fields: Record<string, InferredField>;
|
|
166
|
-
}
|
|
167
|
-
interface InferredSchema {
|
|
168
|
-
readonly collections: Record<string, InferredCollection>;
|
|
169
|
-
}
|
|
170
|
-
/**
|
|
171
|
-
* Infer a {@link InferredSchema} from an `.xlsx` byte stream. Sheets whose name
|
|
172
|
-
* starts with `_` (our smart-export meta sheets) are skipped; pass `skipSheets`
|
|
173
|
-
* to exclude more (e.g. summary sheets).
|
|
174
|
-
*/
|
|
175
|
-
declare function inferSchema(bytes: Uint8Array, options?: {
|
|
176
|
-
skipSheets?: readonly string[];
|
|
177
|
-
}): Promise<InferredSchema>;
|
|
178
|
-
/** Emit a Zod schema snippet (guidance) from an {@link InferredSchema}. */
|
|
179
|
-
declare function zodSourceFor(schema: InferredSchema): string;
|
|
180
|
-
|
|
181
|
-
/**
|
|
182
|
-
* **@noy-db/as-xlsx** — Excel spreadsheet plaintext export for noy-db.
|
|
183
|
-
*
|
|
184
|
-
* Produces a real `.xlsx` file (Office Open XML / OOXML) from one
|
|
185
|
-
* or more noy-db collections. Opens natively in Excel, Numbers,
|
|
186
|
-
* LibreOffice Calc, Google Sheets, and every modern spreadsheet
|
|
187
|
-
* tool.
|
|
188
|
-
*
|
|
189
|
-
* Zero runtime dependencies — the XLSX encoder builds the required
|
|
190
|
-
* SpreadsheetML parts and assembles them with
|
|
191
|
-
* `@noy-db/as-zip`'s `writeZip()` (STORE method; most xlsx
|
|
192
|
-
* contents are XML text which Excel compresses at open time anyway).
|
|
193
|
-
*
|
|
194
|
-
* Part of the `@noy-db/as-*` portable-artefact family, plaintext
|
|
195
|
-
* tier. See [`docs/patterns/as-exports.md`](https://github.com/vLannaAi/noy-db/blob/main/docs/patterns/as-exports.md).
|
|
196
|
-
*
|
|
197
|
-
* ## Authorisation
|
|
198
|
-
*
|
|
199
|
-
* Every call is gated by `assertCanExport('plaintext', 'xlsx')`.
|
|
200
|
-
*
|
|
201
|
-
* ```ts
|
|
202
|
-
* await db.grant('firm', {
|
|
203
|
-
* userId: 'accountant', role: 'viewer', passphrase: '…',
|
|
204
|
-
* exportCapability: { plaintext: ['xlsx'] },
|
|
205
|
-
* })
|
|
206
|
-
* ```
|
|
207
|
-
*
|
|
208
|
-
* @packageDocumentation
|
|
209
|
-
*/
|
|
210
|
-
|
|
211
|
-
/** Per-sheet options for the noy-db consumer API. */
|
|
212
|
-
interface AsXlsxSheetOptions {
|
|
213
|
-
/**
|
|
214
|
-
* Sheet tab name. Excel caps at 31 chars; longer names are
|
|
215
|
-
* truncated with `…`. Duplicates are suffixed `(2)`, `(3)`.
|
|
216
|
-
*/
|
|
217
|
-
readonly name: string;
|
|
218
|
-
/** Source collection. Must be in the caller's read ACL. */
|
|
219
|
-
readonly collection: string;
|
|
220
|
-
/**
|
|
221
|
-
* Field list + order. When omitted, columns are inferred from
|
|
222
|
-
* the union of keys across all records (first-record-wins order).
|
|
223
|
-
*/
|
|
224
|
-
readonly columns?: readonly string[];
|
|
225
|
-
/**
|
|
226
|
-
* Optional predicate against each decrypted record. Runs after
|
|
227
|
-
* decryption; doesn't reduce I/O.
|
|
228
|
-
*/
|
|
229
|
-
readonly filter?: (record: unknown) => boolean;
|
|
230
|
-
/**
|
|
231
|
-
* Optional per-column character widths (Excel `wch` units). When set,
|
|
232
|
-
* the emitted sheet opens with the requested column widths instead of
|
|
233
|
-
* Excel's default 10-character fallback. Index aligned with
|
|
234
|
-
* `columns` / inferred-column order.
|
|
235
|
-
*
|
|
236
|
-
* Non-finite or non-positive entries are skipped so consumers can
|
|
237
|
-
* mix explicit + auto (pass `undefined` for "auto").
|
|
238
|
-
*
|
|
239
|
-
* Length is NOT validated against `columns.length` — extra entries
|
|
240
|
-
* are harmless (no `<col>` is emitted past the column count) and a
|
|
241
|
-
* short array leaves trailing columns at Excel's default. This
|
|
242
|
-
* mirrors `XlsxSheet.widths`, which it threads through.
|
|
243
|
-
*/
|
|
244
|
-
readonly widths?: ReadonlyArray<number | undefined>;
|
|
245
|
-
/**
|
|
246
|
-
* Smart mode only: per-field Excel number-format codes (e.g.
|
|
247
|
-
* `{ amount: '#,##0.00' }` for currency). The value is coerced to a number so
|
|
248
|
-
* the format renders. Money has no introspection signal, so currency
|
|
249
|
-
* formatting is opt-in here.
|
|
250
|
-
*/
|
|
251
|
-
readonly numberFormats?: Record<string, string>;
|
|
252
|
-
/**
|
|
253
|
-
* Smart mode only: per-field explicit dropdown value lists. Overrides the
|
|
254
|
-
* auto-detected enum/ref dropdown for that field.
|
|
255
|
-
*/
|
|
256
|
-
readonly dropdowns?: Record<string, readonly string[]>;
|
|
257
|
-
/**
|
|
258
|
-
* Smart mode only: fields whose stored value is a multi-locale i18n map
|
|
259
|
-
* (`{ en: '…', th: '…' }`). Each becomes per-locale columns plus a display
|
|
260
|
-
* column resolved **live by the global LANG cell** (change LANG → every label
|
|
261
|
-
* re-renders). Read raw, so open the export vault without an active locale.
|
|
262
|
-
*/
|
|
263
|
-
readonly i18nFields?: readonly string[];
|
|
264
|
-
/**
|
|
265
|
-
* Smart mode only: map a dict-backed (code) field to its dictionary name, e.g.
|
|
266
|
-
* `{ status: 'status' }`. Emits a hidden `_Lookups_<dict>` sheet (code +
|
|
267
|
-
* per-locale labels) and a `<field>__label` display column resolved by the
|
|
268
|
-
* global LANG cell via `VLOOKUP(code, …, MATCH(LANG, …))`.
|
|
269
|
-
*/
|
|
270
|
-
readonly dictFields?: Record<string, string>;
|
|
271
|
-
/**
|
|
272
|
-
* Multi-vault export only: pull FK-referenced fields from a supporting vault
|
|
273
|
-
* into this sheet as extra columns. Each entry resolves `localField` on the
|
|
274
|
-
* primary record against the `keyField` of another vault's collection (matched
|
|
275
|
-
* by `from.label`/`from.collection`), and emits the `pick` field value as
|
|
276
|
-
* `column`. Appended AFTER the declared `columns` in declaration order.
|
|
277
|
-
* Unresolved FK (row not in the supporting-vault index) → empty cell.
|
|
278
|
-
* Ignored by single-vault `toBytes`.
|
|
279
|
-
*/
|
|
280
|
-
readonly denormalize?: readonly MultiVaultDenormColumn[];
|
|
281
|
-
}
|
|
282
|
-
/**
|
|
283
|
-
* One denormalized column in a multi-vault export: pulls a field from a
|
|
284
|
-
* supporting vault into the primary sheet via an in-memory join.
|
|
285
|
-
*
|
|
286
|
-
* @example
|
|
287
|
-
* ```ts
|
|
288
|
-
* {
|
|
289
|
-
* column: 'entityName', // new column header in the primary sheet
|
|
290
|
-
* localField: 'entityId', // FK field on the primary record
|
|
291
|
-
* from: { label: 'directory', collection: 'entities', keyField: 'id', pick: 'name' },
|
|
292
|
-
* }
|
|
293
|
-
* ```
|
|
294
|
-
*/
|
|
295
|
-
interface MultiVaultDenormColumn {
|
|
296
|
-
/** Header of the new column to append to the primary sheet. */
|
|
297
|
-
readonly column: string;
|
|
298
|
-
/** Field on the primary record whose value is the FK. */
|
|
299
|
-
readonly localField: string;
|
|
300
|
-
readonly from: {
|
|
301
|
-
/** Label of the supporting vault entry (matches `MultiVaultXlsxEntry.label`). */
|
|
302
|
-
readonly label: string;
|
|
303
|
-
/** Collection in the supporting vault. */
|
|
304
|
-
readonly collection: string;
|
|
305
|
-
/** Field in the supporting record that is the join key (usually `'id'`). */
|
|
306
|
-
readonly keyField: string;
|
|
307
|
-
/** Field in the supporting record to copy as the denorm value. */
|
|
308
|
-
readonly pick: string;
|
|
309
|
-
};
|
|
310
|
-
}
|
|
311
|
-
/** One aggregate column in a smart-mode summary sheet (#414 P3). */
|
|
312
|
-
interface AsXlsxSummaryAggregate {
|
|
313
|
-
/** Column header for this aggregate. */
|
|
314
|
-
readonly label: string;
|
|
315
|
-
readonly op: 'sum' | 'count' | 'avg';
|
|
316
|
-
/** Field to aggregate — required for `sum`/`avg`, ignored for `count`. */
|
|
317
|
-
readonly field?: string;
|
|
318
|
-
}
|
|
319
|
-
/**
|
|
320
|
-
* A groupBy summary sheet (#414 P3): groups the source collection's sheet by
|
|
321
|
-
* `groupBy` and emits live SUMIFS/COUNTIFS/AVERAGEIFS columns (values cached at
|
|
322
|
-
* export). The source value columns must be numeric for the live formulas to
|
|
323
|
-
* compute (apply `numberFormats` to money fields).
|
|
324
|
-
*/
|
|
325
|
-
interface AsXlsxSummarySpec {
|
|
326
|
-
/** Summary sheet name. */
|
|
327
|
-
readonly name: string;
|
|
328
|
-
/** Source collection (must be exported as a sheet). */
|
|
329
|
-
readonly from: string;
|
|
330
|
-
/** Field to group by. */
|
|
331
|
-
readonly groupBy: string;
|
|
332
|
-
readonly aggregates: readonly AsXlsxSummaryAggregate[];
|
|
333
|
-
}
|
|
334
|
-
/** Single-collection convenience — passed where a sheet-list is accepted. */
|
|
335
|
-
interface AsXlsxOptions {
|
|
336
|
-
/** One or more sheets. At least one required. */
|
|
337
|
-
readonly sheets: readonly AsXlsxSheetOptions[];
|
|
338
|
-
/** Smart mode only: groupBy summary sheets (live SUMIFS/COUNTIFS/AVERAGEIFS). */
|
|
339
|
-
readonly summaries?: readonly AsXlsxSummarySpec[];
|
|
340
|
-
/**
|
|
341
|
-
* Smart mode only: summary formula dialect. `'excel'` (default) emits
|
|
342
|
-
* cross-compatible per-row SUMIFS/COUNTIFS/AVERAGEIFS. `'sheets'` emits a
|
|
343
|
-
* single Google-Sheets `QUERY` formula per summary — **Sheets-only** (QUERY
|
|
344
|
-
* errors in Excel); use when the target is Google Sheets.
|
|
345
|
-
*/
|
|
346
|
-
readonly dialect?: 'excel' | 'sheets';
|
|
347
|
-
/**
|
|
348
|
-
* Smart-workbook mode (#414). Emits a relational workbook instead of a flat
|
|
349
|
-
* dump:
|
|
350
|
-
* - every sheet is **id-first** (record `id` in column A);
|
|
351
|
-
* - each foreign-key field (auto-detected via `vault.dumpSchema()`) gets a
|
|
352
|
-
* `<field>__label` column — a cross-sheet `VLOOKUP` that resolves the
|
|
353
|
-
* reference to the target's first field, carrying a **cached** label so it
|
|
354
|
-
* shows immediately and recomputes live on edit;
|
|
355
|
-
* - a `_manifest` index sheet lists every collection, its row count, and
|
|
356
|
-
* its refs.
|
|
357
|
-
*
|
|
358
|
-
* Requires unique sheet names ≤ 31 chars (so cross-sheet refs resolve) and an
|
|
359
|
-
* `id` field on records. Defaults to the existing flat export when omitted.
|
|
360
|
-
*/
|
|
361
|
-
readonly smart?: boolean;
|
|
362
|
-
}
|
|
363
|
-
/** Options for `download()` — adds optional filename. */
|
|
364
|
-
interface AsXlsxDownloadOptions extends AsXlsxOptions {
|
|
365
|
-
/** Filename offered to the browser. Default `'export.xlsx'`. */
|
|
366
|
-
readonly filename?: string;
|
|
367
|
-
}
|
|
368
|
-
/** Options for `write()` — requires explicit risk acknowledgement. */
|
|
369
|
-
interface AsXlsxWriteOptions extends AsXlsxOptions {
|
|
370
|
-
/** Tier 3 egress — see `docs/patterns/as-exports.md`. */
|
|
371
|
-
readonly acknowledgeRisks: true;
|
|
372
|
-
}
|
|
373
|
-
/**
|
|
374
|
-
* Convenience — single-collection shorthand. Equivalent to
|
|
375
|
-
* `toBytes(vault, { sheets: [{ name: collectionName, collection: collectionName }] })`.
|
|
376
|
-
*/
|
|
377
|
-
declare function toBytesFromCollection(vault: Vault, collectionName: string): Promise<Uint8Array>;
|
|
378
|
-
/**
|
|
379
|
-
* Build the `.xlsx` byte stream from one or more sheets. Pure
|
|
380
|
-
* beyond the auth check + store reads.
|
|
381
|
-
*/
|
|
382
|
-
declare function toBytes(vault: Vault, options: AsXlsxOptions): Promise<Uint8Array>;
|
|
383
|
-
/**
|
|
384
|
-
* Browser download. Requires a browser-like environment with
|
|
385
|
-
* `URL.createObjectURL` + `document.createElement`.
|
|
386
|
-
*/
|
|
387
|
-
declare function download(vault: Vault, options: AsXlsxDownloadOptions): Promise<void>;
|
|
388
|
-
/**
|
|
389
|
-
* Node file-write. Requires `acknowledgeRisks: true` because the
|
|
390
|
-
* plaintext xlsx persists past the process (Tier 3 egress).
|
|
391
|
-
*/
|
|
392
|
-
declare function write(vault: Vault, path: string, options: AsXlsxWriteOptions): Promise<void>;
|
|
393
|
-
/**
|
|
394
|
-
* One vault entry in a multi-vault export. Supplies the pre-opened
|
|
395
|
-
* vault, the sheet specs to render for it, and an optional closure
|
|
396
|
-
* (per-collection id allowlist computed externally by the orchestrator).
|
|
397
|
-
*/
|
|
398
|
-
interface MultiVaultXlsxEntry {
|
|
399
|
-
readonly vault: Vault;
|
|
400
|
-
readonly sheets: readonly AsXlsxSheetOptions[];
|
|
401
|
-
/**
|
|
402
|
-
* Optional per-collection id allowlist (e.g. from walkCrossVaultClosure).
|
|
403
|
-
* When set, only rows whose `id` appears in the set are exported for that
|
|
404
|
-
* collection. Omit to export all rows.
|
|
405
|
-
*/
|
|
406
|
-
readonly closure?: ReadonlyMap<string, ReadonlySet<string>>;
|
|
407
|
-
/**
|
|
408
|
-
* Optional display label for sheet-name prefixing.
|
|
409
|
-
* Defaults to `vault.name`.
|
|
410
|
-
*/
|
|
411
|
-
readonly label?: string;
|
|
412
|
-
}
|
|
413
|
-
/** Options for {@link toBytesMultiVault}. */
|
|
414
|
-
interface MultiVaultXlsxOptions {
|
|
415
|
-
/**
|
|
416
|
-
* Separator inserted between the vault label and the sheet name when
|
|
417
|
-
* building tab names. Default `'_'`. Names are then truncated to 31 chars
|
|
418
|
-
* (Excel limit) by `writeXlsx`.
|
|
419
|
-
*/
|
|
420
|
-
readonly sheetSeparator?: string;
|
|
421
|
-
}
|
|
422
|
-
/**
|
|
423
|
-
* Build an `.xlsx` byte stream spanning **multiple vaults**. Each entry
|
|
424
|
-
* supplies a pre-opened vault with its sheet specs and an optional
|
|
425
|
-
* per-collection id-closure (rows filtered to exactly those ids). A
|
|
426
|
-
* `_manifest` sheet is prepended that lists every vault-collection pair
|
|
427
|
-
* and its exported record count.
|
|
428
|
-
*
|
|
429
|
-
* ## Auth
|
|
430
|
-
* Every vault in `entries` must independently hold `assertCanExport('plaintext','xlsx')`.
|
|
431
|
-
* The check fires fail-fast before any rows are materialised.
|
|
432
|
-
*
|
|
433
|
-
* ## Architecture
|
|
434
|
-
* This function is **edge-pure** — it takes pre-opened vaults and a
|
|
435
|
-
* pre-computed closure; it performs no cross-vault FK walk itself.
|
|
436
|
-
* Cross-vault orchestration lives in the outward orchestration layer (allowed direction).
|
|
437
|
-
*
|
|
438
|
-
* ## Two-pass execution (when `denormalize` is declared)
|
|
439
|
-
* **Pass 1** — load and closure-filter ALL entries' rows, building a
|
|
440
|
-
* `Map<"${label}/${collection}", Map<keyValue, row>>` index keyed by each
|
|
441
|
-
* sheet's `keyField` (default `'id'`). Only closure-filtered rows are indexed,
|
|
442
|
-
* so an FK pointing outside the closure yields an empty cell (correct: that
|
|
443
|
-
* row was not referenced / not exported).
|
|
444
|
-
* **Pass 2** — emit each sheet; for sheets with `denormalize`, append each
|
|
445
|
-
* denorm column AFTER the declared columns by resolving the index lookup.
|
|
446
|
-
*/
|
|
447
|
-
declare function toBytesMultiVault(entries: readonly MultiVaultXlsxEntry[], options?: MultiVaultXlsxOptions): Promise<Uint8Array>;
|
|
448
|
-
|
|
449
|
-
type ImportPolicy = 'merge' | 'replace' | 'insert-only';
|
|
450
|
-
/**
|
|
451
|
-
* Thrown when a dict field contains two different keys whose labels are
|
|
452
|
-
* identical in any locale — making label→key inversion ambiguous.
|
|
453
|
-
*
|
|
454
|
-
* @example
|
|
455
|
-
* dict has: { key: 'a', labels: { en: 'Open' } } and { key: 'b', labels: { th: 'Open' } }
|
|
456
|
-
* → XlsxDictAmbiguityError('status', 'Open')
|
|
457
|
-
*/
|
|
458
|
-
declare class XlsxDictAmbiguityError extends Error {
|
|
459
|
-
readonly column: string;
|
|
460
|
-
readonly label: string;
|
|
461
|
-
constructor(column: string, label: string);
|
|
462
|
-
}
|
|
463
|
-
interface AsXlsxImportOptions {
|
|
464
|
-
/** Target collection. xlsx has no native collection grouping. */
|
|
465
|
-
readonly collection: string;
|
|
466
|
-
/**
|
|
467
|
-
* Sheet name to read. Defaults to the first sheet in the workbook.
|
|
468
|
-
*/
|
|
469
|
-
readonly sheet?: string;
|
|
470
|
-
/**
|
|
471
|
-
* 1-based header row index. Default `1` (first row).
|
|
472
|
-
*/
|
|
473
|
-
readonly headerRow?: number;
|
|
474
|
-
/**
|
|
475
|
-
* Optional field type hints. xlsx cells already have a type
|
|
476
|
-
* (number, boolean, shared-string), so this is for the few cases
|
|
477
|
-
* where the writer's emission rules don't preserve intent —
|
|
478
|
-
* notably ISO-date strings the writer routed through the shared-
|
|
479
|
-
* string path. `'date'` parses the value with `new Date()` and
|
|
480
|
-
* keeps the result as an ISO-8601 string for stable round-tripping.
|
|
481
|
-
*/
|
|
482
|
-
readonly fieldTypes?: Record<string, 'string' | 'number' | 'boolean' | 'date'>;
|
|
483
|
-
/** Field carrying the record id. Default `'id'`. */
|
|
484
|
-
readonly idKey?: string;
|
|
485
|
-
/** Reconciliation policy. Default `'merge'`. */
|
|
486
|
-
readonly policy?: ImportPolicy;
|
|
487
|
-
/**
|
|
488
|
-
* Per-field dict definitions for label→key inversion. When a column
|
|
489
|
-
* header matches a key here, cell values are matched against every
|
|
490
|
-
* locale label in the dict entries; matching labels are replaced by
|
|
491
|
-
* their stable key before building the ImportPlan.
|
|
492
|
-
*
|
|
493
|
-
* Takes precedence over any vault dictionary with the same name.
|
|
494
|
-
* For fields not listed here, `fromBytes` automatically tries
|
|
495
|
-
* `vault.dictionary(fieldName).list()` as a fallback.
|
|
496
|
-
*
|
|
497
|
-
* Unknown labels (no match in any locale) pass through as-is.
|
|
498
|
-
*/
|
|
499
|
-
readonly dicts?: Readonly<Record<string, readonly DictEntry[]>>;
|
|
500
|
-
/**
|
|
501
|
-
* Read a sheet produced by smart export (#414 P4). Reverses the smart layout:
|
|
502
|
-
* reconstructs i18n fields from their per-locale columns (`<f>__<loc>` →
|
|
503
|
-
* `{ loc: value }`), and drops derived columns — the i18n display column and
|
|
504
|
-
* every `<f>__label` (FK/dict) formula column. Code columns (the real values)
|
|
505
|
-
* pass through. Maps onto the existing collection schema (Mode A).
|
|
506
|
-
*/
|
|
507
|
-
readonly smart?: boolean;
|
|
508
|
-
}
|
|
509
|
-
interface AsXlsxImportPlan {
|
|
510
|
-
readonly plan: VaultDiff;
|
|
511
|
-
readonly policy: ImportPolicy;
|
|
512
|
-
apply(): Promise<void>;
|
|
513
|
-
}
|
|
514
|
-
/**
|
|
515
|
-
* Build an import plan from an `.xlsx` byte stream. Inverts what
|
|
516
|
-
* `toBytes()` writes — the first row is the header, subsequent rows
|
|
517
|
-
* are records keyed by the column letters in the header row.
|
|
518
|
-
*
|
|
519
|
-
* Capability: `assertCanImport('plaintext', 'xlsx')`.
|
|
520
|
-
* Atomicity: `apply()` runs inside `vault.noydb.transaction()`.
|
|
521
|
-
*
|
|
522
|
-
* **Not supported (matches the writer scope):**
|
|
523
|
-
* - Cell styles / number formats / date format codes
|
|
524
|
-
* - Formulas, merged cells, frozen panes
|
|
525
|
-
* - Inline strings → handled defensively (since some upstream tools
|
|
526
|
-
* emit them) but the writer never produces them
|
|
527
|
-
* - Excel date serials → not auto-detected; pass `fieldTypes: { ts:
|
|
528
|
-
* 'date' }` to coerce a numeric serial to ISO. Date round-trip via
|
|
529
|
-
* the writer (which emits ISO strings) works without a hint.
|
|
530
|
-
*
|
|
531
|
-
* **Dict-label inversion** — supply `dicts` per field (or populate vault
|
|
532
|
-
* dictionaries with `withI18n()`) and the reader automatically inverts
|
|
533
|
-
* human labels back to their stable keys. Ambiguous labels throw
|
|
534
|
-
* `XlsxDictAmbiguityError`; unknown labels pass through unchanged.
|
|
535
|
-
*/
|
|
536
|
-
declare function fromBytes(vault: Vault, bytes: Uint8Array, options: AsXlsxImportOptions): Promise<AsXlsxImportPlan>;
|
|
537
|
-
|
|
538
|
-
export { type AsXlsxDownloadOptions, type AsXlsxImportOptions, type AsXlsxImportPlan, type AsXlsxOptions, type AsXlsxSheetOptions, type AsXlsxSummaryAggregate, type AsXlsxSummarySpec, type AsXlsxWriteOptions, type ImportPolicy, type InferredCollection, type InferredField, type InferredSchema, type InferredType, type MultiVaultDenormColumn, type MultiVaultXlsxEntry, type MultiVaultXlsxOptions, type ReadXlsxResult, type ReadXlsxRow, type ReadXlsxSheet, XlsxDictAmbiguityError, type XlsxFormulaCell, type XlsxRow, type XlsxSheet, type XlsxStyledCell, type XlsxValidation, colLetter, download, formula, fromBytes, inferSchema, readXlsx, styled, toBytes, toBytesFromCollection, toBytesMultiVault, write, writeXlsx, zodSourceFor };
|