@camstack/types 1.2.172 → 1.2.173
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.
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Mint-on-empty, with the read-back that makes it safe.
|
|
3
|
+
*
|
|
4
|
+
* ## The shape, and why it is a trap
|
|
5
|
+
*
|
|
6
|
+
* ```ts
|
|
7
|
+
* let secret = await state.get()
|
|
8
|
+
* if (secret === '') {
|
|
9
|
+
* secret = randomUUID()
|
|
10
|
+
* await state.set(secret)
|
|
11
|
+
* }
|
|
12
|
+
* ```
|
|
13
|
+
*
|
|
14
|
+
* `state.get()` cannot distinguish "never minted" from "the store could not be
|
|
15
|
+
* read": `readAddonStoreWithRetry` gives up and answers `{}`, so a store that
|
|
16
|
+
* is merely unreachable reads as EMPTY and this mints a SECOND secret over a
|
|
17
|
+
* perfectly good first one. For a signing secret that invalidates every link
|
|
18
|
+
* already handed out. For the HomeKit bridge identity it is irreversible —
|
|
19
|
+
* every paired iPhone loses the bridge, and no later write of the store brings
|
|
20
|
+
* it back.
|
|
21
|
+
*
|
|
22
|
+
* The read-back is the only evidence available at this layer that the store is
|
|
23
|
+
* actually answering. `snapshot.addon.ts` (`ensureLinkSecret`) has done this
|
|
24
|
+
* since 2026-08-14 and was the only site that did.
|
|
25
|
+
*
|
|
26
|
+
* ## What it does NOT fix
|
|
27
|
+
*
|
|
28
|
+
* If the write genuinely lands, the read-back confirms it and the old value is
|
|
29
|
+
* already gone — a read-back cannot undo a write. It is a gate on USING the
|
|
30
|
+
* minted value, and it is load-bearing only because the settings view refuses
|
|
31
|
+
* to write at all when the last read of the addon store failed
|
|
32
|
+
* (`writeAddonStore`'s refusal). The two together are what close the window;
|
|
33
|
+
* the durable fix is a discriminated read result carried all the way up —
|
|
34
|
+
* `docs/design/plans/2026-08-27-lettura-fallita-non-diventa-un-default.md`.
|
|
35
|
+
*/
|
|
36
|
+
/** Why a mint was refused. Both mean: the store is not answering. */
|
|
37
|
+
export type MintRefusalReason = 'read-back-empty' | 'read-back-mismatch';
|
|
38
|
+
export interface MintRefusalDetail {
|
|
39
|
+
readonly reason: MintRefusalReason;
|
|
40
|
+
/** True when the read-back answered the fallback — the usual store-down shape. */
|
|
41
|
+
readonly readBackEmpty: boolean;
|
|
42
|
+
}
|
|
43
|
+
export type MintOnceOutcome<TValue> = {
|
|
44
|
+
readonly kind: 'existing';
|
|
45
|
+
readonly value: TValue;
|
|
46
|
+
} | {
|
|
47
|
+
readonly kind: 'minted';
|
|
48
|
+
readonly value: TValue;
|
|
49
|
+
} | {
|
|
50
|
+
readonly kind: 'refused';
|
|
51
|
+
};
|
|
52
|
+
export interface MintOnceReadBackInput<TValue> {
|
|
53
|
+
/** Read the persisted value. MUST answer the fallback (not throw) when absent. */
|
|
54
|
+
readonly read: () => Promise<TValue>;
|
|
55
|
+
/** Is this the fallback — i.e. "nothing persisted, or nothing readable"? */
|
|
56
|
+
readonly isEmpty: (value: TValue) => boolean;
|
|
57
|
+
/** Produce a fresh value. Called at most once, and only when `isEmpty` holds. */
|
|
58
|
+
readonly mint: () => TValue;
|
|
59
|
+
/** Persist the freshly minted value. */
|
|
60
|
+
readonly write: (value: TValue) => Promise<void>;
|
|
61
|
+
/** Value equality for the read-back. Defaults to `Object.is`. */
|
|
62
|
+
readonly equals?: (a: TValue, b: TValue) => boolean;
|
|
63
|
+
/** Always log this: a refusal means a feature is deliberately not starting. */
|
|
64
|
+
readonly onRefused: (detail: MintRefusalDetail) => void;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Resolve a mint-once secret/identity: reuse what is stored, or mint, persist
|
|
68
|
+
* and READ BACK — refusing the minted value when the read-back disagrees.
|
|
69
|
+
*
|
|
70
|
+
* A `refused` outcome is never cached by this function; the caller may retry on
|
|
71
|
+
* the next tick, when the store may be answering again.
|
|
72
|
+
*/
|
|
73
|
+
export declare function mintOnceWithReadBack<TValue>(input: MintOnceReadBackInput<TValue>): Promise<MintOnceOutcome<TValue>>;
|
|
@@ -345,6 +345,21 @@ export interface PipelineInferenceResultPayload {
|
|
|
345
345
|
* → delivery latency. Undefined when the frame carried no capture stamp.
|
|
346
346
|
*/
|
|
347
347
|
readonly capturedAt?: number;
|
|
348
|
+
/**
|
|
349
|
+
* Wall-clock (ms) read on the RUNNER's node at the instant this payload was
|
|
350
|
+
* handed to the bus. A consumer's `now - emittedAt` is the delivery lag —
|
|
351
|
+
* the one number that tells a late DELIVERY apart from a slow CONSUMER when
|
|
352
|
+
* both produce the same signature (a silence, then a burst-drain). See
|
|
353
|
+
* `addon-post-analysis/src/pipeline-analytics/frame-lag-observer.ts` for how
|
|
354
|
+
* it is read and why the absolute value is not a latency.
|
|
355
|
+
*
|
|
356
|
+
* Optional, and undefined is UNKNOWN, never 0 (D8): the bus is telemetry,
|
|
357
|
+
* and during a rolling deploy a runner older than this field emits payloads
|
|
358
|
+
* without it as the normal case. A consumer that folds an absent stamp in as
|
|
359
|
+
* 0 reports "delivered instantly" and fabricates exactly the verdict the
|
|
360
|
+
* field exists to establish.
|
|
361
|
+
*/
|
|
362
|
+
readonly emittedAt?: number;
|
|
348
363
|
/** Child steps enabled for this camera + their scheduling policy (from the catalog). */
|
|
349
364
|
readonly detailSteps?: readonly DetailStepAnnounce[];
|
|
350
365
|
readonly [key: string]: unknown;
|