@camstack/types 1.2.162 → 1.2.163

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.
Files changed (34) hide show
  1. package/dist/addon.js +4 -3
  2. package/dist/addon.mjs +4 -3
  3. package/dist/capabilities/alerts.cap.d.ts +5 -5
  4. package/dist/capabilities/index.d.ts +7 -5
  5. package/dist/capabilities/notifier.cap.d.ts +3 -3
  6. package/dist/capabilities/pet-feeder.cap.d.ts +4 -4
  7. package/dist/capabilities/snapshot.cap.d.ts +2 -2
  8. package/dist/capabilities/storage-occupancy.cap.d.ts +72 -0
  9. package/dist/capabilities/storage-provider.cap.d.ts +110 -0
  10. package/dist/capabilities/storage.cap.d.ts +43 -0
  11. package/dist/capabilities/stream-broker.cap.d.ts +1 -1
  12. package/dist/enums/event-category.d.ts +13 -0
  13. package/dist/enums.js +1 -1
  14. package/dist/enums.mjs +1 -1
  15. package/dist/{event-category-b8kBSOTT.js → event-category-BVo6ta6_.js} +13 -0
  16. package/dist/{event-category-zAv7pMUz.mjs → event-category-CnLqLOKs.mjs} +13 -0
  17. package/dist/generated/addon-api.d.ts +22 -0
  18. package/dist/generated/capability-router-map.d.ts +5 -2
  19. package/dist/generated/collection-array-methods.d.ts +1 -1
  20. package/dist/generated/method-access-map.d.ts +1 -1
  21. package/dist/generated/system-proxy.d.ts +1 -1
  22. package/dist/index.d.ts +4 -2
  23. package/dist/index.js +881 -552
  24. package/dist/index.mjs +862 -553
  25. package/dist/interfaces/event-bus.d.ts +19 -0
  26. package/dist/interfaces/storage-location-mode.d.ts +135 -0
  27. package/dist/interfaces/storage-location.d.ts +54 -6
  28. package/dist/node.d.ts +13 -11
  29. package/dist/node.js +935 -876
  30. package/dist/node.mjs +936 -879
  31. package/dist/{sleep-DDIFZGbc.js → sleep-BZtO-eFY.js} +1 -1
  32. package/dist/{sleep-Cfij6Jj9.mjs → sleep-Bd-Y4RUt.mjs} +1 -1
  33. package/dist/storage/physical-root.d.ts +25 -0
  34. package/package.json +1 -1
@@ -354,6 +354,24 @@ export interface PipelineAudioInferenceResultPayload {
354
354
  readonly nodeId: string;
355
355
  readonly [key: string]: unknown;
356
356
  }
