@fuaran-ui/ops 0.1.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/LICENSE +215 -0
- package/README.md +84 -0
- package/dist/index.cjs +9130 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +552 -0
- package/dist/index.d.ts +552 -0
- package/dist/index.js +9080 -0
- package/dist/index.js.map +1 -0
- package/package.json +53 -0
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,552 @@
|
|
|
1
|
+
import { Result, NodeId, NodeKind, JsonValue, Binding, SemanticStyle, StateBehaviour, Node, Cell, ColExpr, DataSource, Transform, EvalError, Table, TextSource, CellFormat, ColumnWidth, Orientation, ToneVariant, StyleWeight, Emphasis, HeadingVariant, BadgeVariant, IconSource } from '@fuaran-ui/schema';
|
|
2
|
+
|
|
3
|
+
/** Local JSON AST. Shape-for-shape port of the F# decoder's private `Json` DU. */
|
|
4
|
+
type JsonAst = {
|
|
5
|
+
readonly kind: 'JNull';
|
|
6
|
+
} | {
|
|
7
|
+
readonly kind: 'JBool';
|
|
8
|
+
readonly value: boolean;
|
|
9
|
+
} | {
|
|
10
|
+
readonly kind: 'JNumber';
|
|
11
|
+
readonly value: number;
|
|
12
|
+
} | {
|
|
13
|
+
readonly kind: 'JString';
|
|
14
|
+
readonly value: string;
|
|
15
|
+
} | {
|
|
16
|
+
readonly kind: 'JArray';
|
|
17
|
+
readonly items: readonly JsonAst[];
|
|
18
|
+
} | {
|
|
19
|
+
readonly kind: 'JObject';
|
|
20
|
+
readonly fields: ReadonlyMap<string, JsonAst>;
|
|
21
|
+
};
|
|
22
|
+
/** Structural parse failure carrying the byte offset where it was detected. */
|
|
23
|
+
interface ParseError {
|
|
24
|
+
readonly message: string;
|
|
25
|
+
readonly offset: number;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Parse a JSON document into the local AST. Mirrors the F# `tryParse`: empty /
|
|
29
|
+
* whitespace-only input is a structural error; otherwise a single top-level
|
|
30
|
+
* value is parsed (trailing content after the first value is not inspected,
|
|
31
|
+
* matching the F# parser).
|
|
32
|
+
*/
|
|
33
|
+
declare const parse: (input: string) => Result<JsonAst, ParseError>;
|
|
34
|
+
/** Look up an object field by key (key-order tolerant per WIRE_FORMAT.md §2). */
|
|
35
|
+
declare const field: (fields: ReadonlyMap<string, JsonAst>, key: string) => JsonAst | undefined;
|
|
36
|
+
|
|
37
|
+
type TreeOp<TMsg> = {
|
|
38
|
+
readonly kind: 'EditNode';
|
|
39
|
+
readonly target: NodeId;
|
|
40
|
+
readonly newKind: NodeKind<TMsg>;
|
|
41
|
+
} | {
|
|
42
|
+
readonly kind: 'UpdateProp';
|
|
43
|
+
readonly target: NodeId;
|
|
44
|
+
readonly path: string;
|
|
45
|
+
readonly value: JsonValue;
|
|
46
|
+
} | {
|
|
47
|
+
readonly kind: 'ReplaceBinding';
|
|
48
|
+
readonly target: NodeId;
|
|
49
|
+
readonly slot: string;
|
|
50
|
+
readonly binding: Binding<unknown>;
|
|
51
|
+
} | {
|
|
52
|
+
readonly kind: 'UpdateStyle';
|
|
53
|
+
readonly target: NodeId;
|
|
54
|
+
readonly style: SemanticStyle;
|
|
55
|
+
} | {
|
|
56
|
+
readonly kind: 'UpdateState';
|
|
57
|
+
readonly target: NodeId;
|
|
58
|
+
readonly state: StateBehaviour<TMsg>;
|
|
59
|
+
} | {
|
|
60
|
+
readonly kind: 'InsertChild';
|
|
61
|
+
readonly parentId: NodeId;
|
|
62
|
+
readonly position: number;
|
|
63
|
+
readonly child: Node<TMsg>;
|
|
64
|
+
} | {
|
|
65
|
+
readonly kind: 'RemoveNode';
|
|
66
|
+
readonly target: NodeId;
|
|
67
|
+
} | {
|
|
68
|
+
readonly kind: 'MoveNode';
|
|
69
|
+
readonly target: NodeId;
|
|
70
|
+
readonly newParentId: NodeId;
|
|
71
|
+
readonly newPosition: number;
|
|
72
|
+
} | {
|
|
73
|
+
readonly kind: 'ReorderChildren';
|
|
74
|
+
readonly parentId: NodeId;
|
|
75
|
+
readonly newOrder: readonly NodeId[];
|
|
76
|
+
} | {
|
|
77
|
+
readonly kind: 'ReplaceRoot';
|
|
78
|
+
readonly node: Node<TMsg>;
|
|
79
|
+
} | {
|
|
80
|
+
readonly kind: 'Batch';
|
|
81
|
+
readonly ops: readonly TreeOp<TMsg>[];
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Re-render a parsed JSON AST (parse.ts) to canonical wire bytes — Ordinal-
|
|
86
|
+
* sorted object keys (§2 rule 2), the §2 rule-5 number layout, the §2 rule-6
|
|
87
|
+
* string escapes — using the very primitives the encoder uses. For input that
|
|
88
|
+
* was already canonical, `renderAstCanonical(parse(x)) === x`. This is the
|
|
89
|
+
* §15 wire-versioning building block: it re-emits a preserved `Unknown`
|
|
90
|
+
* payload byte-for-byte (must-ignore-but-preserve, WIRE_FORMAT.md §15.3) and
|
|
91
|
+
* renders the `$profile` / `$payload` envelope. Mirrors F#
|
|
92
|
+
* `Fuaran.Core.Wire.Canon.render` composed over the same JVal shape.
|
|
93
|
+
*/
|
|
94
|
+
declare const renderAstCanonical: (ast: JsonAst) => string;
|
|
95
|
+
/** Encode a `DataSource` to its canonical-JSON string (Compute layer). */
|
|
96
|
+
declare const encodeDataSource: (src: DataSource) => string;
|
|
97
|
+
/** Encode a literal `Cell` to its `$type`-tagged canonical-JSON string. */
|
|
98
|
+
declare const encodeCell: (c: Cell) => string;
|
|
99
|
+
/** Encode a `ColExpr` to its canonical-JSON string. */
|
|
100
|
+
declare const encodeColExpr: (e: ColExpr) => string;
|
|
101
|
+
/** Encode a transform `pipeline` (ordered steps) to its canonical-JSON array string. */
|
|
102
|
+
declare const encodePipeline: (pipeline: readonly Transform[]) => string;
|
|
103
|
+
/** Encode a `Node<TMsg>` to its canonical-JSON string (WIRE_FORMAT.md). */
|
|
104
|
+
declare const encodeNode: <TMsg>(n: Node<TMsg>) => string;
|
|
105
|
+
/** Encode a `TreeOp<TMsg>` to its canonical-JSON string (WIRE_FORMAT.md). */
|
|
106
|
+
declare const encodeOp: <TMsg>(op: TreeOp<TMsg>) => string;
|
|
107
|
+
|
|
108
|
+
type DR<T> = Result<T, EvalError>;
|
|
109
|
+
/** The canonical string of a cell (float via the shared `Canon` layout). */
|
|
110
|
+
declare const cellString: (c: Cell) => string;
|
|
111
|
+
/** Evaluate a `ColExpr` against one row. */
|
|
112
|
+
/** The evaluation environment (fuaran-core#77) — binds each `ColExpr.param` name to a `Cell`. */
|
|
113
|
+
type EvalEnv = Readonly<Record<string, Cell>>;
|
|
114
|
+
/** Resolve a `Ref` source to a concrete `Table` (default: reject every ref). */
|
|
115
|
+
type SourceResolver = (ref: string) => DR<Table>;
|
|
116
|
+
/** A `Ref`-rejecting resolver — the default for embedded-only pipelines. */
|
|
117
|
+
declare const noResolve: SourceResolver;
|
|
118
|
+
/** Evaluate a `DataSource` to a concrete `Table`, resolving a `Ref` through `resolve`. */
|
|
119
|
+
declare const evalSource: (resolve: SourceResolver, src: DataSource) => DR<Table>;
|
|
120
|
+
/**
|
|
121
|
+
* The reference evaluator: fold the pipeline over the input table, threading a
|
|
122
|
+
* `Frame`. `resolve` provides any `Ref` source a `Join` / `Union` names.
|
|
123
|
+
*/
|
|
124
|
+
declare const evalPipelineWithInEnv: (resolve: SourceResolver, env: EvalEnv, pipeline: readonly Transform[], input: Table) => DR<Table>;
|
|
125
|
+
declare const evalPipelineWith: (resolve: SourceResolver, pipeline: readonly Transform[], input: Table) => DR<Table>;
|
|
126
|
+
/** The reference evaluator over embedded sources only (`Ref` ⇒ `UnresolvedSource`). */
|
|
127
|
+
declare const evalPipeline: (pipeline: readonly Transform[], input: Table) => DR<Table>;
|
|
128
|
+
/** The env-aware evaluator over embedded sources only (fuaran-core#77 / Phase 424). */
|
|
129
|
+
declare const evalPipelineInEnv: (env: EvalEnv, pipeline: readonly Transform[], input: Table) => DR<Table>;
|
|
130
|
+
/** Render an `EvalError` as a stable human string (mirrors F# `DataFrame.errorString`). */
|
|
131
|
+
declare const evalErrorString: (e: EvalError) => string;
|
|
132
|
+
/** Every `ColExpr.param` name a single step references (only `filter` / `derive` carry a ColExpr). */
|
|
133
|
+
declare const stepParams: (t: Transform) => readonly string[];
|
|
134
|
+
/** Every distinct param name a pipeline references — the TS mirror of Core `Transform.paramsOf`. */
|
|
135
|
+
declare const pipelineParams: (pipeline: readonly Transform[]) => readonly string[];
|
|
136
|
+
|
|
137
|
+
/** Stable AI-friendly discriminator for decode-time failures (WIRE_FORMAT.md §6). */
|
|
138
|
+
type DecodeErrorCode = 'INVALID_JSON' | 'MISSING_FIELD' | 'WRONG_TYPE' | 'UNKNOWN_DU_CASE' | 'WRONG_NODE_KIND' | 'EMPTY_NODE_ID';
|
|
139
|
+
/** AI-recoverable decode-time failure. Mirrors the F# `DecodeError` record. */
|
|
140
|
+
interface DecodeError {
|
|
141
|
+
readonly code: DecodeErrorCode;
|
|
142
|
+
readonly path: string;
|
|
143
|
+
readonly message: string;
|
|
144
|
+
readonly expectedShape?: string;
|
|
145
|
+
}
|
|
146
|
+
type R<T> = Result<T, DecodeError>;
|
|
147
|
+
/** Typed-value coercers for `TreeOp.UpdateProp` (used by the apply engine). */
|
|
148
|
+
declare const coerce: {
|
|
149
|
+
int: (v: JsonValue) => Result<number, string>;
|
|
150
|
+
float: (v: JsonValue) => Result<number, string>;
|
|
151
|
+
bool: (v: JsonValue) => Result<boolean, string>;
|
|
152
|
+
string: (v: JsonValue) => Result<string, string>;
|
|
153
|
+
textSource: (v: JsonValue) => Result<TextSource, string>;
|
|
154
|
+
bindingNumber: (v: JsonValue) => Result<Binding<number>, string>;
|
|
155
|
+
bindingInt: (v: JsonValue) => Result<Binding<number>, string>;
|
|
156
|
+
bindingBool: (v: JsonValue) => Result<Binding<boolean>, string>;
|
|
157
|
+
bindingString: (v: JsonValue) => Result<Binding<string>, string>;
|
|
158
|
+
cellFormat: (v: JsonValue) => Result<CellFormat, string>;
|
|
159
|
+
columnWidth: (v: JsonValue) => Result<ColumnWidth, string>;
|
|
160
|
+
orientation: (v: JsonValue) => Result<Orientation, string>;
|
|
161
|
+
tone: (v: JsonValue) => Result<ToneVariant, string>;
|
|
162
|
+
weight: (v: JsonValue) => Result<StyleWeight, string>;
|
|
163
|
+
emphasis: (v: JsonValue) => Result<Emphasis, string>;
|
|
164
|
+
/**
|
|
165
|
+
* The behavioural `emphasis` BOOL on Fact / LabelValueRow — the UpdateProp
|
|
166
|
+
* twin of `decodeEmphasisFlag`, so a TreeOp edit gets the same
|
|
167
|
+
* cross-vocabulary admission as a fresh decode (0.2.8, 2026-07-19 sweep).
|
|
168
|
+
*/
|
|
169
|
+
emphasisFlag: (v: JsonValue) => Result<boolean, string>;
|
|
170
|
+
headingVariant: (v: JsonValue) => Result<HeadingVariant, string>;
|
|
171
|
+
badgeVariant: (v: JsonValue) => Result<BadgeVariant, string>;
|
|
172
|
+
iconSource: (v: JsonValue) => Result<IconSource, string>;
|
|
173
|
+
};
|
|
174
|
+
/** Decode a canonical-JSON `Node` payload into the storage-shape `Node<unknown>`. */
|
|
175
|
+
declare const decodeNode: (json: string) => R<Node<unknown>>;
|
|
176
|
+
/** Decode a canonical-JSON `TreeOp` payload into the storage-shape `TreeOp<unknown>`. */
|
|
177
|
+
declare const decodeOp: (json: string) => R<TreeOp<unknown>>;
|
|
178
|
+
|
|
179
|
+
type ApplyErrorCode = 'NodeNotFound' | 'ParentNotFound' | 'ChildlessKind' | 'PositionOutOfRange' | 'DuplicateNodeId' | 'FieldNotFound' | 'SlotNotFound' | 'KindMismatch' | 'PathInvalid' | 'PathNotSupportedYet' | 'OrderingMismatch' | 'BatchAborted';
|
|
180
|
+
interface ApplyError {
|
|
181
|
+
readonly code: ApplyErrorCode;
|
|
182
|
+
readonly message: string;
|
|
183
|
+
/** Inner-op index when `code === 'BatchAborted'`. */
|
|
184
|
+
readonly batchIndex?: number;
|
|
185
|
+
}
|
|
186
|
+
/** One record per applied leaf op (Phase 76 telemetry contract). */
|
|
187
|
+
interface OpApplyTelemetryRecord {
|
|
188
|
+
readonly op: TreeOp<unknown>['kind'];
|
|
189
|
+
readonly targetId: string;
|
|
190
|
+
}
|
|
191
|
+
type ApplyResult<TMsg> = Result<{
|
|
192
|
+
readonly newTree: Node<TMsg>;
|
|
193
|
+
readonly emittedTelemetry: readonly OpApplyTelemetryRecord[];
|
|
194
|
+
}, ApplyError>;
|
|
195
|
+
/**
|
|
196
|
+
* Apply a single tree-op against `tree`, returning either the updated tree plus
|
|
197
|
+
* emitted telemetry, or a structured `ApplyError`. Fold this across an op list
|
|
198
|
+
* to apply many; wrap in `TreeOp.Batch` for atomic all-or-nothing application.
|
|
199
|
+
*/
|
|
200
|
+
declare const apply: <TMsg>(tree: Node<TMsg>, op: TreeOp<TMsg>) => ApplyResult<TMsg>;
|
|
201
|
+
|
|
202
|
+
/** The result envelope captured on a DAG record (closed shape). */
|
|
203
|
+
type DagResultEnvelope = {
|
|
204
|
+
readonly $type: 'Success';
|
|
205
|
+
} | {
|
|
206
|
+
readonly $type: 'Failure';
|
|
207
|
+
readonly code: string;
|
|
208
|
+
readonly message: string;
|
|
209
|
+
};
|
|
210
|
+
/**
|
|
211
|
+
* Content-addressed, multi-parent op-record — the branching-DAG generalisation
|
|
212
|
+
* of the linear `OpRecord`. `parents` is in author order (head = primary
|
|
213
|
+
* parent); `outcomeHash` is present only on a merge node (committed to the
|
|
214
|
+
* canonical encoding of the resulting tree). A linear chain is the degenerate
|
|
215
|
+
* single-parent case.
|
|
216
|
+
*/
|
|
217
|
+
interface DagOpRecord<TMsg = unknown> {
|
|
218
|
+
readonly streamId: string;
|
|
219
|
+
readonly hash: string;
|
|
220
|
+
readonly parents: readonly string[];
|
|
221
|
+
readonly op: TreeOp<TMsg>;
|
|
222
|
+
readonly outcomeHash?: string;
|
|
223
|
+
readonly promptId?: string;
|
|
224
|
+
readonly userId: string;
|
|
225
|
+
/** Unix seconds. */
|
|
226
|
+
readonly timestamp: number;
|
|
227
|
+
readonly resultEnvelope: DagResultEnvelope;
|
|
228
|
+
readonly tombstoned: boolean;
|
|
229
|
+
}
|
|
230
|
+
/**
|
|
231
|
+
* Encode a `DagOpRecord` to its canonical JSON wire form. Keys in Ordinal order
|
|
232
|
+
* (hash < op < outcomeHash < parents < promptId < resultEnvelope < streamId <
|
|
233
|
+
* timestamp < tombstoned < userId); `outcomeHash` / `promptId` omitted when
|
|
234
|
+
* absent; `op` nests `encodeOp` verbatim. Byte-identical to the F#
|
|
235
|
+
* `DagWire.encodeRecord`.
|
|
236
|
+
*/
|
|
237
|
+
declare const encodeDagRecord: <TMsg>(record: DagOpRecord<TMsg>) => string;
|
|
238
|
+
type DecodeResult<T> = {
|
|
239
|
+
readonly ok: true;
|
|
240
|
+
readonly value: T;
|
|
241
|
+
} | {
|
|
242
|
+
readonly ok: false;
|
|
243
|
+
readonly error: string;
|
|
244
|
+
};
|
|
245
|
+
/**
|
|
246
|
+
* Decode a canonical DAG-record envelope. The nested `op` AST is routed through
|
|
247
|
+
* the canonical `decodeOp` (the same structural decoder the linear wire path
|
|
248
|
+
* uses). Returns a structured error string on any wire-shape violation.
|
|
249
|
+
*/
|
|
250
|
+
declare const decodeDagRecord: (json: string) => DecodeResult<DagOpRecord<unknown>>;
|
|
251
|
+
|
|
252
|
+
type N = Node<unknown>;
|
|
253
|
+
/** A `(nodeId, facet)` cell that could not be auto-merged. */
|
|
254
|
+
interface MergeConflict {
|
|
255
|
+
readonly nodeId: string;
|
|
256
|
+
readonly facet: string;
|
|
257
|
+
}
|
|
258
|
+
/** Outcome of a 3-way merge: the merged tree, or the conflicting cells. */
|
|
259
|
+
type MergeResult = {
|
|
260
|
+
readonly ok: true;
|
|
261
|
+
readonly tree: N;
|
|
262
|
+
} | {
|
|
263
|
+
readonly ok: false;
|
|
264
|
+
readonly conflicts: readonly MergeConflict[];
|
|
265
|
+
};
|
|
266
|
+
/**
|
|
267
|
+
* Author-agnostic facet 3-way merge of `a` and `b` over their common `base`
|
|
268
|
+
* (all three share the root id). Returns the merged tree on full auto-merge, or
|
|
269
|
+
* the conflicting cells. Deterministic + host-reproducible (NodeId-byte
|
|
270
|
+
* tie-break, no wall-clock) — byte-identical to the F# `TreeMerge.merge3Way`.
|
|
271
|
+
*/
|
|
272
|
+
declare const merge3Way: (base: N, a: N, b: N) => MergeResult;
|
|
273
|
+
|
|
274
|
+
/**
|
|
275
|
+
* A wire profile id — `<name>@<major>.<minor>` (e.g. `core@1.0`). `name` is the
|
|
276
|
+
* capability namespace; `major` is the `/vN/` incompatibility boundary (a
|
|
277
|
+
* removal/rename mints a new major — old consumers cannot interpret it); `minor`
|
|
278
|
+
* is the additive capability counter (a new kind/case/field bumps the minor — an
|
|
279
|
+
* older consumer tolerates it via must-ignore-but-preserve).
|
|
280
|
+
*/
|
|
281
|
+
interface Profile {
|
|
282
|
+
readonly name: string;
|
|
283
|
+
readonly major: number;
|
|
284
|
+
readonly minor: number;
|
|
285
|
+
}
|
|
286
|
+
/** The canonical string form: `<name>@<major>.<minor>`. */
|
|
287
|
+
declare const renderProfile: (p: Profile) => string;
|
|
288
|
+
/** The base `core` profile — `core@1.0` (the current wire). */
|
|
289
|
+
declare const coreV1: Profile;
|
|
290
|
+
/**
|
|
291
|
+
* Parse `<name>@<major>.<minor>`. Names a typed error on any malformed shape —
|
|
292
|
+
* the same envelope discipline as the decoder (no exceptions escape). Mirrors
|
|
293
|
+
* F# `Profile.tryParse`: split on the LAST `@`, require a `<major>.<minor>` of
|
|
294
|
+
* two non-negative integers.
|
|
295
|
+
*/
|
|
296
|
+
declare const tryParseProfile: (s: string) => Result<Profile, string>;
|
|
297
|
+
/** The capability-negotiation outcome of a consumer reading an artifact's profile. */
|
|
298
|
+
type Compatibility =
|
|
299
|
+
/** Authored at-or-below the consumer's profile (same name + major) — decode fully. */
|
|
300
|
+
{
|
|
301
|
+
readonly kind: 'Current';
|
|
302
|
+
}
|
|
303
|
+
/**
|
|
304
|
+
* Authored *ahead* of the consumer (same name + major, higher minor) — the
|
|
305
|
+
* consumer may meet kinds it does not understand; it must tolerate (preserve +
|
|
306
|
+
* degrade), never crash.
|
|
307
|
+
*/
|
|
308
|
+
| {
|
|
309
|
+
readonly kind: 'Behind';
|
|
310
|
+
readonly authored: Profile;
|
|
311
|
+
}
|
|
312
|
+
/**
|
|
313
|
+
* A different namespace or a different major — an incompatible `/vN/` boundary
|
|
314
|
+
* the consumer cannot interpret at all (hard-refuse, never silently mis-decode).
|
|
315
|
+
*/
|
|
316
|
+
| {
|
|
317
|
+
readonly kind: 'Foreign';
|
|
318
|
+
readonly authored: Profile;
|
|
319
|
+
};
|
|
320
|
+
/**
|
|
321
|
+
* Negotiate a consumer's supported profile against an artifact's authored
|
|
322
|
+
* profile. Minor-ahead is `Behind` (tolerable); a different name or major is
|
|
323
|
+
* `Foreign` (refuse). Mirrors F# `Versioning.negotiate`.
|
|
324
|
+
*/
|
|
325
|
+
declare const negotiate: (consumer: Profile, authored: Profile) => Compatibility;
|
|
326
|
+
/** The versioned-envelope payload key. `$`-prefixed so it sorts before data keys. */
|
|
327
|
+
declare const PAYLOAD_KEY = "$payload";
|
|
328
|
+
/** The versioned-envelope profile key. */
|
|
329
|
+
declare const PROFILE_KEY = "$profile";
|
|
330
|
+
/** The optional artifact-declares-its-required-profile key. */
|
|
331
|
+
declare const REQUIRED_PROFILE_KEY = "requiredProfile";
|
|
332
|
+
/**
|
|
333
|
+
* A versioning-layer failure. Extends the six canonical `DecodeErrorCode`s with
|
|
334
|
+
* two envelope-specific codes, kept OUT of the core `DecodeErrorCode` set (the
|
|
335
|
+
* six-code AI-recovery surface stays unpolluted — WIRE_FORMAT.md §6):
|
|
336
|
+
* - `FOREIGN_PROFILE` — negotiate returned `Foreign`; the artifact is refused.
|
|
337
|
+
* - `MALFORMED_PROFILE` — the `$profile` value is not a `<name>@<major>.<minor>`.
|
|
338
|
+
*/
|
|
339
|
+
type EnvelopeErrorCode = DecodeErrorCode | 'FOREIGN_PROFILE' | 'MALFORMED_PROFILE';
|
|
340
|
+
interface EnvelopeError {
|
|
341
|
+
readonly code: EnvelopeErrorCode;
|
|
342
|
+
readonly path: string;
|
|
343
|
+
readonly message: string;
|
|
344
|
+
}
|
|
345
|
+
/**
|
|
346
|
+
* A versioned wire envelope: the producer's authored `profile` + the artifact
|
|
347
|
+
* `payload` (a `Node` / `TreeOp` as the verbatim parsed AST). `$profile` /
|
|
348
|
+
* `$payload` sort before any lower-case data key under the canonical key order,
|
|
349
|
+
* so an enveloped fixture is byte-stable. Mirrors F# `Versioning.Envelope`.
|
|
350
|
+
*/
|
|
351
|
+
interface Envelope {
|
|
352
|
+
readonly profile: Profile;
|
|
353
|
+
readonly payload: JsonAst;
|
|
354
|
+
}
|
|
355
|
+
/** Render an envelope to canonical wire bytes. */
|
|
356
|
+
declare const encodeEnvelope: (env: Envelope) => string;
|
|
357
|
+
/**
|
|
358
|
+
* Decode an envelope from an already-parsed AST — reads `$profile` (parsed) +
|
|
359
|
+
* the verbatim `$payload`. A missing / non-string / malformed `$profile`, or a
|
|
360
|
+
* missing `$payload`, is a structured `EnvelopeError`.
|
|
361
|
+
*/
|
|
362
|
+
declare const decodeEnvelopeAst: (ast: JsonAst) => Result<Envelope, EnvelopeError>;
|
|
363
|
+
/** Parse + decode an envelope from wire bytes. */
|
|
364
|
+
declare const decodeEnvelope: (json: string) => Result<Envelope, EnvelopeError>;
|
|
365
|
+
/**
|
|
366
|
+
* A kind the consumer does not understand, captured on the decode boundary.
|
|
367
|
+
* **Transport-only**: reachable here and nowhere on the authoring/encode path —
|
|
368
|
+
* no host can construct one to emit. `payload` is the *verbatim parsed AST*, so
|
|
369
|
+
* re-rendering it reproduces the producer's bytes (must-ignore-but-preserve);
|
|
370
|
+
* `requiredProfile` is the profile the artifact declared it needs (when a
|
|
371
|
+
* well-formed one was present), so the consumer can name what it is missing in a
|
|
372
|
+
* degraded placeholder. Mirrors F# `Versioning.UnknownKind`.
|
|
373
|
+
*/
|
|
374
|
+
interface UnknownKind {
|
|
375
|
+
readonly kind: string;
|
|
376
|
+
readonly payload: JsonAst;
|
|
377
|
+
readonly requiredProfile?: Profile;
|
|
378
|
+
}
|
|
379
|
+
/** The result of a tolerant decode: a fully-understood `T`, or a preserved `Unknown`. */
|
|
380
|
+
type Decoded<T> = {
|
|
381
|
+
readonly known: true;
|
|
382
|
+
readonly value: T;
|
|
383
|
+
} | {
|
|
384
|
+
readonly known: false;
|
|
385
|
+
readonly unknown: UnknownKind;
|
|
386
|
+
};
|
|
387
|
+
/**
|
|
388
|
+
* Tolerantly decode one artifact AST. `tagOf` reads its discriminator; `isKnown`
|
|
389
|
+
* reports whether this consumer understands that tag; `decodeKnown` decodes a
|
|
390
|
+
* known one. An *unrecognised* tag is NOT an error — it becomes a transport-only
|
|
391
|
+
* `Unknown` carrying the verbatim parsed `payload` and any declared
|
|
392
|
+
* `requiredProfile`. A genuinely malformed object (no discriminator at all)
|
|
393
|
+
* still fails via `tagOf`. Mirrors F# `Versioning.decodeTolerant`.
|
|
394
|
+
*/
|
|
395
|
+
declare const decodeTolerant: <T>(tagOf: (ast: JsonAst) => Result<string, EnvelopeError>, isKnown: (tag: string) => boolean, decodeKnown: (ast: JsonAst) => Result<T, EnvelopeError>, ast: JsonAst) => Result<Decoded<T>, EnvelopeError>;
|
|
396
|
+
/**
|
|
397
|
+
* Re-encode a tolerant decode back to canonical wire bytes. The `Unknown` branch
|
|
398
|
+
* re-renders its preserved `payload` **verbatim** (must-ignore-but-preserve);
|
|
399
|
+
* the `Known` branch re-encodes through the real node encoder. Composed with the
|
|
400
|
+
* canonical renderer's deterministic key order, an unknown artifact round-trips
|
|
401
|
+
* byte-for-byte. Mirrors F# `Versioning.reencode` (specialised to `Node`).
|
|
402
|
+
*/
|
|
403
|
+
declare const reencodeNode: (d: Decoded<Node<unknown>>) => string;
|
|
404
|
+
/**
|
|
405
|
+
* Tolerantly decode a bare (un-enveloped) `Node` wire form. A known kind decodes
|
|
406
|
+
* normally; an unknown top-level kind becomes a transport-only `Unknown` whose
|
|
407
|
+
* bytes round-trip verbatim through `reencodeNode` — a minor-ahead artifact no
|
|
408
|
+
* longer throws `WRONG_NODE_KIND` / `UNKNOWN_DU_CASE`. A genuinely malformed
|
|
409
|
+
* object (no `kind.$type`) still fails.
|
|
410
|
+
*/
|
|
411
|
+
declare const decodeNodeTolerant: (json: string) => Result<Decoded<Node<unknown>>, EnvelopeError>;
|
|
412
|
+
/**
|
|
413
|
+
* The consumer entry point for reading a possibly-versioned `Node` artifact
|
|
414
|
+
* safely. Decodes the `$profile` / `$payload` envelope, negotiates the authored
|
|
415
|
+
* profile against `consumer`, and:
|
|
416
|
+
* - **Foreign** → refuses with `FOREIGN_PROFILE` (never silently mis-decodes);
|
|
417
|
+
* - **Current / Behind** → tolerantly decodes the payload (unknown kinds
|
|
418
|
+
* preserved) and returns the whole envelope re-encoded to canonical bytes.
|
|
419
|
+
*
|
|
420
|
+
* The re-encode is byte-identical to a canonical input (must-ignore-but-preserve
|
|
421
|
+
* keeps an unknown-kind payload verbatim), which is exactly what the
|
|
422
|
+
* `envelope-round-trip` corpus family asserts and the `envelope-reject` family
|
|
423
|
+
* asserts the `FOREIGN_PROFILE` refusal for.
|
|
424
|
+
*/
|
|
425
|
+
declare const negotiateEnvelope: (json: string, consumer?: Profile) => Result<string, EnvelopeError>;
|
|
426
|
+
|
|
427
|
+
/** The envelope format-version tag key (`$`-prefixed, reserved per §2.1). */
|
|
428
|
+
declare const ELICITATION_KEY = "$elicitation";
|
|
429
|
+
/** The envelope format version this codec produces and accepts. */
|
|
430
|
+
declare const ELICITATION_VERSION = "1";
|
|
431
|
+
/**
|
|
432
|
+
* The elicitation error surface: the six §6 codes plus the §18.5 codes, kept
|
|
433
|
+
* OUT of the core `DecodeErrorCode` set (same posture as §15's
|
|
434
|
+
* `FOREIGN_PROFILE`).
|
|
435
|
+
*/
|
|
436
|
+
type ElicitationErrorCode = DecodeErrorCode | 'UNSUPPORTED_VERSION' | 'UNDECLARED_FIELD' | 'CONTRACT_EMPTY' | 'CONTRACT_DUPLICATE_FIELD' | 'CONTRACT_UNKNOWN_NODE' | 'ANSWER_MISSING_FIELD' | 'ANSWER_UNDECLARED_FIELD' | 'ANSWER_TYPE_MISMATCH' | 'ANSWER_OUT_OF_SPACE' | 'DEFAULT_NONCONFORMANT';
|
|
437
|
+
interface ElicitationError {
|
|
438
|
+
readonly code: ElicitationErrorCode;
|
|
439
|
+
readonly path: string;
|
|
440
|
+
readonly message: string;
|
|
441
|
+
}
|
|
442
|
+
/**
|
|
443
|
+
* A value space — the platform's established `$type`-tagged space vocabulary
|
|
444
|
+
* (the same wire shape the capability codec uses). `min`/`max` inclusive;
|
|
445
|
+
* `anyString` is the only unbounded space.
|
|
446
|
+
*/
|
|
447
|
+
type AnswerSpace = {
|
|
448
|
+
readonly kind: 'intRange';
|
|
449
|
+
readonly min: number;
|
|
450
|
+
readonly max: number;
|
|
451
|
+
} | {
|
|
452
|
+
readonly kind: 'floatRange';
|
|
453
|
+
readonly min: number;
|
|
454
|
+
readonly max: number;
|
|
455
|
+
} | {
|
|
456
|
+
readonly kind: 'stringLen';
|
|
457
|
+
readonly min: number;
|
|
458
|
+
readonly max: number;
|
|
459
|
+
} | {
|
|
460
|
+
readonly kind: 'enum';
|
|
461
|
+
readonly values: readonly string[];
|
|
462
|
+
} | {
|
|
463
|
+
readonly kind: 'anyString';
|
|
464
|
+
};
|
|
465
|
+
/** One declared answer field (§18.1). */
|
|
466
|
+
interface AnswerField {
|
|
467
|
+
/** The key this field's value takes in the answer object. */
|
|
468
|
+
readonly name: string;
|
|
469
|
+
/** The id of the NODE whose committed state carries the value. */
|
|
470
|
+
readonly nodeId: string;
|
|
471
|
+
/** The state key the node's binding writes the value under. */
|
|
472
|
+
readonly stateKey: string;
|
|
473
|
+
readonly space: AnswerSpace;
|
|
474
|
+
readonly required: boolean;
|
|
475
|
+
}
|
|
476
|
+
/** The declared answer contract — non-empty on the wire (`CONTRACT_EMPTY`). */
|
|
477
|
+
interface AnswerContract {
|
|
478
|
+
readonly fields: readonly AnswerField[];
|
|
479
|
+
}
|
|
480
|
+
/** A typed answer value — the JSON scalar shapes a space ranges over. */
|
|
481
|
+
type AnswerValue = string | number;
|
|
482
|
+
/** An answer object: declared field names → scalar values. */
|
|
483
|
+
type Answer = ReadonlyMap<string, AnswerValue>;
|
|
484
|
+
/** The elicitation envelope (§18.1). */
|
|
485
|
+
interface ElicitationEnvelope {
|
|
486
|
+
readonly id: string;
|
|
487
|
+
readonly tree: Node<unknown>;
|
|
488
|
+
readonly contract: AnswerContract;
|
|
489
|
+
/** Milliseconds, ≥ 1. DATA only — the presenting host's clock acts on it. */
|
|
490
|
+
readonly timeoutMs?: number;
|
|
491
|
+
/** A proposed answer; must itself conform to the contract. */
|
|
492
|
+
readonly defaultAnswer?: Answer;
|
|
493
|
+
}
|
|
494
|
+
/** The closed outcome set (§18.3). */
|
|
495
|
+
type ElicitationOutcome = {
|
|
496
|
+
readonly kind: 'Answered';
|
|
497
|
+
readonly answer: Answer;
|
|
498
|
+
} | {
|
|
499
|
+
readonly kind: 'Declined';
|
|
500
|
+
} | {
|
|
501
|
+
readonly kind: 'TimedOut';
|
|
502
|
+
} | {
|
|
503
|
+
readonly kind: 'Superseded';
|
|
504
|
+
readonly by?: string;
|
|
505
|
+
};
|
|
506
|
+
/** An outcome on the wire, correlated to its elicitation by id. */
|
|
507
|
+
interface ElicitationOutcomeEnvelope {
|
|
508
|
+
readonly elicitationId: string;
|
|
509
|
+
readonly outcome: ElicitationOutcome;
|
|
510
|
+
}
|
|
511
|
+
/**
|
|
512
|
+
* Validate a typed answer against `contract`, reporting at `basePath`.
|
|
513
|
+
* Deterministic fail-fast order: (1) undeclared keys, in Ordinal key order;
|
|
514
|
+
* (2) per contract field, in declaration order — missing-required, then
|
|
515
|
+
* JSON-type-vs-space, then in-space.
|
|
516
|
+
*/
|
|
517
|
+
declare const validateAnswerAt: (basePath: string, contract: AnswerContract, answer: Answer) => Result<undefined, ElicitationError>;
|
|
518
|
+
/**
|
|
519
|
+
* Validate an answer at the standard `$.answer` root — the gate a resolution
|
|
520
|
+
* host runs before an `Answered` outcome reaches the asking agent.
|
|
521
|
+
*/
|
|
522
|
+
declare const validateAnswer: (contract: AnswerContract, answer: Answer) => Result<undefined, ElicitationError>;
|
|
523
|
+
/**
|
|
524
|
+
* Encode an elicitation envelope to canonical wire bytes. Fails only when the
|
|
525
|
+
* tree is not wire-representable.
|
|
526
|
+
*/
|
|
527
|
+
declare const encodeElicitation: (env: ElicitationEnvelope) => Result<string, ElicitationError>;
|
|
528
|
+
/**
|
|
529
|
+
* Decode + validate an elicitation envelope (fail-fast, §18.4 order): stray
|
|
530
|
+
* keys → version tag → id → tree (standard node decode, errors re-rooted
|
|
531
|
+
* under `$.tree`) → contract (structure, duplicates, node membership) →
|
|
532
|
+
* timeoutMs → default conformance.
|
|
533
|
+
*/
|
|
534
|
+
declare const decodeElicitation: (json: string) => Result<ElicitationEnvelope, ElicitationError>;
|
|
535
|
+
/** Encode an outcome to canonical wire bytes. Total — no embedded tree. */
|
|
536
|
+
declare const encodeElicitationOutcome: (env: ElicitationOutcomeEnvelope) => string;
|
|
537
|
+
/**
|
|
538
|
+
* Decode an outcome envelope. Contract conformance of an `Answered` answer is
|
|
539
|
+
* NOT checked here (the outcome does not carry the contract) — a resolution
|
|
540
|
+
* host pairs the outcome with its pending elicitation and runs
|
|
541
|
+
* `validateAnswer` before the answer reaches the asking agent (§18.4).
|
|
542
|
+
*/
|
|
543
|
+
declare const decodeElicitationOutcome: (json: string) => Result<ElicitationOutcomeEnvelope, ElicitationError>;
|
|
544
|
+
/**
|
|
545
|
+
* Validate a `{"answer": {…}, "contract": {…}}` conformance document — the
|
|
546
|
+
* operation the `elicitation-answer-accept` / `elicitation-answer-reject`
|
|
547
|
+
* corpus families drive. The document carries no tree, so the
|
|
548
|
+
* `CONTRACT_UNKNOWN_NODE` probe does not apply here.
|
|
549
|
+
*/
|
|
550
|
+
declare const validateAnswerDocument: (json: string) => Result<undefined, ElicitationError>;
|
|
551
|
+
|
|
552
|
+
export { type Answer, type AnswerContract, type AnswerField, type AnswerSpace, type AnswerValue, type ApplyError, type ApplyErrorCode, type ApplyResult, type Compatibility, type DagOpRecord, type DagResultEnvelope, type DecodeError, type DecodeErrorCode, type Decoded, ELICITATION_KEY, ELICITATION_VERSION, type ElicitationEnvelope, type ElicitationError, type ElicitationErrorCode, type ElicitationOutcome, type ElicitationOutcomeEnvelope, type Envelope, type EnvelopeError, type EnvelopeErrorCode, type EvalEnv, type JsonAst, type MergeConflict, type MergeResult, type OpApplyTelemetryRecord, PAYLOAD_KEY, PROFILE_KEY, type ParseError, type Profile, REQUIRED_PROFILE_KEY, type SourceResolver, type TreeOp, type UnknownKind, apply, cellString, coerce, coreV1, decodeDagRecord, decodeElicitation, decodeElicitationOutcome, decodeEnvelope, decodeEnvelopeAst, decodeNode, decodeNodeTolerant, decodeOp, decodeTolerant, encodeCell, encodeColExpr, encodeDagRecord, encodeDataSource, encodeElicitation, encodeElicitationOutcome, encodeEnvelope, encodeNode, encodeOp, encodePipeline, evalErrorString, evalPipeline, evalPipelineInEnv, evalPipelineWith, evalPipelineWithInEnv, evalSource, field as jsonField, merge3Way, negotiate, negotiateEnvelope, noResolve, parse, pipelineParams, reencodeNode, renderAstCanonical, renderProfile, stepParams, tryParseProfile, validateAnswer, validateAnswerAt, validateAnswerDocument };
|