@braidlabs/skew 0.1.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 +247 -0
- package/package.json +37 -0
- package/src/index.d.ts +12 -0
- package/src/index.js +14 -0
- package/src/index.js.map +1 -0
- package/src/lib/context.d.ts +26 -0
- package/src/lib/context.js +5 -0
- package/src/lib/context.js.map +1 -0
- package/src/lib/devtools.d.ts +51 -0
- package/src/lib/devtools.js +31 -0
- package/src/lib/devtools.js.map +1 -0
- package/src/lib/disabled.d.ts +48 -0
- package/src/lib/disabled.js +59 -0
- package/src/lib/disabled.js.map +1 -0
- package/src/lib/fingerprint.d.ts +32 -0
- package/src/lib/fingerprint.js +62 -0
- package/src/lib/fingerprint.js.map +1 -0
- package/src/lib/http.d.ts +70 -0
- package/src/lib/http.js +76 -0
- package/src/lib/http.js.map +1 -0
- package/src/lib/identity.d.ts +120 -0
- package/src/lib/identity.js +126 -0
- package/src/lib/identity.js.map +1 -0
- package/src/lib/lens.d.ts +133 -0
- package/src/lib/lens.js +337 -0
- package/src/lib/lens.js.map +1 -0
- package/src/lib/list.d.ts +18 -0
- package/src/lib/list.js +49 -0
- package/src/lib/list.js.map +1 -0
- package/src/lib/registry.d.ts +77 -0
- package/src/lib/registry.js +80 -0
- package/src/lib/registry.js.map +1 -0
- package/src/lib/result.d.ts +103 -0
- package/src/lib/result.js +78 -0
- package/src/lib/result.js.map +1 -0
- package/src/lib/storage.d.ts +86 -0
- package/src/lib/storage.js +190 -0
- package/src/lib/storage.js.map +1 -0
- package/src/lib/versioned.d.ts +242 -0
- package/src/lib/versioned.js +275 -0
- package/src/lib/versioned.js.map +1 -0
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
import { SkewResult } from './result.js';
|
|
2
|
+
import { MigrationContext } from './context.js';
|
|
3
|
+
import { LensOp } from './lens.js';
|
|
4
|
+
/**
|
|
5
|
+
* Anything that crosses a version boundary is wrapped with the version it was
|
|
6
|
+
* *authored* under.
|
|
7
|
+
*
|
|
8
|
+
* The version sits outside the payload deliberately: a reader can determine the
|
|
9
|
+
* shape without parsing, validating, or trusting the payload.
|
|
10
|
+
*/
|
|
11
|
+
export interface VersionedEnvelope<T = unknown> {
|
|
12
|
+
/** Schema version the payload was written under. */
|
|
13
|
+
readonly v: number;
|
|
14
|
+
readonly payload: T;
|
|
15
|
+
/**
|
|
16
|
+
* Contract name the payload belongs to. Optional on the wire — hand-written
|
|
17
|
+
* envelopes and older builds omit it — but written by every `write()`, and
|
|
18
|
+
* checked on read: an envelope naming a *different* contract is refused as
|
|
19
|
+
* `invalid` instead of being silently misread through the wrong chain.
|
|
20
|
+
*/
|
|
21
|
+
readonly n?: string;
|
|
22
|
+
/**
|
|
23
|
+
* Optional build identity of the writer. Not used for migration decisions —
|
|
24
|
+
* it exists so a stale read can be attributed to a specific deployment when
|
|
25
|
+
* debugging.
|
|
26
|
+
*/
|
|
27
|
+
readonly b?: string;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* A single step in a migration chain, from version `to - 1` to version `to`.
|
|
31
|
+
*
|
|
32
|
+
* `up` is mandatory — it is what "declaring the next version" means. `down`
|
|
33
|
+
* is the optional inverse: a projection back onto the older shape, honest but
|
|
34
|
+
* usually lossy. Steps authored as ops (see {@link LensOp}) get `down`,
|
|
35
|
+
* `derives`, and `lossy` computed; steps authored as code declare them.
|
|
36
|
+
*/
|
|
37
|
+
export interface MigrationStep<TFrom = unknown, TTo = unknown> {
|
|
38
|
+
readonly to: number;
|
|
39
|
+
readonly description: string;
|
|
40
|
+
readonly up: (previous: TFrom, ctx: MigrationContext) => TTo;
|
|
41
|
+
readonly down?: (next: TTo, ctx: MigrationContext) => TFrom;
|
|
42
|
+
/** Paths `up` fills with guesses rather than writer-reported data. */
|
|
43
|
+
readonly derives?: readonly string[];
|
|
44
|
+
/** Paths `down` fills with guesses (e.g. a restored default). */
|
|
45
|
+
readonly downDerives?: readonly string[];
|
|
46
|
+
/** Paths `down` discards — the price of projecting onto the older shape. */
|
|
47
|
+
readonly lossy?: readonly string[];
|
|
48
|
+
/** The declarative ops this step was authored from, when it was. */
|
|
49
|
+
readonly ops?: readonly LensOp[];
|
|
50
|
+
}
|
|
51
|
+
/** A code-authored step: an up migration, optionally its down inverse. */
|
|
52
|
+
export interface CodeStepSpec<TFrom, TTo> {
|
|
53
|
+
readonly up: (previous: TFrom, ctx: MigrationContext) => TTo;
|
|
54
|
+
readonly down?: (next: TTo, ctx: MigrationContext) => TFrom;
|
|
55
|
+
readonly derives?: readonly string[];
|
|
56
|
+
readonly downDerives?: readonly string[];
|
|
57
|
+
readonly lossy?: readonly string[];
|
|
58
|
+
}
|
|
59
|
+
/** An ops-authored step: everything else is computed from the ops. */
|
|
60
|
+
export interface OpsStepSpec {
|
|
61
|
+
readonly ops: readonly LensOp[];
|
|
62
|
+
}
|
|
63
|
+
export interface VersionedOptions<T> {
|
|
64
|
+
/**
|
|
65
|
+
* Shape check applied *after* migration completes. Bring your own validator
|
|
66
|
+
* (zod, valibot, a hand-written guard) — core stays dependency-free.
|
|
67
|
+
*/
|
|
68
|
+
readonly validate?: (value: unknown) => value is T;
|
|
69
|
+
/**
|
|
70
|
+
* Version to assume for data that carries no envelope, i.e. records written
|
|
71
|
+
* before this schema was adopted. Defaults to 1, which makes adoption
|
|
72
|
+
* seamless: declare your *existing* shape as v1 and legacy rows migrate
|
|
73
|
+
* forward from there without a backfill.
|
|
74
|
+
*/
|
|
75
|
+
readonly assumeLegacyVersion?: number;
|
|
76
|
+
/**
|
|
77
|
+
* The version of the schema's base shape (`TBase`). Defaults to 1.
|
|
78
|
+
*
|
|
79
|
+
* Raising the base is how a chain is eventually *cleaned up*. Chains are
|
|
80
|
+
* append-only at the top and trim-only at the bottom: once telemetry
|
|
81
|
+
* (`migratedFrom`, ideally with the store's `rewriteOnRead` shrinking the
|
|
82
|
+
* tail) shows a version no longer arrives, re-declare the schema with the
|
|
83
|
+
* oldest surviving shape as its base and delete the retired steps:
|
|
84
|
+
*
|
|
85
|
+
* ```ts
|
|
86
|
+
* // before: versioned<V1>('draft').next<V2>(…).next<V3>(…).next<V4>(…)
|
|
87
|
+
* export const Draft = versioned<V3>('draft', { base: 3 }).next<V4>(…);
|
|
88
|
+
* ```
|
|
89
|
+
*
|
|
90
|
+
* Version numbers are never reused or renumbered — v4 is still v4. Reads of
|
|
91
|
+
* data below the base fail with `reason: 'retired'` (a policy outcome whose
|
|
92
|
+
* remedy is discard/refetch/reset), never `gap` (a bug) — unless another
|
|
93
|
+
* bundle or a resolved contract still supplies the missing steps via the
|
|
94
|
+
* shared registry, in which case the read simply succeeds.
|
|
95
|
+
*
|
|
96
|
+
* Bare (un-enveloped) data is still assumed to be `assumeLegacyVersion`
|
|
97
|
+
* (default 1), so with a raised base it surfaces as `retired` — the safe
|
|
98
|
+
* default, since pre-adoption records carry the retired v1 shape. Set
|
|
99
|
+
* `assumeLegacyVersion: base` only when bare data is known to carry the
|
|
100
|
+
* base shape.
|
|
101
|
+
*/
|
|
102
|
+
readonly base?: number;
|
|
103
|
+
}
|
|
104
|
+
/** Per-call options for {@link VersionedSchema.read}. */
|
|
105
|
+
export interface ReadOptions {
|
|
106
|
+
/**
|
|
107
|
+
* Version of bare (un-enveloped) data, when the caller learned it out of
|
|
108
|
+
* band — a URL (`/v2/funds`), a header, a media type. Most HTTP APIs carry
|
|
109
|
+
* the version there rather than in the body; this is how you tell `read`
|
|
110
|
+
* to trust that instead of `assumeLegacyVersion`. Ignored when the data
|
|
111
|
+
* carries an envelope — the envelope is the writer's own statement.
|
|
112
|
+
*/
|
|
113
|
+
readonly assumeVersion?: number;
|
|
114
|
+
/** Clock and seed for the migrations this read runs. Pin it in tests. */
|
|
115
|
+
readonly context?: MigrationContext;
|
|
116
|
+
}
|
|
117
|
+
/** Options object form for {@link VersionedSchema.write}. */
|
|
118
|
+
export interface WriteOptions {
|
|
119
|
+
/** Stamped onto the envelope for attribution. */
|
|
120
|
+
readonly buildId?: string;
|
|
121
|
+
/**
|
|
122
|
+
* Target version to write at, when addressing a reader known to be older —
|
|
123
|
+
* writer-makes-right. Requires every intervening step to declare `down`;
|
|
124
|
+
* throws otherwise, because a writer's own chain is statically known and
|
|
125
|
+
* asking for an unreachable version is a programming error, not data skew.
|
|
126
|
+
*/
|
|
127
|
+
readonly as?: number;
|
|
128
|
+
/** Clock and seed for any down-migrations this write runs. */
|
|
129
|
+
readonly context?: MigrationContext;
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* A versioned schema: the single place a type's current version, its history,
|
|
133
|
+
* and the functions that move data between them are declared.
|
|
134
|
+
*
|
|
135
|
+
* ```ts
|
|
136
|
+
* export const WeeklyContent = versioned<V1>('weekly-content')
|
|
137
|
+
* .next<V2>('rename themeQuote to scriptureOfWeek', (p) => ({
|
|
138
|
+
* id: p.id,
|
|
139
|
+
* scriptureOfWeek: p.themeQuote,
|
|
140
|
+
* }))
|
|
141
|
+
* .next<V3>('introduce orderOfWorship', {
|
|
142
|
+
* up: (p) => ({ ...p, orderOfWorship: { setting: '', hymns: [] } }),
|
|
143
|
+
* down: ({ orderOfWorship, ...rest }) => rest,
|
|
144
|
+
* derives: ['orderOfWorship'],
|
|
145
|
+
* lossy: ['orderOfWorship'],
|
|
146
|
+
* });
|
|
147
|
+
*
|
|
148
|
+
* const result = WeeklyContent.read(rawFromStorage);
|
|
149
|
+
* if (result.ok) render(result.value);
|
|
150
|
+
* ```
|
|
151
|
+
*
|
|
152
|
+
* ## The one rule
|
|
153
|
+
*
|
|
154
|
+
* A migration must never import your current application types or services.
|
|
155
|
+
* Close each step over its own snapshot types (`V1`, `V2`, …). The moment a
|
|
156
|
+
* migration references a live interface, it silently changes meaning the next
|
|
157
|
+
* time that interface is edited — and your old migrations start lying.
|
|
158
|
+
*
|
|
159
|
+
* ## The second rule
|
|
160
|
+
*
|
|
161
|
+
* Migrations are deterministic. Take the clock (and any uniqueness seed) from
|
|
162
|
+
* the {@link MigrationContext} argument, never from `new Date()` or
|
|
163
|
+
* `Math.random()` — a migration whose output varies between runs breaks
|
|
164
|
+
* replays, retries, and tests in ways that surface far from the cause.
|
|
165
|
+
*/
|
|
166
|
+
export interface VersionedSchema<TCurrent> {
|
|
167
|
+
readonly name: string;
|
|
168
|
+
/** Current version — the base (default 1) plus the number of `next()` steps declared. */
|
|
169
|
+
readonly version: number;
|
|
170
|
+
/** Declared history, oldest first. Useful for tooling and diagnostics. */
|
|
171
|
+
readonly steps: readonly MigrationStep[];
|
|
172
|
+
/**
|
|
173
|
+
* Content fingerprint of the whole chain (name, version, per-step
|
|
174
|
+
* identity). Two builds whose fingerprints match agree about what this
|
|
175
|
+
* contract means; the registry uses this to detect builds that do not.
|
|
176
|
+
*/
|
|
177
|
+
readonly fingerprint: string;
|
|
178
|
+
/**
|
|
179
|
+
* Reads possibly-stale data and migrates it to the current version — in
|
|
180
|
+
* either direction.
|
|
181
|
+
*
|
|
182
|
+
* Older data migrates **up** through the chain (`migratedFrom` set, guessed
|
|
183
|
+
* fields listed in `derivedPaths`). Newer data migrates **down** when every
|
|
184
|
+
* intervening step — from this chain or contributed to the shared registry
|
|
185
|
+
* by a newer bundle or a resolved contract — declares a `down`
|
|
186
|
+
* (`downgradedFrom` set, discarded fields listed in `lossyPaths`).
|
|
187
|
+
* Otherwise the read refuses with `ahead`, exactly as before.
|
|
188
|
+
*
|
|
189
|
+
* Accepts an envelope, or bare legacy data (see
|
|
190
|
+
* {@link VersionedOptions.assumeLegacyVersion} and
|
|
191
|
+
* {@link ReadOptions.assumeVersion}).
|
|
192
|
+
*/
|
|
193
|
+
read(raw: unknown, options?: ReadOptions): SkewResult<TCurrent>;
|
|
194
|
+
/**
|
|
195
|
+
* Wraps a value for storage or transport.
|
|
196
|
+
*
|
|
197
|
+
* With no options, writes the current version. With `{ as }`, down-migrates
|
|
198
|
+
* first and writes the older envelope — the polite move when the reader is
|
|
199
|
+
* known to be older than this build.
|
|
200
|
+
*/
|
|
201
|
+
write(value: TCurrent, buildId?: string): VersionedEnvelope<TCurrent>;
|
|
202
|
+
write(value: TCurrent, options: WriteOptions): VersionedEnvelope;
|
|
203
|
+
/**
|
|
204
|
+
* Extends the schema with the next version. The description is required —
|
|
205
|
+
* it is the human-owned identity of the step, and the only part of a code
|
|
206
|
+
* step that two independent builds can be compared by.
|
|
207
|
+
*
|
|
208
|
+
* The returned schema is fully usable — there is no terminal `build()` call,
|
|
209
|
+
* so the chain reads as a single declaration.
|
|
210
|
+
*/
|
|
211
|
+
next<TNext>(description: string, migrate: (previous: TCurrent, ctx: MigrationContext) => TNext): VersionedSchema<TNext>;
|
|
212
|
+
next<TNext>(description: string, spec: CodeStepSpec<TCurrent, TNext>): VersionedSchema<TNext>;
|
|
213
|
+
next<TNext>(description: string, spec: OpsStepSpec): VersionedSchema<TNext>;
|
|
214
|
+
}
|
|
215
|
+
/** True when `value` looks like a {@link VersionedEnvelope}. */
|
|
216
|
+
export declare function isEnvelope(value: unknown): value is VersionedEnvelope;
|
|
217
|
+
/**
|
|
218
|
+
* Reads the version off raw data without migrating it.
|
|
219
|
+
* Returns `null` for data that carries no envelope.
|
|
220
|
+
*/
|
|
221
|
+
export declare function peekVersion(raw: unknown): number | null;
|
|
222
|
+
/**
|
|
223
|
+
* Begins a versioned schema declaration.
|
|
224
|
+
*
|
|
225
|
+
* @param name Stable identifier, used in diagnostics and by storage keys.
|
|
226
|
+
* @typeParam TBase The shape at version 1 — for an existing codebase, this is
|
|
227
|
+
* your *current* shape, so adoption requires no backfill.
|
|
228
|
+
*/
|
|
229
|
+
export declare function versioned<TBase>(name: string, options?: VersionedOptions<any>): VersionedSchema<TBase>;
|
|
230
|
+
/**
|
|
231
|
+
* Constructs a schema from an explicit step list — the loader's entry point,
|
|
232
|
+
* used by tooling that assembles steps from a contract document rather than
|
|
233
|
+
* declaring them fluently.
|
|
234
|
+
*
|
|
235
|
+
* The list is indexed by target version (`steps[0]` migrates to v2) and MAY
|
|
236
|
+
* contain holes: a hole is a transition this build knows *of* but cannot
|
|
237
|
+
* *run* — a contract's named code step whose implementation this bundle does
|
|
238
|
+
* not carry. Reads that need a missing step fail with `gap` (or fall back to
|
|
239
|
+
* a registry contribution), which is the loud degradation the contract format
|
|
240
|
+
* promises. Application code should prefer {@link versioned}.
|
|
241
|
+
*/
|
|
242
|
+
export declare function versionedFromSteps<TCurrent>(name: string, steps: readonly (MigrationStep | undefined)[], options?: VersionedOptions<any>): VersionedSchema<TCurrent>;
|
|
@@ -0,0 +1,275 @@
|
|
|
1
|
+
import { err, ok } from './result.js';
|
|
2
|
+
import { defaultMigrationContext } from './context.js';
|
|
3
|
+
import { compileLens } from './lens.js';
|
|
4
|
+
import { chainFingerprint } from './fingerprint.js';
|
|
5
|
+
import { registryStep } from './registry.js';
|
|
6
|
+
import { isSkewDisabled } from './disabled.js';
|
|
7
|
+
import { emitSkewTrace } from './devtools.js';
|
|
8
|
+
/** True when `value` looks like a {@link VersionedEnvelope}. */
|
|
9
|
+
export function isEnvelope(value) {
|
|
10
|
+
return (typeof value === 'object' &&
|
|
11
|
+
value !== null &&
|
|
12
|
+
typeof value.v === 'number' &&
|
|
13
|
+
'payload' in value);
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Reads the version off raw data without migrating it.
|
|
17
|
+
* Returns `null` for data that carries no envelope.
|
|
18
|
+
*/
|
|
19
|
+
export function peekVersion(raw) {
|
|
20
|
+
return isEnvelope(raw) ? raw.v : null;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Begins a versioned schema declaration.
|
|
24
|
+
*
|
|
25
|
+
* @param name Stable identifier, used in diagnostics and by storage keys.
|
|
26
|
+
* @typeParam TBase The shape at version 1 — for an existing codebase, this is
|
|
27
|
+
* your *current* shape, so adoption requires no backfill.
|
|
28
|
+
*/
|
|
29
|
+
export function versioned(name, options = {}) {
|
|
30
|
+
return build(name, [], options);
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Constructs a schema from an explicit step list — the loader's entry point,
|
|
34
|
+
* used by tooling that assembles steps from a contract document rather than
|
|
35
|
+
* declaring them fluently.
|
|
36
|
+
*
|
|
37
|
+
* The list is indexed by target version (`steps[0]` migrates to v2) and MAY
|
|
38
|
+
* contain holes: a hole is a transition this build knows *of* but cannot
|
|
39
|
+
* *run* — a contract's named code step whose implementation this bundle does
|
|
40
|
+
* not carry. Reads that need a missing step fail with `gap` (or fall back to
|
|
41
|
+
* a registry contribution), which is the loud degradation the contract format
|
|
42
|
+
* promises. Application code should prefer {@link versioned}.
|
|
43
|
+
*/
|
|
44
|
+
export function versionedFromSteps(name, steps, options = {}) {
|
|
45
|
+
return build(name, steps, options);
|
|
46
|
+
}
|
|
47
|
+
function build(name, steps, options) {
|
|
48
|
+
var _a, _b;
|
|
49
|
+
const base = (_a = options.base) !== null && _a !== void 0 ? _a : 1;
|
|
50
|
+
if (!Number.isInteger(base) || base < 1) {
|
|
51
|
+
throw new TypeError(`[${name}] base must be a positive integer, got ${base}`);
|
|
52
|
+
}
|
|
53
|
+
const version = base + steps.length;
|
|
54
|
+
const legacyVersion = (_b = options.assumeLegacyVersion) !== null && _b !== void 0 ? _b : 1;
|
|
55
|
+
let fingerprint = null;
|
|
56
|
+
/** Steps below the base were retired; the local chain starts above it. */
|
|
57
|
+
const localStep = (to) => to > base ? steps[to - base - 1] : undefined;
|
|
58
|
+
/** Local chain first; the shared registry covers what this build lacks. */
|
|
59
|
+
const stepFor = (to) => { var _a; return (_a = localStep(to)) !== null && _a !== void 0 ? _a : registryStep(name, to); };
|
|
60
|
+
const schema = {
|
|
61
|
+
name,
|
|
62
|
+
version,
|
|
63
|
+
steps,
|
|
64
|
+
get fingerprint() {
|
|
65
|
+
return (fingerprint !== null && fingerprint !== void 0 ? fingerprint : (fingerprint = chainFingerprint(name, version, steps)));
|
|
66
|
+
},
|
|
67
|
+
write(value, buildIdOrOptions) {
|
|
68
|
+
var _a, _b;
|
|
69
|
+
const opts = typeof buildIdOrOptions === 'string' || buildIdOrOptions === undefined
|
|
70
|
+
? { buildId: buildIdOrOptions }
|
|
71
|
+
: buildIdOrOptions;
|
|
72
|
+
const target = (_a = opts.as) !== null && _a !== void 0 ? _a : version;
|
|
73
|
+
const ctx = (_b = opts.context) !== null && _b !== void 0 ? _b : defaultMigrationContext;
|
|
74
|
+
if (!Number.isInteger(target) || target < 1 || target > version) {
|
|
75
|
+
throw new TypeError(`[${name}] cannot write at v${target}: this build knows v${base} through v${version}`);
|
|
76
|
+
}
|
|
77
|
+
if (target < base) {
|
|
78
|
+
throw new TypeError(`[${name}] cannot write at v${target}: versions below v${base} are retired — ` +
|
|
79
|
+
`this build's chain starts at its base, v${base}`);
|
|
80
|
+
}
|
|
81
|
+
let payload = value;
|
|
82
|
+
for (let from = version; from > target; from--) {
|
|
83
|
+
const step = localStep(from);
|
|
84
|
+
if (!(step === null || step === void 0 ? void 0 : step.down)) {
|
|
85
|
+
throw new TypeError(`[${name}] cannot write at v${target}: step v${from - 1} → v${from}` +
|
|
86
|
+
(step
|
|
87
|
+
? ` ("${step.description}") declares no down-migration`
|
|
88
|
+
: ' is missing'));
|
|
89
|
+
}
|
|
90
|
+
payload = step.down(payload, ctx);
|
|
91
|
+
}
|
|
92
|
+
const envelope = {
|
|
93
|
+
v: target,
|
|
94
|
+
n: name,
|
|
95
|
+
payload,
|
|
96
|
+
};
|
|
97
|
+
if (opts.buildId !== undefined)
|
|
98
|
+
envelope.b = opts.buildId;
|
|
99
|
+
emitSkewTrace({
|
|
100
|
+
kind: 'write',
|
|
101
|
+
schema: name,
|
|
102
|
+
from: version,
|
|
103
|
+
to: target,
|
|
104
|
+
ok: true,
|
|
105
|
+
ts: Date.now(),
|
|
106
|
+
});
|
|
107
|
+
return envelope;
|
|
108
|
+
},
|
|
109
|
+
read(raw, readOptions = {}) {
|
|
110
|
+
var _a;
|
|
111
|
+
const result = readImpl(raw, readOptions);
|
|
112
|
+
emitSkewTrace(Object.assign(Object.assign({ kind: 'read', schema: name, from: isEnvelope(raw)
|
|
113
|
+
? raw.v
|
|
114
|
+
: ((_a = readOptions.assumeVersion) !== null && _a !== void 0 ? _a : legacyVersion), to: version, ok: result.ok }, (result.ok
|
|
115
|
+
? {
|
|
116
|
+
migratedFrom: result.migratedFrom,
|
|
117
|
+
downgradedFrom: result.downgradedFrom,
|
|
118
|
+
derivedPaths: result.derivedPaths,
|
|
119
|
+
lossyPaths: result.lossyPaths,
|
|
120
|
+
}
|
|
121
|
+
: { reason: result.reason })), { ts: Date.now() }));
|
|
122
|
+
return result;
|
|
123
|
+
},
|
|
124
|
+
next(description, migrateOrSpec) {
|
|
125
|
+
var _a;
|
|
126
|
+
if (typeof description !== 'string' || description.length === 0) {
|
|
127
|
+
throw new TypeError(`[${name}] next() requires a description — it is the step's identity, ` +
|
|
128
|
+
`and the only thing two independent builds can compare a code step by`);
|
|
129
|
+
}
|
|
130
|
+
let step;
|
|
131
|
+
if (typeof migrateOrSpec === 'function') {
|
|
132
|
+
step = {
|
|
133
|
+
to: version + 1,
|
|
134
|
+
description,
|
|
135
|
+
up: migrateOrSpec,
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
else if (migrateOrSpec !== null &&
|
|
139
|
+
typeof migrateOrSpec === 'object' &&
|
|
140
|
+
'ops' in migrateOrSpec) {
|
|
141
|
+
const lens = compileLens(migrateOrSpec.ops);
|
|
142
|
+
step = {
|
|
143
|
+
to: version + 1,
|
|
144
|
+
description,
|
|
145
|
+
up: lens.up,
|
|
146
|
+
down: (_a = lens.down) !== null && _a !== void 0 ? _a : undefined,
|
|
147
|
+
derives: lens.derivedUp,
|
|
148
|
+
downDerives: lens.derivedDown,
|
|
149
|
+
lossy: lens.lossyDown,
|
|
150
|
+
ops: migrateOrSpec.ops,
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
else if (migrateOrSpec !== null &&
|
|
154
|
+
typeof migrateOrSpec === 'object' &&
|
|
155
|
+
typeof migrateOrSpec.up === 'function') {
|
|
156
|
+
const spec = migrateOrSpec;
|
|
157
|
+
step = {
|
|
158
|
+
to: version + 1,
|
|
159
|
+
description,
|
|
160
|
+
up: spec.up,
|
|
161
|
+
down: spec.down,
|
|
162
|
+
derives: spec.derives,
|
|
163
|
+
downDerives: spec.downDerives,
|
|
164
|
+
lossy: spec.lossy,
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
else {
|
|
168
|
+
throw new TypeError(`[${name}] next() requires a migration function, a { up, down? } spec, or { ops }`);
|
|
169
|
+
}
|
|
170
|
+
return build(name, [...steps, step], options);
|
|
171
|
+
},
|
|
172
|
+
};
|
|
173
|
+
function readImpl(raw, readOptions) {
|
|
174
|
+
var _a, _b;
|
|
175
|
+
// Not public API — see `disabled.ts`. Reproduces `raw as TCurrent`: no
|
|
176
|
+
// envelope check, no version comparison, no migration. Data from a newer
|
|
177
|
+
// build is handed back as though it were current, which is precisely the
|
|
178
|
+
// failure this function exists to prevent.
|
|
179
|
+
if (isSkewDisabled())
|
|
180
|
+
return ok(raw);
|
|
181
|
+
if (raw === null || raw === undefined) {
|
|
182
|
+
return err('invalid', 0, version, `[${name}] no data to read`);
|
|
183
|
+
}
|
|
184
|
+
const ctx = (_a = readOptions.context) !== null && _a !== void 0 ? _a : defaultMigrationContext;
|
|
185
|
+
const enveloped = isEnvelope(raw);
|
|
186
|
+
const found = enveloped
|
|
187
|
+
? raw.v
|
|
188
|
+
: ((_b = readOptions.assumeVersion) !== null && _b !== void 0 ? _b : legacyVersion);
|
|
189
|
+
let data = enveloped ? raw.payload : raw;
|
|
190
|
+
if (enveloped && typeof raw.n === 'string' && raw.n !== name) {
|
|
191
|
+
return err('invalid', found, version, `[${name}] envelope belongs to contract "${raw.n}", not "${name}" — ` +
|
|
192
|
+
`reading it through this schema would migrate the wrong data`);
|
|
193
|
+
}
|
|
194
|
+
if (!Number.isInteger(found) || found < 1) {
|
|
195
|
+
return err('invalid', found, version, `[${name}] envelope carries a non-version: ${found}`);
|
|
196
|
+
}
|
|
197
|
+
const derivedPaths = [];
|
|
198
|
+
const lossyPaths = [];
|
|
199
|
+
if (found > version) {
|
|
200
|
+
// Data from the future. It can still be read *if* every intervening
|
|
201
|
+
// step is known — locally or via the shared registry — and declares a
|
|
202
|
+
// down-migration; the result is an honest, lossy projection. When any
|
|
203
|
+
// step is missing or one-way, refuse exactly as before: guessing
|
|
204
|
+
// would discard data silently.
|
|
205
|
+
const descending = [];
|
|
206
|
+
for (let to = version + 1; to <= found; to++) {
|
|
207
|
+
const step = stepFor(to);
|
|
208
|
+
if (!(step === null || step === void 0 ? void 0 : step.down)) {
|
|
209
|
+
return err('ahead', found, version, `[${name}] data was written by a newer build (v${found}) than this one (v${version})` +
|
|
210
|
+
(step
|
|
211
|
+
? `, and step v${to - 1} → v${to} ("${step.description}") declares no down-migration. `
|
|
212
|
+
: `, and no loaded bundle or resolved contract knows the v${to - 1} → v${to} step. `) +
|
|
213
|
+
`Refetch, resolve the contract, or update the client — guessing would discard data.`);
|
|
214
|
+
}
|
|
215
|
+
descending.push(step);
|
|
216
|
+
}
|
|
217
|
+
for (let i = descending.length - 1; i >= 0; i--) {
|
|
218
|
+
const step = descending[i];
|
|
219
|
+
try {
|
|
220
|
+
data = step.down(data, ctx);
|
|
221
|
+
}
|
|
222
|
+
catch (cause) {
|
|
223
|
+
return err('threw', found, version, `[${name}] down-migration from v${step.to} ("${step.description}") failed`, cause);
|
|
224
|
+
}
|
|
225
|
+
if (step.lossy)
|
|
226
|
+
lossyPaths.push(...step.lossy);
|
|
227
|
+
if (step.downDerives)
|
|
228
|
+
derivedPaths.push(...step.downDerives);
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
if (found < version) {
|
|
232
|
+
for (let target = found + 1; target <= version; target++) {
|
|
233
|
+
const step = stepFor(target);
|
|
234
|
+
if (!step) {
|
|
235
|
+
if (found < base) {
|
|
236
|
+
// Below the declared floor, and nothing on the page supplies the
|
|
237
|
+
// missing step. Unlike `gap` this is not a bug: the steps were
|
|
238
|
+
// deliberately retired (see VersionedOptions.base). Distinct
|
|
239
|
+
// reason, distinct remedy — discard/refetch/reset, not "report".
|
|
240
|
+
return {
|
|
241
|
+
ok: false,
|
|
242
|
+
reason: 'retired',
|
|
243
|
+
found,
|
|
244
|
+
expected: version,
|
|
245
|
+
floor: base,
|
|
246
|
+
message: `[${name}] data at v${found} is below this build's retired floor (v${base}), ` +
|
|
247
|
+
`and no loaded bundle or resolved contract supplies the v${target - 1} → v${target} step. ` +
|
|
248
|
+
`This is a cleanup-policy outcome, not a bug: discard and refetch, or offer a reset.`,
|
|
249
|
+
};
|
|
250
|
+
}
|
|
251
|
+
return err('gap', found, version, `[${name}] no migration declared for v${target - 1} → v${target}`);
|
|
252
|
+
}
|
|
253
|
+
try {
|
|
254
|
+
data = step.up(data, ctx);
|
|
255
|
+
}
|
|
256
|
+
catch (cause) {
|
|
257
|
+
return err('threw', found, version, `[${name}] migration to v${target} ("${step.description}") failed`, cause);
|
|
258
|
+
}
|
|
259
|
+
if (step.derives)
|
|
260
|
+
derivedPaths.push(...step.derives);
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
if (options.validate && !options.validate(data)) {
|
|
264
|
+
return err('invalid', found, version, `[${name}] value failed validation after migrating v${found} → v${version}`);
|
|
265
|
+
}
|
|
266
|
+
return ok(data, {
|
|
267
|
+
migratedFrom: found < version ? found : null,
|
|
268
|
+
downgradedFrom: found > version ? found : null,
|
|
269
|
+
derivedPaths,
|
|
270
|
+
lossyPaths,
|
|
271
|
+
});
|
|
272
|
+
}
|
|
273
|
+
return schema;
|
|
274
|
+
}
|
|
275
|
+
//# sourceMappingURL=versioned.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"versioned.js","sourceRoot":"","sources":["../../../../../libs/skew/src/lib/versioned.ts"],"names":[],"mappings":"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"}
|