@camstack/types 1.2.123 → 1.2.126
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/addon.js +6 -3
- package/dist/addon.mjs +6 -3
- package/dist/capabilities/pipeline-analytics.cap.d.ts +46 -0
- package/dist/capabilities/recording.cap.d.ts +20 -0
- package/dist/capabilities/storage-migration.cap.d.ts +130 -0
- package/dist/capabilities/storage.cap.d.ts +19 -0
- package/dist/capabilities/vector-store.cap.d.ts +113 -6
- package/dist/generated/addon-api.d.ts +56 -0
- package/dist/generated/cap-input-defaults.d.ts +1 -1
- package/dist/generated/method-access-map.d.ts +1 -1
- package/dist/generated/system-proxy.d.ts +2 -2
- package/dist/index.d.ts +3 -2
- package/dist/index.js +656 -24
- package/dist/index.mjs +637 -25
- package/dist/interfaces/addon.d.ts +67 -0
- package/dist/interfaces/config-ui-secrets.d.ts +48 -0
- package/dist/interfaces/config-ui.d.ts +17 -0
- package/dist/interfaces/relocate.d.ts +370 -6
- package/dist/interfaces/storage-location-declaration.d.ts +40 -0
- package/dist/{sleep-DUxF5DdC.js → sleep-CWWLTM6W.js} +2 -0
- package/dist/{sleep-C9C8EoK8.mjs → sleep-bm0x6zZF.mjs} +2 -0
- package/package.json +1 -1
|
@@ -1025,6 +1025,36 @@ export interface AddonDeclaration {
|
|
|
1025
1025
|
* `ctx.deps.installPythonRequirements(absolutePath)`.
|
|
1026
1026
|
*/
|
|
1027
1027
|
readonly python?: AddonPythonRequirements;
|
|
1028
|
+
/**
|
|
1029
|
+
* Host binaries this addon needs on PATH. Same declaration site, same
|
|
1030
|
+
* lifecycle position and same idempotence contract as {@link python} —
|
|
1031
|
+
* the runner satisfies them BEFORE `onInitialize()` runs, so a capability
|
|
1032
|
+
* never advertises itself while the binary it wraps is missing.
|
|
1033
|
+
*
|
|
1034
|
+
* The declaration names WHAT is needed (a binary) plus the package name
|
|
1035
|
+
* each host package manager knows it by — a translation table, not a
|
|
1036
|
+
* procedure. HOW to install (`apt-get update && apt-get install -y …`,
|
|
1037
|
+
* `brew install …`) belongs to the framework, so the next addon that needs
|
|
1038
|
+
* a binary does not re-answer the question.
|
|
1039
|
+
*
|
|
1040
|
+
* Example:
|
|
1041
|
+
* ```jsonc
|
|
1042
|
+
* "camstack": {
|
|
1043
|
+
* "addons": [{
|
|
1044
|
+
* "id": "smb-storage",
|
|
1045
|
+
* "systemDependencies": [
|
|
1046
|
+
* { "binary": "smbclient", "packages": { "apt": "smbclient", "brew": "samba" } }
|
|
1047
|
+
* ]
|
|
1048
|
+
* }]
|
|
1049
|
+
* }
|
|
1050
|
+
* ```
|
|
1051
|
+
*
|
|
1052
|
+
* Failure is NOT fatal: the addon still loads and the capability that needs
|
|
1053
|
+
* the binary must refuse loudly on its own surface. A provider that cannot
|
|
1054
|
+
* run must never make its locations read as *empty* — `empty` is deletable
|
|
1055
|
+
* (D293).
|
|
1056
|
+
*/
|
|
1057
|
+
readonly systemDependencies?: readonly AddonSystemDependency[];
|
|
1028
1058
|
/** Default configuration values */
|
|
1029
1059
|
readonly defaultConfig?: Readonly<Record<string, unknown>>;
|
|
1030
1060
|
/**
|
|
@@ -1046,6 +1076,43 @@ export interface AddonPythonRequirements {
|
|
|
1046
1076
|
*/
|
|
1047
1077
|
readonly requirements: string;
|
|
1048
1078
|
}
|
|
1079
|
+
/**
|
|
1080
|
+
* One host binary an addon needs on PATH. See
|
|
1081
|
+
* `AddonDeclaration.systemDependencies`.
|
|
1082
|
+
*
|
|
1083
|
+
* Deliberately NOT a shell command. A manifest that carried
|
|
1084
|
+
* `"install": "apt-get install -y smbclient"` would be a per-addon script the
|
|
1085
|
+
* framework runs blind — unportable, unverifiable, and a second answer to a
|
|
1086
|
+
* question the Python mechanism already answered once.
|
|
1087
|
+
*/
|
|
1088
|
+
export interface AddonSystemDependency {
|
|
1089
|
+
/**
|
|
1090
|
+
* The executable that must resolve on PATH after the step completes. This
|
|
1091
|
+
* is both the presence check (cheap, and what makes the common path a
|
|
1092
|
+
* no-op) and the success check.
|
|
1093
|
+
*/
|
|
1094
|
+
readonly binary: string;
|
|
1095
|
+
/**
|
|
1096
|
+
* Package name per host package manager. A manager absent from this map
|
|
1097
|
+
* means "this addon has no way to install the binary on that host" — the
|
|
1098
|
+
* runner logs it and continues rather than guessing that the package shares
|
|
1099
|
+
* the binary's name.
|
|
1100
|
+
*/
|
|
1101
|
+
readonly packages: AddonSystemDependencyPackages;
|
|
1102
|
+
/** Operator-facing reason, surfaced in the log line when the install fails. */
|
|
1103
|
+
readonly reason?: string;
|
|
1104
|
+
}
|
|
1105
|
+
/** Package name per supported host package manager. */
|
|
1106
|
+
export interface AddonSystemDependencyPackages {
|
|
1107
|
+
/** Debian / Ubuntu (`apt-get`) — the container base. */
|
|
1108
|
+
readonly apt?: string;
|
|
1109
|
+
/** Alpine (`apk`). */
|
|
1110
|
+
readonly apk?: string;
|
|
1111
|
+
/** Fedora / RHEL (`dnf`). */
|
|
1112
|
+
readonly dnf?: string;
|
|
1113
|
+
/** macOS Homebrew (`brew`) — the desktop build. */
|
|
1114
|
+
readonly brew?: string;
|
|
1115
|
+
}
|
|
1049
1116
|
export interface AddonPackageManifest {
|
|
1050
1117
|
/**
|
|
1051
1118
|
* Human-readable package name for UI display (e.g., "Pipeline", "Core").
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Secret-field discovery over a {@link ConfigUISchema}.
|
|
3
|
+
*
|
|
4
|
+
* A provider already declares its own form. That declaration is the ONLY place
|
|
5
|
+
* that knows which of its config keys hold a credential, so redaction reads it
|
|
6
|
+
* rather than keeping a second, hand-maintained key list somewhere in the
|
|
7
|
+
* orchestrator — a list that would be right on the day it was written and
|
|
8
|
+
* wrong on the day a provider gained a field.
|
|
9
|
+
*
|
|
10
|
+
* The discriminator is deliberately NOT `type === 'password'` alone. That was
|
|
11
|
+
* the first design and it is wrong: the SFTP provider's `privateKey` is a
|
|
12
|
+
* `textarea` holding a full PEM key. Keying off the input widget would have
|
|
13
|
+
* left it on the wire while reporting that secrets were redacted. See
|
|
14
|
+
* `ConfigFieldBase.secret`.
|
|
15
|
+
*
|
|
16
|
+
* The walk takes `unknown` because that is what the caller has: the
|
|
17
|
+
* `storage-provider` cap declares `configSchema: z.unknown()`, so a provider's
|
|
18
|
+
* schema arrives structurally unverified. It narrows defensively at every
|
|
19
|
+
* step and ignores anything it cannot read — an unreadable node contributes no
|
|
20
|
+
* keys, which is the direction that under-reports rather than over-reports.
|
|
21
|
+
* A caller that needs "did I understand this schema at all" asks
|
|
22
|
+
* {@link schemaDeclaresAnyField}, which answers `false` for a shape this
|
|
23
|
+
* cannot read, so "no secrets" and "no schema" stay distinguishable.
|
|
24
|
+
*/
|
|
25
|
+
import type { ConfigField } from './config-ui.js';
|
|
26
|
+
/**
|
|
27
|
+
* The value a redacted secret is replaced with on every read surface.
|
|
28
|
+
*
|
|
29
|
+
* It is also the WRITE-BACK token: an `upsertLocation` that sends this value
|
|
30
|
+
* back for a key means "keep what is stored", which is what lets an operator
|
|
31
|
+
* rename a location without retyping its password. A literal an operator could
|
|
32
|
+
* plausibly choose as a real password would turn that convenience into a way
|
|
33
|
+
* to lock yourself out, hence the sentinel shape.
|
|
34
|
+
*/
|
|
35
|
+
export declare const REDACTED_SECRET = "__camstack_redacted__";
|
|
36
|
+
/** Is this field's stored value a credential? */
|
|
37
|
+
export declare function isSecretConfigField(field: ConfigField): boolean;
|
|
38
|
+
/**
|
|
39
|
+
* Every config key in `schema` whose value is a secret, including keys nested
|
|
40
|
+
* inside `group` / `sub-tabs` containers.
|
|
41
|
+
*/
|
|
42
|
+
export declare function collectSecretConfigKeys(schema: unknown): ReadonlySet<string>;
|
|
43
|
+
/**
|
|
44
|
+
* True when the value is a readable schema declaring at least one field of any
|
|
45
|
+
* kind. Lets a caller tell "this provider has no secrets" from "this provider's
|
|
46
|
+
* schema could not be read", which are the same empty set otherwise.
|
|
47
|
+
*/
|
|
48
|
+
export declare function schemaDeclaresAnyField(schema: unknown): boolean;
|
|
@@ -124,6 +124,23 @@ export interface ConfigFieldBase {
|
|
|
124
124
|
readonly default?: unknown;
|
|
125
125
|
readonly span?: 1 | 2 | 3 | 4;
|
|
126
126
|
readonly showWhen?: ConfigCondition;
|
|
127
|
+
/**
|
|
128
|
+
* The field's stored value is a CREDENTIAL and must never leave the process
|
|
129
|
+
* on a read surface. Redaction machinery keys off
|
|
130
|
+
* {@link isSecretConfigField}, which treats `type: 'password'` as implicitly
|
|
131
|
+
* secret — this flag exists for the fields that carry a secret WITHOUT being
|
|
132
|
+
* a password input.
|
|
133
|
+
*
|
|
134
|
+
* The concrete miss it was added for: the SFTP provider's `privateKey` is a
|
|
135
|
+
* `textarea` (a PEM block does not fit a one-line password box) holding a
|
|
136
|
+
* complete SSH private key. A redaction that trusted `type: 'password'`
|
|
137
|
+
* alone would have shipped with that key still on the wire and an assurance
|
|
138
|
+
* that credentials were redacted — worse than no redaction at all.
|
|
139
|
+
*
|
|
140
|
+
* Mark it on any field whose value would compromise something if read by a
|
|
141
|
+
* non-admin session. It costs nothing when the field is already a password.
|
|
142
|
+
*/
|
|
143
|
+
readonly secret?: boolean;
|
|
127
144
|
/** Per-model knob applicability — see {@link ConfigFieldModelApplicability}. */
|
|
128
145
|
readonly modelApplicability?: ConfigFieldModelApplicability;
|
|
129
146
|
/**
|
|
@@ -91,24 +91,77 @@ export declare const StorageMigrationFootageMoveInputSchema: z.ZodObject<{
|
|
|
91
91
|
leaseId: z.ZodString;
|
|
92
92
|
}, z.core.$strip>;
|
|
93
93
|
export type StorageMigrationFootageMoveInput = z.infer<typeof StorageMigrationFootageMoveInputSchema>;
|
|
94
|
+
/**
|
|
95
|
+
* What a `relocateMedia` pass DOES. One engine, three passes — never a second
|
|
96
|
+
* mover (the engine already walks both collections with a timestamp cursor and
|
|
97
|
+
* already has a stamp-without-copy path).
|
|
98
|
+
*
|
|
99
|
+
* - `move` — the default and the historical behaviour: event-media and
|
|
100
|
+
* retrain blobs move to `toLocationId` and their rows are
|
|
101
|
+
* stamped. The enrolled gallery is skipped (D197).
|
|
102
|
+
* - `seal` — ROWS ONLY, no bytes. Every row whose `locationId` is NULL is
|
|
103
|
+
* stamped with `toLocationId`. `toLocationId` here is the id the
|
|
104
|
+
* bytes ALREADY sit on — today's `eventMedia` default — because
|
|
105
|
+
* a NULL row means "wherever `eventMedia` points *now*", and the
|
|
106
|
+
* instant a repoint moves that pointer the row reads from the
|
|
107
|
+
* new disk while its bytes are on the old one.
|
|
108
|
+
* - `gallery` — the inverse selection of `move`: ONLY the retention-exempt
|
|
109
|
+
* (enrolled-gallery) rows, which `move` deliberately skips.
|
|
110
|
+
* `galleryMedia` is `cardinality: 'single'`, so this pass can
|
|
111
|
+
* never run beside a live second location: it is stop-the-world
|
|
112
|
+
* by construction, which is acceptable only because the gallery
|
|
113
|
+
* is a few KB per enrolled sample.
|
|
114
|
+
*/
|
|
115
|
+
export declare const MediaRelocateModeSchema: z.ZodEnum<{
|
|
116
|
+
move: "move";
|
|
117
|
+
seal: "seal";
|
|
118
|
+
gallery: "gallery";
|
|
119
|
+
}>;
|
|
120
|
+
export type MediaRelocateMode = z.infer<typeof MediaRelocateModeSchema>;
|
|
94
121
|
export declare const RelocateMediaInputSchema: z.ZodObject<{
|
|
95
122
|
toLocationId: z.ZodString;
|
|
96
123
|
throttleMbps: z.ZodOptional<z.ZodNumber>;
|
|
124
|
+
mode: z.ZodOptional<z.ZodEnum<{
|
|
125
|
+
move: "move";
|
|
126
|
+
seal: "seal";
|
|
127
|
+
gallery: "gallery";
|
|
128
|
+
}>>;
|
|
97
129
|
}, z.core.$strip>;
|
|
98
130
|
export type RelocateMediaInput = z.infer<typeof RelocateMediaInputSchema>;
|
|
131
|
+
/** How many rows still carry NO `locationId` — the population a repoint would
|
|
132
|
+
* silently re-aim at a disk that does not hold their bytes. Zero is the only
|
|
133
|
+
* value that permits a non-blocking `eventMedia` cutover. */
|
|
134
|
+
export declare const UnstampedEventMediaCountSchema: z.ZodObject<{
|
|
135
|
+
media: z.ZodNumber;
|
|
136
|
+
retrainFrames: z.ZodNumber;
|
|
137
|
+
total: z.ZodNumber;
|
|
138
|
+
}, z.core.$strip>;
|
|
139
|
+
export type UnstampedEventMediaCount = z.infer<typeof UnstampedEventMediaCountSchema>;
|
|
99
140
|
export declare const StorageMigrationMediaMoveInputSchema: z.ZodObject<{
|
|
100
141
|
toLocationId: z.ZodString;
|
|
101
142
|
throttleMbps: z.ZodOptional<z.ZodNumber>;
|
|
143
|
+
mode: z.ZodOptional<z.ZodEnum<{
|
|
144
|
+
move: "move";
|
|
145
|
+
seal: "seal";
|
|
146
|
+
gallery: "gallery";
|
|
147
|
+
}>>;
|
|
102
148
|
leaseId: z.ZodString;
|
|
103
149
|
}, z.core.$strip>;
|
|
104
150
|
export type StorageMigrationMediaMoveInput = z.infer<typeof StorageMigrationMediaMoveInputSchema>;
|
|
105
|
-
/** The independently selectable logical storage classes
|
|
106
|
-
*
|
|
107
|
-
*
|
|
151
|
+
/** The independently selectable logical storage classes — every class
|
|
152
|
+
* `storage.listLocationDeclarations` reports, so an operator never meets a
|
|
153
|
+
* Zod enum error where they should meet an explanation.
|
|
154
|
+
*
|
|
155
|
+
* `recordings` encompasses the high and mid segment profiles; `recordingsLow`
|
|
156
|
+
* is low segments; `eventMedia` is post-analysis blobs; `galleryMedia` is the
|
|
157
|
+
* enrolled gallery; `backups` is the system backup archive. The last two have
|
|
158
|
+
* their own rules — see {@link StorageMigrationFindingCodeSchema}. */
|
|
108
159
|
export declare const StorageMigrationClassSchema: z.ZodEnum<{
|
|
109
160
|
recordings: "recordings";
|
|
110
161
|
recordingsLow: "recordingsLow";
|
|
111
162
|
eventMedia: "eventMedia";
|
|
163
|
+
backups: "backups";
|
|
164
|
+
galleryMedia: "galleryMedia";
|
|
112
165
|
}>;
|
|
113
166
|
export type StorageMigrationClass = z.infer<typeof StorageMigrationClassSchema>;
|
|
114
167
|
/** A destination is always an existing, fully-qualified location id. The
|
|
@@ -118,21 +171,63 @@ export declare const StorageMigrationDestinationsSchema: z.ZodObject<{
|
|
|
118
171
|
recordings: z.ZodOptional<z.ZodString>;
|
|
119
172
|
recordingsLow: z.ZodOptional<z.ZodString>;
|
|
120
173
|
eventMedia: z.ZodOptional<z.ZodString>;
|
|
174
|
+
backups: z.ZodOptional<z.ZodString>;
|
|
175
|
+
galleryMedia: z.ZodOptional<z.ZodString>;
|
|
121
176
|
}, z.core.$strip>;
|
|
122
177
|
export type StorageMigrationDestinations = z.infer<typeof StorageMigrationDestinationsSchema>;
|
|
178
|
+
/**
|
|
179
|
+
* How a migration sequences the cutover against the byte move.
|
|
180
|
+
*
|
|
181
|
+
* - `blocking` — the historical order: pause, move every byte, repoint,
|
|
182
|
+
* resume. Recording is stopped for the whole move. Right
|
|
183
|
+
* for a small or a cold class, and the only legal mode for
|
|
184
|
+
* a `cardinality: 'single'` class.
|
|
185
|
+
* - `nonBlocking` — repoint FIRST, drain behind: seal, pause, repoint,
|
|
186
|
+
* refresh, resume, then move the past with everything
|
|
187
|
+
* running. The pause is three bounded instants (a detach +
|
|
188
|
+
* attach round, a write-gate drain, a lease) instead of one
|
|
189
|
+
* bounded by bytes. 1.09 TB at 7–14 MB/s is thirty hours of
|
|
190
|
+
* stopped recording under `blocking`; the same move is
|
|
191
|
+
* seconds of stopped recording under `nonBlocking`.
|
|
192
|
+
*
|
|
193
|
+
* The mode is on the JOB, not only on the input, because `status` is where an
|
|
194
|
+
* operator finds out which one is running.
|
|
195
|
+
*/
|
|
196
|
+
export declare const StorageMigrationModeSchema: z.ZodEnum<{
|
|
197
|
+
blocking: "blocking";
|
|
198
|
+
nonBlocking: "nonBlocking";
|
|
199
|
+
}>;
|
|
200
|
+
export type StorageMigrationMode = z.infer<typeof StorageMigrationModeSchema>;
|
|
123
201
|
/** Shared input for planning and starting an orchestrated storage migration. */
|
|
124
202
|
export declare const StorageMigrationInputSchema: z.ZodObject<{
|
|
125
203
|
destinations: z.ZodObject<{
|
|
126
204
|
recordings: z.ZodOptional<z.ZodString>;
|
|
127
205
|
recordingsLow: z.ZodOptional<z.ZodString>;
|
|
128
206
|
eventMedia: z.ZodOptional<z.ZodString>;
|
|
207
|
+
backups: z.ZodOptional<z.ZodString>;
|
|
208
|
+
galleryMedia: z.ZodOptional<z.ZodString>;
|
|
129
209
|
}, z.core.$strip>;
|
|
130
210
|
throttleMbps: z.ZodOptional<z.ZodNumber>;
|
|
211
|
+
mode: z.ZodOptional<z.ZodEnum<{
|
|
212
|
+
blocking: "blocking";
|
|
213
|
+
nonBlocking: "nonBlocking";
|
|
214
|
+
}>>;
|
|
131
215
|
}, z.core.$strip>;
|
|
132
216
|
export type StorageMigrationInput = z.infer<typeof StorageMigrationInputSchema>;
|
|
133
|
-
/**
|
|
134
|
-
*
|
|
135
|
-
*
|
|
217
|
+
/**
|
|
218
|
+
* The durable coordinator state machine.
|
|
219
|
+
*
|
|
220
|
+
* `blocking`:
|
|
221
|
+
* planning → pausing → moving → verifying → repointing → refreshing → resuming → done
|
|
222
|
+
*
|
|
223
|
+
* `nonBlocking`:
|
|
224
|
+
* planning → sealing → pausing → repointing → refreshing → resuming → draining → verifying → done
|
|
225
|
+
*
|
|
226
|
+
* Same phases, different order plus two new ones — not a second mover.
|
|
227
|
+
* `sealing` closes the `eventMedia` NULL-row hole BEFORE anything is paused;
|
|
228
|
+
* `draining` runs the same movers UNLEASED, after every writer is back up.
|
|
229
|
+
* `repointing` is still the only phase that changes a default location.
|
|
230
|
+
*/
|
|
136
231
|
export declare const StorageMigrationPhaseSchema: z.ZodEnum<{
|
|
137
232
|
moving: "moving";
|
|
138
233
|
verifying: "verifying";
|
|
@@ -140,7 +235,9 @@ export declare const StorageMigrationPhaseSchema: z.ZodEnum<{
|
|
|
140
235
|
done: "done";
|
|
141
236
|
cancelled: "cancelled";
|
|
142
237
|
planning: "planning";
|
|
238
|
+
sealing: "sealing";
|
|
143
239
|
pausing: "pausing";
|
|
240
|
+
draining: "draining";
|
|
144
241
|
repointing: "repointing";
|
|
145
242
|
refreshing: "refreshing";
|
|
146
243
|
resuming: "resuming";
|
|
@@ -152,11 +249,41 @@ export declare const StorageMigrationParticipantSchema: z.ZodEnum<{
|
|
|
152
249
|
analytics: "analytics";
|
|
153
250
|
}>;
|
|
154
251
|
export type StorageMigrationParticipant = z.infer<typeof StorageMigrationParticipantSchema>;
|
|
252
|
+
/**
|
|
253
|
+
* The mover's own numbers, folded onto the coordinator's durable move record.
|
|
254
|
+
*
|
|
255
|
+
* The long half of a non-blocking migration is `draining`, and it is measured
|
|
256
|
+
* in hours: 136 885 files at ~4 MB/s is about five of them. Before this shape
|
|
257
|
+
* existed the only place those numbers appeared was a Loki line, so an operator
|
|
258
|
+
* watching the Admin UI saw `phase: draining` and nothing else for a whole
|
|
259
|
+
* afternoon.
|
|
260
|
+
*
|
|
261
|
+
* It is POLLED, never pushed. Events are telemetry and may be dropped
|
|
262
|
+
* (D8/D11), and a dropped progress event is indistinguishable from a stalled
|
|
263
|
+
* mover — which is the exact failure this is meant to end. The coordinator's
|
|
264
|
+
* `waitForMoves` already fetches the whole {@link RelocateJob} on every tick to
|
|
265
|
+
* read `state`; folding the counters costs no extra read and makes the durable
|
|
266
|
+
* record say afterwards how far a move actually got.
|
|
267
|
+
*
|
|
268
|
+
* `filesTotal` is `null` for "no honest denominator" and is never zero-filled:
|
|
269
|
+
* a windowed footage job (`sinceMs`) and a node with no ledger both genuinely
|
|
270
|
+
* cannot say M, and a 0 there would render as "100 % done".
|
|
271
|
+
*/
|
|
272
|
+
export declare const StorageMigrationMoveProgressSchema: z.ZodObject<{
|
|
273
|
+
filesMoved: z.ZodNumber;
|
|
274
|
+
filesTotal: z.ZodNullable<z.ZodNumber>;
|
|
275
|
+
bytesMoved: z.ZodNumber;
|
|
276
|
+
startedAt: z.ZodNumber;
|
|
277
|
+
observedAt: z.ZodNumber;
|
|
278
|
+
}, z.core.$strip>;
|
|
279
|
+
export type StorageMigrationMoveProgress = z.infer<typeof StorageMigrationMoveProgressSchema>;
|
|
155
280
|
export declare const StorageMigrationMoveSchema: z.ZodObject<{
|
|
156
281
|
storageClass: z.ZodEnum<{
|
|
157
282
|
recordings: "recordings";
|
|
158
283
|
recordingsLow: "recordingsLow";
|
|
159
284
|
eventMedia: "eventMedia";
|
|
285
|
+
backups: "backups";
|
|
286
|
+
galleryMedia: "galleryMedia";
|
|
160
287
|
}>;
|
|
161
288
|
fromLocationId: z.ZodString;
|
|
162
289
|
toLocationId: z.ZodString;
|
|
@@ -169,6 +296,13 @@ export declare const StorageMigrationMoveSchema: z.ZodObject<{
|
|
|
169
296
|
cancelled: "cancelled";
|
|
170
297
|
}>>;
|
|
171
298
|
error: z.ZodNullable<z.ZodString>;
|
|
299
|
+
progress: z.ZodNullable<z.ZodObject<{
|
|
300
|
+
filesMoved: z.ZodNumber;
|
|
301
|
+
filesTotal: z.ZodNullable<z.ZodNumber>;
|
|
302
|
+
bytesMoved: z.ZodNumber;
|
|
303
|
+
startedAt: z.ZodNumber;
|
|
304
|
+
observedAt: z.ZodNumber;
|
|
305
|
+
}, z.core.$strip>>;
|
|
172
306
|
}, z.core.$strip>;
|
|
173
307
|
export type StorageMigrationMove = z.infer<typeof StorageMigrationMoveSchema>;
|
|
174
308
|
export declare const StorageMigrationJobSchema: z.ZodObject<{
|
|
@@ -180,15 +314,23 @@ export declare const StorageMigrationJobSchema: z.ZodObject<{
|
|
|
180
314
|
done: "done";
|
|
181
315
|
cancelled: "cancelled";
|
|
182
316
|
planning: "planning";
|
|
317
|
+
sealing: "sealing";
|
|
183
318
|
pausing: "pausing";
|
|
319
|
+
draining: "draining";
|
|
184
320
|
repointing: "repointing";
|
|
185
321
|
refreshing: "refreshing";
|
|
186
322
|
resuming: "resuming";
|
|
187
323
|
}>;
|
|
324
|
+
mode: z.ZodEnum<{
|
|
325
|
+
blocking: "blocking";
|
|
326
|
+
nonBlocking: "nonBlocking";
|
|
327
|
+
}>;
|
|
188
328
|
destinations: z.ZodObject<{
|
|
189
329
|
recordings: z.ZodOptional<z.ZodString>;
|
|
190
330
|
recordingsLow: z.ZodOptional<z.ZodString>;
|
|
191
331
|
eventMedia: z.ZodOptional<z.ZodString>;
|
|
332
|
+
backups: z.ZodOptional<z.ZodString>;
|
|
333
|
+
galleryMedia: z.ZodOptional<z.ZodString>;
|
|
192
334
|
}, z.core.$strip>;
|
|
193
335
|
throttleMbps: z.ZodNumber;
|
|
194
336
|
moves: z.ZodArray<z.ZodObject<{
|
|
@@ -196,6 +338,8 @@ export declare const StorageMigrationJobSchema: z.ZodObject<{
|
|
|
196
338
|
recordings: "recordings";
|
|
197
339
|
recordingsLow: "recordingsLow";
|
|
198
340
|
eventMedia: "eventMedia";
|
|
341
|
+
backups: "backups";
|
|
342
|
+
galleryMedia: "galleryMedia";
|
|
199
343
|
}>;
|
|
200
344
|
fromLocationId: z.ZodString;
|
|
201
345
|
toLocationId: z.ZodString;
|
|
@@ -208,6 +352,13 @@ export declare const StorageMigrationJobSchema: z.ZodObject<{
|
|
|
208
352
|
cancelled: "cancelled";
|
|
209
353
|
}>>;
|
|
210
354
|
error: z.ZodNullable<z.ZodString>;
|
|
355
|
+
progress: z.ZodNullable<z.ZodObject<{
|
|
356
|
+
filesMoved: z.ZodNumber;
|
|
357
|
+
filesTotal: z.ZodNullable<z.ZodNumber>;
|
|
358
|
+
bytesMoved: z.ZodNumber;
|
|
359
|
+
startedAt: z.ZodNumber;
|
|
360
|
+
observedAt: z.ZodNumber;
|
|
361
|
+
}, z.core.$strip>>;
|
|
211
362
|
}, z.core.$strip>>;
|
|
212
363
|
pauseLeaseId: z.ZodNullable<z.ZodString>;
|
|
213
364
|
pausedParticipants: z.ZodArray<z.ZodEnum<{
|
|
@@ -223,20 +374,233 @@ export declare const StorageMigrationJobSchema: z.ZodObject<{
|
|
|
223
374
|
error: z.ZodNullable<z.ZodString>;
|
|
224
375
|
}, z.core.$strip>;
|
|
225
376
|
export type StorageMigrationJob = z.infer<typeof StorageMigrationJobSchema>;
|
|
377
|
+
/**
|
|
378
|
+
* What the planner NOTICED but did not refuse.
|
|
379
|
+
*
|
|
380
|
+
* A refusal throws — the operator cannot miss it. A finding is the other half:
|
|
381
|
+
* something true about this plan that changes what the operator should expect,
|
|
382
|
+
* surfaced where they read it rather than in a document they will not open.
|
|
383
|
+
*
|
|
384
|
+
* - `sharesDeviceWithSource` — the destination realpath's to the same place as
|
|
385
|
+
* the source. The move will be a row re-stamp, not a byte move, and it buys
|
|
386
|
+
* no redundancy. NOTE: this is PATH identity, not `st_dev` — two distinct
|
|
387
|
+
* directories on one filesystem are NOT detected. See
|
|
388
|
+
* `deviceIdentityUnknown`.
|
|
389
|
+
* - `deviceIdentityUnknown` — a location carries a `nodeId` other than this
|
|
390
|
+
* one (or has no `basePath`), so its realpath cannot be taken here and the
|
|
391
|
+
* same-device question was not answered at all. Stated rather than assumed
|
|
392
|
+
* clear: a check that silently never fires is worse than no check.
|
|
393
|
+
* - `unstampedEventMediaRows` — how many `eventMedia`/retrain rows still carry
|
|
394
|
+
* no `locationId`. Non-zero refuses a `nonBlocking` cutover.
|
|
395
|
+
* - `blockingOnly` — this class is `cardinality: 'single'`, so it can never
|
|
396
|
+
* span two locations and can only ever be moved stop-the-world.
|
|
397
|
+
* - `noMover` — the class is selectable and planned, but no addon owns a mover
|
|
398
|
+
* for it. The migration cannot move its bytes.
|
|
399
|
+
*/
|
|
400
|
+
export declare const StorageMigrationFindingCodeSchema: z.ZodEnum<{
|
|
401
|
+
sharesDeviceWithSource: "sharesDeviceWithSource";
|
|
402
|
+
deviceIdentityUnknown: "deviceIdentityUnknown";
|
|
403
|
+
unstampedEventMediaRows: "unstampedEventMediaRows";
|
|
404
|
+
blockingOnly: "blockingOnly";
|
|
405
|
+
noMover: "noMover";
|
|
406
|
+
}>;
|
|
407
|
+
export type StorageMigrationFindingCode = z.infer<typeof StorageMigrationFindingCodeSchema>;
|
|
408
|
+
export declare const StorageMigrationFindingSchema: z.ZodObject<{
|
|
409
|
+
code: z.ZodEnum<{
|
|
410
|
+
sharesDeviceWithSource: "sharesDeviceWithSource";
|
|
411
|
+
deviceIdentityUnknown: "deviceIdentityUnknown";
|
|
412
|
+
unstampedEventMediaRows: "unstampedEventMediaRows";
|
|
413
|
+
blockingOnly: "blockingOnly";
|
|
414
|
+
noMover: "noMover";
|
|
415
|
+
}>;
|
|
416
|
+
storageClass: z.ZodEnum<{
|
|
417
|
+
recordings: "recordings";
|
|
418
|
+
recordingsLow: "recordingsLow";
|
|
419
|
+
eventMedia: "eventMedia";
|
|
420
|
+
backups: "backups";
|
|
421
|
+
galleryMedia: "galleryMedia";
|
|
422
|
+
}>;
|
|
423
|
+
message: z.ZodString;
|
|
424
|
+
}, z.core.$strip>;
|
|
425
|
+
export type StorageMigrationFinding = z.infer<typeof StorageMigrationFindingSchema>;
|
|
226
426
|
export declare const StorageMigrationPlanSchema: z.ZodObject<{
|
|
227
427
|
destinations: z.ZodObject<{
|
|
228
428
|
recordings: z.ZodOptional<z.ZodString>;
|
|
229
429
|
recordingsLow: z.ZodOptional<z.ZodString>;
|
|
230
430
|
eventMedia: z.ZodOptional<z.ZodString>;
|
|
431
|
+
backups: z.ZodOptional<z.ZodString>;
|
|
432
|
+
galleryMedia: z.ZodOptional<z.ZodString>;
|
|
231
433
|
}, z.core.$strip>;
|
|
434
|
+
mode: z.ZodEnum<{
|
|
435
|
+
blocking: "blocking";
|
|
436
|
+
nonBlocking: "nonBlocking";
|
|
437
|
+
}>;
|
|
232
438
|
moves: z.ZodArray<z.ZodObject<{
|
|
233
439
|
storageClass: z.ZodEnum<{
|
|
234
440
|
recordings: "recordings";
|
|
235
441
|
recordingsLow: "recordingsLow";
|
|
236
442
|
eventMedia: "eventMedia";
|
|
443
|
+
backups: "backups";
|
|
444
|
+
galleryMedia: "galleryMedia";
|
|
237
445
|
}>;
|
|
238
446
|
fromLocationId: z.ZodString;
|
|
239
447
|
toLocationId: z.ZodString;
|
|
240
448
|
}, z.core.$strip>>;
|
|
449
|
+
findings: z.ZodArray<z.ZodObject<{
|
|
450
|
+
code: z.ZodEnum<{
|
|
451
|
+
sharesDeviceWithSource: "sharesDeviceWithSource";
|
|
452
|
+
deviceIdentityUnknown: "deviceIdentityUnknown";
|
|
453
|
+
unstampedEventMediaRows: "unstampedEventMediaRows";
|
|
454
|
+
blockingOnly: "blockingOnly";
|
|
455
|
+
noMover: "noMover";
|
|
456
|
+
}>;
|
|
457
|
+
storageClass: z.ZodEnum<{
|
|
458
|
+
recordings: "recordings";
|
|
459
|
+
recordingsLow: "recordingsLow";
|
|
460
|
+
eventMedia: "eventMedia";
|
|
461
|
+
backups: "backups";
|
|
462
|
+
galleryMedia: "galleryMedia";
|
|
463
|
+
}>;
|
|
464
|
+
message: z.ZodString;
|
|
465
|
+
}, z.core.$strip>>;
|
|
241
466
|
}, z.core.$strip>;
|
|
242
467
|
export type StorageMigrationPlan = z.infer<typeof StorageMigrationPlanSchema>;
|
|
468
|
+
/**
|
|
469
|
+
* Which single-flight engine owns a class of work.
|
|
470
|
+
*
|
|
471
|
+
* Shared rather than re-declared per consumer: the coordinator lanes its moves
|
|
472
|
+
* by it, and `storageMigration.movers` labels a mover with it so an operator
|
|
473
|
+
* can see *which* engine is busy when a drain refuses to start beside another.
|
|
474
|
+
*/
|
|
475
|
+
export declare const StorageMigrationLaneSchema: z.ZodEnum<{
|
|
476
|
+
media: "media";
|
|
477
|
+
footage: "footage";
|
|
478
|
+
}>;
|
|
479
|
+
export type StorageMigrationLane = z.infer<typeof StorageMigrationLaneSchema>;
|
|
480
|
+
/**
|
|
481
|
+
* A mover as it exists RIGHT NOW, whether or not a migration job owns it.
|
|
482
|
+
*
|
|
483
|
+
* The coordinator's job record is the state of record for a migration, and its
|
|
484
|
+
* moves carry {@link StorageMigrationMoveProgress}. But the movers are usable
|
|
485
|
+
* standalone — `recording.relocateFootage` and `pipelineAnalytics.relocateMedia`
|
|
486
|
+
* are both operator-callable, and on 2026-08-29 a five-hour drain was armed that
|
|
487
|
+
* way because no supported UI path existed. A mover armed like that has no job
|
|
488
|
+
* to fold progress into, so it has to be readable on its own or it is invisible.
|
|
489
|
+
*
|
|
490
|
+
* `migrationJobId` is what tells the two apart: `null` means nothing here
|
|
491
|
+
* orchestrated it.
|
|
492
|
+
*/
|
|
493
|
+
export declare const StorageMigrationMoverSchema: z.ZodObject<{
|
|
494
|
+
lane: z.ZodEnum<{
|
|
495
|
+
media: "media";
|
|
496
|
+
footage: "footage";
|
|
497
|
+
}>;
|
|
498
|
+
job: z.ZodObject<{
|
|
499
|
+
jobId: z.ZodString;
|
|
500
|
+
state: z.ZodEnum<{
|
|
501
|
+
failed: "failed";
|
|
502
|
+
running: "running";
|
|
503
|
+
queued: "queued";
|
|
504
|
+
done: "done";
|
|
505
|
+
cancelled: "cancelled";
|
|
506
|
+
}>;
|
|
507
|
+
fromLocationId: z.ZodString;
|
|
508
|
+
toLocationId: z.ZodString;
|
|
509
|
+
deviceId: z.ZodNullable<z.ZodNumber>;
|
|
510
|
+
entities: z.ZodArray<z.ZodString>;
|
|
511
|
+
filesMoved: z.ZodNumber;
|
|
512
|
+
bytesMoved: z.ZodNumber;
|
|
513
|
+
filesTotal: z.ZodNullable<z.ZodNumber>;
|
|
514
|
+
startedAt: z.ZodNumber;
|
|
515
|
+
finishedAt: z.ZodNullable<z.ZodNumber>;
|
|
516
|
+
error: z.ZodNullable<z.ZodString>;
|
|
517
|
+
}, z.core.$strip>;
|
|
518
|
+
migrationJobId: z.ZodNullable<z.ZodString>;
|
|
519
|
+
observedAt: z.ZodNumber;
|
|
520
|
+
}, z.core.$strip>;
|
|
521
|
+
export type StorageMigrationMover = z.infer<typeof StorageMigrationMoverSchema>;
|
|
522
|
+
/**
|
|
523
|
+
* What a SOURCE still holds for one storage class — the number that makes a
|
|
524
|
+
* "drain remaining" action honest rather than hopeful.
|
|
525
|
+
*
|
|
526
|
+
* It comes from the archive (`SegmentHourLedger.census` for footage, the media
|
|
527
|
+
* engine's own selection count for media), never from the resident index: a
|
|
528
|
+
* drain sized off `RecordingIndex` is what reported `done` over 80.3 GB it had
|
|
529
|
+
* never been told about (D295).
|
|
530
|
+
*
|
|
531
|
+
* `items`/`bytes` are `null` for "the archive could not be asked", which is
|
|
532
|
+
* deliberately NOT zero: a drain is still offered for an unknown residue,
|
|
533
|
+
* because refusing on an unanswerable read would hide exactly the case an
|
|
534
|
+
* operator needs to act on.
|
|
535
|
+
*/
|
|
536
|
+
export declare const StorageMigrationResidueSchema: z.ZodObject<{
|
|
537
|
+
storageClass: z.ZodEnum<{
|
|
538
|
+
recordings: "recordings";
|
|
539
|
+
recordingsLow: "recordingsLow";
|
|
540
|
+
eventMedia: "eventMedia";
|
|
541
|
+
backups: "backups";
|
|
542
|
+
galleryMedia: "galleryMedia";
|
|
543
|
+
}>;
|
|
544
|
+
fromLocationId: z.ZodString;
|
|
545
|
+
toLocationId: z.ZodString;
|
|
546
|
+
items: z.ZodNullable<z.ZodNumber>;
|
|
547
|
+
bytes: z.ZodNullable<z.ZodNumber>;
|
|
548
|
+
}, z.core.$strip>;
|
|
549
|
+
export type StorageMigrationResidue = z.infer<typeof StorageMigrationResidueSchema>;
|
|
550
|
+
/**
|
|
551
|
+
* Run the DRAIN half and nothing else.
|
|
552
|
+
*
|
|
553
|
+
* A migration that reached `done` has already repointed, so `start` correctly
|
|
554
|
+
* refuses its destination ("already the default") — there is nothing left to
|
|
555
|
+
* repoint. But the drain can fail, be cancelled, be interrupted by a restart,
|
|
556
|
+
* or finish against a work list that was a tenth of the archive (D295), and
|
|
557
|
+
* before this there was no supported way to run only that half: the only way
|
|
558
|
+
* through was calling `recording.relocateFootage` by hand over admin tRPC.
|
|
559
|
+
*
|
|
560
|
+
* `drain` NEVER calls `setDefaultLocations`. That is what keeps `start`'s
|
|
561
|
+
* refusal meaningful: the two verbs are disjoint, so nothing here can silently
|
|
562
|
+
* re-repoint a class that is already migrated.
|
|
563
|
+
*/
|
|
564
|
+
export declare const StorageMigrationDrainInputSchema: z.ZodObject<{
|
|
565
|
+
classes: z.ZodArray<z.ZodEnum<{
|
|
566
|
+
recordings: "recordings";
|
|
567
|
+
recordingsLow: "recordingsLow";
|
|
568
|
+
eventMedia: "eventMedia";
|
|
569
|
+
backups: "backups";
|
|
570
|
+
galleryMedia: "galleryMedia";
|
|
571
|
+
}>>;
|
|
572
|
+
throttleMbps: z.ZodOptional<z.ZodNumber>;
|
|
573
|
+
}, z.core.$strip>;
|
|
574
|
+
export type StorageMigrationDrainInput = z.infer<typeof StorageMigrationDrainInputSchema>;
|
|
575
|
+
/** What a footage source still holds, asked of the durable hour ledger. */
|
|
576
|
+
export declare const RelocateResidueInputSchema: z.ZodObject<{
|
|
577
|
+
fromLocationId: z.ZodString;
|
|
578
|
+
footageClass: z.ZodOptional<z.ZodEnum<{
|
|
579
|
+
recordings: "recordings";
|
|
580
|
+
recordingsLow: "recordingsLow";
|
|
581
|
+
}>>;
|
|
582
|
+
}, z.core.$strip>;
|
|
583
|
+
export type RelocateResidueInput = z.infer<typeof RelocateResidueInputSchema>;
|
|
584
|
+
/** `null` = the archive could not answer (no ledger on this node, or the
|
|
585
|
+
* aggregate failed). Never conflated with an empty source. */
|
|
586
|
+
export declare const RelocateResidueSchema: z.ZodNullable<z.ZodObject<{
|
|
587
|
+
segments: z.ZodNumber;
|
|
588
|
+
bytes: z.ZodNumber;
|
|
589
|
+
}, z.core.$strip>>;
|
|
590
|
+
export type RelocateResidue = z.infer<typeof RelocateResidueSchema>;
|
|
591
|
+
/** How many rows a media pass would still act on against a given target — the
|
|
592
|
+
* media lane's denominator AND its residue, from ONE derivation so the two can
|
|
593
|
+
* never disagree. `null` = the count could not be taken. */
|
|
594
|
+
export declare const RelocatableMediaCountSchema: z.ZodNullable<z.ZodObject<{
|
|
595
|
+
rows: z.ZodNumber;
|
|
596
|
+
}, z.core.$strip>>;
|
|
597
|
+
export type RelocatableMediaCount = z.infer<typeof RelocatableMediaCountSchema>;
|
|
598
|
+
export declare const RelocatableMediaCountInputSchema: z.ZodObject<{
|
|
599
|
+
toLocationId: z.ZodString;
|
|
600
|
+
mode: z.ZodOptional<z.ZodEnum<{
|
|
601
|
+
move: "move";
|
|
602
|
+
seal: "seal";
|
|
603
|
+
gallery: "gallery";
|
|
604
|
+
}>>;
|
|
605
|
+
}, z.core.$strip>;
|
|
606
|
+
export type RelocatableMediaCountInput = z.infer<typeof RelocatableMediaCountInputSchema>;
|