@sigrun/shared 0.1.2 → 0.2.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.
Files changed (48) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/package.json +1 -1
  3. package/dist/access.d.ts +0 -55
  4. package/dist/access.js +0 -72
  5. package/dist/ambient.d.ts +0 -111
  6. package/dist/ambient.js +0 -23
  7. package/dist/blocks/format.d.ts +0 -28
  8. package/dist/blocks/format.js +0 -199
  9. package/dist/blocks/icons.d.ts +0 -12
  10. package/dist/blocks/icons.js +0 -64
  11. package/dist/blocks/index.d.ts +0 -25
  12. package/dist/blocks/index.js +0 -21
  13. package/dist/blocks/instance.d.ts +0 -29
  14. package/dist/blocks/instance.js +0 -51
  15. package/dist/blocks/lttb.d.ts +0 -16
  16. package/dist/blocks/lttb.js +0 -67
  17. package/dist/blocks/ops.d.ts +0 -44
  18. package/dist/blocks/ops.js +0 -294
  19. package/dist/blocks/text.d.ts +0 -43
  20. package/dist/blocks/text.js +0 -790
  21. package/dist/blocks/transport.d.ts +0 -77
  22. package/dist/blocks/transport.js +0 -11
  23. package/dist/blocks/types.d.ts +0 -541
  24. package/dist/blocks/types.js +0 -17
  25. package/dist/commands.d.ts +0 -75
  26. package/dist/commands.js +0 -25
  27. package/dist/conversations.d.ts +0 -31
  28. package/dist/conversations.js +0 -94
  29. package/dist/interactions.d.ts +0 -91
  30. package/dist/interactions.js +0 -21
  31. package/dist/jobs.d.ts +0 -109
  32. package/dist/jobs.js +0 -19
  33. package/dist/json.d.ts +0 -20
  34. package/dist/json.js +0 -13
  35. package/dist/live.d.ts +0 -71
  36. package/dist/live.js +0 -82
  37. package/dist/session-meta.d.ts +0 -119
  38. package/dist/session-meta.js +0 -13
  39. package/dist/settings.d.ts +0 -408
  40. package/dist/settings.js +0 -19
  41. package/dist/themes.d.ts +0 -50
  42. package/dist/themes.js +0 -156
  43. package/dist/turns.d.ts +0 -119
  44. package/dist/turns.js +0 -197
  45. package/dist/view-delta.d.ts +0 -54
  46. package/dist/view-delta.js +0 -135
  47. package/dist/views.d.ts +0 -822
  48. package/dist/views.js +0 -38