357
+ /** Why the storage location set changed. */
358
+ export type StorageLocationsChangedReason = 'upsert' | 'delete';
359
+ /**
360
+ * One change to the SET of storage locations (`EventCategory.StorageLocationsChanged`).
361
+ *
362
+ * Deliberately thin: it names WHICH location moved and WHAT kind of change it
363
+ * was, and nothing about the row itself. A consumer re-reads
364
+ * `storage.listLocations` — the event is a doorbell, and a payload carrying the
365
+ * row would be a second, staler authority for it.
366
+ *
367
+ * A bulk edit rings this once per row, so every consumer coalesces.
368
+ */
369
+ export interface StorageLocationsChangedPayload {
370
+ readonly locationId: string;
371
+ readonly locationType: string;
372
+ readonly reason: StorageLocationsChangedReason;
373
+ readonly [key: string]: unknown;
374
+ }
357
375
  /**
358
376
  * Camera assignment lifecycle payload emitted by `addon-pipeline-orchestrator`
359
377
  * when a camera is assigned to or unassigned from an agent runner. Used by
@@ -840,6 +858,7 @@ export interface EventCatalog {
840
858
  'process.restarted': {
841
859
  processId: string;
842
860
  };
861
+ 'storage.locations-changed': StorageLocationsChangedPayload;
843
862
  'recording.started': {
844
863
  deviceId: number;
845
864
  streamId?: string;
@@ -0,0 +1,135 @@
1
+ import { z } from 'zod';
2
+ /**
3
+ * The storage-location STATE MODEL (D385) — one typed state, one policy module.
4
+ *
5
+ * A location's state used to be split across two authorities: the typed
6
+ * `enabled` field (THE write switch since D383) and an untyped `config.readOnly`
7
+ * key. They did not mean the same thing — `enabled: false` was still evicted
8
+ * under disk pressure while `config.readOnly` was deliberately excluded — and
9
+ * neither name said which. Every consumer re-derived the difference, and the
10
+ * three questions that actually matter were answered in six places.
11
+ *
12
+ * This module is the ONLY place in the repo allowed to interpret the state. It
13
+ * answers three questions and nothing else:
14
+ *
15
+ * - may this location be WRITTEN to? {@link modeMayWrite}
16
+ * - may this location be READ? {@link modeMayRead}
17
+ * - what is its eviction policy? {@link evictionPolicyForMode}
18
+ *
19
+ * | mode | write | read | eviction |
20
+ * | ---------- | ----- | ---- | ------------------------------ |
21
+ * | `active` | yes | yes | `normal` (pressure + usage cap) |
22
+ * | `readonly` | no | yes | `never` |
23
+ * | `drain` | no | yes | `drain` (paced, until empty) |
24
+ * | `disabled` | no | no | `never` |
25
+ *
26
+ * `scripts/check-storage-location-mode-single-owner.ts` fails the build when
27
+ * anything outside this module reads `config['readOnly']` or compares `enabled`
28
+ * directly. A rule nothing checks has already been broken somewhere.
29
+ */
30
+ export declare const STORAGE_LOCATION_MODES: readonly ["active", "readonly", "drain", "disabled"];
31
+ /**
32
+ * The one typed state of a storage location. Authoritative Zod schema — the TS
33
+ * alias below is `z.infer<>` of it, never a second spelling.
34
+ */
35
+ export declare const StorageLocationModeSchema: z.ZodEnum<{
36
+ readonly: "readonly";
37
+ active: "active";
38
+ drain: "drain";
39
+ disabled: "disabled";
40
+ }>;
41
+ export type StorageLocationMode = z.infer<typeof StorageLocationModeSchema>;
42
+ /**
43
+ * What disk-pressure and usage-cap relief may do to a location.
44
+ *
45
+ * - `normal` — the existing behaviour: free-percent guard plus `maxUsedGb`.
46
+ * - `never` — excluded entirely. A retiring disk the operator is copying off
47
+ * must not race the relocate mover, and a disabled one is not the
48
+ * system's to erase.
49
+ * - `drain` — a monotonically descending effective usage cap, paced to what
50
+ * the ACTIVE locations of the same class gained (D386). This is
51
+ * the only policy that shrinks a location the system is not
52
+ * writing to.
53
+ */
54
+ export declare const StorageEvictionPolicySchema: z.ZodEnum<{
55
+ never: "never";
56
+ drain: "drain";
57
+ normal: "normal";
58
+ }>;
59
+ export type StorageEvictionPolicy = z.infer<typeof StorageEvictionPolicySchema>;
60
+ /**
61
+ * The legacy untyped drain key. Named ONCE, here, so the guard has exactly one
62
+ * sanctioned reader and the string never appears anywhere else.
63
+ */
64
+ export declare const LEGACY_READ_ONLY_CONFIG_KEY = "readOnly";
65
+ /**
66
+ * The shape this module needs off a location row. Structural rather than
67
+ * `StorageLocation` so the recorder's own resolved-location type, the admin
68
+ * UI's row and a persisted row can all be asked the same three questions
69
+ * without importing each other.
70
+ */
71
+ export interface StorageLocationStateSource {
72
+ /** The typed state, once stamped. Absent on a row written before D385. */
73
+ readonly mode?: StorageLocationMode;
74
+ /** The retired write switch (D383). Read ONLY by the legacy fold below. */
75
+ readonly enabled?: boolean;
76
+ /** The provider-facing config blob, which carried the retired drain key. */
77
+ readonly config: Readonly<Record<string, unknown>>;
78
+ }
79
+ /** Is this mode a write target? Only `active` is. */
80
+ export declare function modeMayWrite(mode: StorageLocationMode): boolean;
81
+ /** May this mode be read (playback, timeline, scrub, relocate source)? */
82
+ export declare function modeMayRead(mode: StorageLocationMode): boolean;
83
+ /** What eviction may do here. See {@link StorageEvictionPolicy}. */
84
+ export declare function evictionPolicyForMode(mode: StorageLocationMode): StorageEvictionPolicy;
85
+ /**
86
+ * The mode a LEGACY row implies, or `null` when it implies nothing — the row is
87
+ * already stamped, or it carried neither flag.
88
+ *
89
+ * Both legacy flags fold to `readonly`, which is the CONSERVATIVE direction: a
90
+ * state change must never start deleting footage on its own, and it must never
91
+ * make footage that was still being served disappear. `enabled: false` used to
92
+ * leave the location evictable under pressure; folding it to `readonly` stops
93
+ * that, which is a strictly safer answer than the one it replaces.
94
+ */
95
+ export declare function legacyModeOf(location: StorageLocationStateSource): StorageLocationMode | null;
96
+ /**
97
+ * The state of a location, stamped or folded. THE one interpretation: a row
98
+ * that predates D385 is never ambiguous, and a stamped `mode` always wins over
99
+ * whatever the legacy pair still says.
100
+ */
101
+ export declare function resolveLocationMode(location: StorageLocationStateSource): StorageLocationMode;
102
+ /** Is this one of the four states? The stamped value crosses a wire, and a
103
+ * value nobody defined must not be rendered as if it were a state. */
104
+ export declare function isStorageLocationMode(value: unknown): value is StorageLocationMode;
105
+ /** May this location be written to? */
106
+ export declare function mayWriteToLocation(location: StorageLocationStateSource): boolean;
107
+ /** May this location be read? A `disabled` one may not — and that is an
108
+ * operator CHOICE, which callers must report as unavailable rather than as an
109
+ * unknown-location fault. */
110
+ export declare function mayReadLocation(location: StorageLocationStateSource): boolean;
111
+ /** What eviction may do to this location. */
112
+ export declare function evictionPolicyOfLocation(location: StorageLocationStateSource): StorageEvictionPolicy;
113
+ /**
114
+ * The config blob with the retired drain key removed. Returns the SAME object
115
+ * when there was nothing to strip, so a caller can tell "changed" from
116
+ * "unchanged" by identity and skip a pointless persist.
117
+ */
118
+ export declare function strippedOfLegacyReadOnly(config: Readonly<Record<string, unknown>>): Readonly<Record<string, unknown>>;
119
+ /** The subset of a location row {@link withLocationMode} rewrites. */
120
+ export interface StorageLocationModePatch {
121
+ readonly mode: StorageLocationMode;
122
+ readonly enabled: boolean;
123
+ readonly config: Readonly<Record<string, unknown>>;
124
+ }
125
+ /**
126
+ * Set a location's mode, and with it everything that must agree with it.
127
+ *
128
+ * `enabled` stays readable for one release as a DERIVED value (`mode ===
129
+ * 'active'`) so consumers that have not moved yet keep working, and the legacy
130
+ * `config.readOnly` key is DELETED. This function is the only way to write
131
+ * either, which is what makes it impossible for the two to disagree.
132
+ *
133
+ * Returns a new object — the input is never mutated.
134
+ */
135
+ export declare function withLocationMode<T extends StorageLocationStateSource>(location: T, mode: StorageLocationMode): T & StorageLocationModePatch;
@@ -1,4 +1,5 @@
1
1
  import { z } from 'zod';
