cesr-ts 0.2.3 → 0.3.1
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/README.md +36 -3
- package/esm/src/adapters/async-iterable.js +9 -9
- package/esm/src/annotate/annotator.js +18 -10
- package/esm/src/annotate/comments.js +3 -6
- package/esm/src/annotate/render.js +123 -24
- package/esm/src/bench/parser-benchmark.js +134 -0
- package/esm/src/core/bytes.js +6 -0
- package/esm/src/core/errors.js +24 -0
- package/esm/src/core/parser-attachment-collector.js +154 -0
- package/esm/src/core/parser-constants.js +74 -0
- package/esm/src/core/parser-deferred-frames.js +73 -0
- package/esm/src/core/parser-engine.js +128 -505
- package/esm/src/core/parser-frame-parser.js +643 -0
- package/esm/src/core/parser-policy.js +137 -0
- package/esm/src/core/parser-stream-state.js +62 -0
- package/esm/src/core/recovery-diagnostics.js +25 -0
- package/esm/src/index.js +4 -0
- package/esm/src/parser/attachment-fallback-policy.js +142 -0
- package/esm/src/parser/group-dispatch.js +547 -233
- package/esm/src/primitives/counter.js +4 -5
- package/esm/src/primitives/mapper.js +126 -45
- package/esm/src/primitives/matter.js +1 -1
- package/esm/src/router/router-stub.js +6 -6
- package/esm/src/serder/serder.js +44 -7
- package/esm/src/serder/smell.js +2 -1
- package/esm/src/tables/counter-version-registry.js +201 -0
- package/esm/src/version.js +2 -2
- package/package.json +3 -1
- package/types/_dnt.polyfills.d.ts +5 -0
- package/types/_dnt.polyfills.d.ts.map +1 -1
- package/types/src/adapters/async-iterable.d.ts +2 -2
- package/types/src/adapters/async-iterable.d.ts.map +1 -1
- package/types/src/adapters/effection.d.ts +2 -2
- package/types/src/adapters/effection.d.ts.map +1 -1
- package/types/src/annotate/annotator.d.ts.map +1 -1
- package/types/src/annotate/comments.d.ts.map +1 -1
- package/types/src/annotate/render.d.ts +8 -2
- package/types/src/annotate/render.d.ts.map +1 -1
- package/types/src/annotate/types.d.ts +2 -2
- package/types/src/annotate/types.d.ts.map +1 -1
- package/types/src/bench/parser-benchmark.d.ts +70 -0
- package/types/src/bench/parser-benchmark.d.ts.map +1 -0
- package/types/src/core/bytes.d.ts +6 -0
- package/types/src/core/bytes.d.ts.map +1 -1
- package/types/src/core/errors.d.ts +10 -0
- package/types/src/core/errors.d.ts.map +1 -1
- package/types/src/core/parser-attachment-collector.d.ts +51 -0
- package/types/src/core/parser-attachment-collector.d.ts.map +1 -0
- package/types/src/core/parser-constants.d.ts +30 -0
- package/types/src/core/parser-constants.d.ts.map +1 -0
- package/types/src/core/parser-deferred-frames.d.ts +38 -0
- package/types/src/core/parser-deferred-frames.d.ts.map +1 -0
- package/types/src/core/parser-engine.d.ts +53 -44
- package/types/src/core/parser-engine.d.ts.map +1 -1
- package/types/src/core/parser-frame-parser.d.ts +89 -0
- package/types/src/core/parser-frame-parser.d.ts.map +1 -0
- package/types/src/core/parser-policy.d.ts +27 -0
- package/types/src/core/parser-policy.d.ts.map +1 -0
- package/types/src/core/parser-stream-state.d.ts +30 -0
- package/types/src/core/parser-stream-state.d.ts.map +1 -0
- package/types/src/core/recovery-diagnostics.d.ts +59 -0
- package/types/src/core/recovery-diagnostics.d.ts.map +1 -0
- package/types/src/core/types.d.ts +61 -7
- package/types/src/core/types.d.ts.map +1 -1
- package/types/src/index.d.ts +4 -0
- package/types/src/index.d.ts.map +1 -1
- package/types/src/parser/attachment-fallback-policy.d.ts +78 -0
- package/types/src/parser/attachment-fallback-policy.d.ts.map +1 -0
- package/types/src/parser/group-dispatch.d.ts +85 -15
- package/types/src/parser/group-dispatch.d.ts.map +1 -1
- package/types/src/primitives/aggor.d.ts +2 -2
- package/types/src/primitives/aggor.d.ts.map +1 -1
- package/types/src/primitives/blinder.d.ts +2 -2
- package/types/src/primitives/blinder.d.ts.map +1 -1
- package/types/src/primitives/counter.d.ts.map +1 -1
- package/types/src/primitives/mapper.d.ts +44 -1
- package/types/src/primitives/mapper.d.ts.map +1 -1
- package/types/src/primitives/mediar.d.ts +2 -2
- package/types/src/primitives/mediar.d.ts.map +1 -1
- package/types/src/primitives/sealer.d.ts +2 -2
- package/types/src/primitives/sealer.d.ts.map +1 -1
- package/types/src/router/router-stub.d.ts +5 -5
- package/types/src/router/router-stub.d.ts.map +1 -1
- package/types/src/serder/serder.d.ts +2 -2
- package/types/src/serder/serder.d.ts.map +1 -1
- package/types/src/serder/serdery.d.ts +2 -2
- package/types/src/serder/serdery.d.ts.map +1 -1
- package/types/src/serder/smell.d.ts.map +1 -1
- package/types/src/tables/counter-version-registry.d.ts +90 -0
- package/types/src/tables/counter-version-registry.d.ts.map +1 -0
- package/types/src/version.d.ts +2 -2
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Greedy frame-boundary policy for `framed=false` mode.
|
|
3
|
+
*
|
|
4
|
+
* What:
|
|
5
|
+
* - continue draining as long as parse boundaries permit
|
|
6
|
+
* - continue collecting contiguous attachment groups in the same cycle
|
|
7
|
+
* - defer body-only end-of-buffer frames to preserve attachment lookahead
|
|
8
|
+
*
|
|
9
|
+
* Why:
|
|
10
|
+
* unframed mode prioritizes maximal parse progress and compatibility with
|
|
11
|
+
* legacy greedy continuation semantics.
|
|
12
|
+
*/
|
|
13
|
+
class GreedyFrameBoundaryPolicy {
|
|
14
|
+
/**
|
|
15
|
+
* Keep draining after one queued frame emission.
|
|
16
|
+
*
|
|
17
|
+
* Why `false`:
|
|
18
|
+
* greedy mode should emit all immediately available deferred siblings before
|
|
19
|
+
* returning control to the caller.
|
|
20
|
+
*/
|
|
21
|
+
shouldStopAfterQueuedFrameEmission() {
|
|
22
|
+
return false;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Keep draining after one completed frame emission.
|
|
26
|
+
*
|
|
27
|
+
* Why `false`:
|
|
28
|
+
* unframed callers expect `feed()` to make as much deterministic progress as
|
|
29
|
+
* possible with currently buffered input.
|
|
30
|
+
*/
|
|
31
|
+
shouldStopAfterCompletedFrameEmission() {
|
|
32
|
+
return false;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Keep collecting attachment groups until boundary/shortage.
|
|
36
|
+
*
|
|
37
|
+
* Why `false`:
|
|
38
|
+
* greedy mode intentionally aggregates all contiguous trailing attachment
|
|
39
|
+
* groups into one frame in the same drain cycle.
|
|
40
|
+
*/
|
|
41
|
+
shouldStopAfterAttachmentGroupCollection() {
|
|
42
|
+
return false;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Do not emit pending frame immediately after one resumed attachment append.
|
|
46
|
+
*
|
|
47
|
+
* Why `false`:
|
|
48
|
+
* greedy continuation should keep waiting until a clear frame boundary is
|
|
49
|
+
* observed, so additional attachments can still be absorbed.
|
|
50
|
+
*/
|
|
51
|
+
shouldEmitPendingAfterAttachmentResume() {
|
|
52
|
+
return false;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Defer body-only frame when no bytes remain.
|
|
56
|
+
*
|
|
57
|
+
* Why conditional `true`:
|
|
58
|
+
* when attachment count is zero and the buffer is exhausted, hold as pending
|
|
59
|
+
* to allow a following chunk to provide trailing attachments.
|
|
60
|
+
*/
|
|
61
|
+
shouldDeferBodyOnlyFrame(attachmentCount, remainingBufferLength) {
|
|
62
|
+
return attachmentCount === 0 && remainingBufferLength === 0;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Bounded frame-boundary policy for `framed=true` mode.
|
|
67
|
+
*
|
|
68
|
+
* What:
|
|
69
|
+
* - enforce one bounded parser work unit per drain cycle
|
|
70
|
+
* - emit promptly instead of greedy continuation
|
|
71
|
+
*
|
|
72
|
+
* Why:
|
|
73
|
+
* framed mode exists for deterministic stepwise consumption by callers that
|
|
74
|
+
* interleave parsing with downstream processing.
|
|
75
|
+
*/
|
|
76
|
+
class BoundedFrameBoundaryPolicy {
|
|
77
|
+
/**
|
|
78
|
+
* Stop after one queued frame emission.
|
|
79
|
+
*
|
|
80
|
+
* Why `true`:
|
|
81
|
+
* framed mode caps per-cycle output to a single unit of deferred progress.
|
|
82
|
+
*/
|
|
83
|
+
shouldStopAfterQueuedFrameEmission() {
|
|
84
|
+
return true;
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Stop after one completed frame emission.
|
|
88
|
+
*
|
|
89
|
+
* Why `true`:
|
|
90
|
+
* preserves bounded cadence guarantees for framed consumers.
|
|
91
|
+
*/
|
|
92
|
+
shouldStopAfterCompletedFrameEmission() {
|
|
93
|
+
return true;
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Stop after one attachment-group collection step.
|
|
97
|
+
*
|
|
98
|
+
* Why `true`:
|
|
99
|
+
* bounded mode avoids greedy attachment accumulation and returns control after
|
|
100
|
+
* the first attachment parsing unit.
|
|
101
|
+
*/
|
|
102
|
+
shouldStopAfterAttachmentGroupCollection() {
|
|
103
|
+
return true;
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Emit pending frame immediately after one resumed attachment append.
|
|
107
|
+
*
|
|
108
|
+
* Why `true`:
|
|
109
|
+
* framed continuation is intentionally stepwise and should not retain pending
|
|
110
|
+
* once one bounded continuation step has succeeded.
|
|
111
|
+
*/
|
|
112
|
+
shouldEmitPendingAfterAttachmentResume() {
|
|
113
|
+
return true;
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Never defer body-only frame waiting for possible future attachments.
|
|
117
|
+
*
|
|
118
|
+
* Why `false`:
|
|
119
|
+
* framed mode emits completed units as soon as possible instead of applying
|
|
120
|
+
* greedy end-of-buffer hold behavior.
|
|
121
|
+
*/
|
|
122
|
+
shouldDeferBodyOnlyFrame(_attachmentCount, _remainingBufferLength) {
|
|
123
|
+
return false;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Build default frame-boundary strategy from legacy parser options.
|
|
128
|
+
*
|
|
129
|
+
* Why:
|
|
130
|
+
* maintains backward compatibility for `framed` while allowing call sites to
|
|
131
|
+
* inject explicit `FrameBoundaryPolicy` implementations.
|
|
132
|
+
*/
|
|
133
|
+
export function createFrameBoundaryPolicy(framed = false) {
|
|
134
|
+
return framed
|
|
135
|
+
? new BoundedFrameBoundaryPolicy()
|
|
136
|
+
: new GreedyFrameBoundaryPolicy();
|
|
137
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { sniff } from "../parser/cold-start.js";
|
|
2
|
+
import { concatBytes } from "./bytes.js";
|
|
3
|
+
/**
|
|
4
|
+
* Owns mutable stream-level parser state (buffer, absolute offset, stream version).
|
|
5
|
+
*
|
|
6
|
+
* This class intentionally has no parse policy; it only provides deterministic
|
|
7
|
+
* state transitions used by parser orchestration.
|
|
8
|
+
*/
|
|
9
|
+
export class ParserStreamState {
|
|
10
|
+
/** Initialize stream state with the parser's default top-level version. */
|
|
11
|
+
constructor(initialVersion) {
|
|
12
|
+
Object.defineProperty(this, "state", {
|
|
13
|
+
enumerable: true,
|
|
14
|
+
configurable: true,
|
|
15
|
+
writable: true,
|
|
16
|
+
value: { buffer: new Uint8Array(0), offset: 0 }
|
|
17
|
+
});
|
|
18
|
+
Object.defineProperty(this, "activeVersion", {
|
|
19
|
+
enumerable: true,
|
|
20
|
+
configurable: true,
|
|
21
|
+
writable: true,
|
|
22
|
+
value: void 0
|
|
23
|
+
});
|
|
24
|
+
this.activeVersion = initialVersion;
|
|
25
|
+
}
|
|
26
|
+
/** Current unconsumed bytes. */
|
|
27
|
+
get buffer() {
|
|
28
|
+
return this.state.buffer;
|
|
29
|
+
}
|
|
30
|
+
/** Absolute consumed-byte offset (monotonic). */
|
|
31
|
+
get offset() {
|
|
32
|
+
return this.state.offset;
|
|
33
|
+
}
|
|
34
|
+
/** Active top-level stream version context. */
|
|
35
|
+
get streamVersion() {
|
|
36
|
+
return this.activeVersion;
|
|
37
|
+
}
|
|
38
|
+
/** Update active top-level stream version context. */
|
|
39
|
+
set streamVersion(version) {
|
|
40
|
+
this.activeVersion = version;
|
|
41
|
+
}
|
|
42
|
+
/** Append bytes to the buffered stream tail. */
|
|
43
|
+
append(chunk) {
|
|
44
|
+
this.state.buffer = concatBytes(this.state.buffer, chunk);
|
|
45
|
+
}
|
|
46
|
+
/** Consume a prefix from the buffer and advance absolute offset. */
|
|
47
|
+
consume(length) {
|
|
48
|
+
this.state.buffer = this.state.buffer.slice(length);
|
|
49
|
+
this.state.offset += length;
|
|
50
|
+
}
|
|
51
|
+
/** Consume all leading annotation-domain separator bytes (`ano`). */
|
|
52
|
+
consumeLeadingAno() {
|
|
53
|
+
while (this.state.buffer.length > 0 && sniff(this.state.buffer) === "ano") {
|
|
54
|
+
this.consume(1);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
/** Reset buffer/offset/version to initial parser state. */
|
|
58
|
+
reset(initialVersion) {
|
|
59
|
+
this.state = { buffer: new Uint8Array(0), offset: 0 };
|
|
60
|
+
this.activeVersion = initialVersion;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Compose diagnostics and legacy fallback callback observers.
|
|
3
|
+
*
|
|
4
|
+
* Why:
|
|
5
|
+
* keeps compatibility with legacy fallback callbacks while normalizing
|
|
6
|
+
* observability through one structured diagnostics stream.
|
|
7
|
+
*/
|
|
8
|
+
export function composeRecoveryDiagnosticObserver(options = {}) {
|
|
9
|
+
const { onRecoveryDiagnostic, onAttachmentVersionFallback, } = options;
|
|
10
|
+
if (!onRecoveryDiagnostic && !onAttachmentVersionFallback) {
|
|
11
|
+
return undefined;
|
|
12
|
+
}
|
|
13
|
+
return (diagnostic) => {
|
|
14
|
+
onRecoveryDiagnostic?.(diagnostic);
|
|
15
|
+
if (diagnostic.type !== "version-fallback-accepted") {
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
onAttachmentVersionFallback?.({
|
|
19
|
+
from: diagnostic.from,
|
|
20
|
+
to: diagnostic.to,
|
|
21
|
+
domain: diagnostic.domain,
|
|
22
|
+
reason: diagnostic.reason,
|
|
23
|
+
});
|
|
24
|
+
};
|
|
25
|
+
}
|
package/esm/src/index.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
export * from "./core/types.js";
|
|
2
2
|
export * from "./core/errors.js";
|
|
3
3
|
export * from "./core/parser-engine.js";
|
|
4
|
+
export * from "./core/parser-policy.js";
|
|
5
|
+
export * from "./core/recovery-diagnostics.js";
|
|
4
6
|
export * from "./parser/cold-start.js";
|
|
5
7
|
export * from "./parser/group-dispatch.js";
|
|
6
8
|
export * from "./serder/smell.js";
|
|
@@ -39,8 +41,10 @@ export * from "./router/router-stub.js";
|
|
|
39
41
|
export * from "./tables/versions.js";
|
|
40
42
|
export * from "./tables/table-types.js";
|
|
41
43
|
export * from "./tables/counter-codex.js";
|
|
44
|
+
export * from "./tables/counter-version-registry.js";
|
|
42
45
|
export * from "./annotate/types.js";
|
|
43
46
|
export * from "./annotate/comments.js";
|
|
44
47
|
export * from "./annotate/render.js";
|
|
45
48
|
export * from "./annotate/annotator.js";
|
|
46
49
|
export * from "./annotate/denot.js";
|
|
50
|
+
export * from "./bench/parser-benchmark.js";
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
import { DeserializeError, UnknownCodeError } from "../core/errors.js";
|
|
2
|
+
/**
|
|
3
|
+
* Classify parse failures that are safe for alternate-major retry.
|
|
4
|
+
*
|
|
5
|
+
* Why:
|
|
6
|
+
* only unknown-code and deserialize failures are treated as compatibility
|
|
7
|
+
* boundaries; structural/boundary errors should remain fail-fast.
|
|
8
|
+
*/
|
|
9
|
+
function isVersionFallbackError(error) {
|
|
10
|
+
return error instanceof UnknownCodeError || error instanceof DeserializeError;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Compute one-step alternate-major retry target.
|
|
14
|
+
*
|
|
15
|
+
* Why:
|
|
16
|
+
* compat behavior intentionally toggles between v1 and v2 majors and does not
|
|
17
|
+
* perform multi-step or minor-version search.
|
|
18
|
+
*/
|
|
19
|
+
function alternateMajorVersion(version) {
|
|
20
|
+
return version.major >= 2 ? { major: 1, minor: 0 } : { major: 2, minor: 0 };
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Strict fallback policy.
|
|
24
|
+
*
|
|
25
|
+
* What:
|
|
26
|
+
* - no version retry
|
|
27
|
+
* - no wrapper opaque-tail recovery
|
|
28
|
+
*
|
|
29
|
+
* Why:
|
|
30
|
+
* strict mode is intended for parity/fail-fast validation where ambiguous
|
|
31
|
+
* compatibility recovery must not hide malformed or mixed-major input.
|
|
32
|
+
*/
|
|
33
|
+
class StrictAttachmentVersionFallbackPolicy {
|
|
34
|
+
/**
|
|
35
|
+
* Always reject retry and preserve original error.
|
|
36
|
+
*
|
|
37
|
+
* Why `throw`:
|
|
38
|
+
* strict policy must not reinterpret unknown/deserialize failures as
|
|
39
|
+
* compatibility drift.
|
|
40
|
+
*/
|
|
41
|
+
onVersionDispatchFailure(_error, _version, _domain) {
|
|
42
|
+
return { action: "throw" };
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* No-op fallback observer.
|
|
46
|
+
*
|
|
47
|
+
* Why:
|
|
48
|
+
* strict policy never accepts fallback; observer is intentionally inert.
|
|
49
|
+
*/
|
|
50
|
+
onVersionFallback(_info) {
|
|
51
|
+
// Strict policy never falls back; this is intentionally a no-op.
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Disable wrapper opaque remainder preservation.
|
|
55
|
+
*
|
|
56
|
+
* Why `false`:
|
|
57
|
+
* strict mode must expose nested wrapper parse failures directly.
|
|
58
|
+
*/
|
|
59
|
+
shouldPreserveWrapperRemainder(_error) {
|
|
60
|
+
return false;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Compatibility fallback policy.
|
|
65
|
+
*
|
|
66
|
+
* What:
|
|
67
|
+
* - retry unknown/deserialize failures on alternate major version
|
|
68
|
+
* - preserve unread wrapper remainder as opaque payload on recoverable errors
|
|
69
|
+
*
|
|
70
|
+
* Why:
|
|
71
|
+
* interop streams in the ecosystem can mix major-version counters/payloads, and
|
|
72
|
+
* compat mode intentionally favors successful parse continuity.
|
|
73
|
+
*/
|
|
74
|
+
class CompatAttachmentVersionFallbackPolicy {
|
|
75
|
+
/**
|
|
76
|
+
* @param fallbackObserver Optional callback for accepted fallback events.
|
|
77
|
+
*/
|
|
78
|
+
constructor(fallbackObserver) {
|
|
79
|
+
Object.defineProperty(this, "fallbackObserver", {
|
|
80
|
+
enumerable: true,
|
|
81
|
+
configurable: true,
|
|
82
|
+
writable: true,
|
|
83
|
+
value: void 0
|
|
84
|
+
});
|
|
85
|
+
this.fallbackObserver = fallbackObserver;
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Retry only for compatibility-classified failures.
|
|
89
|
+
*
|
|
90
|
+
* Why conditional:
|
|
91
|
+
* unknown/deserialize errors often indicate major-table mismatch; other error
|
|
92
|
+
* classes generally represent structural issues that should not be retried.
|
|
93
|
+
*/
|
|
94
|
+
onVersionDispatchFailure(error, version, domain) {
|
|
95
|
+
if (!isVersionFallbackError(error)) {
|
|
96
|
+
return { action: "throw" };
|
|
97
|
+
}
|
|
98
|
+
const retryVersion = alternateMajorVersion(version);
|
|
99
|
+
return {
|
|
100
|
+
action: "retry",
|
|
101
|
+
retryVersion,
|
|
102
|
+
info: {
|
|
103
|
+
from: version,
|
|
104
|
+
to: retryVersion,
|
|
105
|
+
domain,
|
|
106
|
+
reason: error.message,
|
|
107
|
+
},
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Emit fallback event through optional callback.
|
|
112
|
+
*
|
|
113
|
+
* Why:
|
|
114
|
+
* keeps observability side effects caller-controlled.
|
|
115
|
+
*/
|
|
116
|
+
onVersionFallback(info) {
|
|
117
|
+
this.fallbackObserver?.(info);
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Preserve unread wrapper payload as opaque units.
|
|
121
|
+
*
|
|
122
|
+
* Why `true`:
|
|
123
|
+
* compat mode intentionally tolerates nested wrapper irregularities and
|
|
124
|
+
* retains undecoded remainder for downstream visibility.
|
|
125
|
+
*/
|
|
126
|
+
shouldPreserveWrapperRemainder(_error) {
|
|
127
|
+
return true;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Build default fallback strategy from legacy options.
|
|
132
|
+
*
|
|
133
|
+
* Why:
|
|
134
|
+
* preserves backward-compatible `mode` API while allowing explicit policy
|
|
135
|
+
* injection for new call sites.
|
|
136
|
+
*/
|
|
137
|
+
export function createAttachmentVersionFallbackPolicy(options = {}) {
|
|
138
|
+
const mode = options.mode ?? "compat";
|
|
139
|
+
return mode === "strict"
|
|
140
|
+
? new StrictAttachmentVersionFallbackPolicy()
|
|
141
|
+
: new CompatAttachmentVersionFallbackPolicy(options.onVersionFallback);
|
|
142
|
+
}
|