@@ -1,51 +0,0 @@
1
- /**
2
- * The instance-key helpers the CHANNELS need (UI-blocks U3 Task 5, spec
3
- * §7.3): `canonicalJson` (the default `instanceKey`) and
4
- * `eventKeyWeb`/`eventKeyNode` (the wire `k` — sha256 hex of
5
- * `slug\0id\0key`). The server's copy lives in
6
- * `src/server/surfaces/instance.ts`; these are the DOM- and Node-safe
7
- * twins (WebCrypto's `crypto.subtle.digest` vs `node:crypto`), kept
8
- * byte-compatible by the shared canonical-JSON rule.
9
- *
10
- * The wire's purity rule holds: NO node: imports here — the Node flavor
11
- * is a separate module (`instance-node.ts`) so the webui never sees it.
12
- */
13
- /**
14
- * Canonical JSON: every object serializes with keys SORTED (recursive);
15
- * primitives and arrays serialize as usual. Two params objects equal up
16
- * to key order produce byte-identical strings — the same rule as the
17
- * server's `canonicalJson` (kept in sync by hand; both sides pin it by
18
- * test).
19
- */
20
- export function canonicalJson(value) {
21
- if (Array.isArray(value)) {
22
- return `[${value.map((entry) => canonicalJson(entry)).join(",")}]`;
23
- }
24
- if (typeof value === "object" && value !== null) {
25
- const keys = Object.keys(value).sort();
26
- const parts = keys.map((key) => `${JSON.stringify(key)}:${canonicalJson(value[key])}`);
27
- return `{${parts.join(",")}}`;
28
- }
29
- return JSON.stringify(value);
30
- }
31
- /** The default instance key (spec §7.3): canonical JSON of the params. */
32
- export function instanceKey(params) {
33
- return canonicalJson(params);
34
- }
35
- /** The hex encoding of a sha256 digest buffer. */
36
- function hex(buffer) {
37
- const bytes = buffer instanceof Uint8Array ? buffer : new Uint8Array(buffer);
38
- let out = "";
39
- for (const byte of bytes)
40
- out += byte.toString(16).padStart(2, "0");
41
- return out;
42
- }
43
- /**
44
- * The wire `k` for one surface instance (spec §7.3), WebCrypto flavor:
45
- * `sha256(slug + "\0" + id + "\0" + key)` hex. Async (the DOM digest is
46
- * promise-shaped); the Node twin (`instance-node.ts`) is sync.
47
- */
48
- export async function eventKeyWeb(slug, id, key) {
49
- const digest = await crypto.subtle.digest("SHA-256", new TextEncoder().encode([slug, id, key].join("\u0000")));
50
- return hex(digest);
51
- }
@@ -1,16 +0,0 @@
1
- /**
2
- * Largest-triangle-three-buckets downsampling (UI-blocks spec §5.4):
3
- * the display-side downsample channels apply to line and area series
4
- * (at most 2,000 points per series on the wire; a channel shows fewer).
5
- *
6
- * Pure: returns a fresh array of fresh tuples; never mutates `points`.
7
- */
8
- /**
9
- * Downsample `points` to at most `threshold` points, always keeping the
10
- * first and the last point. The interior is bucketed into `threshold -
11
- * 2` buckets; each bucket keeps the point forming the largest triangle
12
- * with the previously selected point and the next bucket's average —
13
- * which preserves visual shape (peaks and troughs) rather than
14
- * sampling on a fixed interval.
15
- */
16
- export declare function lttb(points: readonly (readonly [number, number])[], threshold: number): [number, number][];
@@ -1,67 +0,0 @@
1
- /**
2
- * Largest-triangle-three-buckets downsampling (UI-blocks spec §5.4):
3
- * the display-side downsample channels apply to line and area series
4
- * (at most 2,000 points per series on the wire; a channel shows fewer).
5
- *
6
- * Pure: returns a fresh array of fresh tuples; never mutates `points`.
7
- */
8
- /**
9
- * Downsample `points` to at most `threshold` points, always keeping the
10
- * first and the last point. The interior is bucketed into `threshold -
11
- * 2` buckets; each bucket keeps the point forming the largest triangle
12
- * with the previously selected point and the next bucket's average —
13
- * which preserves visual shape (peaks and troughs) rather than
14
- * sampling on a fixed interval.
15
- */
16
- export function lttb(points, threshold) {
17
- const count = points.length;
18
- if (count === 0 || threshold <= 0)
19
- return [];
20
- if (threshold === 1)
21
- return [[points[0][0], points[0][1]]];
22
- if (threshold === 2) {
23
- return [
24
- [points[0][0], points[0][1]],
25
- [count === 1 ? points[0][0] : points[count - 1][0],
26
- count === 1 ? points[0][1] : points[count - 1][1]],
27
- ];
28
- }
29
- if (threshold >= count) {
30
- return points.map((point) => [point[0], point[1]]);
31
- }
32
- const sampled = [[points[0][0], points[0][1]]];
33
- const bucketSize = (count - 2) / (threshold - 2);
34
- for (let bucket = 0; bucket < threshold - 2; bucket++) {
35
- const start = Math.floor(1 + bucket * bucketSize);
36
- const end = Math.min(Math.floor(1 + (bucket + 1) * bucketSize), count - 1);
37
- // The average of the NEXT bucket's points — the third corner of
38
- // every candidate triangle. The last bucket averages the final
39
- // point's window [count-1, count).
40
- const nextStart = end;
41
- const nextEnd = Math.min(Math.floor(1 + (bucket + 2) * bucketSize), count);
42
- let avgX = 0;
43
- let avgY = 0;
44
- for (let i = nextStart; i < nextEnd; i++) {
45
- avgX += points[i][0];
46
- avgY += points[i][1];
47
- }
48
- avgX /= nextEnd - nextStart;
49
- avgY /= nextEnd - nextStart;
50
- const previous = sampled[sampled.length - 1];
51
- let bestArea = -1;
52
- let bestIndex = start;
53
- for (let i = start; i < end; i++) {
54
- // Twice the signed area of the triangle (previous, candidate,
55
- // average) — the factor is constant, so abs is enough to rank.
56
- const area = Math.abs((previous[0] - avgX) * (points[i][1] - previous[1]) -
57
- (previous[0] - points[i][0]) * (avgY - previous[1]));
58
- if (area > bestArea) {
59
- bestArea = area;
60
- bestIndex = i;
61
- }
62
- }
63
- sampled.push([points[bestIndex][0], points[bestIndex][1]]);
64
- }
65
- sampled.push([points[count - 1][0], points[count - 1][1]]);
66
- return sampled;
67
- }
@@ -1,44 +0,0 @@
1
- /**
2
- * `applyOps` and `resolvePointer` (UI-blocks spec §4.2/§4.3): the single
3
- * applier every surface's data updates go through, and the pointer
4
- * reader bindings resolve with.
5
- *
6
- * Purity contract:
7
- *
8
- * - `applyOps` NEVER mutates its input — it clones along the touched
9
- * path only (copy-on-write), so a batch of ops over a large document
10
- * shares every untouched branch by reference with the input. The
11
- * property suite pins this (frozen inputs, snapshot equality).
12
- * - Pointers are RFC 6901 with `~0` (`~`) and `~1` (`/`) escaping, plus
13
- * the one extension (spec §4.2): a pointer starting `./` resolves
14
- * against the passed `item` (a collection's item template), which
15
- * only `resolvePointer` takes — the DATA side never sees `./`.
16
- * - A failing op throws `DataOpError` carrying the op's INDEX, so the
17
- * caller (U3/U5) can treat it as the full-refetch signal (spec §16).
18
- */
19
- import type { JsonObject, JsonValue } from "../json.js";
20
- import type { DataOp } from "./types.js";
21
- /** An op that could not be applied; `opIndex` names which one failed. */
22
- export declare class DataOpError extends Error {
23
- readonly opIndex: number;
24
- constructor(opIndex: number, message: string);
25
- }
26
- /**
27
- * Apply a batch of `DataOp`s (spec §4.3) to `data`, returning a NEW
28
- * object. Pure: untouched branches are shared by reference with the
29
- * input; the input is never mutated. Ops apply sequentially — an
30
- * earlier op's write is visible to the next.
31
- *
32
- * Throws `DataOpError` (naming the op's index) on any op whose path
33
- * does not exist, or whose target is not an array where one is required.
34
- */
35
- export declare function applyOps(data: JsonObject, ops: readonly DataOp[]): JsonObject;
36
- /**
37
- * Resolve an RFC 6901 `pointer` against `data`; a pointer starting
38
- * `./` resolves against `item` instead (spec §4.2's one extension,
39
- * used inside collection item templates). A missing path — including a
40
- * path THROUGH a JSON null, and a malformed pointer (no `/` or `./`
41
- * prefix) — is `undefined`, never an error: "a binding to a missing
42
- * path renders as empty, never as an error".
43
- */
44
- export declare function resolvePointer(data: JsonValue, pointer: string, item?: JsonValue): JsonValue | undefined;
@@ -1,294 +0,0 @@
1
- /**
2
- * `applyOps` and `resolvePointer` (UI-blocks spec §4.2/§4.3): the single
3
- * applier every surface's data updates go through, and the pointer
4
- * reader bindings resolve with.
5
- *
6
- * Purity contract:
7
- *
8
- * - `applyOps` NEVER mutates its input — it clones along the touched
9
- * path only (copy-on-write), so a batch of ops over a large document
10
- * shares every untouched branch by reference with the input. The
11
- * property suite pins this (frozen inputs, snapshot equality).
12
- * - Pointers are RFC 6901 with `~0` (`~`) and `~1` (`/`) escaping, plus
13
- * the one extension (spec §4.2): a pointer starting `./` resolves
14
- * against the passed `item` (a collection's item template), which
15
- * only `resolvePointer` takes — the DATA side never sees `./`.
16
- * - A failing op throws `DataOpError` carrying the op's INDEX, so the
17
- * caller (U3/U5) can treat it as the full-refetch signal (spec §16).
18
- */
19
- /** An op that could not be applied; `opIndex` names which one failed. */
20
- export class DataOpError extends Error {
21
- opIndex;
22
- constructor(opIndex, message) {
23
- super(message);
24
- this.name = "DataOpError";
25
- this.opIndex = opIndex;
26
- }
27
- }
28
- function isContainer(value) {
29
- // `typeof null === "object"` — a JSON null is NOT a container; a path
30
- // through it is a missing path (undefined), never a walk into it.
31
- return Array.isArray(value) || (typeof value === "object" && value !== null);
32
- }
33
- /** Split an RFC 6901 pointer into unescaped reference tokens. */
34
- function pointerTokens(pointer) {
35
- if (pointer === "")
36
- return [];
37
- if (!pointer.startsWith("/")) {
38
- throw new Error(`invalid pointer: ${pointer}`);
39
- }
40
- return pointer
41
- .slice(1)
42
- .split("/")
43
- .map((token) => token.replaceAll("~1", "/").replaceAll("~0", "~"));
44
- }
45
- /** Read `token` from a container; `undefined` when absent. */
46
- function readToken(container, token) {
47
- if (Array.isArray(container)) {
48
- if (!/^\d+$/.test(token))
49
- return undefined;
50
- const index = Number(token);
51
- return index < container.length ? container[index] : undefined;
52
- }
53
- return Object.prototype.hasOwnProperty.call(container, token)
54
- ? container[token]
55
- : undefined;
56
- }
57
- /** Parse `key` as an array index valid INSIDE `array` (not for append). */
58
- function arrayIndex(array, key, pointer) {
59
- if (!/^\d+$/.test(key)) {
60
- throw new Error(`not an array index: ${pointer}`);
61
- }
62
- const index = Number(key);
63
- if (index >= array.length) {
64
- throw new Error(`index out of bounds: ${pointer}`);
65
- }
66
- return index;
67
- }
68
- /** Parse `key` as an array index valid for INSERTION (== length allowed). */
69
- function insertIndex(array, key, pointer) {
70
- if (key === "-")
71
- return array.length;
72
- if (!/^\d+$/.test(key)) {
73
- throw new Error(`not an array index: ${pointer}`);
74
- }
75
- const index = Number(key);
76
- if (index > array.length) {
77
- throw new Error(`index out of bounds: ${pointer}`);
78
- }
79
- return index;
80
- }
81
- /**
82
- * READ-ONLY walk: resolve the tokens before the last and return the
83
- * parent container plus the final token. Throws when any step is
84
- * missing or not a container.
85
- */
86
- function resolveParent(root, tokens, opIndex, pointer) {
87
- let node = root;
88
- for (let i = 0; i < tokens.length - 1; i++) {
89
- if (!isContainer(node)) {
90
- throw new DataOpError(opIndex, `path not found: ${pointer}`);
91
- }
92
- const next = readToken(node, tokens[i]);
93
- if (next === undefined) {
94
- throw new DataOpError(opIndex, `path not found: ${pointer}`);
95
- }
96
- node = next;
97
- }
98
- if (!isContainer(node)) {
99
- throw new DataOpError(opIndex, `path not found: ${pointer}`);
100
- }
101
- return { parent: node, key: tokens[tokens.length - 1] };
102
- }
103
- /**
104
- * Clone-on-write rewrite: copies every container along `tokens` from
105
- * `data` down, hands the (fresh, cloned) final container to `mutate`,
106
- * and returns the new root. The input is never touched; branches off
107
- * the path are shared by reference with it.
108
- */
109
- function withWrite(data, tokens, mutate) {
110
- const rootClone = { ...data };
111
- let node = rootClone;
112
- for (let i = 0; i < tokens.length - 1; i++) {
113
- const child = readToken(node, tokens[i]);
114
- if (child === undefined || !isContainer(child)) {
115
- throw new Error(`path not found: /${tokens.join("/")}`);
116
- }
117
- const childClone = Array.isArray(child)
118
- ? [...child]
119
- : { ...child };
120
- if (Array.isArray(node)) {
121
- node[Number(tokens[i])] = childClone;
122
- }
123
- else {
124
- node[tokens[i]] = childClone;
125
- }
126
- node = childClone;
127
- }
128
- mutate(node, tokens[tokens.length - 1]);
129
- return rootClone;
130
- }
131
- /**
132
- * Apply a batch of `DataOp`s (spec §4.3) to `data`, returning a NEW
133
- * object. Pure: untouched branches are shared by reference with the
134
- * input; the input is never mutated. Ops apply sequentially — an
135
- * earlier op's write is visible to the next.
136
- *
137
- * Throws `DataOpError` (naming the op's index) on any op whose path
138
- * does not exist, or whose target is not an array where one is required.
139
- */
140
- export function applyOps(data, ops) {
141
- let current = data;
142
- for (let opIndex = 0; opIndex < ops.length; opIndex++) {
143
- const op = ops[opIndex];
144
- try {
145
- current = applyOne(current, op, opIndex);
146
- }
147
- catch (error) {
148
- if (error instanceof DataOpError)
149
- throw error;
150
- throw new DataOpError(opIndex, `${op.op} ${"path" in op ? op.path : ""}: ${error instanceof Error ? error.message : String(error)}`);
151
- }
152
- }
153
- return current;
154
- }
155
- function applyOne(data, op, opIndex) {
156
- switch (op.op) {
157
- case "set":
158
- return opSet(data, op.path, op.value, opIndex);
159
- case "remove":
160
- return opRemove(data, op.path, opIndex);
161
- case "insert":
162
- return opInsert(data, op.path, op.value, opIndex);
163
- case "move":
164
- return opMove(data, op.from, op.path, opIndex);
165
- }
166
- }
167
- /** `set`: assign at `path` (an existing array slot, or a created object member). */
168
- function opSet(data, path, value, opIndex) {
169
- const tokens = pointerTokens(path);
170
- if (tokens.length === 0) {
171
- throw new DataOpError(opIndex, "set at the root is not allowed");
172
- }
173
- const { parent, key } = resolveParent(data, tokens, opIndex, path);
174
- if (Array.isArray(parent)) {
175
- arrayIndex(parent, key, path); // validate before cloning
176
- }
177
- return withWrite(data, tokens, (container, finalKey) => {
178
- if (Array.isArray(container)) {
179
- container[arrayIndex(container, finalKey, path)] = value;
180
- }
181
- else {
182
- container[finalKey] = value;
183
- }
184
- });
185
- }
186
- /** `remove`: delete the member at `path` (shifting array elements). */
187
- function opRemove(data, path, opIndex) {
188
- const tokens = pointerTokens(path);
189
- if (tokens.length === 0) {
190
- throw new DataOpError(opIndex, "remove at the root is not allowed");
191
- }
192
- const { parent, key } = resolveParent(data, tokens, opIndex, path);
193
- if (Array.isArray(parent)) {
194
- arrayIndex(parent, key, path); // throws (→ opIndex) when out of bounds
195
- }
196
- else if (!Object.prototype.hasOwnProperty.call(parent, key)) {
197
- throw new DataOpError(opIndex, `path not found: ${path}`);
198
- }
199
- return withWrite(data, tokens, (container, finalKey) => {
200
- if (Array.isArray(container)) {
201
- container.splice(arrayIndex(container, finalKey, path), 1);
202
- }
203
- else {
204
- delete container[finalKey];
205
- }
206
- });
207
- }
208
- /** `insert`: insert `value` into the array at `path` (`-` appends). */
209
- function opInsert(data, path, value, opIndex) {
210
- const tokens = pointerTokens(path);
211
- if (tokens.length === 0) {
212
- throw new DataOpError(opIndex, `not an array: ${path}`);
213
- }
214
- const { parent } = resolveParent(data, tokens, opIndex, path);
215
- if (!Array.isArray(parent)) {
216
- throw new DataOpError(opIndex, `not an array: ${path}`);
217
- }
218
- return withWrite(data, tokens, (container, finalKey) => {
219
- if (Array.isArray(container)) {
220
- container.splice(insertIndex(container, finalKey, path), 0, value);
221
- }
222
- });
223
- }
224
- /**
225
- * `move`: remove the item at `from`, then insert it at `path` — a
226
- * reorder within one array or a move across arrays (spec §4.3: it
227
- * exists so reorders don't re-send the moved item). Both ends must be
228
- * array slots; the destination index is resolved against the
229
- * post-removal array.
230
- */
231
- function opMove(data, from, path, opIndex) {
232
- const fromTokens = pointerTokens(from);
233
- const toTokens = pointerTokens(path);
234
- if (fromTokens.length === 0 || toTokens.length === 0) {
235
- throw new DataOpError(opIndex, "move at the root is not allowed");
236
- }
237
- const source = resolveParent(data, fromTokens, opIndex, from);
238
- if (!Array.isArray(source.parent)) {
239
- throw new DataOpError(opIndex, `not an array: ${from}`);
240
- }
241
- const value = readToken(source.parent, source.key);
242
- if (value === undefined) {
243
- throw new DataOpError(opIndex, `path not found: ${from}`);
244
- }
245
- // Remove first: a move into the same array sees post-removal indices.
246
- const removed = withWrite(data, fromTokens, (container, finalKey) => {
247
- if (Array.isArray(container)) {
248
- container.splice(arrayIndex(container, finalKey, from), 1);
249
- }
250
- });
251
- const to = resolveParent(removed, toTokens, opIndex, path);
252
- if (!Array.isArray(to.parent)) {
253
- throw new DataOpError(opIndex, `not an array: ${path}`);
254
- }
255
- return withWrite(removed, toTokens, (container, finalKey) => {
256
- if (Array.isArray(container)) {
257
- container.splice(insertIndex(container, finalKey, path), 0, value);
258
- }
259
- });
260
- }
261
- /**
262
- * Resolve an RFC 6901 `pointer` against `data`; a pointer starting
263
- * `./` resolves against `item` instead (spec §4.2's one extension,
264
- * used inside collection item templates). A missing path — including a
265
- * path THROUGH a JSON null, and a malformed pointer (no `/` or `./`
266
- * prefix) — is `undefined`, never an error: "a binding to a missing
267
- * path renders as empty, never as an error".
268
- */
269
- export function resolvePointer(data, pointer, item) {
270
- const base = pointer.startsWith("./") ? item : data;
271
- if (base === undefined)
272
- return undefined;
273
- const rest = pointer.startsWith("./") ? pointer.slice(1) : pointer;
274
- let tokens;
275
- try {
276
- tokens = pointerTokens(rest);
277
- }
278
- catch {
279
- // A malformed binding renders empty — the render contract is
280
- // undefined-never-throws (only `applyOps`, the server-side applier,
281
- // reports bad pointers, as `DataOpError`).
282
- return undefined;
283
- }
284
- let node = base;
285
- for (const token of tokens) {
286
- if (!isContainer(node))
287
- return undefined;
288
- const next = readToken(node, token);
289
- if (next === undefined)
290
- return undefined;
291
- node = next;
292
- }
293
- return node;
294
- }
@@ -1,43 +0,0 @@
1
- /**
2
- * `toText` (UI-blocks spec §14.3): the deterministic plain-text
3
- * projection of a surface — headings, aligned tables, lists with
4
- * checkboxes and numbers, lanes as sections, charts as one summary
5
- * line per series. Used for the model's view of its own `show_blocks`
6
- * call, the default `fallback` text, extension unit tests, logs and
7
- * notifications.
8
- *
9
- * Determinism (spec §14.3): the same input, width and locale give the
10
- * same bytes, so model context stays cacheable. Three rules make that
11
- * hold:
12
- *
13
- * - object keys are visited in SCHEMA order, never insertion order —
14
- * card slots, log lines, tree nodes and table cells are read through
15
- * their named props, and anything rendered as JSON goes through
16
- * `formatValue`'s sorted-key serializer;
17
- * - no clock reads in the render path: `TextOptions.timeZone` defaults
18
- * to UTC (a datetime projection is stable across hosts; pass a zone
19
- * to localize), and only the `relative` format consults `Date.now()`;
20
- * - unknown blocks render their `fallback`, else
21
- * `[unsupported block: <type>]` (§4.4) — never a throw.
22
- */
23
- import type { Tree } from "./types.js";
24
- import type { JsonObject } from "../json.js";
25
- /** Options for `toText`: the width to wrap at, and the `Intl` locale. */
26
- export interface TextOptions {
27
- /** Wrap target in columns (the §14.3 snapshots use 80 and 160). */
28
- width: number;
29
- /** BCP-47 locale for every `Intl` format. */
30
- locale: string;
31
- /**
32
- * Time zone for datetime renders. Defaults to UTC inside `toText`
33
- * (byte-stable projections across hosts); pass one to localize.
34
- */
35
- timeZone?: string;
36
- }
37
- /**
38
- * Render `tree` against `data` as plain text (spec §14.3).
39
- * Deterministic per (input, width, locale): the same arguments give the
40
- * same bytes. Unknown blocks render their `fallback`, else
41
- * `[unsupported block: <type>]`.
42
- */
43
- export declare function toText(tree: Tree, data: JsonObject, opts: TextOptions): string;