2
+ import type { StorageLocationMode } from './storage-location-mode.js';
2
3
  /**
3
4
  * `StorageLocationType` — an addon-declared id that identifies the *kind* of
4
5
  * storage a location serves. Defined here (not in `capabilities/storage.cap.ts`)
@@ -50,10 +51,20 @@ export declare const StorageLocationSchema: z.ZodObject<{
50
51
  nodeId: z.ZodOptional<z.ZodString>;
51
52
  isSystem: z.ZodDefault<z.ZodBoolean>;
52
53
  enabled: z.ZodOptional<z.ZodBoolean>;
54
+ mode: z.ZodOptional<z.ZodEnum<{
55
+ readonly: "readonly";
56
+ active: "active";
57
+ drain: "drain";
58
+ disabled: "disabled";
59
+ }>>;
53
60
  capacity: z.ZodOptional<z.ZodNullable<z.ZodObject<{
54
61
  totalBytes: z.ZodNumber;
55
62
  availableBytes: z.ZodNumber;
56
63
  }, z.core.$strip>>>;
64
+ owned: z.ZodOptional<z.ZodObject<{
65
+ bytes: z.ZodNumber;
66
+ measuredAtMs: z.ZodNumber;
67
+ }, z.core.$strip>>;
57
68
  createdAt: z.ZodNumber;
58
69
  updatedAt: z.ZodNumber;
59
70
  }, z.core.$strip>;
@@ -74,14 +85,51 @@ export declare const LegacyStorageLocationDefaultSchema: z.ZodObject<{
74
85
  }, z.core.$strip>;
75
86
  export type LegacyStorageLocationDefault = z.infer<typeof LegacyStorageLocationDefaultSchema>;
76
87
  /**
77
- * Is this location a write target? THE one place that decides what an absent
78
- * `enabled` means on a persisted row — legacy rows predate the flag and were
79
- * active, so absence is enabled. Every consumer asks here rather than spelling
80
- * `enabled !== false` again, so the tri-state has exactly one interpretation.
88
+ * Is this location a write target?
89
+ *
90
+ * A THIN delegate to the policy module (D385) — `mode` is the state, and
91
+ * `mayWriteToLocation` is the only thing that interprets it (folding the legacy
92
+ * `enabled` / `config.readOnly` pair for rows that predate the stamp). Kept for
93
+ * one release because the name is spelled in a dozen call sites; new code asks
94
+ * `mayWriteToLocation` directly.
81
95
  */
