@fuaran-ui/ops 0.21.0 → 0.22.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/dist/index.cjs +1113 -140
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +209 -6
- package/dist/index.d.ts +209 -6
- package/dist/index.js +1101 -142
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/dist/index.d.cts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { Result, NodeId, NodeKind, JsonValue, Binding, SemanticStyle, StateBehaviour, Node, Cell, ColExpr, DataSource, Transform, EvalError, Table, TextSource, CellFormat, ColumnWidth, Orientation, ToneVariant, StyleWeight, Emphasis, TrendPolarity, HeadingVariant, BadgeVariant, IconSource, IconSize, DecodePolicy } from '@fuaran-ui/schema';
|
|
1
|
+
import { Result, NodeId, NodeKind, JsonValue, Binding, SemanticStyle, StateBehaviour, Node, Cell, ColExpr, DataSource, Transform, EvalError, Table, TextSource, CellFormat, ColumnWidth, Orientation, ToneVariant, StyleWeight, Emphasis, TrendPolarity, HeadingVariant, BadgeVariant, IconSource, IconSize, DecodePolicy, Capability } from '@fuaran-ui/schema';
|
|
2
|
+
export { Capability, Placement as CapabilityPlacement, CapabilitySigEntry, CapabilitySignature, IslandKind } from '@fuaran-ui/schema';
|
|
2
3
|
|
|
3
4
|
/** Local JSON AST. Shape-for-shape port of the F# decoder's private `Json` DU. */
|
|
4
5
|
type JsonAst = {
|
|
@@ -35,9 +36,11 @@ interface ParseError {
|
|
|
35
36
|
}
|
|
36
37
|
/**
|
|
37
38
|
* Parse a JSON document into the local AST. Mirrors the F# `tryParse`: empty /
|
|
38
|
-
* whitespace-only input is a structural error;
|
|
39
|
-
*
|
|
40
|
-
*
|
|
39
|
+
* whitespace-only input is a structural error; a document past the §21.7
|
|
40
|
+
* ceiling is refused BEFORE the parse; and per §20.2 row 2 the root value must
|
|
41
|
+
* be followed by nothing but whitespace — §1 makes a wire artefact a single
|
|
42
|
+
* JSON document, and this parser used to stop at the first value and ignore the
|
|
43
|
+
* remainder, which is a framing ambiguity rather than a tolerance.
|
|
41
44
|
*/
|
|
42
45
|
declare const parse: (input: string) => Result<JsonAst, ParseError>;
|
|
43
46
|
/** Look up an object field by key (key-order tolerant per WIRE_FORMAT.md §2). */
|
|
@@ -179,6 +182,17 @@ interface DecodeError {
|
|
|
179
182
|
readonly expectedShape?: string;
|
|
180
183
|
}
|
|
181
184
|
type R<T> = Result<T, DecodeError>;
|
|
185
|
+
type CR<T> = {
|
|
186
|
+
readonly ok: true;
|
|
187
|
+
readonly value: T;
|
|
188
|
+
} | {
|
|
189
|
+
readonly ok: false;
|
|
190
|
+
readonly error: string;
|
|
191
|
+
};
|
|
192
|
+
/** A `DataSource` — port of F# `ColumnCodec.decodeJson` (Phase 88: `schema`
|
|
193
|
+
* may be omitted on an embedded source; inferred in Ordinal column order). */
|
|
194
|
+
declare const decodeDataSource: (j: JsonAst) => CR<DataSource>;
|
|
195
|
+
declare const decodePipelineCore: (j: JsonAst) => CR<Transform[]>;
|
|
182
196
|
/**
|
|
183
197
|
* Phase 818 — materialise a LIVE Transform source's resolved store value as the
|
|
184
198
|
* evaluation input table: row-major rows transpose through the same 815
|
|
@@ -256,6 +270,54 @@ declare const decodeNode: (json: string, policy?: DecodePolicy) => R<Node<unknow
|
|
|
256
270
|
* only rather than a closure.
|
|
257
271
|
*/
|
|
258
272
|
declare const decodeOp: (json: string, policy?: DecodePolicy) => R<TreeOp<unknown>>;
|
|
273
|
+
/**
|
|
274
|
+
* Decode a canonical-JSON payload holding EITHER one `TreeOp` or an array of
|
|
275
|
+
* them — the shape a host sends down an op channel.
|
|
276
|
+
*
|
|
277
|
+
* It exists because the obvious composition is unsound. A consumer holding
|
|
278
|
+
* "one op or an array" reaches for `JSON.parse`, walks the array, and calls
|
|
279
|
+
* `decodeOp(JSON.stringify(entry))` per element; the embedded standalone bundle
|
|
280
|
+
* did exactly that. Three things go wrong, and none of them is visible from the
|
|
281
|
+
* call site:
|
|
282
|
+
*
|
|
283
|
+
* - The whole payload passes through `JSON.parse` BEFORE any bound applies, so
|
|
284
|
+
* the §21 depth gate never sees it. `JSON.parse` is native and will not
|
|
285
|
+
* overflow, but the document it hands back is unbounded, and the per-op
|
|
286
|
+
* decode that follows measures each op against a limit the batch already
|
|
287
|
+
* escaped.
|
|
288
|
+
* - `JSON.parse` is a different parser with different §20 answers: it keeps the
|
|
289
|
+
* LAST duplicate member, reads `1e999` as `Infinity`, and accepts nothing
|
|
290
|
+
* this parser refuses. Re-stringifying its output launders every one of those
|
|
291
|
+
* differences into bytes this decoder then accepts without complaint — the
|
|
292
|
+
* §20.1 undeclared-entry-point defect, arrived at by composition.
|
|
293
|
+
* - `MAX_NODES` is reset per `decodeOp` call, so it bounded ONE op rather than
|
|
294
|
+
* the batch: 1 000 ops of 100 000 nodes each passed every check.
|
|
295
|
+
*
|
|
296
|
+
* So the batch is parsed ONCE through this package's own parser, the array is
|
|
297
|
+
* split at the AST, and the node budget is carried ACROSS the ops rather than
|
|
298
|
+
* reset per op.
|
|
299
|
+
*/
|
|
300
|
+
declare const decodeOps: (json: string, policy?: DecodePolicy) => R<readonly TreeOp<unknown>[]>;
|
|
301
|
+
|
|
302
|
+
/** A total codec result — a value, or a named refusal. Never a throw. */
|
|
303
|
+
type CapabilityDeclResult<T> = {
|
|
304
|
+
readonly ok: true;
|
|
305
|
+
readonly value: T;
|
|
306
|
+
} | {
|
|
307
|
+
readonly ok: false;
|
|
308
|
+
readonly error: string;
|
|
309
|
+
};
|
|
310
|
+
/**
|
|
311
|
+
* Encode a capability declaration to its canonical-JSON string. Total: every
|
|
312
|
+
* field of every case is representable, so there is nothing to refuse.
|
|
313
|
+
*/
|
|
314
|
+
declare const encodeCapabilityDeclaration: (cap: Capability) => string;
|
|
315
|
+
/**
|
|
316
|
+
* Decode a canonical capability-declaration string. Total — a malformed or
|
|
317
|
+
* un-carryable declaration yields `{ ok: false, error }` naming what was wrong,
|
|
318
|
+
* never an exception and never a partially-built capability.
|
|
319
|
+
*/
|
|
320
|
+
declare const decodeCapabilityDeclaration: (json: string) => CapabilityDeclResult<Capability>;
|
|
259
321
|
|
|
260
322
|
type ApplyErrorCode = 'NodeNotFound' | 'ParentNotFound' | 'ChildlessKind' | 'PositionOutOfRange' | 'DuplicateNodeId' | 'FieldNotFound' | 'SlotNotFound' | 'KindMismatch' | 'PathInvalid' | 'PathNotSupportedYet' | 'OrderingMismatch' | 'BatchAborted';
|
|
261
323
|
interface ApplyError {
|
|
@@ -509,10 +571,62 @@ type DecodeResult<T> = {
|
|
|
509
571
|
declare const decodeDagRecord: (json: string) => DecodeResult<DagOpRecord<unknown>>;
|
|
510
572
|
|
|
511
573
|
type N = Node<unknown>;
|
|
512
|
-
/**
|
|
574
|
+
/**
|
|
575
|
+
* The class of a merge refusal. Mirrors the reference host's
|
|
576
|
+
* `MergeConflictClass` spelling-for-spelling — these strings are the `class`
|
|
577
|
+
* member of the committed refusal envelope, so they are wire, not prose.
|
|
578
|
+
*/
|
|
579
|
+
type MergeConflictClass = 'ConcurrentEdit' | 'ConcurrentMove' | 'DeleteModify' | 'KindSwapOrphansPin' | 'ReorderVsStructural' | 'CombinedCycle';
|
|
580
|
+
/**
|
|
581
|
+
* One SIDE of a two-sided refusal: that branch's value for the contended cell,
|
|
582
|
+
* plus the branch's own opaque provenance tag.
|
|
583
|
+
*
|
|
584
|
+
* The `value` is the contended cell's canonical encoding, EXCEPT for the
|
|
585
|
+
* `style.*` sub-facets, whose value is the sub-field's case name — which
|
|
586
|
+
* coincides with its wire spelling only because every style sub-field is
|
|
587
|
+
* enum-shaped. Do not generalise it to a compound cell.
|
|
588
|
+
*/
|
|
589
|
+
interface MergeSide {
|
|
590
|
+
readonly value: string;
|
|
591
|
+
readonly tag?: string;
|
|
592
|
+
}
|
|
593
|
+
/**
|
|
594
|
+
* A `(nodeId, facet)` cell that could not be auto-merged, as a two-sided
|
|
595
|
+
* recovery envelope.
|
|
596
|
+
*
|
|
597
|
+
* `a` and `b` are the SIDES view: the first- and second-argument branches'
|
|
598
|
+
* values for the contended cell, populated on EVERY refusal. Swapping the
|
|
599
|
+
* branches TRANSPOSES them and changes nothing else — which is what lets two
|
|
600
|
+
* replicas that merged the same pair in opposite orders agree about what the
|
|
601
|
+
* other side wanted. `base` is the LCA value (the empty string for a cell that
|
|
602
|
+
* exists on neither side of the LCA, such as an `insert`).
|
|
603
|
+
*
|
|
604
|
+
* `primacyHeld` is the precedence view, and on this tier it is always `false`:
|
|
605
|
+
* `merge3Way` is the author-agnostic entry point, so neither side is pinned.
|
|
606
|
+
* The reference host's precedence slots (`primary` / `secondary` /
|
|
607
|
+
* `secondaryTag`) are deliberately NOT mirrored here — they are populated
|
|
608
|
+
* exactly when a pin is held, and this tier has no author classifier to hold one
|
|
609
|
+
* with, so they could only ever be absent. They arrive with the entry point that
|
|
610
|
+
* supplies an author, not before.
|
|
611
|
+
*
|
|
612
|
+
* The reference host's `choices` menu is not mirrored either, but for a
|
|
613
|
+
* different reason, and the difference matters to whoever ports it. It is NOT
|
|
614
|
+
* empty on this tier: every choice the reference offers names a slot the
|
|
615
|
+
* envelope populated, so an unpinned refusal offers `KeepBase` / `KeepA` /
|
|
616
|
+
* `KeepB` — all three well-defined here — rather than the `KeepSecondary` that
|
|
617
|
+
* would name the empty precedence slot. The menu is left out because it is
|
|
618
|
+
* derivable from the sides plus the pin, which is also why the shared refusal
|
|
619
|
+
* corpus does not encode it; a port that wants it computes it, and must not
|
|
620
|
+
* infer from the absence that this tier has no menu to offer.
|
|
621
|
+
*/
|
|
513
622
|
interface MergeConflict {
|
|
514
623
|
readonly nodeId: string;
|
|
515
624
|
readonly facet: string;
|
|
625
|
+
readonly class: MergeConflictClass;
|
|
626
|
+
readonly base: string;
|
|
627
|
+
readonly a: MergeSide;
|
|
628
|
+
readonly b: MergeSide;
|
|
629
|
+
readonly primacyHeld: boolean;
|
|
516
630
|
}
|
|
517
631
|
/** Outcome of a 3-way merge: the merged tree, or the conflicting cells. */
|
|
518
632
|
type MergeResult = {
|
|
@@ -529,6 +643,25 @@ type MergeResult = {
|
|
|
529
643
|
* tie-break, no wall-clock) — byte-identical to the F# `TreeMerge.merge3Way`.
|
|
530
644
|
*/
|
|
531
645
|
declare const merge3Way: (base: N, a: N, b: N) => MergeResult;
|
|
646
|
+
/**
|
|
647
|
+
* Order a refusal set deterministically. `(nodeId, facet)` is unique within one
|
|
648
|
+
* merge — a facet of a node is merged once — so this totally orders an envelope
|
|
649
|
+
* regardless of the fold's internal emission order.
|
|
650
|
+
*/
|
|
651
|
+
declare const sortConflictsCanonical: (conflicts: readonly MergeConflict[]) => readonly MergeConflict[];
|
|
652
|
+
/**
|
|
653
|
+
* Canonical JSON of a REFUSAL envelope: the conflict set as a sorted array of
|
|
654
|
+
* `{a,b,base,class,facet,nodeId,primacyHeld}` objects (object keys alphabetical,
|
|
655
|
+
* array entries in `(nodeId, facet)` order). Byte-stable across hosts, so a
|
|
656
|
+
* sha256 over it is the cross-host refusal hash — the determinism artefact for a
|
|
657
|
+
* REFUSED structural merge, the analogue of the outcome hash for an auto-merge.
|
|
658
|
+
*
|
|
659
|
+
* The precedence view is deliberately projected as `primacyHeld` alone: the
|
|
660
|
+
* pinned winner and loser are derivable from the sides plus the pin, and a
|
|
661
|
+
* corpus that committed both would pin the same value twice and go red on a host
|
|
662
|
+
* that agreed about the merge.
|
|
663
|
+
*/
|
|
664
|
+
declare const encodeMergeEnvelope: (conflicts: readonly MergeConflict[]) => string;
|
|
532
665
|
|
|
533
666
|
/**
|
|
534
667
|
* A wire profile id — `<name>@<major>.<minor>` (e.g. `core@1.0`). `name` is the
|
|
@@ -840,4 +973,74 @@ declare const withStateSeeds: <TMsg, S extends {
|
|
|
840
973
|
readonly state?: Readonly<Record<string, unknown>>;
|
|
841
974
|
}>(tree: Node<TMsg>, sources: S) => S;
|
|
842
975
|
|
|
843
|
-
|
|
976
|
+
/**
|
|
977
|
+
* The identity text rendition of a buffered value.
|
|
978
|
+
*
|
|
979
|
+
* `String(v)` is deliberately not used for numbers: it spells `1e21` as `1e+21`
|
|
980
|
+
* here and `1E+21` on .NET, and the hosts have to agree. `formatFiniteDouble` is
|
|
981
|
+
* the layout the corpus bytes already go through, so a number reads here exactly
|
|
982
|
+
* as it reads on the wire.
|
|
983
|
+
*/
|
|
984
|
+
declare const identityFormat: (v: unknown) => string;
|
|
985
|
+
/**
|
|
986
|
+
* The JSON number grammar, and nothing wider. Surrounding ASCII whitespace is
|
|
987
|
+
* trimmed first — a reader's trailing space is not a type error — but a leading
|
|
988
|
+
* `+`, a bare `.5`, a hex literal and a thousands separator are all refused,
|
|
989
|
+
* because a grammar each host guesses at is a grammar each host guesses at
|
|
990
|
+
* differently.
|
|
991
|
+
*
|
|
992
|
+
* `Number(text)` is emphatically NOT the implementation: it accepts `0x10`,
|
|
993
|
+
* `Infinity`, `1_0` and the empty string, all of which this must refuse.
|
|
994
|
+
*/
|
|
995
|
+
declare const tryNumberText: (text: string) => number | undefined;
|
|
996
|
+
/**
|
|
997
|
+
* The scalar a piece of buffer text denotes, when it denotes one. `true` /
|
|
998
|
+
* `false` and the JSON number grammar only — an empty string is NOT null here,
|
|
999
|
+
* because a cleared text field is an empty string and reading it as "no value"
|
|
1000
|
+
* would make the buffer lie about what the reader did.
|
|
1001
|
+
*/
|
|
1002
|
+
declare const scalarOfText: (text: string) => string | number | boolean | undefined;
|
|
1003
|
+
/**
|
|
1004
|
+
* Fixed-point text: sign, integer part, and EXACTLY `decimals` fraction digits,
|
|
1005
|
+
* `.` as the point, no grouping. Rounding is half-away-from-zero, spelled as
|
|
1006
|
+
* `floor(x + 0.5)` on the absolute value rather than as `toFixed` — `toFixed`
|
|
1007
|
+
* rounds half-to-even on some values through the double's binary expansion, and
|
|
1008
|
+
* a rounding mode each host picks a default for is a divergence waiting to be
|
|
1009
|
+
* found by a fixture.
|
|
1010
|
+
*/
|
|
1011
|
+
declare const fixedText: (decimals: number, v: number) => string;
|
|
1012
|
+
/**
|
|
1013
|
+
* The `Format.Number` codec's rendition: fixed-point at the declared decimals,
|
|
1014
|
+
* or the identity when the codec declares none.
|
|
1015
|
+
*
|
|
1016
|
+
* A NON-numeric buffered value falls back to the identity text rather than
|
|
1017
|
+
* failing. The codec is a declaration about presentation, and a value of the
|
|
1018
|
+
* wrong shape underneath it is the slot's problem, reported by the slot — a
|
|
1019
|
+
* format function that threw here would take out the render of a tree whose only
|
|
1020
|
+
* defect is a mistyped binding.
|
|
1021
|
+
*/
|
|
1022
|
+
declare const numberText: (decimals: number | undefined, v: unknown) => string;
|
|
1023
|
+
/**
|
|
1024
|
+
* The wire-survivability failure a DECODED host-only projection throws when a
|
|
1025
|
+
* reader tries to run it.
|
|
1026
|
+
*
|
|
1027
|
+
* It exists because the alternative — returning a default — is
|
|
1028
|
+
* indistinguishable from a real answer at the slot: a decoded `Binding.Computed`
|
|
1029
|
+
* used to hand back `undefined` and render it as though the computation had run.
|
|
1030
|
+
*
|
|
1031
|
+
* The `name` is set explicitly and consumers match on IT rather than on
|
|
1032
|
+
* `instanceof`: the renderer lives in another package with its own bundle, so an
|
|
1033
|
+
* identity check across the boundary is a check on which copy of the class was
|
|
1034
|
+
* loaded, which is not the question being asked.
|
|
1035
|
+
*/
|
|
1036
|
+
declare class WireSurvivabilityError extends Error {
|
|
1037
|
+
constructor(message: string);
|
|
1038
|
+
}
|
|
1039
|
+
/**
|
|
1040
|
+
* The one message a decoded `Binding.Computed` carries. A constant rather than a
|
|
1041
|
+
* template at each site so the resolver can recognise it, the corpus can pin it,
|
|
1042
|
+
* and every host can render the same sentence.
|
|
1043
|
+
*/
|
|
1044
|
+
declare const DECODED_COMPUTED_MESSAGE = "Binding.Computed has no wire projection (decoded from a '<closure>' sentinel) \u2014 use Binding.Expr / Transform / State";
|
|
1045
|
+
|
|
1046
|
+
export { type Answer, type AnswerContract, type AnswerField, type AnswerSpace, type AnswerValue, type ApplyError, type ApplyErrorCode, type ApplyResult, type CapabilityDeclResult, type Compatibility, DECODED_COMPUTED_MESSAGE, type DagActor, 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 FreshIds, HOST_RESERVED_PREFIX, type JsonAst, type MergeConflict, type MergeConflictClass, type MergeResult, type MergeSide, type OpApplyTelemetryRecord, PAYLOAD_KEY, PROFILE_KEY, type ParseError, type PlaceError, type PlaceTarget, type Placement, type Profile, REQUIRED_PROFILE_KEY, type SourceResolver, type TreeOp, type UnknownKind, WireSurvivabilityError, apply, canPlace, cellString, coerce, collectStateSeeds, coreV1, decodeCapabilityDeclaration, decodeDagRecord, decodeDataSource, decodeElicitation, decodeElicitationOutcome, decodeEnvelope, decodeEnvelopeAst, decodeNode, decodeNodeTolerant, decodeOp, decodeOps, decodePipelineCore as decodePipeline, decodeTolerant, derivedFreshIds, duplicateOp, duplicateOpWith, encodeCapabilityDeclaration, encodeCell, encodeColExpr, encodeDagRecord, encodeDataSource, encodeElicitation, encodeElicitationOutcome, encodeEnvelope, encodeMergeEnvelope, encodeNode, encodeOp, encodePipeline, evalErrorString, evalPipeline, evalPipelineInEnv, evalPipelineWith, evalPipelineWithInEnv, evalSource, fixedText, identityFormat, field as jsonField, liveValueToTable, merge3Way, moveOp, negotiate, negotiateEnvelope, noResolve, nudgeOp, numberText, parse, pasteOp, pasteOpWith, pipelineParams, placeOp, reencodeNode, renderAstCanonical, renderProfile, scalarOfText, sequentialFreshIds, sortConflictsCanonical, stepParams, substituteListParams, tryNumberText, tryParseProfile, validateAnswer, validateAnswerAt, validateAnswerDocument, withStateSeeds };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { Result, NodeId, NodeKind, JsonValue, Binding, SemanticStyle, StateBehaviour, Node, Cell, ColExpr, DataSource, Transform, EvalError, Table, TextSource, CellFormat, ColumnWidth, Orientation, ToneVariant, StyleWeight, Emphasis, TrendPolarity, HeadingVariant, BadgeVariant, IconSource, IconSize, DecodePolicy } from '@fuaran-ui/schema';
|
|
1
|
+
import { Result, NodeId, NodeKind, JsonValue, Binding, SemanticStyle, StateBehaviour, Node, Cell, ColExpr, DataSource, Transform, EvalError, Table, TextSource, CellFormat, ColumnWidth, Orientation, ToneVariant, StyleWeight, Emphasis, TrendPolarity, HeadingVariant, BadgeVariant, IconSource, IconSize, DecodePolicy, Capability } from '@fuaran-ui/schema';
|
|
2
|
+
export { Capability, Placement as CapabilityPlacement, CapabilitySigEntry, CapabilitySignature, IslandKind } from '@fuaran-ui/schema';
|
|
2
3
|
|
|
3
4
|
/** Local JSON AST. Shape-for-shape port of the F# decoder's private `Json` DU. */
|
|
4
5
|
type JsonAst = {
|
|
@@ -35,9 +36,11 @@ interface ParseError {
|
|
|
35
36
|
}
|
|
36
37
|
/**
|
|
37
38
|
* Parse a JSON document into the local AST. Mirrors the F# `tryParse`: empty /
|
|
38
|
-
* whitespace-only input is a structural error;
|
|
39
|
-
*
|
|
40
|
-
*
|
|
39
|
+
* whitespace-only input is a structural error; a document past the §21.7
|
|
40
|
+
* ceiling is refused BEFORE the parse; and per §20.2 row 2 the root value must
|
|
41
|
+
* be followed by nothing but whitespace — §1 makes a wire artefact a single
|
|
42
|
+
* JSON document, and this parser used to stop at the first value and ignore the
|
|
43
|
+
* remainder, which is a framing ambiguity rather than a tolerance.
|
|
41
44
|
*/
|
|
42
45
|
declare const parse: (input: string) => Result<JsonAst, ParseError>;
|
|
43
46
|
/** Look up an object field by key (key-order tolerant per WIRE_FORMAT.md §2). */
|
|
@@ -179,6 +182,17 @@ interface DecodeError {
|
|
|
179
182
|
readonly expectedShape?: string;
|
|
180
183
|
}
|
|
181
184
|
type R<T> = Result<T, DecodeError>;
|
|
185
|
+
type CR<T> = {
|
|
186
|
+
readonly ok: true;
|
|
187
|
+
readonly value: T;
|
|
188
|
+
} | {
|
|
189
|
+
readonly ok: false;
|
|
190
|
+
readonly error: string;
|
|
191
|
+
};
|
|
192
|
+
/** A `DataSource` — port of F# `ColumnCodec.decodeJson` (Phase 88: `schema`
|
|
193
|
+
* may be omitted on an embedded source; inferred in Ordinal column order). */
|
|
194
|
+
declare const decodeDataSource: (j: JsonAst) => CR<DataSource>;
|
|
195
|
+
declare const decodePipelineCore: (j: JsonAst) => CR<Transform[]>;
|
|
182
196
|
/**
|
|
183
197
|
* Phase 818 — materialise a LIVE Transform source's resolved store value as the
|
|
184
198
|
* evaluation input table: row-major rows transpose through the same 815
|
|
@@ -256,6 +270,54 @@ declare const decodeNode: (json: string, policy?: DecodePolicy) => R<Node<unknow
|
|
|
256
270
|
* only rather than a closure.
|
|
257
271
|
*/
|
|
258
272
|
declare const decodeOp: (json: string, policy?: DecodePolicy) => R<TreeOp<unknown>>;
|
|
273
|
+
/**
|
|
274
|
+
* Decode a canonical-JSON payload holding EITHER one `TreeOp` or an array of
|
|
275
|
+
* them — the shape a host sends down an op channel.
|
|
276
|
+
*
|
|
277
|
+
* It exists because the obvious composition is unsound. A consumer holding
|
|
278
|
+
* "one op or an array" reaches for `JSON.parse`, walks the array, and calls
|
|
279
|
+
* `decodeOp(JSON.stringify(entry))` per element; the embedded standalone bundle
|
|
280
|
+
* did exactly that. Three things go wrong, and none of them is visible from the
|
|
281
|
+
* call site:
|
|
282
|
+
*
|
|
283
|
+
* - The whole payload passes through `JSON.parse` BEFORE any bound applies, so
|
|
284
|
+
* the §21 depth gate never sees it. `JSON.parse` is native and will not
|
|
285
|
+
* overflow, but the document it hands back is unbounded, and the per-op
|
|
286
|
+
* decode that follows measures each op against a limit the batch already
|
|
287
|
+
* escaped.
|
|
288
|
+
* - `JSON.parse` is a different parser with different §20 answers: it keeps the
|
|
289
|
+
* LAST duplicate member, reads `1e999` as `Infinity`, and accepts nothing
|
|
290
|
+
* this parser refuses. Re-stringifying its output launders every one of those
|
|
291
|
+
* differences into bytes this decoder then accepts without complaint — the
|
|
292
|
+
* §20.1 undeclared-entry-point defect, arrived at by composition.
|
|
293
|
+
* - `MAX_NODES` is reset per `decodeOp` call, so it bounded ONE op rather than
|
|
294
|
+
* the batch: 1 000 ops of 100 000 nodes each passed every check.
|
|
295
|
+
*
|
|
296
|
+
* So the batch is parsed ONCE through this package's own parser, the array is
|
|
297
|
+
* split at the AST, and the node budget is carried ACROSS the ops rather than
|
|
298
|
+
* reset per op.
|
|
299
|
+
*/
|
|
300
|
+
declare const decodeOps: (json: string, policy?: DecodePolicy) => R<readonly TreeOp<unknown>[]>;
|
|
301
|
+
|
|
302
|
+
/** A total codec result — a value, or a named refusal. Never a throw. */
|
|
303
|
+
type CapabilityDeclResult<T> = {
|
|
304
|
+
readonly ok: true;
|
|
305
|
+
readonly value: T;
|
|
306
|
+
} | {
|
|
307
|
+
readonly ok: false;
|
|
308
|
+
readonly error: string;
|
|
309
|
+
};
|
|
310
|
+
/**
|
|
311
|
+
* Encode a capability declaration to its canonical-JSON string. Total: every
|
|
312
|
+
* field of every case is representable, so there is nothing to refuse.
|
|
313
|
+
*/
|
|
314
|
+
declare const encodeCapabilityDeclaration: (cap: Capability) => string;
|
|
315
|
+
/**
|
|
316
|
+
* Decode a canonical capability-declaration string. Total — a malformed or
|
|
317
|
+
* un-carryable declaration yields `{ ok: false, error }` naming what was wrong,
|
|
318
|
+
* never an exception and never a partially-built capability.
|
|
319
|
+
*/
|
|
320
|
+
declare const decodeCapabilityDeclaration: (json: string) => CapabilityDeclResult<Capability>;
|
|
259
321
|
|
|
260
322
|
type ApplyErrorCode = 'NodeNotFound' | 'ParentNotFound' | 'ChildlessKind' | 'PositionOutOfRange' | 'DuplicateNodeId' | 'FieldNotFound' | 'SlotNotFound' | 'KindMismatch' | 'PathInvalid' | 'PathNotSupportedYet' | 'OrderingMismatch' | 'BatchAborted';
|
|
261
323
|
interface ApplyError {
|
|
@@ -509,10 +571,62 @@ type DecodeResult<T> = {
|
|
|
509
571
|
declare const decodeDagRecord: (json: string) => DecodeResult<DagOpRecord<unknown>>;
|
|
510
572
|
|
|
511
573
|
type N = Node<unknown>;
|
|
512
|
-
/**
|
|
574
|
+
/**
|
|
575
|
+
* The class of a merge refusal. Mirrors the reference host's
|
|
576
|
+
* `MergeConflictClass` spelling-for-spelling — these strings are the `class`
|
|
577
|
+
* member of the committed refusal envelope, so they are wire, not prose.
|
|
578
|
+
*/
|
|
579
|
+
type MergeConflictClass = 'ConcurrentEdit' | 'ConcurrentMove' | 'DeleteModify' | 'KindSwapOrphansPin' | 'ReorderVsStructural' | 'CombinedCycle';
|
|
580
|
+
/**
|
|
581
|
+
* One SIDE of a two-sided refusal: that branch's value for the contended cell,
|
|
582
|
+
* plus the branch's own opaque provenance tag.
|
|
583
|
+
*
|
|
584
|
+
* The `value` is the contended cell's canonical encoding, EXCEPT for the
|
|
585
|
+
* `style.*` sub-facets, whose value is the sub-field's case name — which
|
|
586
|
+
* coincides with its wire spelling only because every style sub-field is
|
|
587
|
+
* enum-shaped. Do not generalise it to a compound cell.
|
|
588
|
+
*/
|
|
589
|
+
interface MergeSide {
|
|
590
|
+
readonly value: string;
|
|
591
|
+
readonly tag?: string;
|
|
592
|
+
}
|
|
593
|
+
/**
|
|
594
|
+
* A `(nodeId, facet)` cell that could not be auto-merged, as a two-sided
|
|
595
|
+
* recovery envelope.
|
|
596
|
+
*
|
|
597
|
+
* `a` and `b` are the SIDES view: the first- and second-argument branches'
|
|
598
|
+
* values for the contended cell, populated on EVERY refusal. Swapping the
|
|
599
|
+
* branches TRANSPOSES them and changes nothing else — which is what lets two
|
|
600
|
+
* replicas that merged the same pair in opposite orders agree about what the
|
|
601
|
+
* other side wanted. `base` is the LCA value (the empty string for a cell that
|
|
602
|
+
* exists on neither side of the LCA, such as an `insert`).
|
|
603
|
+
*
|
|
604
|
+
* `primacyHeld` is the precedence view, and on this tier it is always `false`:
|
|
605
|
+
* `merge3Way` is the author-agnostic entry point, so neither side is pinned.
|
|
606
|
+
* The reference host's precedence slots (`primary` / `secondary` /
|
|
607
|
+
* `secondaryTag`) are deliberately NOT mirrored here — they are populated
|
|
608
|
+
* exactly when a pin is held, and this tier has no author classifier to hold one
|
|
609
|
+
* with, so they could only ever be absent. They arrive with the entry point that
|
|
610
|
+
* supplies an author, not before.
|
|
611
|
+
*
|
|
612
|
+
* The reference host's `choices` menu is not mirrored either, but for a
|
|
613
|
+
* different reason, and the difference matters to whoever ports it. It is NOT
|
|
614
|
+
* empty on this tier: every choice the reference offers names a slot the
|
|
615
|
+
* envelope populated, so an unpinned refusal offers `KeepBase` / `KeepA` /
|
|
616
|
+
* `KeepB` — all three well-defined here — rather than the `KeepSecondary` that
|
|
617
|
+
* would name the empty precedence slot. The menu is left out because it is
|
|
618
|
+
* derivable from the sides plus the pin, which is also why the shared refusal
|
|
619
|
+
* corpus does not encode it; a port that wants it computes it, and must not
|
|
620
|
+
* infer from the absence that this tier has no menu to offer.
|
|
621
|
+
*/
|
|
513
622
|
interface MergeConflict {
|
|
514
623
|
readonly nodeId: string;
|
|
515
624
|
readonly facet: string;
|
|
625
|
+
readonly class: MergeConflictClass;
|
|
626
|
+
readonly base: string;
|
|
627
|
+
readonly a: MergeSide;
|
|
628
|
+
readonly b: MergeSide;
|
|
629
|
+
readonly primacyHeld: boolean;
|
|
516
630
|
}
|
|
517
631
|
/** Outcome of a 3-way merge: the merged tree, or the conflicting cells. */
|
|
518
632
|
type MergeResult = {
|
|
@@ -529,6 +643,25 @@ type MergeResult = {
|
|
|
529
643
|
* tie-break, no wall-clock) — byte-identical to the F# `TreeMerge.merge3Way`.
|
|
530
644
|
*/
|
|
531
645
|
declare const merge3Way: (base: N, a: N, b: N) => MergeResult;
|
|
646
|
+
/**
|
|
647
|
+
* Order a refusal set deterministically. `(nodeId, facet)` is unique within one
|
|
648
|
+
* merge — a facet of a node is merged once — so this totally orders an envelope
|
|
649
|
+
* regardless of the fold's internal emission order.
|
|
650
|
+
*/
|
|
651
|
+
declare const sortConflictsCanonical: (conflicts: readonly MergeConflict[]) => readonly MergeConflict[];
|
|
652
|
+
/**
|
|
653
|
+
* Canonical JSON of a REFUSAL envelope: the conflict set as a sorted array of
|
|
654
|
+
* `{a,b,base,class,facet,nodeId,primacyHeld}` objects (object keys alphabetical,
|
|
655
|
+
* array entries in `(nodeId, facet)` order). Byte-stable across hosts, so a
|
|
656
|
+
* sha256 over it is the cross-host refusal hash — the determinism artefact for a
|
|
657
|
+
* REFUSED structural merge, the analogue of the outcome hash for an auto-merge.
|
|
658
|
+
*
|
|
659
|
+
* The precedence view is deliberately projected as `primacyHeld` alone: the
|
|
660
|
+
* pinned winner and loser are derivable from the sides plus the pin, and a
|
|
661
|
+
* corpus that committed both would pin the same value twice and go red on a host
|
|
662
|
+
* that agreed about the merge.
|
|
663
|
+
*/
|
|
664
|
+
declare const encodeMergeEnvelope: (conflicts: readonly MergeConflict[]) => string;
|
|
532
665
|
|
|
533
666
|
/**
|
|
534
667
|
* A wire profile id — `<name>@<major>.<minor>` (e.g. `core@1.0`). `name` is the
|
|
@@ -840,4 +973,74 @@ declare const withStateSeeds: <TMsg, S extends {
|
|
|
840
973
|
readonly state?: Readonly<Record<string, unknown>>;
|
|
841
974
|
}>(tree: Node<TMsg>, sources: S) => S;
|
|
842
975
|
|
|
843
|
-
|
|
976
|
+
/**
|
|
977
|
+
* The identity text rendition of a buffered value.
|
|
978
|
+
*
|
|
979
|
+
* `String(v)` is deliberately not used for numbers: it spells `1e21` as `1e+21`
|
|
980
|
+
* here and `1E+21` on .NET, and the hosts have to agree. `formatFiniteDouble` is
|
|
981
|
+
* the layout the corpus bytes already go through, so a number reads here exactly
|
|
982
|
+
* as it reads on the wire.
|
|
983
|
+
*/
|
|
984
|
+
declare const identityFormat: (v: unknown) => string;
|
|
985
|
+
/**
|
|
986
|
+
* The JSON number grammar, and nothing wider. Surrounding ASCII whitespace is
|
|
987
|
+
* trimmed first — a reader's trailing space is not a type error — but a leading
|
|
988
|
+
* `+`, a bare `.5`, a hex literal and a thousands separator are all refused,
|
|
989
|
+
* because a grammar each host guesses at is a grammar each host guesses at
|
|
990
|
+
* differently.
|
|
991
|
+
*
|
|
992
|
+
* `Number(text)` is emphatically NOT the implementation: it accepts `0x10`,
|
|
993
|
+
* `Infinity`, `1_0` and the empty string, all of which this must refuse.
|
|
994
|
+
*/
|
|
995
|
+
declare const tryNumberText: (text: string) => number | undefined;
|
|
996
|
+
/**
|
|
997
|
+
* The scalar a piece of buffer text denotes, when it denotes one. `true` /
|
|
998
|
+
* `false` and the JSON number grammar only — an empty string is NOT null here,
|
|
999
|
+
* because a cleared text field is an empty string and reading it as "no value"
|
|
1000
|
+
* would make the buffer lie about what the reader did.
|
|
1001
|
+
*/
|
|
1002
|
+
declare const scalarOfText: (text: string) => string | number | boolean | undefined;
|
|
1003
|
+
/**
|
|
1004
|
+
* Fixed-point text: sign, integer part, and EXACTLY `decimals` fraction digits,
|
|
1005
|
+
* `.` as the point, no grouping. Rounding is half-away-from-zero, spelled as
|
|
1006
|
+
* `floor(x + 0.5)` on the absolute value rather than as `toFixed` — `toFixed`
|
|
1007
|
+
* rounds half-to-even on some values through the double's binary expansion, and
|
|
1008
|
+
* a rounding mode each host picks a default for is a divergence waiting to be
|
|
1009
|
+
* found by a fixture.
|
|
1010
|
+
*/
|
|
1011
|
+
declare const fixedText: (decimals: number, v: number) => string;
|
|
1012
|
+
/**
|
|
1013
|
+
* The `Format.Number` codec's rendition: fixed-point at the declared decimals,
|
|
1014
|
+
* or the identity when the codec declares none.
|
|
1015
|
+
*
|
|
1016
|
+
* A NON-numeric buffered value falls back to the identity text rather than
|
|
1017
|
+
* failing. The codec is a declaration about presentation, and a value of the
|
|
1018
|
+
* wrong shape underneath it is the slot's problem, reported by the slot — a
|
|
1019
|
+
* format function that threw here would take out the render of a tree whose only
|
|
1020
|
+
* defect is a mistyped binding.
|
|
1021
|
+
*/
|
|
1022
|
+
declare const numberText: (decimals: number | undefined, v: unknown) => string;
|
|
1023
|
+
/**
|
|
1024
|
+
* The wire-survivability failure a DECODED host-only projection throws when a
|
|
1025
|
+
* reader tries to run it.
|
|
1026
|
+
*
|
|
1027
|
+
* It exists because the alternative — returning a default — is
|
|
1028
|
+
* indistinguishable from a real answer at the slot: a decoded `Binding.Computed`
|
|
1029
|
+
* used to hand back `undefined` and render it as though the computation had run.
|
|
1030
|
+
*
|
|
1031
|
+
* The `name` is set explicitly and consumers match on IT rather than on
|
|
1032
|
+
* `instanceof`: the renderer lives in another package with its own bundle, so an
|
|
1033
|
+
* identity check across the boundary is a check on which copy of the class was
|
|
1034
|
+
* loaded, which is not the question being asked.
|
|
1035
|
+
*/
|
|
1036
|
+
declare class WireSurvivabilityError extends Error {
|
|
1037
|
+
constructor(message: string);
|
|
1038
|
+
}
|
|
1039
|
+
/**
|
|
1040
|
+
* The one message a decoded `Binding.Computed` carries. A constant rather than a
|
|
1041
|
+
* template at each site so the resolver can recognise it, the corpus can pin it,
|
|
1042
|
+
* and every host can render the same sentence.
|
|
1043
|
+
*/
|
|
1044
|
+
declare const DECODED_COMPUTED_MESSAGE = "Binding.Computed has no wire projection (decoded from a '<closure>' sentinel) \u2014 use Binding.Expr / Transform / State";
|
|
1045
|
+
|
|
1046
|
+
export { type Answer, type AnswerContract, type AnswerField, type AnswerSpace, type AnswerValue, type ApplyError, type ApplyErrorCode, type ApplyResult, type CapabilityDeclResult, type Compatibility, DECODED_COMPUTED_MESSAGE, type DagActor, 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 FreshIds, HOST_RESERVED_PREFIX, type JsonAst, type MergeConflict, type MergeConflictClass, type MergeResult, type MergeSide, type OpApplyTelemetryRecord, PAYLOAD_KEY, PROFILE_KEY, type ParseError, type PlaceError, type PlaceTarget, type Placement, type Profile, REQUIRED_PROFILE_KEY, type SourceResolver, type TreeOp, type UnknownKind, WireSurvivabilityError, apply, canPlace, cellString, coerce, collectStateSeeds, coreV1, decodeCapabilityDeclaration, decodeDagRecord, decodeDataSource, decodeElicitation, decodeElicitationOutcome, decodeEnvelope, decodeEnvelopeAst, decodeNode, decodeNodeTolerant, decodeOp, decodeOps, decodePipelineCore as decodePipeline, decodeTolerant, derivedFreshIds, duplicateOp, duplicateOpWith, encodeCapabilityDeclaration, encodeCell, encodeColExpr, encodeDagRecord, encodeDataSource, encodeElicitation, encodeElicitationOutcome, encodeEnvelope, encodeMergeEnvelope, encodeNode, encodeOp, encodePipeline, evalErrorString, evalPipeline, evalPipelineInEnv, evalPipelineWith, evalPipelineWithInEnv, evalSource, fixedText, identityFormat, field as jsonField, liveValueToTable, merge3Way, moveOp, negotiate, negotiateEnvelope, noResolve, nudgeOp, numberText, parse, pasteOp, pasteOpWith, pipelineParams, placeOp, reencodeNode, renderAstCanonical, renderProfile, scalarOfText, sequentialFreshIds, sortConflictsCanonical, stepParams, substituteListParams, tryNumberText, tryParseProfile, validateAnswer, validateAnswerAt, validateAnswerDocument, withStateSeeds };
|