@rotorsoft/act 2.1.1 → 2.1.2
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/.tsbuildinfo +1 -1
- package/dist/@types/act.d.ts.map +1 -1
- package/dist/@types/csv.d.ts +2 -1
- package/dist/@types/csv.d.ts.map +1 -1
- package/dist/@types/internal/correlate-cycle.d.ts.map +1 -1
- package/dist/@types/scoped.d.ts +2 -4
- package/dist/@types/scoped.d.ts.map +1 -1
- package/dist/@types/types/action.d.ts +1 -213
- package/dist/@types/types/action.d.ts.map +1 -1
- package/dist/@types/types/index.d.ts +1 -0
- package/dist/@types/types/index.d.ts.map +1 -1
- package/dist/@types/types/ports.d.ts +2 -1
- package/dist/@types/types/ports.d.ts.map +1 -1
- package/dist/@types/types/restore.d.ts +220 -0
- package/dist/@types/types/restore.d.ts.map +1 -0
- package/dist/adapter.cjs +3 -3
- package/dist/adapter.js +2 -2
- package/dist/{chunk-QPVUARKL.js → chunk-ADMH76IO.js} +3 -3
- package/dist/{chunk-QPVUARKL.js.map → chunk-ADMH76IO.js.map} +1 -1
- package/dist/{chunk-W3PHEA5Q.js → chunk-C35J3SNT.js} +1 -1
- package/dist/chunk-C35J3SNT.js.map +1 -0
- package/dist/{chunk-PZQXTGWF.cjs → chunk-D7LQNOEV.cjs} +4 -4
- package/dist/{chunk-PZQXTGWF.cjs.map → chunk-D7LQNOEV.cjs.map} +1 -1
- package/dist/{chunk-7VYSJIXD.cjs → chunk-QFYPSI6P.cjs} +1 -1
- package/dist/chunk-QFYPSI6P.cjs.map +1 -0
- package/dist/{chunk-LN3OP4OL.cjs → chunk-QWYMR7ZP.cjs} +17 -17
- package/dist/{chunk-LN3OP4OL.cjs.map → chunk-QWYMR7ZP.cjs.map} +1 -1
- package/dist/{chunk-UXDNSZAD.js → chunk-TUALNYW2.js} +2 -2
- package/dist/index.cjs +192 -196
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +9 -13
- package/dist/index.js.map +1 -1
- package/dist/test/index.cjs +5 -5
- package/dist/test/index.js +3 -3
- package/dist/types/index.cjs +2 -2
- package/dist/types/index.js +1 -1
- package/package.json +1 -1
- package/dist/chunk-7VYSJIXD.cjs.map +0 -1
- package/dist/chunk-W3PHEA5Q.js.map +0 -1
- /package/dist/{chunk-UXDNSZAD.js.map → chunk-TUALNYW2.js.map} +0 -0
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module act/types/restore
|
|
3
|
+
* Types for restore and transfer: the scan options and result, the source
|
|
4
|
+
* an `IAct.restore` reads and the sink it writes.
|
|
5
|
+
*/
|
|
6
|
+
import type { Committed, Query, Schemas } from "./action.js";
|
|
7
|
+
import type { Disposable } from "./ports.js";
|
|
8
|
+
/**
|
|
9
|
+
* Options for the orchestrator's restore scan loop, consumed by
|
|
10
|
+
* {@link IAct.restore} (and threaded through to the internal `scan`).
|
|
11
|
+
* Adapters never see these — they're entirely interpreted on the
|
|
12
|
+
* orchestrator side.
|
|
13
|
+
*
|
|
14
|
+
* Compaction flags ({@link drop_snapshots}, {@link drop_closed_streams})
|
|
15
|
+
* and the migration overlay ({@link event_migrations},
|
|
16
|
+
* {@link stream_rename}) all apply per event before the sink writes
|
|
17
|
+
* anything. Any throw aborts the whole scan — atomic rollback in the
|
|
18
|
+
* sink means a failing transform leaves the target byte-for-byte
|
|
19
|
+
* unchanged.
|
|
20
|
+
*/
|
|
21
|
+
export type ScanOptions = {
|
|
22
|
+
/**
|
|
23
|
+
* Skip events with `name === SNAP_EVENT`. The next snap policy
|
|
24
|
+
* regenerates snapshots against current code; useful for backups
|
|
25
|
+
* that should compact stale snapshot bytes. Counted in
|
|
26
|
+
* {@link ScanResult.dropped}`.snapshots`.
|
|
27
|
+
*
|
|
28
|
+
* Single-pass: no source-shape implications. Default `false`.
|
|
29
|
+
*/
|
|
30
|
+
readonly drop_snapshots?: boolean;
|
|
31
|
+
/**
|
|
32
|
+
* Optional progress callback. The scan loop fires it once per event
|
|
33
|
+
* during iteration. Three fields:
|
|
34
|
+
*
|
|
35
|
+
* - `processed` — running 1-based count of events processed.
|
|
36
|
+
* - `id` — current event's id.
|
|
37
|
+
* - `max_id` — highest id in the source, probed once at scan start
|
|
38
|
+
* via `source.query(noop, { backward: true, limit: 1 })`. O(1) on
|
|
39
|
+
* indexed stores. Left `undefined` when the probe can't determine
|
|
40
|
+
* it (e.g. `CsvFile`-style sources that ignore the filter and
|
|
41
|
+
* stream more than one event from the probe call).
|
|
42
|
+
*
|
|
43
|
+
* UIs render either `processed / ?` (event count) or `id / max_id`
|
|
44
|
+
* (position through the id space) depending on need.
|
|
45
|
+
*
|
|
46
|
+
* Synchronous handler — the scan loop calls it directly.
|
|
47
|
+
* **Throttling / batching is the caller's responsibility**: for a
|
|
48
|
+
* million-event restore, debounce in the handler rather than
|
|
49
|
+
* expecting the loop to coalesce calls. Keeping it unthrottled
|
|
50
|
+
* means callers that want every-event reporting get it without a
|
|
51
|
+
* config knob.
|
|
52
|
+
*/
|
|
53
|
+
readonly on_progress?: (p: {
|
|
54
|
+
processed: number;
|
|
55
|
+
id: number;
|
|
56
|
+
max_id?: number;
|
|
57
|
+
}) => void;
|
|
58
|
+
/**
|
|
59
|
+
* Per-batch row count for the scan pagination loop. Each
|
|
60
|
+
* call to `source.query` requests `limit: batch_size` and `after:
|
|
61
|
+
* <last id seen>`. Default `500`. Lower values trade round trips for
|
|
62
|
+
* memory; higher values approach the cost of an unbounded query.
|
|
63
|
+
*/
|
|
64
|
+
readonly batch_size?: number;
|
|
65
|
+
/**
|
|
66
|
+
* When `true`, {@link IAct.restore} runs the scan loop without
|
|
67
|
+
* touching the store — events are validated and counted but no
|
|
68
|
+
* transaction is opened and no rows are written. Returned `kept` /
|
|
69
|
+
* `dropped` reflect what a subsequent destructive restore against
|
|
70
|
+
* the same source would land; a throw means the source has a
|
|
71
|
+
* blocker (the running index pinpoints it).
|
|
72
|
+
*
|
|
73
|
+
* No `Store.restore` capability is required for a dry-run — the
|
|
74
|
+
* adapter is never called. Default `false`.
|
|
75
|
+
*/
|
|
76
|
+
readonly dry_run?: boolean;
|
|
77
|
+
/**
|
|
78
|
+
* Compact streams that have been closed (tombstoned) via
|
|
79
|
+
* {@link IAct.close}. The scan walks the source once
|
|
80
|
+
* upfront to collect streams with a `__tombstone__` event, then
|
|
81
|
+
* the main loop drops every **pre-close event** whose stream is in
|
|
82
|
+
* that set. The tombstone itself is **kept** — it's the gate that
|
|
83
|
+
* makes {@link IAct.do} throw `StreamClosedError` in the rebuilt
|
|
84
|
+
* store, so dropping it would silently reopen the stream.
|
|
85
|
+
*
|
|
86
|
+
* Useful for compaction during transfer: the new (migrated) store
|
|
87
|
+
* keeps the close gate but drops the historical detail.
|
|
88
|
+
*
|
|
89
|
+
* Counted in {@link ScanResult.dropped}`.closed_streams` (pre-close
|
|
90
|
+
* events only; the tombstone is counted in `kept`).
|
|
91
|
+
*
|
|
92
|
+
* Default `false`.
|
|
93
|
+
*/
|
|
94
|
+
readonly drop_closed_streams?: boolean;
|
|
95
|
+
/**
|
|
96
|
+
* Per-event migrations applied during scan. Keys are
|
|
97
|
+
* source event names; values describe how to rewrite the event into
|
|
98
|
+
* its current-version form before the sink writes it.
|
|
99
|
+
*
|
|
100
|
+
* Transfer-time only — never registered at app build time and never
|
|
101
|
+
* auto-applied to a live store. Operators configure migrations
|
|
102
|
+
* explicitly per-call (typically through the inspector's transfer
|
|
103
|
+
* dialog when moving from an old store to a new one).
|
|
104
|
+
*
|
|
105
|
+
* Each row that matches a key:
|
|
106
|
+
* 1. parses `event.data` against `from_schema` (validates source);
|
|
107
|
+
* 2. runs `migrate(parsed)` to transform the payload;
|
|
108
|
+
* 3. parses the result against `to_schema` (validates target);
|
|
109
|
+
* 4. is rewritten with `name = to` and `data = migrated`.
|
|
110
|
+
*
|
|
111
|
+
* Any throw aborts the whole scan — atomic transaction rollback in
|
|
112
|
+
* the sink means a failing migration leaves the target byte-for-byte
|
|
113
|
+
* unchanged.
|
|
114
|
+
*/
|
|
115
|
+
readonly event_migrations?: Record<string, EventMigration<any, any>>;
|
|
116
|
+
/**
|
|
117
|
+
* Per-stream rename applied during scan. The returned string
|
|
118
|
+
* replaces `event.stream` and the streams named in its causation. Useful for
|
|
119
|
+
* tenant relocation (`s => s.replace(/^old-tenant-/, "new-tenant-")`)
|
|
120
|
+
* or prefix cleanup.
|
|
121
|
+
*
|
|
122
|
+
* Applied AFTER {@link event_migrations} so the migration sees the
|
|
123
|
+
* original stream name (in case the migration's `migrate` function
|
|
124
|
+
* inspects it).
|
|
125
|
+
*/
|
|
126
|
+
readonly stream_rename?: (stream: string) => string;
|
|
127
|
+
};
|
|
128
|
+
/**
|
|
129
|
+
* Per-event migration definition for {@link ScanOptions.event_migrations}.
|
|
130
|
+
* Carries both the rename target and the schema-guarded transform that
|
|
131
|
+
* rewrites the event's `data` payload.
|
|
132
|
+
*/
|
|
133
|
+
export type EventMigration<TOld, TNew> = {
|
|
134
|
+
/** Target event name (the current version). */
|
|
135
|
+
readonly to: string;
|
|
136
|
+
/** Schema of the source event's `data`. Throws on mismatch. */
|
|
137
|
+
readonly from_schema: {
|
|
138
|
+
parse: (data: unknown) => TOld;
|
|
139
|
+
};
|
|
140
|
+
/** Schema of the migrated event's `data`. Throws on mismatch. */
|
|
141
|
+
readonly to_schema: {
|
|
142
|
+
parse: (data: unknown) => TNew;
|
|
143
|
+
};
|
|
144
|
+
/** Pure data transformer. */
|
|
145
|
+
readonly migrate: (data: TOld) => TNew;
|
|
146
|
+
};
|
|
147
|
+
/**
|
|
148
|
+
* Result of {@link IAct.restore}.
|
|
149
|
+
*
|
|
150
|
+
* `kept` and `duration_ms` are always populated. `dropped` carries
|
|
151
|
+
* per-category counters when {@link ScanOptions.drop_snapshots} (or
|
|
152
|
+
* future compaction flags) trigger drops; otherwise zeros. Live
|
|
153
|
+
* restore is atomic — any error throws and rolls back, so there's no
|
|
154
|
+
* per-event error reporting on the result.
|
|
155
|
+
*/
|
|
156
|
+
export type ScanResult = {
|
|
157
|
+
/** Number of events written to the rebuilt store. */
|
|
158
|
+
readonly kept: number;
|
|
159
|
+
/** Wall-clock duration of the call, in milliseconds. */
|
|
160
|
+
readonly duration_ms: number;
|
|
161
|
+
/** Per-category drop counters. */
|
|
162
|
+
readonly dropped: {
|
|
163
|
+
readonly closed_streams: number;
|
|
164
|
+
readonly snapshots: number;
|
|
165
|
+
};
|
|
166
|
+
/** Events rewritten by {@link ScanOptions.event_migrations}. */
|
|
167
|
+
readonly migrated: number;
|
|
168
|
+
};
|
|
169
|
+
/**
|
|
170
|
+
* Construct a {@link CsvFile} from either a filesystem path (for
|
|
171
|
+
* reading and/or writing through the OS) or an in-memory blob (a
|
|
172
|
+
* pre-loaded CSV string, used by the inspector when a CSV arrives
|
|
173
|
+
* over the wire via tRPC).
|
|
174
|
+
*
|
|
175
|
+
* Both modes share the same on-disk format, so the same blob shape
|
|
176
|
+
* can be round-tripped through the transfer pipeline.
|
|
177
|
+
*/
|
|
178
|
+
export type CsvFileOptions = {
|
|
179
|
+
path: string;
|
|
180
|
+
} | {
|
|
181
|
+
blob: string;
|
|
182
|
+
};
|
|
183
|
+
/**
|
|
184
|
+
* Read end of the transfer pipeline. Anything
|
|
185
|
+
* that exposes a `Store.query`-shaped reader plus `dispose` can be
|
|
186
|
+
* used as a source for {@link IAct.restore}.
|
|
187
|
+
*
|
|
188
|
+
* `Store` extends this interface; the framework's `CsvFile` utility
|
|
189
|
+
* implements it on top of file I/O so a CSV can be a transfer
|
|
190
|
+
* source. The pipeline never sees a discriminator — both ends speak
|
|
191
|
+
* the same shape.
|
|
192
|
+
*/
|
|
193
|
+
export interface EventSource extends Disposable {
|
|
194
|
+
/**
|
|
195
|
+
* Read events into a per-event callback. Adapters MUST `await
|
|
196
|
+
* Promise.resolve(callback(event))` per event — sync callbacks
|
|
197
|
+
* resolve immediately (zero overhead), async callbacks throttle
|
|
198
|
+
* the read loop. This is the seam that lets `iterate()` apply
|
|
199
|
+
* backpressure without changing the callback's declared return
|
|
200
|
+
* type. Callback returns `void`, which TypeScript treats as
|
|
201
|
+
* "return value ignored" — existing call sites passing
|
|
202
|
+
* `e => arr.push(e)` (which returns `number`) keep working.
|
|
203
|
+
*/
|
|
204
|
+
query<E extends Schemas>(callback: (event: Committed<E, keyof E>) => void, query?: Query): Promise<number>;
|
|
205
|
+
}
|
|
206
|
+
/**
|
|
207
|
+
* Write end of the transfer pipeline. Anything
|
|
208
|
+
* that can host the destructive driver-pattern `restore` HOF (atomic
|
|
209
|
+
* wipe + per-event commit) is an `EventSink` — `Store` adapters
|
|
210
|
+
* that ship the optional `restore` method, plus the framework's
|
|
211
|
+
* `CsvFile` utility for "write to a file" targets.
|
|
212
|
+
*
|
|
213
|
+
* `restore` is required here (vs. optional on `Store`) because the
|
|
214
|
+
* sink slot in {@link IAct.restore} demands a writer; non-restorable
|
|
215
|
+
* stores satisfy {@link EventSource} only.
|
|
216
|
+
*/
|
|
217
|
+
export interface EventSink extends Disposable {
|
|
218
|
+
restore(driver: (callback: (event: Committed<Schemas, keyof Schemas>) => Promise<number>) => Promise<void>): Promise<void>;
|
|
219
|
+
}
|
|
220
|
+
//# sourceMappingURL=restore.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"restore.d.ts","sourceRoot":"","sources":["../../../src/types/restore.ts"],"names":[],"mappings":"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"}
|
package/dist/adapter.cjs
CHANGED
|
@@ -6,8 +6,8 @@
|
|
|
6
6
|
|
|
7
7
|
|
|
8
8
|
|
|
9
|
-
var
|
|
10
|
-
require('./chunk-
|
|
9
|
+
var _chunkD7LQNOEVcjs = require('./chunk-D7LQNOEV.cjs');
|
|
10
|
+
require('./chunk-QFYPSI6P.cjs');
|
|
11
11
|
|
|
12
12
|
|
|
13
13
|
|
|
@@ -16,5 +16,5 @@ require('./chunk-7VYSJIXD.cjs');
|
|
|
16
16
|
|
|
17
17
|
|
|
18
18
|
|
|
19
|
-
exports.checkAppends =
|
|
19
|
+
exports.checkAppends = _chunkD7LQNOEVcjs.checkAppends; exports.checkVersion = _chunkD7LQNOEVcjs.checkVersion; exports.concurrencyError = _chunkD7LQNOEVcjs.concurrencyError; exports.fairSlots = _chunkD7LQNOEVcjs.fairSlots; exports.isStreamName = _chunkD7LQNOEVcjs.isStreamName; exports.parseNotification = _chunkD7LQNOEVcjs.parseNotification; exports.seedEvent = _chunkD7LQNOEVcjs.seedEvent;
|
|
20
20
|
//# sourceMappingURL=adapter.cjs.map
|
package/dist/adapter.js
CHANGED
|
@@ -3,7 +3,7 @@ import {
|
|
|
3
3
|
checkVersion,
|
|
4
4
|
fairSlots,
|
|
5
5
|
seedEvent
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-TUALNYW2.js";
|
|
7
7
|
import {
|
|
8
8
|
DEFAULT_LANE,
|
|
9
9
|
DEFAULT_QUERY_STREAMS_LIMIT,
|
|
@@ -11,7 +11,7 @@ import {
|
|
|
11
11
|
LogLevels,
|
|
12
12
|
SNAP_EVENT,
|
|
13
13
|
ValidationError
|
|
14
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-C35J3SNT.js";
|
|
15
15
|
|
|
16
16
|
// src/adapters/console-logger.ts
|
|
17
17
|
var LEVEL_VALUES = {
|
|
@@ -1201,4 +1201,4 @@ export {
|
|
|
1201
1201
|
disposeAndExit,
|
|
1202
1202
|
dispose
|
|
1203
1203
|
};
|
|
1204
|
-
//# sourceMappingURL=chunk-
|
|
1204
|
+
//# sourceMappingURL=chunk-ADMH76IO.js.map
|