82
- export declare function isLocationEnabled(location: {
96
+ export interface LocationWriteTargetQuery {
97
+ readonly mode?: StorageLocationMode;
83
98
  readonly enabled?: boolean;
84
- }): boolean;
99
+ readonly config?: Readonly<Record<string, unknown>>;
100
+ }
101
+ export declare function isLocationEnabled(location: LocationWriteTargetQuery): boolean;
102
+ /**
103
+ * Bytes in one GB, for every storage figure an operator types.
104
+ *
105
+ * BINARY (1024³), everywhere. The repo had both: the orchestrator's
106
+ * `maxUsedGb` → bytes conversion used 1024³ while the recorder's placement
107
+ * headroom used 10⁹ for the SAME stored key, so a location with a cap set was
108
+ * silently 7.4% off depending on which side of the pipe asked. The persisted
109
+ * values were entered against the binary unit and the admin UI reads it, so
110
+ * that is the one that stays. Every GB knob — `maxUsedGb`, `minFreeGb` —
111
+ * converts through {@link gbToBytes} and nowhere else.
112
+ */
113
+ export declare const STORAGE_BYTES_PER_GB: number;
114
+ /** GB → bytes, binary. Fractional GB is admitted and floored. */
115
+ export declare function gbToBytes(gb: number): number;
116
+ /**
117
+ * How far a `drain` has got (D386) — the read a UI renders, and nothing more.
118
+ *
119
+ * `estimatedEmptyAtMs` is derived from the growth the ratchet has actually
120
+ * OBSERVED and is `null` when it has observed none. Never a fabricated date: a
121
+ * drain with no observed growth has no honest ETA, and inventing one is how an
122
+ * operator learns not to believe the screen.
123
+ */
124
+ export declare const StorageDrainProgressSchema: z.ZodObject<{
125
+ locationId: z.ZodString;
126
+ startedAtMs: z.ZodNumber;
127
+ startBytes: z.ZodNumber;
128
+ bytesRemaining: z.ZodNumber;
129
+ drained: z.ZodBoolean;
130
+ estimatedEmptyAtMs: z.ZodNullable<z.ZodNumber>;
131
+ }, z.core.$strip>;
132
+ export type StorageDrainProgress = z.infer<typeof StorageDrainProgressSchema>;
85
133
  /**
86
134
  * Reference accepted by consumer-facing `api.storage.*` calls.
87
135
  * Either:
package/dist/node.d.ts CHANGED
@@ -1,18 +1,20 @@
1
- export { ensureBinary, downloadBinary, findInPath, getPlatformInfo, buildBinaryPath, } from './deps/binary-downloader.js';
2
1
  export type { PlatformInfo } from './deps/binary-downloader.js';
2
+ export { buildBinaryPath, downloadBinary, ensureBinary, findInPath, getPlatformInfo, } from './deps/binary-downloader.js';
3
3
  export { ensureFfmpeg, getFfmpegDownloadUrl } from './deps/ffmpeg-downloader.js';
4
- export { ensurePython, installPythonPackages, installPythonRequirements, getPythonDownloadUrl, PYTHON_VERSION, } from './deps/python-downloader.js';
5
- export { ChildCostRegistry, NO_COST_CLAIM, nodeProcStatReader, parseProcCpuSeconds, parseProcRssBytes, readProcessCost, } from './process/child-cost-registry.js';
4
+ export { ensurePython, getPythonDownloadUrl, installPythonPackages, installPythonRequirements, PYTHON_VERSION, } from './deps/python-downloader.js';
5
+ export type { Fmp4FragmentChildArgs, Fmp4FragmentChildDeps, } from './ffmpeg/fmp4-fragment-child.js';
6
+ export { Fmp4FragmentChild } from './ffmpeg/fmp4-fragment-child.js';
7
+ export type { Fmp4CloseReason, Fmp4Packet, Fmp4PrebufferOptions, Fmp4PrebufferStats, Fmp4SubscribeInput, Fmp4SubscriberInfo, Fmp4Subscription, } from './ffmpeg/fmp4-fragment-plane.js';
8
+ export { Fmp4FragmentPlane } from './ffmpeg/fmp4-fragment-plane.js';
9
+ export type { FfmpegExit, FfmpegExitClass, FfmpegProcessOptions } from './ffmpeg/process.js';
10
+ export { FfmpegProcess } from './ffmpeg/process.js';
6
11
  export type { ChildCostClaimHandle, ChildCostClaimInput, ProcStatReader, } from './process/child-cost-registry.js';
12
+ export { ChildCostRegistry, NO_COST_CLAIM, nodeProcStatReader, parseProcCpuSeconds, parseProcRssBytes, readProcessCost, } from './process/child-cost-registry.js';
7
13
  export { FilesystemStorageProvider } from './storage/filesystem-storage-provider.js';
14
+ export type { PhysicalRoot, RealpathSync } from './storage/physical-root.js';
15
+ export { containsOrEquals, physicalRootOf } from './storage/physical-root.js';
8
16
  export { canonicalHash } from './utils/canonical-hash.js';
9
- export { signExpiringUrl, verifyExpiringUrl } from './utils/expiring-url-signature.js';
10
17
  export type { VerifyExpiringUrlInput } from './utils/expiring-url-signature.js';
11
- export { canonicalDeviceFingerprint, diffExportTargets, resolveExportFingerprint, } from './utils/export-reconciler.js';
18
+ export { signExpiringUrl, verifyExpiringUrl } from './utils/expiring-url-signature.js';
12
19
  export type { DeviceExportShape, ExportDelta, ExportTargetEntry, } from './utils/export-reconciler.js';
13
- export { FfmpegProcess } from './ffmpeg/process.js';
14
- export type { FfmpegProcessOptions, FfmpegExit, FfmpegExitClass } from './ffmpeg/process.js';
15
- export { Fmp4FragmentPlane } from './ffmpeg/fmp4-fragment-plane.js';
16
- export type { Fmp4CloseReason, Fmp4Packet, Fmp4PrebufferOptions, Fmp4PrebufferStats, Fmp4SubscribeInput, Fmp4SubscriberInfo, Fmp4Subscription, } from './ffmpeg/fmp4-fragment-plane.js';
17
- export { Fmp4FragmentChild } from './ffmpeg/fmp4-fragment-child.js';
18
- export type { Fmp4FragmentChildArgs, Fmp4FragmentChildDeps, } from './ffmpeg/fmp4-fragment-child.js';
20
+ export { canonicalDeviceFingerprint, diffExportTargets, resolveExportFingerprint, } from './utils/export-reconciler.js';